okstra 0.111.0 → 0.113.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 (64) hide show
  1. package/README.kr.md +2 -2
  2. package/README.md +2 -2
  3. package/bin/okstra +7 -1
  4. package/docs/for-ai/README.md +2 -2
  5. package/docs/for-ai/skills/okstra-brief.md +2 -3
  6. package/docs/for-ai/skills/okstra-container-build.md +2 -3
  7. package/docs/for-ai/skills/okstra-inspect.md +5 -12
  8. package/docs/for-ai/skills/okstra-rollup.md +3 -4
  9. package/docs/for-ai/skills/okstra-run.md +3 -5
  10. package/docs/for-ai/skills/okstra-schedule.md +2 -7
  11. package/docs/for-ai/skills/okstra-setup.md +1 -1
  12. package/docs/kr/architecture/storage-model.md +1 -2
  13. package/docs/kr/architecture.md +2 -2
  14. package/docs/kr/cli.md +4 -2
  15. package/docs/project-structure-overview.md +5 -3
  16. package/package.json +1 -1
  17. package/runtime/BUILD.json +2 -2
  18. package/runtime/agents/workers/antigravity-worker.md +1 -1
  19. package/runtime/agents/workers/claude-worker.md +1 -1
  20. package/runtime/agents/workers/codex-worker.md +1 -1
  21. package/runtime/prompts/coding-preflight/overview.md +3 -1
  22. package/runtime/prompts/launch.template.md +1 -5
  23. package/runtime/prompts/lead/context-loader.md +2 -4
  24. package/runtime/prompts/lead/convergence.md +11 -240
  25. package/runtime/prompts/lead/okstra-lead-contract.md +70 -34
  26. package/runtime/prompts/lead/plan-body-verification.md +240 -0
  27. package/runtime/prompts/lead/report-writer.md +7 -7
  28. package/runtime/prompts/lead/team-contract.md +15 -17
  29. package/runtime/prompts/profiles/_common-contract.md +1 -37
  30. package/runtime/prompts/profiles/_implementation-executor.md +2 -2
  31. package/runtime/prompts/profiles/_implementation-self-check.md +1 -0
  32. package/runtime/prompts/profiles/_implementation-verifier.md +2 -2
  33. package/runtime/prompts/profiles/final-verification.md +6 -5
  34. package/runtime/prompts/profiles/implementation-planning.md +6 -4
  35. package/runtime/prompts/profiles/implementation.md +1 -1
  36. package/runtime/prompts/profiles/improvement-discovery.md +1 -0
  37. package/runtime/prompts/profiles/requirements-discovery.md +1 -0
  38. package/runtime/python/okstra_ctl/path_hints.py +1 -0
  39. package/runtime/python/okstra_ctl/paths.py +3 -0
  40. package/runtime/python/okstra_ctl/render.py +8 -0
  41. package/runtime/python/okstra_ctl/set_work_status.py +147 -0
  42. package/runtime/python/okstra_ctl/team_reconcile.py +1 -1
  43. package/runtime/schemas/final-report-v1.0.schema.json +6 -4
  44. package/runtime/skills/okstra-brief/SKILL.md +32 -176
  45. package/runtime/skills/okstra-brief/references/reporter-confirmations.md +71 -0
  46. package/runtime/skills/okstra-brief/references/tracker-recursion.md +90 -0
  47. package/runtime/skills/okstra-container-build/SKILL.md +7 -20
  48. package/runtime/skills/okstra-graphify/SKILL.md +8 -8
  49. package/runtime/skills/okstra-inspect/SKILL.md +27 -43
  50. package/runtime/skills/okstra-rollup/SKILL.md +6 -6
  51. package/runtime/skills/okstra-run/SKILL.md +7 -16
  52. package/runtime/skills/okstra-schedule/SKILL.md +64 -419
  53. package/runtime/skills/okstra-setup/SKILL.md +25 -223
  54. package/runtime/skills/okstra-setup/references/project-config.md +188 -0
  55. package/runtime/templates/reports/final-report.template.md +24 -1
  56. package/runtime/templates/reports/improvement-discovery-input.template.md +3 -2
  57. package/runtime/templates/reports/schedule.template.md +2 -2
  58. package/runtime/templates/worker-prompt-preamble.md +5 -1
  59. package/runtime/validators/validate-run.py +8 -7
  60. package/src/cli-registry.mjs +14 -0
  61. package/src/commands/inspect/set-work-status.mjs +31 -0
  62. package/src/commands/lifecycle/check-project.mjs +68 -56
  63. package/src/commands/lifecycle/install.mjs +1 -0
  64. package/src/commands/lifecycle/preflight.mjs +82 -0
@@ -45,6 +45,13 @@ export const COMMAND_REGISTRY = [
45
45
  category: "admin",
46
46
  summary: ["Verify the current project has been registered with setup"],
47
47
  },
48
+ {
49
+ name: "preflight",
50
+ module: "./commands/lifecycle/preflight.mjs",
51
+ export: "run",
52
+ category: "admin",
53
+ summary: ["One-call skill preflight: ensure-installed + check-project (JSON)"],
54
+ },
48
55
  {
49
56
  name: "config",
50
57
  module: "./commands/lifecycle/config.mjs",
@@ -117,6 +124,13 @@ export const COMMAND_REGISTRY = [
117
124
  category: "introspection",
118
125
  summary: ["Resolve a bare task-id to candidate task-keys from the catalog"],
119
126
  },
127
+ {
128
+ name: "set-work-status",
129
+ module: "./commands/inspect/set-work-status.mjs",
130
+ export: "run",
131
+ category: "introspection",
132
+ summary: ["Set a task's user-managed workStatus in task-manifest.json"],
133
+ },
120
134
  {
121
135
  name: "time-report",
122
136
  module: "./commands/inspect/time-report.mjs",
@@ -0,0 +1,31 @@
1
+ import { runPythonModule } from "../../lib/python-helper.mjs";
2
+
3
+ const USAGE = `okstra set-work-status — set a task's user-managed workStatus
4
+
5
+ Usage:
6
+ okstra set-work-status <token> <status> [--note <text>] [--task-group <g>]
7
+ [--project-root <dir>] [--cwd <dir>] [--json]
8
+
9
+ <token> is a full task-key (<project-id>:<task-group>:<task-id>) or a bare
10
+ task-id. <status> is one of: todo | in-progress | blocked | done.
11
+
12
+ Updates workStatus + workStatusUpdatedAt in task-manifest.json (workStatusNote
13
+ only when --note is passed) using the same JSON serialization as the manifest
14
+ renderer. Output: JSON { ok, taskKey, previousWorkStatus, workStatus, ... };
15
+ ok:false stages: resolve | catalog | not-found | ambiguous (pick from
16
+ matches[]) | manifest-missing | manifest-invalid.
17
+ `;
18
+
19
+ export async function run(args) {
20
+ if (args.includes("--help") || args.includes("-h")) {
21
+ process.stdout.write(USAGE);
22
+ return 0;
23
+ }
24
+
25
+ const result = await runPythonModule({
26
+ module: "okstra_ctl.set_work_status",
27
+ args,
28
+ stdio: "inherit-stdout",
29
+ });
30
+ return result.code;
31
+ }
@@ -63,6 +63,14 @@ export async function run(args) {
63
63
  process.stderr.write(`error: ${err.message}\n\n${USAGE}`);
64
64
  return 2;
65
65
  }
66
+ const { code, payload } = await checkProject({ cwd: opts.cwd });
67
+ emit(opts, payload);
68
+ return code;
69
+ }
70
+
71
+ // Core check shared with 'okstra preflight' — resolves PROJECT_ROOT from cwd
72
+ // and validates .okstra/project.json without writing to stdout.
73
+ export async function checkProject({ cwd = process.cwd() } = {}) {
66
74
  const paths = await resolvePaths();
67
75
 
68
76
  const probe = await runProcess(
@@ -79,23 +87,25 @@ export async function run(args) {
79
87
  "except ResolverError as e:",
80
88
  " print('RESOLVER_ERROR', e)",
81
89
  ].join("\n"),
82
- opts.cwd,
90
+ cwd,
83
91
  ],
84
92
  { PYTHONPATH: buildPythonpath(paths) },
85
93
  );
86
94
 
87
95
  if (probe.code !== 0) {
88
96
  const raw = probe.stderr.trim() || probe.stdout.trim();
89
- emit(opts, {
90
- ok: false,
91
- stage: "python",
92
- reason:
93
- `python invocation failed: ${raw}. ` +
94
- "This usually means the okstra runtime is stale or missing — " +
95
- "run 'okstra doctor' to diagnose, then 'okstra ensure-installed' " +
96
- "to repair.",
97
- });
98
- return 1;
97
+ return {
98
+ code: 1,
99
+ payload: {
100
+ ok: false,
101
+ stage: "python",
102
+ reason:
103
+ `python invocation failed: ${raw}. ` +
104
+ "This usually means the okstra runtime is stale or missing — " +
105
+ "run 'okstra doctor' to diagnose, then 'okstra ensure-installed' " +
106
+ "to repair.",
107
+ },
108
+ };
99
109
  }
100
110
 
101
111
  const lines = probe.stdout.trim().split("\n");
@@ -107,36 +117,37 @@ export async function run(args) {
107
117
 
108
118
  const resolverError = tagOf("RESOLVER_ERROR");
109
119
  if (resolverError) {
110
- emit(opts, {
111
- ok: false,
112
- stage: "resolve",
113
- reason: resolverError,
114
- cwd: opts.cwd,
115
- });
116
- return 2;
120
+ return {
121
+ code: 2,
122
+ payload: { ok: false, stage: "resolve", reason: resolverError, cwd },
123
+ };
117
124
  }
118
125
 
119
126
  const projectRoot = tagOf("PROJECT_ROOT");
120
127
  const projectJsonPath = tagOf("PROJECT_JSON");
121
128
  if (!projectRoot || !projectJsonPath) {
122
- emit(opts, {
123
- ok: false,
124
- stage: "parse",
125
- reason: "could not parse python output",
126
- raw: probe.stdout,
127
- });
128
- return 1;
129
+ return {
130
+ code: 1,
131
+ payload: {
132
+ ok: false,
133
+ stage: "parse",
134
+ reason: "could not parse python output",
135
+ raw: probe.stdout,
136
+ },
137
+ };
129
138
  }
130
139
 
131
140
  if (!(await fileExists(projectJsonPath))) {
132
- emit(opts, {
133
- ok: false,
134
- stage: "project_json_missing",
135
- reason: `${projectJsonPath} not found — run /okstra-setup in this project first`,
136
- projectRoot,
137
- projectJsonPath,
138
- });
139
- return 1;
141
+ return {
142
+ code: 1,
143
+ payload: {
144
+ ok: false,
145
+ stage: "project_json_missing",
146
+ reason: `${projectJsonPath} not found — run /okstra-setup in this project first`,
147
+ projectRoot,
148
+ projectJsonPath,
149
+ },
150
+ };
140
151
  }
141
152
 
142
153
  let projectId = null;
@@ -144,32 +155,33 @@ export async function run(args) {
144
155
  const data = JSON.parse(await fs.readFile(projectJsonPath, "utf8"));
145
156
  projectId = typeof data?.projectId === "string" ? data.projectId : null;
146
157
  } catch (err) {
147
- emit(opts, {
148
- ok: false,
149
- stage: "project_json_invalid",
150
- reason: `failed to parse ${projectJsonPath}: ${err.message}`,
151
- projectRoot,
152
- projectJsonPath,
153
- });
154
- return 1;
158
+ return {
159
+ code: 1,
160
+ payload: {
161
+ ok: false,
162
+ stage: "project_json_invalid",
163
+ reason: `failed to parse ${projectJsonPath}: ${err.message}`,
164
+ projectRoot,
165
+ projectJsonPath,
166
+ },
167
+ };
155
168
  }
156
169
 
157
170
  if (!projectId) {
158
- emit(opts, {
159
- ok: false,
160
- stage: "project_json_invalid",
161
- reason: `${projectJsonPath} missing projectId field`,
162
- projectRoot,
163
- projectJsonPath,
164
- });
165
- return 1;
171
+ return {
172
+ code: 1,
173
+ payload: {
174
+ ok: false,
175
+ stage: "project_json_invalid",
176
+ reason: `${projectJsonPath} missing projectId field`,
177
+ projectRoot,
178
+ projectJsonPath,
179
+ },
180
+ };
166
181
  }
167
182
 
168
- emit(opts, {
169
- ok: true,
170
- projectRoot,
171
- projectJsonPath,
172
- projectId,
173
- });
174
- return 0;
183
+ return {
184
+ code: 0,
185
+ payload: { ok: true, projectRoot, projectJsonPath, projectId },
186
+ };
175
187
  }
@@ -48,6 +48,7 @@ const REQUIRED_PROMPT_RESOURCE_FILES = Object.freeze([
48
48
  ["prompts", "lead", "context-loader.md"],
49
49
  ["prompts", "lead", "team-contract.md"],
50
50
  ["prompts", "lead", "convergence.md"],
51
+ ["prompts", "lead", "plan-body-verification.md"],
51
52
  ["prompts", "lead", "report-writer.md"],
52
53
  ["prompts", "coding-preflight", "overview.md"],
53
54
  ["prompts", "coding-preflight", "clean-code.md"],
@@ -0,0 +1,82 @@
1
+ import { checkProject } from "./check-project.mjs";
2
+ import { runEnsureInstalled } from "./install.mjs";
3
+
4
+ const USAGE = `okstra preflight — one-call skill preflight (ensure-installed + check-project)
5
+
6
+ Usage:
7
+ okstra preflight [--runtime <name>] [--cwd <dir>] [--json]
8
+
9
+ Runs the runtime freshness check (quietly reinstalling when stale), then
10
+ verifies the target project has .okstra/project.json. Prints one JSON object:
11
+
12
+ ok: true {ok, projectRoot, projectJsonPath, projectId}
13
+ ok: false {ok, stage, reason, ...}
14
+ stage: install | resolve | project_json_missing |
15
+ project_json_invalid | python | parse
16
+
17
+ Options:
18
+ --runtime <name> Runtime whose assets must be present (e.g. claude-code);
19
+ forwarded to ensure-installed.
20
+ --cwd <dir> Resolve PROJECT_ROOT from <dir> instead of process cwd.
21
+ --json Default output format (kept for symmetry).
22
+
23
+ Exit codes:
24
+ 0 runtime fresh and project registered
25
+ 1 runtime install failed, or project setup missing/invalid
26
+ 2 PROJECT_ROOT could not be resolved from cwd (pass --cwd), or bad flags
27
+ `;
28
+
29
+ function parseArgs(args) {
30
+ const opts = { cwd: process.cwd(), runtime: null };
31
+ for (let i = 0; i < args.length; i++) {
32
+ const a = args[i];
33
+ if (a === "--json") continue;
34
+ if (a === "--cwd" || a === "--runtime") {
35
+ const next = args[i + 1];
36
+ if (!next || next.startsWith("--")) throw new Error(`${a} requires a value`);
37
+ if (a === "--cwd") opts.cwd = next;
38
+ else opts.runtime = next;
39
+ i++;
40
+ } else {
41
+ throw new Error(`unknown argument '${a}'`);
42
+ }
43
+ }
44
+ return opts;
45
+ }
46
+
47
+ function emit(payload) {
48
+ process.stdout.write(JSON.stringify(payload, null, 2) + "\n");
49
+ }
50
+
51
+ export async function run(args) {
52
+ if (args.includes("--help") || args.includes("-h")) {
53
+ process.stdout.write(USAGE);
54
+ return 0;
55
+ }
56
+
57
+ let opts;
58
+ try {
59
+ opts = parseArgs(args);
60
+ } catch (err) {
61
+ process.stderr.write(`error: ${err.message}\n\n${USAGE}`);
62
+ return 2;
63
+ }
64
+
65
+ const ensureArgs = ["--quiet"];
66
+ if (opts.runtime) ensureArgs.push("--runtime", opts.runtime);
67
+ const installCode = await runEnsureInstalled(ensureArgs);
68
+ if (installCode !== 0) {
69
+ emit({
70
+ ok: false,
71
+ stage: "install",
72
+ reason:
73
+ "okstra runtime install failed — run 'okstra doctor' to diagnose, " +
74
+ "then 'okstra install' to repair.",
75
+ });
76
+ return installCode === 2 ? 2 : 1;
77
+ }
78
+
79
+ const { code, payload } = await checkProject({ cwd: opts.cwd });
80
+ emit(payload);
81
+ return code;
82
+ }