Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .cursor-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"anti-slop"
],
"license": "PolyForm-Noncommercial-1.0.0",
"version": "5.5.0",
"version": "5.6.0",
"homepage": "https://github.com/agent-kit-startup/agent-kit",
"repository": "https://github.com/agent-kit-startup/agent-kit",
"logo": "dashboard/logo-marketplace.svg",
Expand Down
2 changes: 1 addition & 1 deletion .cursor/agent-kit.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"schemaVersion": 1,
"version": "5.5.0",
"version": "5.6.0",
"protected": [
".cursor/HANDOFF.md",
".cursor/agents/test-suites.md",
Expand Down
68 changes: 67 additions & 1 deletion .cursor/scripts/plan-external-review-model-routing.test.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import { readFileSync } from "node:fs";
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join, resolve } from "node:path";
import { test } from "node:test";
import { fileURLToPath } from "node:url";
Expand Down Expand Up @@ -29,6 +30,31 @@ ${body}
return spawnSync("bash", ["-c", bash], { encoding: "utf8" });
}

function extractVarAssignment(name) {
const out = spawnSync("grep", ["-m1", `^${name}=`, SCRIPT], { encoding: "utf8" });
assert.ok(out.stdout.trim().length > 0, `failed to extract ${name}`);
return out.stdout;
}

// Runs the real monitor_wants_advisor() from the script (plus its
// ADVISOR_ESCALATE_SENTINEL constant) against a scratch file, mirroring how
// maybe_run_advisor() gates the opus escalation.
function monitorWantsAdvisor(root, rel) {
const prelude = [
extractVarAssignment("ADVISOR_ESCALATE_SENTINEL"),
extractFn("monitor_wants_advisor"),
].join("\n");
const bash = `
set -euo pipefail
ROOT=${JSON.stringify(root)}
${prelude}
if monitor_wants_advisor ${JSON.stringify(rel)}; then echo yes; else echo no; fi
`;
const out = spawnSync("bash", ["-c", bash], { encoding: "utf8" });
assert.equal(out.status, 0, out.stderr);
return out.stdout.trim();
}

// Historical default at f27910a was Haiku; classifier-capable Sonnet is the post-amendment default.
test("launcher model routing: classifier-capable reviewer spawn, escalate sentinel, same-model refuse", () => {
assert.match(SRC, /--reviewer-model/);
Expand All @@ -43,6 +69,46 @@ test("launcher model routing: classifier-capable reviewer spawn, escalate sentin
assert.match(SRC, /This is not a silent self-review/);
});

test("monitor_wants_advisor: anchored to a standalone sentinel line, ignores prose/negated mentions", () => {
const dir = mkdtempSync(join(tmpdir(), "audits-advisor-sentinel-"));
try {
const proseFile = "prose-negated.md";
writeFileSync(
join(dir, proseFile),
[
"**To-do:** Opus advisor only when monitor marks `<!-- audits-advisor-escalate -->`.",
"Neither finding is high/critical severity; no `<!-- audits-advisor-escalate -->` needed.",
].join("\n"),
);
assert.equal(
monitorWantsAdvisor(dir, proseFile),
"no",
"inline/negated prose mention of the sentinel must not trigger escalation",
);

const genuineFile = "genuine-escalate.md";
writeFileSync(
join(dir, genuineFile),
["## Advisor", "", "<!-- audits-advisor-escalate -->", ""].join("\n"),
);
assert.equal(
monitorWantsAdvisor(dir, genuineFile),
"yes",
"a genuine standalone sentinel comment line must trigger escalation",
);

const indentedFile = "genuine-indented.md";
writeFileSync(join(dir, indentedFile), "text\n <!-- audits-advisor-escalate --> \nmore\n");
assert.equal(
monitorWantsAdvisor(dir, indentedFile),
"yes",
"surrounding whitespace on an otherwise-standalone sentinel line must still trigger escalation",
);
} finally {
rmSync(dir, { recursive: true, force: true });
}
});

test("normalize_model_family collapses vendor aliases", () => {
const out = runBash(`
echo "$(normalize_model_family "")"
Expand Down
6 changes: 5 additions & 1 deletion .cursor/scripts/plan-external-review.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1731,7 +1731,11 @@ exec_reviewer() {

monitor_wants_advisor() {
local rel="$1"
[[ -f "$ROOT/$rel" ]] && grep -qF "$ADVISOR_ESCALATE_SENTINEL" "$ROOT/$rel"
# Anchored: must be a standalone HTML-comment line (per the prompt template's
# "exactly one HTML comment line" contract), not just any substring/prose
# mention (including negations like "no ...advisor-escalate... needed").
local pattern="^[[:space:]]*${ADVISOR_ESCALATE_SENTINEL}[[:space:]]*$"
[[ -f "$ROOT/$rel" ]] && grep -qE "$pattern" "$ROOT/$rel"
}

build_advisor_prompt() {
Expand Down
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,10 @@ __pycache__/
# Landing build output — derived from the Claude Design export by
# `pnpm landing:build`; never edit by hand. See docs/agentkit-landing.md.
.cursor/context/landing-missionkit/dist/

# Landing promote/rollback release archives — timestamped zips of bytes that
# were actually deployed to missionkit.io, written by `pnpm landing:promote`
# / archived pre-promote for `pnpm landing:rollback`. Derived, potentially
# large (binary assets), and account-specific; not source. See
# docs/agentkit-landing.md and missionkit-staging-promote.plan.md.
.cursor/context/landing-missionkit/releases/
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,23 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and

## [Unreleased]

## [5.6.0] - 2026-08-24

### Added

- Mission Kit landing gains a **staging.missionkit.io hop before every production deploy**: `pnpm landing:deploy:staging` (per-file upload into a `staging/` subdomain directory, never the production root), `pnpm landing:verify:staging` (headless-Chrome acceptance gate, reused as `scripts/verify-landing.mjs --url <any URL>`), and a Phase-3 HITL gate (operator compares staging against the Claude Design canvas) before `pnpm landing:promote` re-deploys the *exact* staging-validated `dist/` bytes to `missionkit.io` — never rebuilding — with `pnpm landing:rollback [release]` restoring a prior archived production artifact in one command. New `scripts/lib/hostinger.mjs` reimplements the Hostinger REST calls the prior interactive-MCP deploy used, standalone (zero new dependencies). Staging noindex ships as a generated `staging/.htaccess` + `robots.txt`, not a `dist/` toggle, so promote's identical-bytes invariant can't accidentally noindex production. **Live-verified in production 2026-08-23**: staged, operator-approved, and promoted to `missionkit.io` for real, byte-identical DOM confirmed on both hosts. Plan `missionkit-staging-promote`.
- `scripts/build-landing.mjs` gains a **build-time changelog box injector**: it reads `CHANGELOG.md`'s latest public-facing (non-`[Unreleased]`) release entry and injects a plain-text (markdown decoration stripped, not converted — so truncation can never leak an unclosed token), HTML-escaped preview into a canvas-provided `<div data-changelog-content></div>` container. The container does not exist in the current Mission Kit Landing canvas export yet, so this step currently no-ops with a logged warning; it is the repo-side half of replacing the Footer CTA's terminal-typer animation with a real changelog box. Canvas-side change (plus the hero eyebrow → live Mission Kit release badge, scoped to the one authorized `img.shields.io` live-request exception) is a pending hand-off: `.cursor/context/landing-missionkit/UPSTREAM-DESIGN-FIX-PROMPT-badge-changelog.md`. Confirmed edit route (this account has no owned/shared write access to that canvas) and the scoped self-containment exception are recorded in ADR `2026-08-05_landing-external-design-source-of-record.md` (2026-08-22 addendum). Plan `landing-eyebrow-live-badge-and-changelog-box`.
- `registry/registry.json`'s L0 section is now **generated from code** (`packages/cli/src/lifecycle/l0.ts`'s `L0_ARTIFACTS`) on every `scripts/build-registry.mjs` run, instead of hand-curated — reviving the abandoned `archive/l0-generate-from-code` tag against the current pipeline. New `scripts/derive-l0-artifacts.ts` + `scripts/emit-l0-artifacts.mjs` (via `pnpm --filter @dadado/agent-kit-cli exec tsx`, since `tsx` isn't hoisted to the repo root). Verified idempotent (two consecutive rebuilds produce zero diff) and non-regressive on hand-curated L2 entries (`readCuratedArtifacts` narrowed to `layer === "L2"` only — L0 no longer needs preserving-by-hand). Closed two real drift gaps surfaced along the way: `dashboard-broadcast`/`update` commands added to `L0_ARTIFACTS` (existed on disk, were never declared), and `install.md`'s Port B table reconciled to match. `l0.test.ts` deliberately keeps its portable "legacy `onboard` absent" assert rather than a strict `registryL0Paths === canonicalSources` equality — private-repo parity is already enforced by CI's repo-gated "Registry catalog parity" step, and the public mirror independently owns `registry/**`, so a second unconditional test-level assert would reintroduce the public-CI break `errors/2026-07-24_public-sync-ci-test-portability.md` already paid down twice. Plan `l0-generate-from-code-revival`.
- Public storefront README gets the visual identity it never had: a shields badge row (npm version, PolyForm NC license, Node >=20, public Release Latest — no CI badge, the public mirror pipeline skips factory tests), a helmet hero (`dashboard/logo.svg`, visual-kit palette) plus the CLI's 9-line `HELMET_ASCII` as a monochrome fenced block, a curated 2×2 Mission Control screenshot gallery (`assets/production/*.png`, newly synced), and a GitHub social preview asset (`dashboard/social-preview.svg`/`.png`, 1280×640, helmet on the `#0b0e14` plate per the marketplace logo spec) with an apply checklist in `docs/github-about.md`. `packages/cli/README.md` (the actual npm storefront) gets minimal badge/hero parity. Plan `readme-public-hero-badges`.
- **DeepSeek Harness (`dsh`) modernization study**, docs-only: ADR `2026-08-22_deepseek-harness-reject-adapt-concepts-docs.md` ranks 12 deepseek-harness concepts against Agent Kit surfaces (`/run-plan` tick contract, Task worker dispatch, HITL Ask questions, memory-loop) — 6 reject, 4 already covered kit-native, 1 adapt-concepts (docs-awareness only: a durable per-step replayable event log is a real gap but stays unadopted to avoid a second state system alongside markdown HANDOFF/memory), 1 thin-adapter note (a second, unrelated ACP surface). No `dsh`/Cordis dependency, no plugin-composition runtime, no relaxation of sequential one-Task-per-plan dispatch. No incorporation/modernization work ships from this study; any uptake of the two non-reject items is deferred to a separately-scoped future plan. Plan `deepseek-harness-modernization-study` (Phase 0/1; Phase 2 is this changelog closeout).

### Fixed

- Audits `monitor_wants_advisor()` (`.cursor/scripts/plan-external-review.sh:1734`) used an unanchored `grep -qF` substring match on the `<!-- audits-advisor-escalate -->` sentinel, so any prose *mention* of it — including a negation like "no `<!-- audits-advisor-escalate -->` needed" — false-positived and re-spawned a costly Opus advisor pass on every future audit run touching that monitor. Now anchored to a standalone HTML-comment line (`grep -qE '^[[:space:]]*<!-- audits-advisor-escalate -->[[:space:]]*$'`), matching the prompt template's own "exactly one HTML comment line" contract. Verified against both known false positives (`plan-monitor-audits-atomic-wait-reviewer-fallback.md`, `plan-monitor-deepseek-harness-modernization-study.md:79`), which no longer match; a genuine standalone sentinel line still triggers escalation. Regression test added (`plan-external-review-model-routing.test.mjs`). Found by an Opus advisor pass during the 2026-08-22 `deepseek-harness-modernization-study` audit; done-marker suppression (Phase 2) considered and skipped as unsafe — see plan body. Plan `audits-advisor-escalate-sentinel-anchor-fix`.
- `scripts/deploy-landing-staging.mjs`'s DNS-record step raced Hostinger's own auto-provisioning: creating a new subdomain already auto-adds an `ALIAS` record for it, but the script immediately re-checked the zone and, seeing it not yet propagated, tried to add a conflicting `CNAME` — a real `HTTP 422` (`RRset ... IN ALIAS must not be used with CNAME on the same name`) on the first live production run. Now skips the explicit DNS step entirely when this run just created the subdomain; only checks/adds on the branch where the subdomain already existed. Found live 2026-08-23, plan `missionkit-staging-promote`.
- `check-public-deny-links.mjs` failed closed only on an explicit manifest `!exclude`; a README/docs link into a path the manifest never mentions at all (neither included nor excluded) passed silently and 404'd on the public mirror. Now checks `isPublicSyncedPath` directly, so "absent from the manifest" fails too. Also fixes two by-products of the stricter check rather than suppressing them: template `{placeholder}` interpolations (`isPlaceholderTarget`, matching the existing `check-markdown-links.mjs` convention) and a real folder link in a `.mdc` rule file whose trailing-slash target needs restoring before it matches the `git-hooks/**` glob. Broad Intake 2026-08-16 error finding, plan `readme-public-hero-badges`.
- `sync-public.mjs`'s content-denylist scan read every synced file via `readFileSync(path, "utf8")` and relied on a try/catch to skip binaries — but that read never throws on binary bytes in Node, so the intended binary exemption never actually applied. Latent since the manifest never included a binary file before; surfaced as a false positive (a private-client-name denylist term coincidentally present in a screenshot's compressed PNG bytes) the moment `assets/production/*.png` was added. Fixed with a real binary check (NUL byte in the first 8000 bytes, the same heuristic `git`/`grep -I` use) ahead of the UTF-8 decode + regex scan.

## [5.5.0] - 2026-08-22

### Added
Expand Down
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Mission Kit

[![npm version of @dadado/agent-kit-cli](https://img.shields.io/npm/v/%40dadado%2Fagent-kit-cli?label=npm&color=0C8DEB)](https://www.npmjs.com/package/@dadado/agent-kit-cli)
[![License: PolyForm Noncommercial 1.0.0](https://img.shields.io/badge/license-PolyForm--Noncommercial--1.0.0-blue)](LICENSE)
[![Node.js >=20](https://img.shields.io/badge/node-%3E%3D20-339933)](https://nodejs.org)
[![Latest release of the public agent-kit repository](https://img.shields.io/github/v/release/agent-kit-startup/agent-kit?label=release&color=00D0E7)](https://github.com/agent-kit-startup/agent-kit/releases/latest)

<p align="center">
<img src="dashboard/logo.svg" alt="Mission Kit helmet mark" width="190">
</p>

[Watch the demo on YouTube](https://www.youtube.com/watch?v=9mrAg6Mczfg) · [missionkit.io](https://missionkit.io)

**Development operations built into Cursor and VS Code.**
Expand Down Expand Up @@ -34,6 +43,21 @@ Long AI coding sessions fall apart when the context window fills up. Mission Kit

Deep dives: [getting started](docs/getting-started.md), [five-layer claim matrix](docs/five-layer-claim-matrix.md), [external plan review](docs/external-plan-review.md), [domain packs](docs/domain-packs.md), [personas](docs/personas-contract.md).

## Mission Control

A local dashboard over the same workspace state the CLI drives — current mission, checklist, crew activity, and the flight log.

<table>
<tr>
<td width="50%">![Mission Control Current mission panel](assets/production/1-mission-control-current-mission.png)</td>
<td width="50%">![Mission Control Checklist panel](assets/production/2-mission-control-check-list.png)</td>
</tr>
<tr>
<td width="50%">![Mission Control Crew Monitor panel](assets/production/3-mission-control-Crew-Monitor.png)</td>
<td width="50%">![Mission Control Flight Log panel](assets/production/4-mission-control-flight-log.png)</td>
</tr>
</table>

## Install

### In Cursor (recommended)
Expand All @@ -54,6 +78,20 @@ From your project root:
npx @dadado/agent-kit-cli install
```

The CLI welcome screen greets you with the same helmet, in ASCII:

```text
____
.-' '-.
/ .--. \
| / \ |
| | () | |
| \ / |
\ '--' /
'-.____.-'
/_/ \_\
```

Unpinned `npx` resolves to the latest publish. Pin when you need a reproducible install: `npx @dadado/agent-kit-cli@x.y.z install`.

That installs slash commands and a small set of rules into the project. Walkthrough: [docs/getting-started.md](docs/getting-started.md).
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added dashboard/social-preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions dashboard/social-preview.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading