@mstar-harness/opencode 1.8.9 → 2.0.1

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +30 -2
  2. package/README.md +10 -0
  3. package/dist/mstar.js +572 -0
  4. package/harness-commands/iteration-drive.md +17 -1
  5. package/harness-commands/iteration-loop.md +16 -0
  6. package/harness-commands/iteration-start.md +16 -0
  7. package/harness-skills/mstar-audit/SKILL.md +2 -0
  8. package/harness-skills/mstar-branch-worktree/SKILL.md +4 -0
  9. package/harness-skills/mstar-coding-behavior/SKILL.md +5 -0
  10. package/harness-skills/mstar-compound/SKILL.md +2 -0
  11. package/harness-skills/mstar-compound-refresh/SKILL.md +2 -0
  12. package/harness-skills/mstar-design-md/SKILL.md +2 -0
  13. package/harness-skills/mstar-design-md/templates/DESIGN.dark.md.template +5 -0
  14. package/harness-skills/mstar-design-md/templates/DESIGN.md.template +5 -0
  15. package/harness-skills/mstar-dispatch-gates/SKILL.md +6 -0
  16. package/harness-skills/mstar-host/SKILL.md +4 -0
  17. package/harness-skills/mstar-iteration/SKILL.md +12 -4
  18. package/harness-skills/mstar-iteration/references/phase-4-5-pr-delivery.md +2 -0
  19. package/harness-skills/mstar-phase-gates/SKILL.md +2 -0
  20. package/harness-skills/mstar-plan-artifacts/SKILL.md +13 -2
  21. package/harness-skills/mstar-plan-artifacts/references/plan-quality-bar.md +1 -1
  22. package/harness-skills/mstar-plan-artifacts/references/status-and-residuals.md +12 -13
  23. package/harness-skills/mstar-plan-artifacts/templates/README.md +1 -1
  24. package/harness-skills/mstar-plan-conventions/SKILL.md +9 -1
  25. package/harness-skills/mstar-plan-conventions/references/harness-bootstrap-and-agents-layering.md +1 -1
  26. package/harness-skills/mstar-review-qc/SKILL.md +2 -0
  27. package/harness-skills/mstar-roles/SKILL.md +2 -0
  28. package/harness-skills/mstar-roles/references/project-manager/dispatch-and-assignment.md +1 -1
  29. package/harness-skills/mstar-sdd/SKILL.md +18 -14
  30. package/harness-skills/mstar-sdd/references/file-handoffs.md +8 -8
  31. package/harness-skills/mstar-sdd/references/sticky-implementer-session.md +2 -2
  32. package/harness-skills/mstar-skill-authoring/SKILL.md +4 -0
  33. package/harness-skills/mstar-strategy/SKILL.md +2 -0
  34. package/package.json +6 -2
  35. package/harness-skills/mstar-plan-artifacts/scripts/tech-debt-rollup.sh +0 -115
  36. package/harness-skills/mstar-sdd/scripts/review-package +0 -43
  37. package/harness-skills/mstar-sdd/scripts/sdd-workspace +0 -90
  38. package/harness-skills/mstar-sdd/scripts/task-brief +0 -40
@@ -23,6 +23,8 @@ If you were dispatched as an SDD implementer or task reviewer, skip PM orchestra
23
23
 
24
24
  **Optional:** **`SDD implementer session: sticky`** — same implementer subagent across sequential tasks on one plan/branch; **task reviewers stay fresh per task**. SSOT → **`references/sticky-implementer-session.md`**.
25
25
 
26
+ > **Engine check (when available):** import `implementerSessionStickyRules` from `@mstar-harness/engine` in a host hook to validate the sticky resume decision above (no CLI form yet). On `fail` -> do not proceed; fix and re-run. Skill text below remains authoritative when the runtime is absent.
27
+
26
28
  **Narration:** at most one short line between tool calls — ledger and file paths carry the record.
27
29
 
28
30
  **Continuous execution:** do not check in with the human between tasks. Stop only for BLOCKED, genuine ambiguity, or all tasks complete.
@@ -39,12 +41,12 @@ Batch all findings for the human in one message. If clean, proceed silently.
39
41
  ## Per-task loop (PM only)
40
42
 
41
43
  1. Record `BASE_SHA` (never use `HEAD~1` later)
42
- 2. skill **`mstar-sdd`** → `scripts/sdd-workspace <plan-id>` → `SDD_DIR`(iteration L1 从 feature cwd 调用时:`MSTAR_CONTROL_ROOT=<control_worktree_path>` 或 `scripts/sdd-workspace <plan-id> <control_worktree_path>`;缺 status.json 的 linked worktree 会 fail closed)
43
- 3. `scripts/task-brief <plan> N` → brief file
44
+ 2. `mstar sdd workspace <plan-id>` → `SDD_DIR`(iteration L1 从 feature cwd 调用时:`MSTAR_CONTROL_ROOT=<control_worktree_path>` 或 `mstar sdd workspace <plan-id> <control_worktree_path>`;缺 status.json 的 linked worktree 会 fail closed)
45
+ 3. `mstar sdd task-brief <plan> N` → brief file
44
46
  4. Dispatch implementer:
45
- - **`SDD implementer session: fresh`** (default) — new subagent; templates: `references/implementer-prompt.md`
46
- - **`SDD implementer session: sticky`** — first task: same as fresh + write `{SDD_DIR}/implementer-session.json` with `host_agent_id`; later tasks: host **resume** + `references/implementer-continuation-prompt.md` (see **`references/sticky-implementer-session.md`**)
47
- 5. On `DONE`: `scripts/review-package BASE HEAD` → diff file
47
+ - **`SDD implementer session: fresh`** (default) — new subagent; templates: `references/implementer-prompt.md`
48
+ - **`SDD implementer session: sticky`** — first task: same as fresh + write `{SDD_DIR}/implementer-session.json` with `host_agent_id`; later tasks: host **resume** + `references/implementer-continuation-prompt.md` (see **`references/sticky-implementer-session.md`**)
49
+ 5. On `DONE`: `mstar sdd review-package BASE HEAD` → diff file
48
50
  6. Dispatch **fresh** task reviewer — role **`generalPurpose`** (L2; **not** `qc-specialist*`; host role field → `mstar-host` C5) — brief, report, diff, Global Constraints — `references/task-reviewer-prompt.md` — **never** sticky resume for reviewers
49
51
  7. Fix loop for Critical/Important; re-review until approved
50
52
  8. Append `progress.md`; update `status.json` `task_commits[]` and `implementer-session.json` `last_task` if sticky
@@ -54,6 +56,8 @@ Batch all findings for the human in one message. If clean, proceed silently.
54
56
 
55
57
  Detail: **`references/file-handoffs.md`**.
56
58
 
59
+ > **Engine check (when available):** run `mstar sdd workspace <plan-id>` / `mstar sdd task-brief <plan-file> <task-number>` / `mstar sdd review-package <base> <head>` (or `import { assertBaseSha, sddWorkspace, taskBrief, reviewPackage } from "@mstar-harness/engine"` in a host hook) to drive the loop steps above. On `fail` -> do not proceed; fix and re-run. Skill text below remains authoritative when the runtime is absent.
60
+
57
61
  ## Implementer statuses
58
62
 
59
63
  | Status | PM action |
@@ -81,7 +85,7 @@ Host mapping → **`mstar-host`** references (`model` / Task field).
81
85
 
82
86
  ## After all tasks
83
87
 
84
- 1. `scripts/review-package MERGE_BASE HEAD` → branch diff in `{SDD_DIR}/review/`
88
+ 1. `mstar sdd review-package MERGE_BASE HEAD` → branch diff in `{SDD_DIR}/review/`
85
89
  2. PM dispatches **plan QC tri-review (L3)** — **`QC mode: full tri-review`**, **N=3** — with branch review-package path and report paths under `{SDD_DIR}/review/` → **`mstar-review-qc`** · **`mstar-dispatch-gates`**. Layer SSOT → **`mstar-review-qc/references/review-responsibility-boundaries.md`**. PM writes `{SDD_DIR}/review/qc-consolidated.md` and durable main-plan gate summary. **Mandatory whenever `Execution mode: sdd`** (single-plan or iteration).
86
90
  3. Critical/Important QC findings → **one** fix dispatch (full list), then targeted re-review
87
91
  4. QA gate → **`mstar-harness-core`** Done rules; PM **`mstar-roles/references/project-manager/qa-trigger-matrix.md`**
@@ -94,6 +98,8 @@ Append on clean review: `Task N: complete (<base>..<head>, review clean)`.
94
98
 
95
99
  Minor findings → `## Minor (for plan QC)` section in same file.
96
100
 
101
+ > **Engine check (when available):** import `readProgressLedger` from `@mstar-harness/engine` in a host hook to read the ledger above (no CLI form yet). On `fail` -> do not proceed; fix and re-run. Skill text below remains authoritative when the runtime is absent.
102
+
97
103
  ## Red flags (NEVER)
98
104
 
99
105
  - Parallel implementer dispatches
@@ -107,17 +113,15 @@ Minor findings → `## Minor (for plan QC)` section in same file.
107
113
  - Sticky **resume** for task reviewers
108
114
  - Resume implementer without `host_agent_id` in `implementer-session.json`
109
115
 
110
- ## Scripts
111
-
112
- Scripts live under this skill: **`mstar-sdd`** → `scripts/<name>`.
116
+ ## CLI
113
117
 
114
- Resolve the loaded **`mstar-sdd`** skill directory first, then run the script by skill-relative path. **Do not** treat `skills/mstar-sdd/scripts/...` as a consumer-project cwd path that layout exists only in the harness source tree (and OpenCode's bundled `harness-skills/mstar-sdd/scripts/`).
118
+ The SDD helpers are engine-backed commands under **`mstar sdd`**(引擎 CLI;原 bash 脚本已移除,行为语义不变)。Run the `mstar` binary from any checkout; env vars `MSTAR_CONTROL_ROOT` / `MSTAR_HARNESS_DIR` / `SDD_DIR` are honored exactly as before.
115
119
 
116
- | Script | Usage |
120
+ | Command | Usage |
117
121
  |--------|--------|
118
- | `scripts/sdd-workspace` | `PLAN_ID [CONTROL_ROOT]` → creates `{SDD_DIR}` under control harness when set (`MSTAR_CONTROL_ROOT` or 2nd arg); fail closed on linked worktree without `status.json` |
119
- | `scripts/task-brief` | `PLAN_FILE TASK_N [OUTFILE]` |
120
- | `scripts/review-package` | `BASE HEAD [OUTFILE]` |
122
+ | `mstar sdd workspace` | `PLAN_ID [CONTROL_ROOT]` → creates `{SDD_DIR}` under control harness when set (`MSTAR_CONTROL_ROOT` or 2nd arg); fail closed on linked worktree without `status.json` |
123
+ | `mstar sdd task-brief` | `PLAN_FILE TASK_N [OUTFILE]` |
124
+ | `mstar sdd review-package` | `BASE HEAD [OUTFILE]` |
121
125
 
122
126
  ## References
123
127
 
@@ -4,14 +4,14 @@ PM and subagents move artifacts as **files**, not pasted text. Pasted content st
4
4
 
5
5
  ## Before implementer dispatch
6
6
 
7
- Resolve scripts from skill **`mstar-sdd`** `scripts/…` (loaded skill directory). Do **not** run `skills/mstar-sdd/scripts/…` from a consumer project cwd.
7
+ Run the SDD helpers through the engine CLI **`mstar sdd …`** (engine-backed; the former bash scripts are removed semantics unchanged).
8
8
 
9
- 1. `export SDD_DIR=$(<mstar-sdd>/scripts/sdd-workspace <plan-id>)`
10
- - Iteration L1 (implementer cwd = feature worktree):
11
- `export MSTAR_CONTROL_ROOT=<control_worktree_path>`
12
- or `sdd-workspace <plan-id> <control_worktree_path>`
9
+ 1. `export SDD_DIR=$(mstar sdd workspace <plan-id>)`
10
+ - Iteration L1 (implementer cwd = feature worktree):
11
+ `export MSTAR_CONTROL_ROOT=<control_worktree_path>`
12
+ or `mstar sdd workspace <plan-id> <control_worktree_path>`
13
13
  so `{SDD_DIR}` lands on the control harness (default-gitignored plans/status/sdd). Do not create a second SDD tree under the feature checkout.
14
- 2. `<mstar-sdd>/scripts/task-brief <plan-file> <N> "$SDD_DIR/task-N-brief.md"`
14
+ 2. `mstar sdd task-brief <plan-file> <N> "$SDD_DIR/task-N-brief.md"`
15
15
  3. Record `BASE_SHA` (`git rev-parse HEAD` before dispatch).
16
16
  4. Dispatch implementer with:
17
17
  - One line scene-setting (where task fits)
@@ -33,7 +33,7 @@ Implementer writes full report to `task-N-report.md`. Return to PM only:
33
33
  ## After implementer DONE
34
34
 
35
35
  1. `HEAD_SHA=$(git rev-parse HEAD)`
36
- 2. `<mstar-sdd>/scripts/review-package "$BASE_SHA" "$HEAD_SHA" "$SDD_DIR/review-....diff"`
36
+ 2. `mstar sdd review-package "$BASE_SHA" "$HEAD_SHA" "$SDD_DIR/review-....diff"`
37
37
  3. Dispatch task reviewer with: brief path, report path, diff path, Global Constraints (verbatim from plan).
38
38
 
39
39
  **Never use `HEAD~1` as BASE** — multi-commit tasks truncate.
@@ -65,7 +65,7 @@ After all tasks:
65
65
  ```bash
66
66
  MERGE_BASE=$(git merge-base <target-branch> HEAD)
67
67
  mkdir -p "$SDD_DIR/review"
68
- <mstar-sdd>/scripts/review-package "$MERGE_BASE" HEAD "$SDD_DIR/review/branch-review-....diff"
68
+ mstar sdd review-package "$MERGE_BASE" HEAD "$SDD_DIR/review/branch-review-....diff"
69
69
  ```
70
70
 
71
71
  Pass **branch** diff path and bundle report paths (`$SDD_DIR/review/qc1.md` …) to QC dispatch — not task-level diffs. Raw QC/QA files stay in the gitignored review bundle; PM records durable summary and open residuals in **local** plan/`status.json` (session SSOT) and promotes cross-clone decisions into tracked knowledge/specs/`AGENTS.md` per `mstar-plan-conventions` git policy.
@@ -52,12 +52,12 @@ After each completed task review, PM sets `last_task` to N. **Do not** resume if
52
52
 
53
53
  Same as default SDD for artifacts and L2 review; only implementer dispatch differs:
54
54
 
55
- 1. `task-brief` → `{SDD_DIR}/task-N-brief.md`
55
+ 1. `mstar sdd task-brief` → `{SDD_DIR}/task-N-brief.md`
56
56
  2. Record `BASE_SHA`
57
57
  3. **Implementer dispatch**
58
58
  - **First task** (`fresh` or sticky start): normal Task/subagent invoke → save `host_agent_id` to ledger
59
59
  - **Next tasks** (`sticky`): host **resume** with same `host_agent_id` + continuation prompt (`implementer-prompt.md` § Continuation)
60
- 4. On `DONE` → `review-package` → **fresh** task reviewer (never resume reviewer)
60
+ 4. On `DONE` → `mstar sdd review-package` → **fresh** task reviewer (never resume reviewer)
61
61
  5. Append `progress.md`; update ledger `last_task`
62
62
  6. Next task
63
63
 
@@ -70,6 +70,8 @@ description: Use when...
70
70
  Bad:`Explains how to write plans with steps, tests, commits, and review gates.`
71
71
  Better:`Use when a non-trivial task has a spec or requirements and needs a written implementation plan before code changes.`
72
72
 
73
+ > **Engine check (when available):** run `mstar skill lint <skill-dir>` (or `import { lintFrontmatter, lintFiveQuestion } from "@mstar-harness/engine"` in a host hook) to lint the frontmatter contract and the five-question body contract above. On `fail` -> do not proceed; fix and re-run. Skill text below remains authoritative when the runtime is absent.
74
+
73
75
  ## 默认 Body 结构
74
76
 
75
77
  ```markdown
@@ -97,6 +99,8 @@ Agents 按 **skill 名** 发现 skill;文档若给出完整仓内相对路径
97
99
 
98
100
  在本 harness:解析方式见 **`mstar-host`** § Resolve loaded skill root(omp `skill://`、各宿主插件挂载等)。其它环境按当地 skill 安装约定解析。
99
101
 
102
+ > **Engine check (when available):** import `resolveAssetPath` from `@mstar-harness/engine` in a host hook to resolve a skill-relative asset per the convention above (no CLI form yet). On `fail` -> do not proceed; fix and re-run. Skill text below remains authoritative when the runtime is absent.
103
+
100
104
  ## Progressive Disclosure
101
105
 
102
106
  1. Frontmatter:仅触发
@@ -58,6 +58,8 @@ A good strategy document is opinionated and concise. It should fit in one screen
58
58
  <Major past decisions with context — why, not just what>
59
59
  ```
60
60
 
61
+ > **Engine check (when available):** run `mstar lint <STRATEGY.md>` (or `import { lintStrategySections } from "@mstar-harness/engine"` in a host hook) to check the six required sections above (Vision, What we build, What we don't build, Guiding Principles, Technology Direction, Decision Log). On `fail` -> do not proceed; fix and re-run. Skill text below remains authoritative when the runtime is absent.
62
+
61
63
  ### Optional sections
62
64
 
63
65
  - **Current Focus** — what the team is working on now
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mstar-harness/opencode",
3
- "version": "1.8.9",
4
- "description": "Morning Star harness OpenCode plugin (skills bootstrap and agent loading).",
3
+ "version": "2.0.1",
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": {
7
7
  "type": "git",
@@ -23,6 +23,7 @@
23
23
  "scripts": {
24
24
  "bundle-assets": "bun run scripts/bundle-harness-assets.ts",
25
25
  "build": "bun run bundle-assets && rm -rf dist && bun build src/mstar.ts --target node --outfile dist/mstar.js",
26
+ "test": "bun test",
26
27
  "prepublishOnly": "bun run build"
27
28
  },
28
29
  "engines": {
@@ -33,5 +34,8 @@
33
34
  },
34
35
  "publishConfig": {
35
36
  "access": "public"
37
+ },
38
+ "devDependencies": {
39
+ "@mstar-harness/engine": "2.0.1"
36
40
  }
37
41
  }
@@ -1,115 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Read-only rollup of open residual_findings into tech_debt_summary aggregates.
3
- # Does not write status.json — PM applies output manually.
4
- set -euo pipefail
5
-
6
- STATUS_FILE="${1:-.mstar/status.json}"
7
-
8
- if [[ ! -f "$STATUS_FILE" ]]; then
9
- echo "error: status file not found: $STATUS_FILE" >&2
10
- exit 1
11
- fi
12
-
13
- if ! command -v jq >/dev/null 2>&1; then
14
- echo "error: jq is required" >&2
15
- exit 1
16
- fi
17
-
18
- # Merge canonical + legacy maps (canonical keys win). Legacy "warning" -> low.
19
- # Skip entries with lifecycle != open (default open when omitted).
20
- read -r -d '' JQ_FILTER <<'JQEOF' || true
21
- def norm_sev:
22
- if . == "warning" then "low"
23
- elif . == null or . == "" then "medium"
24
- else .
25
- end;
26
-
27
- def is_open:
28
- (.lifecycle // "open") == "open";
29
-
30
- (.residual_findings // {}) as $canon
31
- | (.metadata.residual_findings // {}) as $legacy
32
- | ($canon + $legacy) as $merged
33
- | [
34
- $merged
35
- | to_entries[]
36
- | .key as $plan
37
- | .value[]
38
- | select(is_open)
39
- | . + { _plan_id: $plan }
40
- ] as $items
41
- | {
42
- total_open: ($items | length),
43
- by_severity: (
44
- ["critical", "high", "medium", "low", "nit"]
45
- | map(. as $s
46
- | { ($s): ([$items[] | select((.severity | norm_sev) == $s)] | length) })
47
- | add
48
- ),
49
- by_target: (
50
- $items
51
- | map(.target // "unspecified")
52
- | group_by(.)
53
- | map({ key: .[0], value: length })
54
- | from_entries
55
- ),
56
- by_plan: (
57
- $items
58
- | group_by(._plan_id)
59
- | map({ key: .[0]._plan_id, value: length })
60
- | from_entries
61
- )
62
- }
63
- JQEOF
64
-
65
- COMPUTED=$(jq -c "$JQ_FILTER" "$STATUS_FILE")
66
- STORED=$(jq -c '.metadata.tech_debt_summary // null' "$STATUS_FILE")
67
-
68
- echo "=== tech_debt_summary (computed from open residual_findings) ==="
69
- echo "$COMPUTED" | jq '.'
70
-
71
- echo ""
72
- echo "=== stored metadata.tech_debt_summary ==="
73
- if [[ "$STORED" == "null" ]]; then
74
- echo "(none)"
75
- else
76
- echo "$STORED" | jq '.'
77
- fi
78
-
79
- echo ""
80
- echo "=== consistency check ==="
81
-
82
- compare_field() {
83
- local field="$1"
84
- local computed stored
85
- computed=$(echo "$COMPUTED" | jq -c ".$field")
86
- if [[ "$STORED" == "null" ]]; then
87
- echo "DRIFT: no stored tech_debt_summary (computed $field = $computed)"
88
- return 1
89
- fi
90
- stored=$(echo "$STORED" | jq -c ".$field // null")
91
- if [[ "$computed" == "$stored" ]]; then
92
- echo "PASS: $field"
93
- return 0
94
- fi
95
- echo "DRIFT: $field"
96
- echo " computed: $computed"
97
- echo " stored: $stored"
98
- return 1
99
- }
100
-
101
- FAIL=0
102
- compare_field total_open || FAIL=1
103
- compare_field by_severity || FAIL=1
104
- compare_field by_target || FAIL=1
105
- compare_field by_plan || FAIL=1
106
-
107
- if [[ "$FAIL" -eq 0 ]]; then
108
- echo ""
109
- echo "OVERALL: PASS"
110
- exit 0
111
- fi
112
-
113
- echo ""
114
- echo "OVERALL: DRIFT — refresh metadata.tech_debt_summary in status.json"
115
- exit 1
@@ -1,43 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Write commit list, stat summary, and diff to a file for reviewer Read.
3
- # Usage: review-package BASE HEAD [OUTFILE]
4
- # Never use HEAD~1 as BASE for multi-commit tasks.
5
- set -euo pipefail
6
-
7
- if [ $# -lt 2 ] || [ $# -gt 3 ]; then
8
- echo "usage: review-package BASE HEAD [OUTFILE]" >&2
9
- exit 2
10
- fi
11
-
12
- base=$1
13
- head=$2
14
-
15
- git rev-parse --verify --quiet "$base" >/dev/null || { echo "bad BASE: $base" >&2; exit 2; }
16
- git rev-parse --verify --quiet "$head" >/dev/null || { echo "bad HEAD: $head" >&2; exit 2; }
17
-
18
- if [ $# -eq 3 ]; then
19
- out=$3
20
- else
21
- if [ -z "${SDD_DIR:-}" ]; then
22
- echo "review-package: set SDD_DIR or pass OUTFILE" >&2
23
- exit 2
24
- fi
25
- mkdir -p "$SDD_DIR"
26
- out="$SDD_DIR/review-$(git rev-parse --short "$base")..$(git rev-parse --short "$head").diff"
27
- fi
28
-
29
- {
30
- echo "# Review package: ${base}..${head}"
31
- echo
32
- echo "## Commits"
33
- git log --oneline "${base}..${head}"
34
- echo
35
- echo "## Files changed"
36
- git diff --stat "${base}..${head}"
37
- echo
38
- echo "## Diff"
39
- git diff -U10 "${base}..${head}"
40
- } > "$out"
41
-
42
- commits=$(git rev-list --count "${base}..${head}" 2>/dev/null || echo 0)
43
- echo "wrote ${out}: ${commits} commit(s), $(wc -c < "$out" | tr -d ' ') bytes"
@@ -1,90 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Resolve and ensure {SDD_DIR} for Morning Star SDD artifacts.
3
- # Usage: sdd-workspace PLAN_ID [CONTROL_ROOT]
4
- # CONTROL_ROOT — optional absolute repo root of the control worktree
5
- # (or set MSTAR_CONTROL_ROOT). Required when cwd is a linked feature
6
- # worktree that lacks harness status.json (default gitignore).
7
- # Prints absolute path to {HARNESS_DIR}/sdd/<plan-id>/ (or legacy .agents/sdd/).
8
- set -euo pipefail
9
-
10
- if [ $# -lt 1 ] || [ $# -gt 2 ]; then
11
- echo "usage: sdd-workspace PLAN_ID [CONTROL_ROOT]" >&2
12
- echo " Set MSTAR_CONTROL_ROOT=<control_worktree_path> when running from a feature worktree." >&2
13
- exit 2
14
- fi
15
-
16
- plan_id=$1
17
- control_root="${2:-${MSTAR_CONTROL_ROOT:-}}"
18
-
19
- abs_dir() {
20
- (cd "$1" && pwd -P)
21
- }
22
-
23
- if [ -n "$control_root" ]; then
24
- if [ ! -d "$control_root" ]; then
25
- echo "sdd-workspace: CONTROL_ROOT / MSTAR_CONTROL_ROOT is not a directory: $control_root" >&2
26
- exit 1
27
- fi
28
- root=$(abs_dir "$control_root")
29
- else
30
- root=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
31
- root=$(abs_dir "$root")
32
- fi
33
-
34
- resolve_harness_with_status() {
35
- local r=$1
36
- if [ -f "$r/.mstar/status.json" ]; then
37
- printf '%s\n' "$r/.mstar"
38
- return 0
39
- fi
40
- if [ -f "$r/.agents/status.json" ]; then
41
- printf '%s\n' "$r/.agents"
42
- return 0
43
- fi
44
- return 1
45
- }
46
-
47
- # Linked worktree from `git worktree add`: --git-dir ≠ --git-common-dir
48
- is_linked_worktree() {
49
- local r=$1
50
- local git_dir common
51
- git_dir=$(git -C "$r" rev-parse --git-dir 2>/dev/null) || return 1
52
- common=$(git -C "$r" rev-parse --git-common-dir 2>/dev/null) || return 1
53
- case "$git_dir" in
54
- /*) ;;
55
- *) git_dir="$r/$git_dir" ;;
56
- esac
57
- case "$common" in
58
- /*) ;;
59
- *) common="$r/$common" ;;
60
- esac
61
- # Path contains /worktrees/ → definitely linked
62
- case "$git_dir" in
63
- */.git/worktrees/*|*/worktrees/*) return 0 ;;
64
- esac
65
- local gd_parent cm_abs
66
- gd_parent=$(abs_dir "$(dirname "$git_dir")")
67
- cm_abs=$(abs_dir "$common")
68
- [ "$gd_parent/$(basename "$git_dir")" != "$cm_abs" ] && [ "$git_dir" != "$cm_abs" ]
69
- }
70
-
71
- if harness=$(resolve_harness_with_status "$root"); then
72
- :
73
- elif [ -z "$control_root" ] && is_linked_worktree "$root"; then
74
- echo "sdd-workspace: linked worktree at $root has no {HARNESS_DIR}/status.json (default gitignore)." >&2
75
- echo " Refusing to create a second SDD tree under the feature checkout." >&2
76
- echo " Re-run with MSTAR_CONTROL_ROOT=<control_worktree_path> or: sdd-workspace $plan_id <control_worktree_path>" >&2
77
- echo " See mstar-branch-worktree «Harness path SSOT under default gitignore»." >&2
78
- exit 1
79
- elif [ -d "$root/.mstar" ]; then
80
- harness="$root/.mstar"
81
- elif [ -d "$root/.agents" ]; then
82
- harness="$root/.agents"
83
- else
84
- harness="$root/.mstar"
85
- fi
86
-
87
- dir="$harness/sdd/$plan_id"
88
- mkdir -p "$dir"
89
- printf '*\n' > "$dir/.gitignore"
90
- cd "$dir" && pwd
@@ -1,40 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Extract one task's full text from a plan into a file for the implementer.
3
- # Usage: task-brief PLAN_FILE TASK_NUMBER [OUTFILE]
4
- # Default OUTFILE: {SDD_DIR}/task-N-brief.md (SDD_DIR from env or second arg via sdd-workspace)
5
- set -euo pipefail
6
-
7
- if [ $# -lt 2 ] || [ $# -gt 3 ]; then
8
- echo "usage: task-brief PLAN_FILE TASK_NUMBER [OUTFILE]" >&2
9
- exit 2
10
- fi
11
-
12
- plan=$1
13
- n=$2
14
- [ -f "$plan" ] || { echo "no such plan file: $plan" >&2; exit 2; }
15
-
16
- if [ $# -eq 3 ]; then
17
- out=$3
18
- else
19
- if [ -z "${SDD_DIR:-}" ]; then
20
- echo "task-brief: set SDD_DIR or pass OUTFILE (run sdd-workspace PLAN_ID first)" >&2
21
- exit 2
22
- fi
23
- mkdir -p "$SDD_DIR"
24
- out="$SDD_DIR/task-${n}-brief.md"
25
- fi
26
-
27
- awk -v n="$n" '
28
- /^```/ { infence = !infence }
29
- !infence && /^#+[ \t]+Task[ \t]+[0-9]+/ {
30
- intask = ($0 ~ ("^#+[ \t]+Task[ \t]+" n "([^0-9]|$)"))
31
- }
32
- intask { print }
33
- ' "$plan" > "$out"
34
-
35
- if [ ! -s "$out" ]; then
36
- echo "task ${n} not found in ${plan} (no heading matching Task ${n})" >&2
37
- exit 3
38
- fi
39
-
40
- echo "wrote ${out}: $(wc -l < "$out" | tr -d ' ') lines"