okstra 0.111.0 → 0.112.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/README.kr.md +2 -2
- package/README.md +2 -2
- package/bin/okstra +7 -1
- package/docs/for-ai/README.md +2 -2
- package/docs/for-ai/skills/okstra-brief.md +2 -3
- package/docs/for-ai/skills/okstra-container-build.md +2 -3
- package/docs/for-ai/skills/okstra-inspect.md +5 -12
- package/docs/for-ai/skills/okstra-rollup.md +3 -4
- package/docs/for-ai/skills/okstra-run.md +3 -5
- package/docs/for-ai/skills/okstra-schedule.md +2 -7
- package/docs/for-ai/skills/okstra-setup.md +1 -1
- package/docs/kr/architecture/storage-model.md +1 -2
- package/docs/kr/architecture.md +2 -2
- package/docs/kr/cli.md +4 -2
- package/docs/project-structure-overview.md +5 -3
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/prompts/coding-preflight/overview.md +3 -1
- package/runtime/prompts/launch.template.md +1 -5
- package/runtime/prompts/lead/context-loader.md +2 -4
- package/runtime/prompts/lead/convergence.md +11 -240
- package/runtime/prompts/lead/okstra-lead-contract.md +70 -34
- package/runtime/prompts/lead/plan-body-verification.md +240 -0
- package/runtime/prompts/lead/report-writer.md +7 -7
- package/runtime/prompts/lead/team-contract.md +15 -17
- package/runtime/prompts/profiles/_common-contract.md +1 -37
- package/runtime/prompts/profiles/_implementation-executor.md +2 -2
- package/runtime/prompts/profiles/_implementation-verifier.md +1 -1
- package/runtime/prompts/profiles/final-verification.md +1 -1
- package/runtime/prompts/profiles/implementation-planning.md +2 -2
- package/runtime/prompts/profiles/implementation.md +1 -1
- package/runtime/python/okstra_ctl/path_hints.py +1 -0
- package/runtime/python/okstra_ctl/paths.py +3 -0
- package/runtime/python/okstra_ctl/render.py +8 -0
- package/runtime/python/okstra_ctl/set_work_status.py +147 -0
- package/runtime/python/okstra_ctl/team_reconcile.py +1 -1
- package/runtime/skills/okstra-brief/SKILL.md +32 -176
- package/runtime/skills/okstra-brief/references/reporter-confirmations.md +71 -0
- package/runtime/skills/okstra-brief/references/tracker-recursion.md +90 -0
- package/runtime/skills/okstra-container-build/SKILL.md +7 -20
- package/runtime/skills/okstra-graphify/SKILL.md +8 -8
- package/runtime/skills/okstra-inspect/SKILL.md +27 -43
- package/runtime/skills/okstra-rollup/SKILL.md +6 -6
- package/runtime/skills/okstra-run/SKILL.md +7 -16
- package/runtime/skills/okstra-schedule/SKILL.md +64 -419
- package/runtime/skills/okstra-setup/SKILL.md +25 -223
- package/runtime/skills/okstra-setup/references/project-config.md +188 -0
- package/runtime/templates/reports/schedule.template.md +2 -2
- package/runtime/templates/worker-prompt-preamble.md +1 -1
- package/runtime/validators/validate-run.py +7 -7
- package/src/cli-registry.mjs +14 -0
- package/src/commands/inspect/set-work-status.mjs +31 -0
- package/src/commands/lifecycle/check-project.mjs +68 -56
- package/src/commands/lifecycle/install.mjs +1 -0
- package/src/commands/lifecycle/preflight.mjs +82 -0
|
@@ -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
|
-
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
stage: "resolve",
|
|
113
|
-
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
projectRoot,
|
|
171
|
-
|
|
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
|
+
}
|