okstra 0.173.0 → 0.174.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.
Files changed (62) hide show
  1. package/docs/architecture/storage-model.md +13 -3
  2. package/docs/architecture.md +5 -21
  3. package/docs/cli.md +3 -2
  4. package/docs/container.md +1 -1
  5. package/docs/contributor-change-matrix.md +1 -1
  6. package/docs/project-structure-overview.md +13 -13
  7. package/docs/task-process/README.md +1 -1
  8. package/docs/task-process/implementation-planning.md +1 -1
  9. package/package.json +1 -1
  10. package/runtime/BUILD.json +2 -2
  11. package/runtime/agents/workers/claude-worker.md +1 -1
  12. package/runtime/bin/lib/okstra/globals.sh +1 -1
  13. package/runtime/bin/okstra-provider-exec.py +29 -12
  14. package/runtime/bin/okstra-trace-cleanup.sh +58 -129
  15. package/runtime/prompts/lead/adapters/cmux.md +2 -0
  16. package/runtime/prompts/lead/okstra-lead-contract.md +1 -1
  17. package/runtime/prompts/lead/plan-body-verification.md +3 -3
  18. package/runtime/prompts/lead/report-writer.md +6 -6
  19. package/runtime/prompts/profiles/_common-contract.md +2 -2
  20. package/runtime/prompts/profiles/_implementation-executor.md +2 -0
  21. package/runtime/prompts/profiles/_implementation-verifier.md +2 -2
  22. package/runtime/prompts/profiles/error-analysis.md +1 -1
  23. package/runtime/prompts/profiles/implementation-planning.md +12 -9
  24. package/runtime/prompts/profiles/implementation.md +2 -1
  25. package/runtime/prompts/profiles/release-handoff.md +1 -1
  26. package/runtime/python/okstra_ctl/adapters/dispatch/__init__.py +1 -6
  27. package/runtime/python/okstra_ctl/adapters/hosts/external/relay.md +4 -4
  28. package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +5 -0
  29. package/runtime/python/okstra_ctl/conformance.py +68 -0
  30. package/runtime/python/okstra_ctl/dispatch_core.py +89 -39
  31. package/runtime/python/okstra_ctl/dispatch_state.py +142 -14
  32. package/runtime/python/okstra_ctl/doctor.py +2 -2
  33. package/runtime/python/okstra_ctl/domain/worker_exec.py +5 -0
  34. package/runtime/python/okstra_ctl/final_report_schema.py +5 -4
  35. package/runtime/python/okstra_ctl/pane_reclaim.py +13 -22
  36. package/runtime/python/okstra_ctl/render_final_report.py +15 -19
  37. package/runtime/python/okstra_ctl/report_contract.py +0 -1
  38. package/runtime/python/okstra_ctl/report_finalize.py +68 -9
  39. package/runtime/python/okstra_ctl/run.py +43 -2
  40. package/runtime/python/okstra_ctl/schema_excerpt.py +1 -1
  41. package/runtime/python/okstra_ctl/scope_provenance.py +1 -1
  42. package/runtime/python/okstra_ctl/session.py +69 -12
  43. package/runtime/python/okstra_ctl/team.py +51 -25
  44. package/runtime/python/okstra_ctl/tmux.py +19 -149
  45. package/runtime/python/okstra_ctl/worker_request.py +2 -0
  46. package/runtime/python/okstra_ctl/worktree.py +69 -3
  47. package/runtime/python/okstra_token_usage/cli.py +1 -1
  48. package/runtime/python/okstra_token_usage/collect.py +66 -6
  49. package/runtime/skills/okstra-setup/references/project-config.md +11 -0
  50. package/runtime/templates/reports/settings.template.json +0 -24
  51. package/runtime/validators/lib/fixtures.sh +49 -17
  52. package/runtime/validators/validate-implementation-plan-stages.py +63 -3
  53. package/runtime/validators/validate-run.py +14 -473
  54. package/runtime/validators/validate_session_conformance.py +1 -1
  55. package/src/cli-registry.mjs +8 -1
  56. package/src/commands/execute/team.mjs +3 -3
  57. package/src/commands/execute/worktree-status.mjs +109 -0
  58. package/src/commands/lifecycle/install.mjs +0 -2
  59. package/src/commands/report/finalize.mjs +13 -6
  60. package/runtime/bin/okstra-subagent-reclaim.sh +0 -26
  61. package/runtime/schemas/final-report-v1.0.schema.json +0 -6366
  62. package/runtime/templates/reports/final-report.template.md +0 -1258
@@ -0,0 +1,109 @@
1
+ import { runPythonSnippet, emitJsonError } from "../../lib/python-helper.mjs";
2
+
3
+ const USAGE = `okstra worktree-status — clean-worktree check that ignores okstra's own scaffolding
4
+
5
+ Usage:
6
+ okstra worktree-status [--path <dir>] [--check-clean]
7
+
8
+ --path <dir> directory to inspect (default: current directory)
9
+ --check-clean exit 1 when the tree is dirty (default: always exit 0)
10
+
11
+ okstra provisions \`.okstra\` plus the configured sync entries (\`.project-docs\`,
12
+ \`.claude\`, …) into every task worktree, and an \`implementation\` stage worktree
13
+ sits inside its task worktree. A bare \`git status --porcelain\` therefore never
14
+ comes back empty there, so a plan step asserting a clean tree with one fails on
15
+ okstra's scaffolding rather than on the stage's own work. This command asks the
16
+ same question against source paths only — the exact gate okstra's own handoff
17
+ and stage-integration steps use.
18
+
19
+ Use it as the assertion in a plan step:
20
+ okstra worktree-status --check-clean && git tag -f stage-<N>-exit
21
+
22
+ Output: JSON { ok, path, clean, entries, excluded }. \`entries\` holds the
23
+ \`git status --short\` rows that made it dirty; \`excluded\` lists the paths left
24
+ out of the question.
25
+ `;
26
+
27
+ function parseArgs(args) {
28
+ const opts = { path: ".", checkClean: false };
29
+ for (let i = 0; i < args.length; i += 1) {
30
+ const arg = args[i];
31
+ if (arg === "--check-clean") {
32
+ opts.checkClean = true;
33
+ } else if (arg === "--path") {
34
+ i += 1;
35
+ if (i >= args.length) throw new Error("--path requires a directory");
36
+ opts.path = args[i];
37
+ } else if (arg.startsWith("--path=")) {
38
+ opts.path = arg.slice("--path=".length);
39
+ } else {
40
+ throw new Error(`unknown argument '${arg}'`);
41
+ }
42
+ }
43
+ if (!opts.path) throw new Error("--path requires a directory");
44
+ return opts;
45
+ }
46
+
47
+ const SCRIPT = `
48
+ import json, sys
49
+ from pathlib import Path
50
+ from okstra_ctl.worktree import (
51
+ dirty_entries_excluding_okstra,
52
+ is_git_work_tree,
53
+ nested_worktree_excludes,
54
+ okstra_clean_gate_excludes,
55
+ )
56
+
57
+ path = Path(sys.argv[1]).resolve()
58
+ check_clean = sys.argv[2] == "1"
59
+
60
+ if not path.is_dir():
61
+ print(json.dumps({"ok": False, "stage": "input",
62
+ "reason": f"not a directory: {path}"}))
63
+ sys.exit(2)
64
+ if not is_git_work_tree(path):
65
+ print(json.dumps({"ok": False, "stage": "input",
66
+ "reason": f"not inside a git work tree: {path}"}))
67
+ sys.exit(2)
68
+
69
+ entries = dirty_entries_excluding_okstra(path)
70
+ excluded = [*okstra_clean_gate_excludes(path), *nested_worktree_excludes(path)]
71
+ print(json.dumps({
72
+ "ok": True,
73
+ "path": str(path),
74
+ "clean": not entries,
75
+ "entries": entries,
76
+ "excluded": excluded,
77
+ }, ensure_ascii=False, indent=2))
78
+ sys.exit(1 if (check_clean and entries) else 0)
79
+ `;
80
+
81
+ export async function run(args) {
82
+ if (args.includes("--help") || args.includes("-h")) {
83
+ process.stdout.write(USAGE);
84
+ return 0;
85
+ }
86
+ let opts;
87
+ try {
88
+ opts = parseArgs(args);
89
+ } catch (err) {
90
+ process.stderr.write(`error: ${err.message}\n\n${USAGE}`);
91
+ return 2;
92
+ }
93
+
94
+ const result = await runPythonSnippet({
95
+ script: SCRIPT,
96
+ args: [opts.path, opts.checkClean ? "1" : "0"],
97
+ });
98
+
99
+ if (result.code !== 0 && !result.stdout.trim()) {
100
+ emitJsonError({
101
+ stage: "python",
102
+ reason: `python invocation failed: ${result.stderr.trim() || "no output"}`,
103
+ });
104
+ return 1;
105
+ }
106
+
107
+ process.stdout.write(result.stdout);
108
+ return result.code;
109
+ }
@@ -37,7 +37,6 @@ const BIN_ENTRYPOINTS = [
37
37
  "okstra-kimi-exec.sh",
38
38
  "okstra-provider-exec.py",
39
39
  "okstra-trace-cleanup.sh",
40
- "okstra-subagent-reclaim.sh",
41
40
  "okstra-team-reconcile.sh",
42
41
  "okstra-central.sh",
43
42
  "okstra-token-usage.py",
@@ -1136,7 +1135,6 @@ export async function runEnsureInstalled(args) {
1136
1135
  if (!(await dirExists(paths.pythonpath))) reasons.push(`missing ${paths.pythonpath}`);
1137
1136
  if (!(await dirExists(paths.agents))) reasons.push(`missing agents dir ${paths.agents}`);
1138
1137
  for (const relative of [
1139
- ["schemas", "final-report-v1.0.schema.json"],
1140
1138
  ["schemas", "final-report-v2.0.schema.json"],
1141
1139
  ["templates", "reports", "final-report-v2.template.md"],
1142
1140
  ["templates", "reports", "html", "base.template.html"],
@@ -7,16 +7,23 @@ Usage:
7
7
  okstra report-finalize --project-root <dir> --run-manifest <path> \\
8
8
  --report <final-report-<task-type>-<seq>.md> [--team-state <path>]
9
9
 
10
- Runs the four Phase 7 steps in their contractual order against one final-report:
10
+ Runs the six Phase 7 steps in their contractual order against one final-report:
11
11
 
12
- 1. token-usage substitute real token/cost numbers into the data.json
13
- 2. render-views write the schema-v2 task-specific *.html sibling; v1
12
+ 1. project-activity project the run's activity events into the data.json
13
+ 2. check-source verify the data.json is the English SSOT
14
+ 3. token-usage substitute real token/cost numbers into the data.json
15
+ 4. render-views write the schema-v2 task-specific *.html sibling; v1
14
16
  keeps the legacy conditional interactive view
15
- 3. spawn-followups turn section 4 rows into task stubs
16
- 4. validate-run validate the finished run artifacts
17
+ 5. spawn-followups turn section 4 rows into task stubs
18
+ 6. validate-run validate the finished run artifacts
17
19
 
18
20
  Every step is idempotent, so re-running after a fixed failure is safe. The
19
- sequence stops at the first non-zero exit and reports which step failed.
21
+ sequence stops at the first non-zero exit and reports which step failed, except
22
+ token-usage: its input is the lead session log, so a failure there does not
23
+ take the html, follow-ups and validation after it down with it. Whenever a step
24
+ exits non-zero the command prints the --only flags that resume the sequence
25
+ from the earliest failing step — follow those rather than rerunning the failing
26
+ step alone, which would leave the html rendered before the tokens landed.
20
27
 
21
28
  This is the same code path the Codex lead adapter runs automatically after its
22
29
  report-writer completes, so a Claude-led and a Codex-led run finalize
@@ -1,26 +0,0 @@
1
- #!/usr/bin/env bash
2
- #
3
- # okstra-subagent-reclaim.sh — SubagentStop / TaskCompleted 훅 엔트리.
4
- #
5
- # stdin(JSON)은 읽고 버린다: 어느 worker 가 끝났든 활성 run 전체의 "완료" pane 만
6
- # 회수하므로 session_id 매핑이 필요 없다. active.jsonl 의 각 활성 run 에 대해
7
- # okstra-trace-cleanup.sh --reclaim-completed 를 호출한다 — 완료 판정(pane_reclaim)이
8
- # cross-run 안전을 보장하므로 다른 run 의 진행 중 pane 은 건드리지 않는다.
9
- #
10
- # 훅은 세션 진행을 절대 막지 않는다: 모든 실패는 조용히 삼키고 항상 exit 0.
11
- set -u
12
-
13
- cat >/dev/null 2>&1 || true # drain stdin
14
-
15
- _dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
16
- home="${OKSTRA_HOME:-$HOME/.okstra}"
17
- # pane_reclaim 패키지는 repo 레이아웃(scripts/okstra_ctl)과 설치 레이아웃
18
- # ($OKSTRA_HOME/lib/python) 양쪽에 있을 수 있으므로 둘 다 PYTHONPATH 에 둔다.
19
- export PYTHONPATH="${_dir}:${home}/lib/python${PYTHONPATH:+:$PYTHONPATH}"
20
-
21
- while IFS= read -r run_dir; do
22
- [[ -n "$run_dir" ]] || continue
23
- "$_dir/okstra-trace-cleanup.sh" --reclaim-completed --run-dir "$run_dir" >/dev/null 2>&1 || true
24
- done < <(python3 -m okstra_ctl.pane_reclaim --active-dirs "$home" 2>/dev/null || true)
25
-
26
- exit 0