@mstar-harness/opencode 2.1.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,19 @@ The monorepo root [CHANGELOG.md](../../CHANGELOG.md) summarizes cross-surface re
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [2.2.0] - 2026-08-13
10
+
11
+ ### Bundled harness skills (`harness-skills/` at publish)
12
+
13
+ - Added the **dsh host reference** to `mstar-host`: a detect-table row for dsh's `subagent` delegation tool and `references/dsh.md` (tool map, in-process gates/enforcement, bundled commands, PM dispatch, gotchas).
14
+ - **Sync upstream v2.1.1**: merged the upstream `mstar-harness` v2.1.1 line into the dev-dsh branch — adds the `code-reviewer` role (read-only L2 SDD task reviewer / audit executor; replaces `generalPurpose` as the SDD per-task review seat, with generic fallback only when the role agent is absent on the host), ships the canonical default-ignore harness `.gitignore` format (`.mstar/**` + tracked re-includes `AGENTS.md` / `knowledge/` / `specs/`) across the engine, CLI `init` fence and bundled skills, and aligns all 11 version surfaces to 2.1.1.
15
+ - **engine**: `emitGitignoreSnippet` / `validateGitignore` / `HARNESS_PROCESS_GITIGNORE` now emit the default-ignore + re-include format instead of the flat per-directory ignore list; `ROLE_MAPPING` grows to 14 ids with `code-reviewer`.
16
+ - **bundle-assets**: re-synced `packages/dsh/harness-skills` / `harness-commands` from the merged `skills/` tree — the 6+ upstream-touched bundled skills and all `mstar-host/references/*.md` host adapters (cursor/kimi/omp/opencode/zcode) now carry the v2.1.1 wording (SDD task reviewer → `code-reviewer`).
17
+
18
+ - Version alignment with harness **2.2.0** (no OpenCode package API change).
19
+
20
+ See root [CHANGELOG.md](../../CHANGELOG.md) **2.2.0**.
21
+
9
22
  ## [2.1.1] - 2026-08-12
10
23
 
11
24
  ### Harness
package/dist/mstar.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // ../engine/dist/engine.js
2
2
  import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
3
3
  import { mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync2, statSync } from "node:fs";
4
+ import { execFileSync } from "node:child_process";
4
5
  import { basename as basename2, dirname as dirname2, isAbsolute, join as join2, relative, resolve as resolve2 } from "node:path";
5
6
  import { existsSync as existsSync2, readFileSync as readFileSync3, readdirSync as readdirSync2 } from "node:fs";
6
7
  import { join as join4, resolve as resolve4 } from "node:path";
@@ -26,18 +27,45 @@ function resolveHarnessDir(startDir = process.cwd(), opts = {}) {
26
27
  const explicit = opts.harnessDir ?? process.env.MSTAR_HARNESS_DIR;
27
28
  if (explicit)
28
29
  return resolve2(start, explicit);
30
+ const boundary = resolve2(start, opts.workspaceRoot ?? defaultWorkspaceRoot(start));
29
31
  let dir = start;
30
32
  for (;; ) {
33
+ if (!isAtOrBelow(dir, boundary))
34
+ return null;
31
35
  for (const candidate of [join2(dir, ".mstar"), join2(dir, ".agents"), join2(dir, ".plans"), join2(dir, "plans")]) {
32
36
  if (isDirectory(candidate))
33
37
  return candidate;
34
38
  }
39
+ if (dir === boundary)
40
+ return null;
35
41
  const parent = dirname2(dir);
36
42
  if (parent === dir)
37
43
  return null;
38
44
  dir = parent;
39
45
  }
40
46
  }
47
+ function defaultWorkspaceRoot(startDir) {
48
+ try {
49
+ const cdup = execFileSync("git", ["rev-parse", "--show-cdup"], {
50
+ cwd: startDir,
51
+ encoding: "utf8",
52
+ stdio: ["ignore", "pipe", "ignore"]
53
+ }).trim();
54
+ if (!cdup)
55
+ return startDir;
56
+ let boundary = startDir;
57
+ for (const segment of cdup.split(/[\\/]/)) {
58
+ if (segment && segment !== ".")
59
+ boundary = dirname2(boundary);
60
+ }
61
+ return resolve2(boundary);
62
+ } catch {}
63
+ return startDir;
64
+ }
65
+ function isAtOrBelow(dir, root) {
66
+ const rel = relative(root, dir);
67
+ return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
68
+ }
41
69
  function resolveIterationDir(harnessDir) {
42
70
  return join2(resolve2(harnessDir), "iterations");
43
71
  }
@@ -2,6 +2,7 @@
2
2
  name: codebase-audit
3
3
  description: Survey a codebase as a senior advisor and produce prioritized, self-contained improvement plans. Read-only on source code. Use standalone before iteration-start to discover what's worth doing, or independently to build a prioritized backlog.
4
4
  agent: project-manager
5
+ input: "[no args]"
5
6
  ---
6
7
 
7
8
  # Audit Codebase
@@ -2,6 +2,7 @@
2
2
  name: iteration-drive
3
3
  description: Drive the active iteration to completion — Phase 2 Autonomous Execute, Phase 3 iteration-close, Phase 4 Create PR, Phase 5 PR merge-ready loop (prefer babysit/*-babysit; optional greploop when repo has it; else CI fallback) until mergeable. Not Done until Phase 5 exit checklist passes.
4
4
  agent: project-manager
5
+ input: "[no args]"
5
6
  ---
6
7
 
7
8
  # Drive Iteration
@@ -78,7 +79,7 @@ command -v mstar-harness >/dev/null 2>&1 && mstar-harness dispatch validate "<la
78
79
  if command -v mstar-harness >/dev/null 2>&1; then mstar-harness dispatch validate "<latest-assignment-file>" || exit 1; fi
79
80
  ```
80
81
 
81
- > 路径必须加引号且替换为具体文件(如最新 `{SDD_DIR}/task-N-brief.md`,勿留尖括号)——agent 代入的路径不得进入 shell 无引号展开(qc2 W-2)。
82
+ > 路径必须加引号且替换为具体文件(如最新 `{SDD_DIR}/task-N-brief.md`,勿留尖括号)——agent 代入的路径不得进入 shell 无引号展开。
82
83
 
83
84
  ## Phase 3: iteration-close
84
85
 
@@ -2,6 +2,7 @@
2
2
  name: iteration-loop
3
3
  description: "Autonomous full iteration loop for cloud agents — Phase 1 (code-first auto direction lock + compass/plans + Review & Edit chain) through Phase 2–5 (execute → close → PR → merge-ready). Optional args: direction, scale (S|M|L|XL, default M). Not Done until Phase 5 exit checklist passes. Minimal human intervention; no grill-me."
4
4
  agent: project-manager
5
+ input: "[direction] [scale]"
5
6
  ---
6
7
 
7
8
  # Iteration Loop
@@ -129,7 +130,7 @@ command -v mstar-harness >/dev/null 2>&1 && mstar-harness dispatch validate "<la
129
130
  if command -v mstar-harness >/dev/null 2>&1; then mstar-harness dispatch validate "<latest-assignment-file>" || exit 1; fi
130
131
  ```
131
132
 
132
- > 路径必须加引号且替换为具体文件(如最新 `{SDD_DIR}/task-N-brief.md`,勿留尖括号)——agent 代入的路径不得进入 shell 无引号展开(qc2 W-2)。
133
+ > 路径必须加引号且替换为具体文件(如最新 `{SDD_DIR}/task-N-brief.md`,勿留尖括号)——agent 代入的路径不得进入 shell 无引号展开。
133
134
 
134
135
  **Loop 特有**:Phase 5 push cadence(HARD)→ **`mstar-iteration` §5.1a**;exit checklist → **`mstar-iteration` §5.2**(`references/phase-4-5-pr-delivery.md` §5.2)。
135
136
 
@@ -2,6 +2,7 @@
2
2
  name: iteration-start
3
3
  description: "Start a new harness iteration — optional direction hint, research, grill-me, compass/plans, Review & Edit chain (long-lived {SPECS_DIR}/ + {ITERATION_DIR}/<id>/ package; compound promotes package at close only), PM lock, integration branch; then auto-continue Phase 2→5 (execute → close → PR → merge-ready) unless `pause` arg given."
4
4
  agent: project-manager
5
+ input: "[direction] [pause]"
5
6
  ---
6
7
 
7
8
  # Start Iteration
@@ -111,7 +112,7 @@ command -v mstar-harness >/dev/null 2>&1 && mstar-harness dispatch validate "<la
111
112
  if command -v mstar-harness >/dev/null 2>&1; then mstar-harness dispatch validate "<latest-assignment-file>" || exit 1; fi
112
113
  ```
113
114
 
114
- > 路径必须加引号且替换为具体文件(如最新 `{SDD_DIR}/task-N-brief.md`,勿留尖括号)——agent 代入的路径不得进入 shell 无引号展开(qc2 W-2)。
115
+ > 路径必须加引号且替换为具体文件(如最新 `{SDD_DIR}/task-N-brief.md`,勿留尖括号)——agent 代入的路径不得进入 shell 无引号展开。
115
116
 
116
117
  **Prepare gate (per plan in compass)**:
117
118
 
@@ -150,7 +150,7 @@ Default process artifacts (`plans/`, `iterations/`, `status.json`, `sdd/`, `note
150
150
  **Naming conventions (PM / ops; examples only — paths MUST be canonical absolute)**
151
151
 
152
152
  1. **Control worktree** — usually the primary checkout or a PM-designated path on `spec_integration_branch`; record once in `metadata.control_worktree_path`.
153
- 2. **Feature worktree (per plan)** — one distinct sibling directory per active `plan_id`, e.g. `<repo-parent>/worktrees/<plan-id>` or team `.worktrees/<plan-id>`; Assignment **`Worktree path`** must match lease `worktree_path`.
153
+ 2. **Feature worktree (per plan)** — one distinct subdirectory under the workspace root **`.worktrees/`** per active `plan_id` (e.g. `.worktrees/<plan-id>-<slug>`; AGENTS.md「Local scratch layout」), gitignored by the repo convention; Assignment **`Worktree path`** must match lease `worktree_path`.
154
154
  3. **L2 track worktrees (within-plan)** — additional distinct directories per parallel implement track under the **same** plan (see **`references/parallel-writable-pre-dispatch.md`**), each with its own PM-approved **`Working branch`**.
155
155
 
156
156
  > **Engine check (when available):** run `mstar worktree check <plan-id>` (L1) / `mstar worktree check --l2 --tracks <json>` (L2) (or `import { l1PreDispatchCheck, l2PreDispatchCheck, assertControlVsFeaturePath, assertBranchAlignment } from "@mstar-harness/engine"` in a host hook) to verify the L1/L2 isolation rules above (lease worktree ≠ control path; checked-out branch matches `Working branch`). On `fail` -> do not proceed; fix and re-run. Skill text below remains authoritative when the runtime is absent.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: mstar-host
3
- description: Morning Star host adapter (OpenCode, Cursor, Codex, Kimi, ZCode, omp). Use after mstar-harness-core whenever host entry, clarify, dispatch, or plan UX differs by platform - OpenCode question/task-tool subagent invoke, Cursor /pm and CreatePlan/SwitchMode dual-write and Task parallel QC, Codex plugin skills plus Plan/Goal Mode, Kimi Agent/AgentSwarm with built-in subagent types only (coder/explore/plan) and role-in-prompt binding, ZCode Agent/AskUserQuestion/EnterPlanMode with built-in subagent types and role-in-prompt binding, omp task/ask/hub preferring live-schema role agents (agents/*.md) with C5b skill-load binding (generic task/scout only as fallback), sandboxed tools, and tool discovery. Auto-detect host from session tools; then Read references/<host>.md. Always load after mstar-harness-core.
3
+ description: Morning Star host adapter (OpenCode, Cursor, Codex, Kimi, ZCode, omp, dsh). Use after mstar-harness-core whenever host entry, clarify, dispatch, or plan UX differs by platform - OpenCode question/task-tool subagent invoke, Cursor /pm and CreatePlan/SwitchMode dual-write and Task parallel QC, Codex plugin skills plus Plan/Goal Mode, Kimi Agent/AgentSwarm with built-in subagent types only (coder/explore/plan) and role-in-prompt binding, ZCode Agent/AskUserQuestion/EnterPlanMode with built-in subagent types and role-in-prompt binding, omp task/ask/hub preferring live-schema role agents (agents/*.md) with C5b skill-load binding (generic task/scout only as fallback), dsh (DeepSeek Harness) subagent tool with in-process engine gates and bundled mstar commands, sandboxed tools, and tool discovery. Auto-detect host from session tools; then Read references/<host>.md. Always load after mstar-harness-core.
4
4
  ---
5
5
 
6
6
  # Morning Star Host Adapter
@@ -30,12 +30,13 @@ Detect from **session tool shapes and available commands** — not from plugin m
30
30
  | **`subagent_type`** param on the Task tool (plus **CreatePlan**/**SwitchMode** when Plan mode is active) | `cursor` | `references/cursor.md`; Plan mode also `references/cursor-plan-mode-bridge.md` |
31
31
  | **`question`** tool, or **`task`** tool with **`subagent`** (singular) — no `tasks[]` batch | `opencode` | `references/opencode.md` |
32
32
  | **`task`** tool with **`agent`** / **`tasks[]`** batch, **`ask`**, **`hub`** (omp also exposes `/goal`; goal rule is host-agnostic per below) | `omp` | `references/omp.md`; Plan mode also `references/omp-plan-mode-bridge.md` |
33
+ | **`subagent`** tool (dsh's model-facing delegation tool — `@deepseek-ai/dsh-tool-subagent` default `toolName`) | `dsh` | `references/dsh.md` |
33
34
  | **`Agent`** / **`AskUserQuestion`** / **`EnterPlanMode`** + **`AgentSwarm`** (Kimi-only) | `kimi` | `references/kimi.md`; Plan mode also `references/kimi-plan-mode-bridge.md` |
34
35
  | **`Agent`** / **`AskUserQuestion`** / **`EnterPlanMode`** / **`TodoWrite`**, **no `AgentSwarm`** | `zcode` | `references/zcode.md`; Plan mode also `references/zcode-plan-mode-bridge.md` |
35
36
  | `/plan`, `/goal` slash commands; **Goal tools**; `functions.*` / `codex_app.*` tool namespaces; `tool_search`; Browser plugin tools | `codex` | `references/codex.md`; Plan mode also `references/_shared/plan-mode-bridge-core.md` |
36
- | Still ambiguous | - | Read sections in **`cursor.md`**, **`opencode.md`**, **`codex.md`**, **`kimi.md`**, **`zcode.md`**, and **`omp.md`** that match tools you have; **`mstar-harness-core` wins** on conflict |
37
+ | Still ambiguous | - | Read sections in **`cursor.md`**, **`opencode.md`**, **`codex.md`**, **`kimi.md`**, **`zcode.md`**, **`omp.md`**, and **`dsh.md`** that match tools you have; **`mstar-harness-core` wins** on conflict |
37
38
 
38
- Order matters: check `cursor` → `opencode` → `omp` → `kimi` → `zcode` → `codex`. `subagent_type` (Cursor) vs `subagent` (OpenCode) vs `agent`/`tasks[]` (omp) is the sharpest split among the Task-based hosts.
39
+ Order matters: check `cursor` → `opencode` → `omp` → `dsh` → `kimi` → `zcode` → `codex`. `subagent_type` (Cursor) vs `subagent` (OpenCode) vs `agent`/`tasks[]` (omp) is the sharpest split among the Task-based hosts; dsh's `subagent` tool collides with no other row, so it sits with the agent-tool hosts.
39
40
 
40
41
  > **Engine check (when available):** run `mstar host detect --signals <comma-list>` (or `import { detectHost } from "@mstar-harness/engine"` in a host hook) to resolve the detection table above from session tool shapes (prints the host id, or `ambiguous` to fall back on the table + judgment). On `fail` -> do not proceed; fix and re-run. Skill text below remains authoritative when the runtime is absent.
41
42
 
@@ -62,6 +63,7 @@ Docs name assets as skill **`<name>`** → `scripts/…` / `references/…`. **R
62
63
  | **Cursor** | Skill **name** via plugin skills | Global `~/.cursor/plugins/local/morning-star-harness/skills/<name>/`; project `.cursor/plugins/morning-star-harness/skills/<name>/` |
63
64
  | **Codex** | Skill **name** via plugin | Plugin-mounted `skills/<name>/`; project command skills under `.agents/skills/<name>/` |
64
65
  | **OpenCode** | Skill **name** via `@mstar-harness/opencode` | Package-internal `harness-skills/<name>/` — never `process.cwd()/skills/` |
66
+ | **dsh** | Skill **name** via the mstar skill-local provider (`providerName: mstar`) | `$DSH_BUNDLED_SKILL_DIR/<name>[/<rel>]` — the packaged `harness-skills/` mirror mounted package-relative by `@mstar-harness/dsh`; never app cwd |
65
67
  | **Kimi / ZCode** | Skill **name** / `/skill:<name>` | Plugin mount `./skills/<name>/` from the installed plugin root |
66
68
 
67
69
  Authoring convention: **`mstar-skill-authoring`** § Skill-relative script and asset paths. Per-host URI / mount detail: `references/<host>.md`.
@@ -0,0 +1,502 @@
1
+ # dsh host reference
2
+
3
+ Load when **`mstar-host`** detection resolves **dsh** (DeepSeek Harness — session
4
+ has the **`subagent`** model-facing delegation tool, the `@deepseek-ai/dsh`
5
+ cordis plugin stack; `@mstar-harness/dsh` mounted via the `web` profile bundle
6
+ or a custom profile).
7
+
8
+ ## dsh-only context
9
+
10
+ - Plugin markers: **`@mstar-harness/dsh`** (cordis function plugin) + the
11
+ **profile bundle** (`dsh.bundle.patch` manifest) installed into the `web`
12
+ profile via `dsh plugin --profile web add <spec>`. The composed app rows:
13
+ `@deepseek-ai/dsh-skill` (skill registry), `@deepseek-ai/dsh-tools` (tool
14
+ registry), `@deepseek-ai/dsh-commands` (command registry), then the `mstar`
15
+ row.
16
+ - Runtime skills: the plugin mounts the packaged **`harness-skills/`** mirror
17
+ (repo `skills/`, synced by `bundle-assets`) through the dsh skill-local
18
+ provider as a **single canonical mount** (`providerName: mstar`). Skills are
19
+ loadable by **name** via `ctx.skills`; the canonical skill-root form is
20
+ `$DSH_BUNDLED_SKILL_DIR/<name>[/<rel>]`.
21
+ - Plugin commands: the plugin registers the bundled **`harness-commands/`**
22
+ mirror as slash commands on `ctx.commands` — **`/iteration-start`**,
23
+ **`/iteration-drive`**, **`/iteration-loop`**, **`/codebase-audit`**. Each
24
+ command steers its command body into the receiving agent as a USER-source
25
+ message (the mstar workflow prompt — the model executes it as a task, not
26
+ injected context), returning a success result.
27
+ - **No `sessionStart.skill`** — enter PM manually via the `pm` skill (the
28
+ `mstar-roles` load path), then **Read next** → `mstar-harness-core` →
29
+ `project-manager.md`.
30
+ - Model-facing tools: the plugin registers **`mstar_sdd_workspace`**,
31
+ **`mstar_sdd_task_brief`**, **`mstar_iteration_gate`**, and the seam
32
+ validators **`mstar_design_md_validate`** / **`mstar_audit_validate`** /
33
+ **`mstar_compound_validate`** / **`mstar_roles_validate`** on `ctx.tools`.
34
+ - Web client plugin (workflow panel): the same `mstar` bundle row carries a
35
+ browser client half (`dsh.client` + `exports["./client"]`) discovered
36
+ automatically by `ClientModuleHostService` — no separate profile layer or
37
+ install step. It registers a **`conversation.view`** view-ring tab
38
+ (`id: 'mstar-workflow'`, `order: 20`) labeled **"MStar 工作流" / "MStar
39
+ Workflow"** rendering the latest `mstar-engine-status` catalog row as the
40
+ **MStar Workflow layout** — a right sidebar (plans ≤5 in time-desc order +
41
+ `+N more`, open residual findings ≤10 with severity chips + overflow hint,
42
+ policy with **enforcement first** then push / worktree / control worktree,
43
+ leases, knowledge, direction) over a bottom **fixed meta dock** (version +
44
+ harness dir; small muted, hairline-separated, does NOT scroll with the
45
+ sidebar digest — the former header row was removed), and an **HTML/CSS zone
46
+ dashboard** (the react-flow cyclic graph was removed in plan
47
+ `20260810-panel-canvas-zones`): the canvas fills the Tab (the page never
48
+ scrolls; the zone container is the only scroll body) with an **iteration
49
+ zone** (Step 1–5 stepper + `Step N/5` badge + active-highlight / inactive
50
+ dimmed state; the steps carry a FOUR-STATE machine — `current` / `next` /
51
+ `done` / `idle` (plan `20260812-panel-f5-iteration-zone-fix` Task 1): every
52
+ step BEFORE the current one projects `done`「已完成」(completed — a finished
53
+ Step 1 must not read as idle while Step 2 is current), `next` is the single
54
+ forward target, `idle` is schema-only + the branch panel — iteration base /
55
+ target / spec integration, rendered only while active; the expanded head is
56
+ a LEFT-RIGHT SPLIT — branches (small left half, WIDTH-CAPPED — `flex: 0 1
57
+ 260px` + `max-width: 280px`, never stretches with the container; the <860px
58
+ column stack resets to content height) + steps (large right half, `flex: 1 1
59
+ 0` absorbing the remaining width) via `data-iteration-head-split`, stacking
60
+ on narrow widths, and NO branch panel
61
+ when there is no active iteration; the current step follows the steering
62
+ compass: `compassStatus: 'active'` (Phase 1 in flight) → Step 1
63
+ (iteration-start) is CURRENT with verdict `unknown` — no PASS/FAIL badge,
64
+ plan `20260811-panel-f4-iteration-zone`; **the iteration info section is
65
+ SHARED by the tasks AND agents tabs** (plan
66
+ `20260812-panel-f5-design-system` Task 8, user round-4 decision #4 — one
67
+ `IterationInfoSection` component, both tabs render the same `view.iteration`
68
+ block: summary + steps + branches), a **tasks zone** (5-column
69
+ kanban: Todo / InProgress / InReview / Done / `blocked-unknown` — the
70
+ Blocked state and the former `unknown` catch-all fold into ONE merged
71
+ column titled「受阻/未知」/「Blocked / Unknown」, plan
72
+ `20260813-panel-quick-fixes` Task 1 — with count badges; every column
73
+ caps its rendered rows at `PLAN_CAP` and shows a clickable 「更多」/「收起」
74
+ expand button (`data-kanban-more` anchor) unfolding the full column — the
75
+ projection keeps ALL plan rows, the cap is a render concern never a
76
+ discard), an **agent-execution zone** (the FOUR EXPECTED_ROLE_FLOW stage/phase
77
+ columns — review-edit-chain → sdd-implement → qc-tri → qa-gate, the
78
+ terminal stage; the former `sdd-task-review` stage is removed and its SDD
79
+ L2 reviewer is now the PIPELINE role `code-reviewer` (v2.1.1, the former
80
+ `generalPurpose` seat) — a strict FOUR-column layout with NO standalone
81
+ unknown column (plan `20260812-panel-f5-design-system` Task 5, user
82
+ 2026-08-12 round-2 decision — the former rightmost UNKNOWN column of plan
83
+ `20260812-panel-f5-agent-layout` is superseded): the `general` bucket
84
+ sinks into an **unknown SUB-PARTITION at the bottom of the `qa-gate`
85
+ column** (a `data-sub-bucket="unknown"` caption row 「unknown / 未匹配角色」
86
+ after the last qa-gate card, then the general cards; the standalone
87
+ on-demand column was already removed in the agent-layout plan); `explore`
88
+ is removed — no card, no column. The columns are laid out in **TWO
89
+ side-by-side Phase groups** (plan `20260812-panel-f5-design-system` Task 8,
90
+ user round-4 decision #2; side-by-side layout per plan
91
+ `20260813-panel-agent-canvas-legend-layout` Task 2): the **Phase 1 group
92
+ on the LEFT** (review-edit-chain — the sequential Review & Edit chain:
93
+ product-manager → architect → writing-specialist) and the **Phase 2 group
94
+ on the RIGHT** (sdd-implement → qc-tri → qa-gate — the iterative plan
95
+ loop), top-aligned (all group label rows share the same `y = PAD_Y`), each
96
+ with its group label row; the **Phase-2 label annotates the CURRENT PLAN**
97
+ (projected `agents.activePlanId` = the first InProgress `state.plans[]`
98
+ row, `data-canvas-group-plan`; `+N more` when several plans run in
99
+ parallel, muted「无进行中 plan」when none). The `sdd-implement` column is split into SUB-BUCKETS by
100
+ the PROJECTED `entity.bucket` (never a render guess): the **implementor**
101
+ partition ABOVE — the flow roles in the stage's original order
102
+ (fullstack-dev / fullstack-dev-2 / frontend-dev), then the on-demand
103
+ roles (ops-engineer / prompt-engineer, carrying the **on-demand badge** —
104
+ the standalone on-demand column is gone) — and the **sdd-reviewer**
105
+ partition BELOW (code-reviewer, idle included), with the implementor /
106
+ sdd-reviewer caption labels; `zone: 'on-demand'` entities live in the
107
+ implementor partition, `zone: 'general'` entities render in the qa-gate
108
+ column's bottom unknown sub-partition. The subagent ENTITY cards aggregate **by role** from actual
109
+ dispatch evidence: the same role across sessions folds into one card ×N,
110
+ and every off-roster dispatch (the former `generalPurpose` SDD reviewer,
111
+ `scout`, anonymous `role === ''`) folds into the single `general` bucket
112
+ entity — the card is ROLE-TITLED (the role id, e.g. `fullstack-dev`); the
113
+ agent session id / task tag (`planId#taskId`) ride the RECORD line, never
114
+ the title. Cards show the role chip / status point / ×N count; running
115
+ entities carry the business glow-pulse
116
+ highlight, un-evidenced stages render the dashed "待执行" pending
117
+ placeholder with their expected role chips, un-evidenced KNOWN_AGENTS
118
+ members render dashed idle cards (the full 14-role roster is never
119
+ hidden), and the header shows the `N executing · M pending` summary.
120
+ Cards carry the projected **emphasis tier** (plan
121
+ `20260812-panel-f5-design-system` Task 4, design doc §3): `emphasis:
122
+ 'current' | 'next' | 'off' | null` — the iteration's current-phase roles
123
+ render at **100%** chrome intensity, later-phase expected roles at **75%**,
124
+ already-passed / stage-less (on-demand, general) roles at **45%**, and
125
+ `null` (no iteration / unresolved transition) applies NO override — always
126
+ a chrome **alpha mix** (`--mstar-canvas-emphasis-*` tokens; never a
127
+ whole-card `opacity`, so the status point + running glow stay opaque).
128
+ Settled entities get a **standalone GREEN done frame + green ✓** (plan
129
+ `20260812-panel-f5-design-system` Task 8, user round-4 decisions #1/#3:
130
+ `data-agent-done="true"` — a full-strength success border + 1px ring on
131
+ the rounded card body + the ✓ in the status point) **ONLY when
132
+ `emphasis ≠ 'off'`** — an off-tier role (already-passed / stage-less
133
+ on-demand + general) renders the muted dot instead and NEVER shows the
134
+ completion marker (the completed state never appears on a stage-less
135
+ role). The canvas filters to the CURRENT iteration only (plan
136
+ `20260813-panel-quick-fixes` Task 2): dispatch evidence projects for the
137
+ current iteration's plans — the steering compass `iterationId` when
138
+ active, else the nearest iteration derived from the catalog
139
+ `plans[].iterationRefs` (the most-recent plan's refs by 8-digit id date
140
+ prefix + doneAt); provably cross-iteration events produce no entity/edge
141
+ (the roster keeps its idle cards); plan-less / unknown-plan / standalone
142
+ dispatches are never hidden. Status honesty (Task 2): `advisory` is NO
143
+ LONGER terminal — a soft-enforcement dispatch falls through to its paired
144
+ settle (green ✓ when a settle exists, `running` when none) while `denied`
145
+ stays terminal; the advisory verdict still renders in the event log. The
146
+ canvas legend sits BELOW the viewport (Task 3 — moved from above, user
147
+ 2026-08-13 feedback).
148
+ Edges (plan `20260812-panel-f5-design-system` Task 5, design doc §2):
149
+ the `expected` stage skeleton arrows AND the ANIMATED **next** edge (the
150
+ former `@keyframes agent-dash-flow` dash-flow arrow of plan
151
+ `20260810-panel-agent-flow-zone`) are **REMOVED** — flow order is implied
152
+ by the fixed column order + column labels, the current position by the
153
+ running card glow + status point — leaving TWO semantic kinds: the
154
+ evidence-driven **`actual` handoff** edges (same-plan ts-adjacent dispatch
155
+ entity-key pairs, `general` endpoints filtered, ≤1 per entity pair) drawn
156
+ as **bezier `C` curves** anchored to card **PORTS** — 4 fixed
157
+ edge-midpoint ports (north / south / east / west; static-invisible,
158
+ hover-revealed as small dots) with the arrow tip pulled back to a **10px
159
+ standoff** off the port — the arrow follows the line's local tangent at
160
+ the anchor (**H1**), and no line's stroke or arrow crosses any text
161
+ (**H2**: standoff + side-gap routing, design doc §2.0/§2.5/§2.6;
162
+ tightened in plan `20260813-panel-quick-fixes` Task 3 — same-column
163
+ vertical flows whose center-x line would cross an in-between card body
164
+ (e.g. fullstack-dev → frontend-dev skipping an idle fullstack-dev-2)
165
+ reroute into the column's LEFT side gap, forward AND reverse, and reverse
166
+ horizontal beziers keep direction-aware control points BETWEEN the
167
+ endpoints so they never bulge into the adjacent column) — plus
168
+ the **bidirectional supervise line** (plan `20260812-panel-f5-agent-layout`
169
+ Task 1/2) — ONE static design-knowledge sub-bucket edge inside the
170
+ `sdd-implement` column (implementor ↔ sdd-reviewer — the mstar-sdd
171
+ mutual-supervision contract), now anchored at the **side-gap vertical
172
+ anchor** (`x = card right edge + 18px`, vertical bezier flow, arrows along
173
+ the vertical tangent — design doc §2.5/§2.7); dim dashed by default, lit
174
+ business SOLID when the projected `evidenced` flag is true —
175
+ evidence-driven lighting, never a fabricated activation); the 事件记录 tab
176
+ (`EventLogPage`, spec panel-tabs §5, plan `20260811-panel-event-log`) is a
177
+ NON-canvas log page with two partitions — **Agent 流转事件** (`view.events`
178
+ ≤50 latest-first; off-pipeline unexpected dispatches fold in once via
179
+ `expected: false` and carry a dispatch-only 「未匹配角色」 badge — settle
180
+ rows are completion records and never flag as unexpected) and **违规记录**
181
+ (`view.violations`, gate violations with severity/code/message); every row
182
+ is an expandable native `<details>` (no-JS, keyboard-accessible) whose body
183
+ shows the full catalog fields — missing fields render「—」, never a guessed
184
+ value. Layout (plan `20260811-panel-f3-agent-general`): the two partitions
185
+ render SIDE BY SIDE in a locked-height two-column grid
186
+ (`repeat(2, minmax(0, 1fr))` — the page never scrolls as a whole; each
187
+ partition pins its title and owns an internal `overflow-y` scroll on its
188
+ row list; plan `20260813-panel-quick-fixes` Task 4 root-caused the
189
+ whole-page scroll — the panel root opts into the host
190
+ `data-conversation-composer-overlay` (the host's documented full-height
191
+ opt-in), so the host `.viewArea` becomes a definite-height container and
192
+ `height:100%` resolves: `.rowList`'s `overflow-y: auto` now scrolls
193
+ INSIDE the partition and the host page no longer scrolls, with bottom
194
+ clearance reserving the floating composer via the host-published
195
+ `--dsh-composer-height`), falling back to two stacked 50/50 locked rows
196
+ below 1200px —
197
+ the `data-event-log-*` anchor family is unchanged. The canvas-corner **`AgentEventDock`** is REMOVED with the page
198
+ (无双份日志 — its row layout + status chips migrated into `EventLogPage`);
199
+ the fixed footer bar (zone legend + gate summary + violations) died with
200
+ the WorkflowCanvas in plan `20260811-panel-tabs-shell` — the footer that
201
+ remains is the freshness marker. Empty branches (spec §2 — plan
202
+ `20260812-panel-f5-agent-layout` Task 3): waiting keeps the muted hint,
203
+ and NO harness renders a **CENTERED inactive-state card** (folder icon +
204
+ 「No Morning Star harness detected」 title + the hint copy — the detail
205
+ panel stays inactive, no tabs / no sidebar, activating automatically once
206
+ a harness is detected; the `data-mstar-empty="no-harness"` anchor stays on
207
+ the title, `data-mstar-graph` on the main container). Below 1200px
208
+ the zones stack vertically. Pure `projectGraph` projection (never throws,
209
+ explicit degraded states — muted empty states, never orange warn boxes).
210
+ The branches block left the sidebar in plan `20260810-panel-sidebar-info`
211
+ (its anchor fields stay in the catalog source; the iteration zone renders
212
+ them via plan `20260810-panel-canvas-zones`); refresh follows the session
213
+ snapshot, no polling — while the main agent is ACTIVELY orchestrating, a
214
+ ledger record (dispatch/settle) invalidates the workspace's TTL-cached
215
+ catalog row so the next pre-step rebuilds and (digest text change)
216
+ re-injects it, and the panel refreshes per step (seconds, not the 60 s TTL);
217
+ while the main agent IDLES (waiting, no tool calls) the panel keeps the
218
+ LAST snapshot — no live push channel (documented limit, plan
219
+ `20260811-panel-f4-timeliness`). Bundle served at
220
+ `/plugins/@mstar-harness/dsh/client.js` (closure-factory CJS with NO graph
221
+ library inlined — react-flow removed; the build asserts the bundle contains
222
+ no `xyflow`/`reactflow` markers, no `@deepseek-ai/*` value imports, and no
223
+ `import.meta` / ESM statements — the loader runs plugin bundles as classic
224
+ scripts). **Known limitations**: the stepper's Step 1 (iteration-start) IS
225
+ the current step while the steering compass is `status: active` (Phase 1 in
226
+ flight — catalog `compassStatus` field), carrying NO PASS/FAIL badge (Phase
227
+ 1 has no gate verdict); Step 5 (merge-ready) can never be the CURRENT step —
228
+ the engine phase gate only evaluates Phase 2→3→4 (merge-ready is never a gate
229
+ transition); it renders `next` only while Step 4 (pr-delivery) is current,
230
+ idle otherwise;
231
+ the current step follows the TTL-refreshed `compassStatus` — up to one
232
+ catalog interval (60 s) behind a mid-session `active`→`locked` flip (bounded,
233
+ documented staleness, never a wrong verdict); the agent-entity
234
+ status derivation pairs a PAIRED settle exactly by its dispatch identity
235
+ (`agent`, `role`, `planId`, `taskId` — under QC-tri N=3 concurrency each
236
+ settle lands on ITS dispatch), and an unpaired dispatch stays `running`
237
+ (no paired settle — never guessed, never faked); the current-iteration
238
+ filter with NO steering compass infers the iteration from plan ids
239
+ (8-digit date prefix) + doneAt — deterministic, documented heuristic, and
240
+ only provably cross-iteration events are dropped; no historical back-scan of
241
+ resumed long logs; no custom
242
+ top-level slot (the `conversation.view` tab is the only session-level panel
243
+ seat without dsh-private layout changes); no-session → shell hero
244
+ (strict-session view ring). Panel acceptance is dual-track: in-loop browser
245
+ harness verification (agent-browser/CDP against the rebuilt bundle,
246
+ iteration guides record the verified runs) plus user-restart final GUI
247
+ acceptance.
248
+
249
+ ## Skill loading
250
+
251
+ 1. On entry: invoke **`pm`** (skill name via the mstar provider) → **Read
252
+ next** loads `mstar-harness-core`, then `mstar-roles` →
253
+ `project-manager.md` when PM is active.
254
+ 2. Read `mstar-host` and this dsh reference.
255
+ 3. Load `mstar-roles` and the active role reference.
256
+ 4. Load topic skills on demand per the role reference (skill **names** —
257
+ never app-cwd `skills/<name>/…`).
258
+
259
+ ## Tools map
260
+
261
+ | dsh tool | Harness use |
262
+ |----------|-------------|
263
+ | **`subagent`** | Primary dispatch — the model-facing delegation tool the dispatch gate matches (default `toolName`; a renamed instance must be declared via Config `dispatchTools`) |
264
+ | **`mstar_iteration_gate`** | Evaluate the iteration phase gate in-app (`evaluatePhaseGate` — `mstar iteration gate` parity) |
265
+ | **`mstar_sdd_workspace`** / **`mstar_sdd_task_brief`** | SDD workspace resolve + task brief extraction (`mstar sdd …` parity) |
266
+ | **`mstar_*_validate`** | On-demand seam validators (design-md / audit / compound / roles) |
267
+ | **bash / read / write / edit / grep / glob / web_search** | Standard agent tools — evidence per `mstar-coding-behavior` |
268
+
269
+ ### `subagent` dispatch shape
270
+
271
+ The dsh `subagent` tool is the delegation channel (schema rendered by
272
+ `@deepseek-ai/dsh-tool-subagent`; `provider`-bound, default toolName
273
+ `subagent`). Dispatch an Assignment the same way as other agent-tool hosts:
274
+ the dispatch gate validates the **Assignment header region** (`## Assignment`
275
+ + `**Execute as**` / `**Delegation**` / `**Task category**` / `**Working
276
+ branch**` / `**Branch policy**` fields — engine `composeDispatchGate`, same
277
+ violation codes as opencode/omp/CLI).
278
+
279
+ Envelope-first discipline applies: put the header fields at the top of the
280
+ Assignment body — the dsh dispatch gate reads only the header region, so
281
+ body-quoted examples never leak into header fields.
282
+
283
+ ## Gates and enforcement
284
+
285
+ The plugin wires the engine gates on dsh seams (all in-process):
286
+
287
+ | Gate | Seam | Hard-mode channel |
288
+ |------|------|-------------------|
289
+ | Status gate | `fs/write-intent` + `fs/edit-intent` on `{HARNESS_DIR}/status.json` | repair-escape advisory (never vetoes the repairing write) |
290
+ | Dispatch gate | `tools/pre-execute` on the `subagent` tool | `PreToolDecision { kind: 'deny', reason }` |
291
+ | Lease gate | inside the dispatch gate (SDD / InProgress dispatches) | deny under hard |
292
+ | Worktree L1/L2 | inside the dispatch gate | deny under hard |
293
+ | Skill-authoring lint | `fs/write-intent` on `SKILL.md` under mounted roots | repair-escape advisory |
294
+ | Seam lints | `fs/write-intent` on DESIGN.md / audit / compound / roles | repair-escape advisory |
295
+
296
+ **Enforcement semantics**: warn-only by default. `Enforcement: hard` —
297
+ resolved from the plugin Config (`enforcement: hard`), the Assignment header
298
+ flag, or the iteration compass frontmatter — escalates dispatch violations to
299
+ a real veto; status/skill-lint writes are never hard-vetoed because the intent
300
+ waterfall is content-blind (an already-invalid document is allowed as a
301
+ repair escape). Config `soft` is the only local rollback. Hard gates are never
302
+ a global default.
303
+
304
+ Every composed agent step carries ONE **`<mstar_engine_status>`** catalog
305
+ message: the watermark (unified mstar version, harness dir, enforcement),
306
+ the iteration phase-gate section when a steering compass resolved, and the
307
+ workspace-state digest section (plan registry, open residuals,
308
+ branch/policy anchors, active leases, knowledge digest, compass direction)
309
+ when the workspace has a `status.json`. The row is digest-gated (once per
310
+ turn, re-injected only when it changed) over one per-workspace TTL-cached
311
+ build (`catalogTtlMs`, default 60 s).
312
+
313
+ ## Agent-flow ledger
314
+
315
+ The plugin records ACTUAL subagent dispatch and real-completion settle events —
316
+ the evidence of what really happened, distinct from the client-side expected
317
+ role flow. The workflow panel's agent-execution zone (the stage/entity
318
+ projection — plan `20260810-panel-agent-flow-zone`) and the 事件记录 tab's
319
+ `EventLogPage` log page (plan `20260811-panel-event-log`) are pure consumers
320
+ of this evidence.
321
+
322
+ - **Recording point (one core)**: `DshHostAdapter.dispatchGate` is the SINGLE
323
+ record path behind both dispatch surfaces — the `tools/pre-execute` listener
324
+ (exec-bound; the lease gate joins here) and the host `beforeDispatch` hook
325
+ (exec-less). Every Assignment-shaped dispatch that reaches the gate records,
326
+ including hard denies (verdict derived: ok / advisory / denied); the shape
327
+ guard lives at the shared core, so non-Assignment text stays silent on BOTH
328
+ surfaces (the listener's own guard plus the core's guard for the exec-less
329
+ hook path — no phantom records). Recording is advisory (try/catch-contained,
330
+ logs only `mstar/agent-flow`) — a failing ledger never blocks dispatch.
331
+ Known tradeoff: the same logical dispatch crossing BOTH surfaces (a host
332
+ `beforeDispatch` followed by the identical text as an in-loop subagent tool
333
+ call) records two dispatch events — the surfaces are mutually exclusive by
334
+ design; the double record is documented, not deduplicated.
335
+ - **File / bounds**: events append to `{HARNESS_DIR}/agent-flow.jsonl` (JSON
336
+ Lines, one event per line; harness dirs are gitignored by convention). The
337
+ ledger assumes ONE dsh process writes each harness dir (single-writer):
338
+ concurrent dsh sessions on the same repo can lose events (the append itself
339
+ is near-atomic O_APPEND, but truncation is a read-modify-write) — the loss
340
+ only under-reports actual flow in the panel, never a gate impact. After each
341
+ append the file truncates to the most recent **500** events; truncation is
342
+ size-gated (≈500 lines' typical size — small files stay append-only) and
343
+ performed as an atomic temp-file rename. The catalog read returns the
344
+ latest-first view with a default window of **50** and a role × outcome
345
+ summary. A MISSING file reads as the empty view ("no actual dispatches yet"
346
+ — recording starts at plan merge); an unreadable file is absent evidence;
347
+ malformed lines are skipped, never fatal.
348
+ - **Settle = real completion pairing, never faked** (plan
349
+ `20260811-panel-f4-timeliness`): `tools/post-execute` IS part of the
350
+ verified dsh-tools registry surface (`runPostExecute` dispatches the
351
+ waterfall for every tool call — verified against the upstream source and
352
+ pinned by a real-call probe). The pairing listener matches dispatch TOOLS
353
+ (Config `dispatchTools`, default `['subagent']`), looks up the exec's
354
+ `callId` in the apply-scoped pairing store, and branches on the verified
355
+ result shapes:
356
+ - `{ kind: 'background', taskId }` → store `taskId → dispatchRef`; the REAL
357
+ settle arrives via `ctx.tasks.onTaskDone` (terminal mapping
358
+ completed → ok / killed → denied / failed → error, `durationMs` when
359
+ available), wired through `ctx.inject(['tasks'])`.
360
+ - `{ kind: 'continuable', subagentId }` → no terminal signal this round →
361
+ no settle (documented limit — the child owns its turns).
362
+ - any other successful value (foreground included) → settle `ok`; a failed
363
+ result (`isError`) → settle `error`.
364
+ Pairing is apply-scoped (in-memory `callId → dispatchRef` /
365
+ `taskId → dispatchRef` maps created in the entry `apply`; an HMR restart
366
+ resets them, and completions outside the window stay unpaired). Every
367
+ PAIRED settle carries the paired dispatch's identity (`role`/`planId`/
368
+ `taskId` — same field names + semantics as the dispatch event; the registry
369
+ background-task id is never written as `taskId`, `taskRef` is reserved for
370
+ it). Unpaired payloads (non-dispatch tools, calls outside the pairing
371
+ window) record NOTHING — the ledger stays dispatch-only, never a
372
+ fabricated settle.
373
+ - **Catalog**: `state.agentFlow` carries the ledger view (`events` ≤ 50,
374
+ latest-first, + `summary`); the model-facing `<mstar_engine_status>` text
375
+ renders ONE compact `agent flow: …` line only when events > 0 (role totals
376
+ top-5 + latest dispatch with HH:MM — the event detail lives in the
377
+ structured source, never the model text). A ledger record (dispatch/settle)
378
+ invalidates the affected workspace's TTL cache entry IMMEDIATELY
379
+ (apply-scoped `harnessDir → cache key` reverse map + invalidation closure,
380
+ plan `20260811-panel-f4-timeliness`) → the next pre-step rebuilds and (digest
381
+ text change) re-injects the row — the 60 s TTL no longer bounds
382
+ ledger-change latency; it still bounds non-ledger staleness.
383
+ - **Maintainer view**: change the ledger shape (event schema, bounds, settle
384
+ seam) and update the projections together — `gates/agent-flow.ts` (record /
385
+ read / settle listener), `gates/catalog.ts` (agent-flow line + `source`
386
+ view) and `client/panel/graph/project-graph.ts` (the ZoneView flow/agents
387
+ projection) — the panel renders ONLY what the evidence shows.
388
+
389
+ ## PM dispatch
390
+
391
+ Harness **dispatch** on dsh = a `subagent` tool call with the full Assignment
392
+ text (role binding in the prompt — `Execute as` / `Act as` + skill load;
393
+ there is no separate `agent` field, the Assignment body IS the prompt). **N
394
+ assignees = N `subagent` calls = N independent delegations** (dispatch-gate
395
+ 口径: one assistant message carries all N invokes — the gate counts each
396
+ dispatched Assignment). Paste-only Assignment without an invoke is **not**
397
+ dispatch.
398
+
399
+ **Execution: concurrent dispatch REQUIRES background mode.** The `subagent`
400
+ tool does **not** declare `isConcurrencySafe` → fail-closed `exclusive`
401
+ classification, so same-message invokes are issued one-at-a-time (the next
402
+ invoke starts only after the previous one settles). Foreground invokes (no
403
+ `run_in_background`) settle only when the child completes → end-to-end serial
404
+ (wall ≈ N× single seat). **Therefore any N≥2 dispatch that needs parallel
405
+ execution MUST set `run_in_background: true` on EVERY invoke of the batch**:
406
+ background invokes settle at task start (task id returned) and their child
407
+ agents run CONCURRENTLY in background tasks (wall ≈ single seat, not N×).
408
+ Foreground N≥2 invokes run SERIALLY and do NOT satisfy an N-parallel
409
+ requirement — emitting them as "the dispatch" is dispatch-incomplete; if the N
410
+ background invokes cannot be emitted in one message → **`Blocked`** (same as
411
+ paste-only). **Future path (upstream suggestion, not editable from this
412
+ repo):** dsh-private declares `isConcurrencySafe: () => true` on the
413
+ tool-subagent so same-message foreground invokes can also run concurrently —
414
+ needs dsh maintainer evaluation (roadmap §7e).
415
+
416
+ **Leaf completion discipline — closing message, not the report tool (PM
417
+ 2026-08-12).** Leaf subagents hand back their Completion Report in the
418
+ **final (closing) message** — do NOT call the `report` tool to deliver it.
419
+ The dsh tool-subagent-report default `reportDelivery: quiet` routes a report
420
+ through `parent.inject` into the parent's **next-step queue**; when the
421
+ parent's turn has ended (no step boundary follows), the report strands in
422
+ the "queued messages" dock instead of reaching the parent (observed on dsh).
423
+ The closing message is the guaranteed delivery channel; reserve `report` for
424
+ MID-turn findings that change what the parent should do next.
425
+
426
+ ### QC default
427
+
428
+ - **`Execution mode: sdd`**: **N=3** `subagent` dispatches — one per QC seat
429
+ (`qc-specialist`, `qc-specialist-2`, `qc-specialist-3`), each body **Act as**
430
+ the respective QC role + QC skill load. **MUST dispatch all three with
431
+ `run_in_background: true` in one message** → the seats run CONCURRENTLY
432
+ (background children; wall ≈ single seat); foreground (no
433
+ `run_in_background`) runs serially (wall ≈ 3× single seat) and does NOT
434
+ count as parallel tri. Cannot emit required **N** → **`Blocked`**.
435
+ - **`inline`**: **N=1**.
436
+
437
+ ### SDD implement (serial)
438
+
439
+ - **`Execution mode: sdd`**: one implementer `subagent` dispatch per task id;
440
+ task reviewer = a separate dispatch (SDD review role) — no sticky resume
441
+ unless the host's continuable-subagent id is available and recorded.
442
+
443
+ ## Commands and skills paths
444
+
445
+ | Surface | Path / invocation |
446
+ |---------|-------------------|
447
+ | Plugin skills | Skill **name** via the mstar skill-local provider (`ctx.skills`); canonical `$DSH_BUNDLED_SKILL_DIR/<name>` |
448
+ | Plugin commands | `/iteration-start`, `/iteration-drive`, `/iteration-loop`, `/codebase-audit` (registered from `harness-commands/`) |
449
+ | Session entry | `pm` skill → `mstar-harness-core` via pm **Read next** |
450
+
451
+ ## Command delivery (dsh host, updated 2026-08-11)
452
+
453
+ The dsh web client resolves slash commands against a client-side lexicon driven by the registry's `input.hint`. Every mstar command declares a frontmatter `input` hint (see `commands/*.md`), so the client **claims** it on menu pick: `/name ` is inserted into the composer with the command highlight and the hint as ghost text (e.g. `/iteration-start [direction] [pause]`), the user types follow-up args (or just presses Enter for arg-less commands), and the line submits only on Enter. The handler steers the command body into the receiving agent as a USER-source message, appending the typed args as a `## User input` section when present.
454
+
455
+ **Degradation fallback:** when a command is NOT claimed client-side (lexicon fetch timing, args parsing, manual typing), the model receives the **bare text** (`/iteration-loop <方向> …`) with NO command body — unlike opencode/cursor/omp where the body always arrives.
456
+
457
+ **Rule:** when a user message begins with a registered mstar command name (`/iteration-start`, `/iteration-drive`, `/iteration-loop`, `/codebase-audit`) but carries no command body, treat it as that command invoked with the user text as its argument — execute the command's OWN semantics from the repo `commands/<name>.md` (or the mirrored `harness-commands/`): in particular **`/iteration-loop` = autonomous (code-first direction lock, NO grill-me questions)**, `/iteration-drive` = Phase 2–5 on the active iteration, `/iteration-start` = interactive (grill-me). Do not silently substitute the interactive start flow for `/iteration-loop`. Also do not re-ask what the command already specifies (e.g. scale auto → M default, branch policy continuity).
458
+
459
+ ## Harness dir and environment
460
+
461
+ - `{HARNESS_DIR}` resolves via the engine `resolveHarnessDir` (`.mstar/` →
462
+ `.agents/` → `.plans/`/`plans/`), with the plugin Config `harnessDir`
463
+ override winning. The probe starts from the SESSION workspace root (the
464
+ session cwd — **never the dsh launch/process cwd**) and **STOPS there** — it
465
+ never walks above the session workspace, so the watermark and gates follow
466
+ the workspace the session actually works in. Repos using a
467
+ non-standard harness root (e.g. `.harness/`) MUST set Config `harnessDir`
468
+ (absolute path) — the gates are inert without a resolvable harness dir.
469
+ - The dispatch gate needs the dispatching agent's own role for the
470
+ anti-recursion precheck: declare it via Config **`dispatchBinding`** (dsh
471
+ exposes no per-agent role on the tool-execution context). Under hard
472
+ enforcement with no binding, the plugin logs the absence.
473
+
474
+ ## Files, shell, and approvals
475
+
476
+ - Prefer host search/edit tools over shell find/sed when available.
477
+ - Respect dsh approval prompts for destructive operations.
478
+ - Do not edit `$DSH_HOME` credentials or user secrets without explicit consent.
479
+
480
+ ## Git and final evidence
481
+
482
+ - Git work follows `mstar-branch-worktree` and Assignment **Working branch** /
483
+ **Branch policy**; the worktree L1/L2 gates run in-process.
484
+ - Completion reports cite concrete commands, artifacts, and commit lines when
485
+ required.
486
+
487
+ ## Gotchas
488
+
489
+ - Do not confuse dsh **`subagent`** with opencode **`task_subagent`** or Cursor
490
+ **`subagent_type`** — the detect rows differ by tool shape.
491
+ - A renamed `subagent` tool (Config `toolName`) silently disables the dispatch
492
+ gate AND host detection unless `dispatchTools` declares the new name (the
493
+ plugin warns under hard enforcement).
494
+ - Role binding is prompt-only on dsh: always include **`Execute as`** +
495
+ **`Act as`** + skill load in the Assignment body — there is no separate
496
+ `agent` field.
497
+ - Session plan UI / todos are not durable SSOT unless mirrored to
498
+ `{HARNESS_DIR}`.
499
+ - The plugin's bundled skills/commands mirror is synced by `bundle-assets`
500
+ (gitignored, package-local) — an explicit `bundledSkillDir` /
501
+ `skillRoots` Config override wins when a deployment wants a different
502
+ mirror.
@@ -45,7 +45,7 @@ Phase 5: PR merge-ready loop —— 至 mergeable + CI 全绿 + reviews resolved
45
45
  | **→ 迭代交付完成** | §5.5 exit checklist 全 `[x]` | PR mergeable;required CI 全绿;reviews resolved | Phase 4 开 PR 即宣称完成 |
46
46
  | **iteration-start → integration branch** | §1.6 Review & Edit chain | 三角色按序 invoke;**specs** 为主产出;**禁止** start 链向 `{KNOWLEDGE_DIR}/` 新增;writing-specialist corpus hygiene + compass `status: locked` | PM 代做专业编辑;并行三角色;product/architect 写 knowledge;临时笔记进 specs |
47
47
 
48
- > **Engine check (when available):** run `mstar iteration gate --status <status.json> --compass <delivery-compass.md>` (or `import { evaluatePhaseGate } from "@mstar-harness/engine"` in a host hook) to evaluate the transition gate above. On `fail` (gate-blocking violations) -> do not proceed; fix and re-run. Note: during the Phase-3 window (`transition: phase-3-close`) the gate exits 1 until the §3.4 close items (`status: completed` + `end_date`) are written — that exit-1 is the expected "close work pending" signal (the exit checklist gates Phase 4, not the Phase-3 entry; qc2 F-003), so proceed with Phase 3 per the table below. Skill text below remains authoritative when the runtime is absent.
48
+ > **Engine check (when available):** run `mstar iteration gate --status <status.json> --compass <delivery-compass.md>` (or `import { evaluatePhaseGate } from "@mstar-harness/engine"` in a host hook) to evaluate the transition gate above. On `fail` (gate-blocking violations) -> do not proceed; fix and re-run. Note: during the Phase-3 window (`transition: phase-3-close`) the gate exits 1 until the §3.4 close items (`status: completed` + `end_date`) are written — that exit-1 is the expected "close work pending" signal (the exit checklist gates Phase 4, not the Phase-3 entry), so proceed with Phase 3 per the table below. Skill text below remains authoritative when the runtime is absent.
49
49
 
50
50
  **误判信号**:对话里出现 compound 摘要、roadmap 更新、或「所有 plan 已完成」但 **未** 打印 §3.1 / §3.5 checklist → 视为 **Phase 3 未执行**,回到 §3.0。
51
51
 
@@ -1,10 +1,9 @@
1
1
  # Phase 2 control worktree + execution lease
2
2
 
3
- Normative field names and claim/release/merge semantics → maintenance ADR
4
- `.harness/docs/2026-07-22-iteration-worktree-plan-lease.md` (this repo) or
5
- `mstar-plan-artifacts/references/status-and-residuals.md` (runtime SSOT after
6
- plan-artifacts sync). This reference is the **iteration-command execution
7
- checklist**; do not invent alternate lease field names.
3
+ Normative field names and claim/release/merge semantics → runtime SSOT
4
+ `mstar-plan-artifacts/references/status-and-residuals.md`. This reference is
5
+ the **iteration-command execution checklist**; do not invent alternate lease
6
+ field names.
8
7
 
9
8
  ## When it applies
10
9
 
@@ -27,7 +27,7 @@ description: Morning Star (启明星) harness 计划目录约定 —— `{HARNES
27
27
 
28
28
  > **Engine check (when available):** import `resolveHarnessDir` / `resolvePlanDir` / `resolveSddDir` / `resolveIterationDir` / `resolveSpecsDir` from `@mstar-harness/engine` in a host hook — or run `mstar path resolve [path]` (`--json` for machine output) to print the resolved dirs — to confirm the resolution below. On `fail` -> do not proceed; fix and re-run. Skill text below remains authoritative when the runtime is absent.
29
29
 
30
- ### `{HARNESS_DIR}` 解析顺序(找到即停)
30
+ ### `{HARNESS_DIR}` 解析顺序(找到即停;探测**永不越过工作区根**——CLI=start 的 git top-level(非 git→start 自身);dsh=会话工作区)
31
31
 
32
32
  1. `.mstar/` → `{HARNESS_DIR}=.mstar/`, `{PLAN_DIR}=.mstar/plans/`
33
33
  2. 否则 `.agents/` → legacy `{HARNESS_DIR}=.agents/`, `{PLAN_DIR}=.agents/plans/`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mstar-harness/opencode",
3
- "version": "2.1.1",
3
+ "version": "2.2.0",
4
4
  "description": "Morning Star harness OpenCode plugin — skills bootstrap + engine-backed runtime hooks (status lint, dispatch validation, Enforcement: hard gates).",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -36,6 +36,6 @@
36
36
  "access": "public"
37
37
  },
38
38
  "devDependencies": {
39
- "@mstar-harness/engine": "2.1.1"
39
+ "@mstar-harness/engine": "2.2.0"
40
40
  }
41
41
  }