okstra 0.6.0 → 0.6.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.
package/package.json
CHANGED
package/runtime/BUILD.json
CHANGED
|
@@ -285,15 +285,27 @@ def prepare_task_bundle(inp: PrepareInputs) -> PrepareOutputs:
|
|
|
285
285
|
project_root = Path(inp.project_root)
|
|
286
286
|
|
|
287
287
|
# ---- validate inputs ----
|
|
288
|
+
# Hint suffix added to every "okstra runtime asset missing" PrepareError below.
|
|
289
|
+
# These files ship with the package and live under runtime/ — if any are
|
|
290
|
+
# missing the install is incomplete or stale, not a user-content issue.
|
|
291
|
+
_INSTALL_HINT = (
|
|
292
|
+
" This file ships with the okstra package; its absence usually means a stale "
|
|
293
|
+
"or partial install. Run 'okstra ensure-installed' (or 'okstra install' again) "
|
|
294
|
+
"to repair the runtime. If the problem persists, run 'okstra doctor' for a "
|
|
295
|
+
"fuller diagnostic."
|
|
296
|
+
)
|
|
288
297
|
profile_dir = workspace_root / "prompts" / "profiles"
|
|
289
298
|
profile_file = profile_dir / f"{inp.task_type}.md"
|
|
290
299
|
if not profile_file.is_file():
|
|
291
300
|
raise PrepareError(
|
|
292
|
-
f"analysis profile file not found for task-type {inp.task_type}:
|
|
301
|
+
f"analysis profile file not found for task-type {inp.task_type}: "
|
|
302
|
+
f"{profile_file}.{_INSTALL_HINT}"
|
|
293
303
|
)
|
|
294
304
|
prompt_template = workspace_root / "prompts" / "launch.template.md"
|
|
295
305
|
if not prompt_template.is_file():
|
|
296
|
-
raise PrepareError(
|
|
306
|
+
raise PrepareError(
|
|
307
|
+
f"okstra prompt template not found: {prompt_template}.{_INSTALL_HINT}"
|
|
308
|
+
)
|
|
297
309
|
task_index_template = (
|
|
298
310
|
workspace_root / "templates" / "project-docs" / "task-index.template.md"
|
|
299
311
|
)
|
|
@@ -304,7 +316,9 @@ def prepare_task_bundle(inp: PrepareInputs) -> PrepareOutputs:
|
|
|
304
316
|
run_validator = workspace_root / "validators" / "validate-run.py"
|
|
305
317
|
for required in (task_index_template, final_report_template, run_validator, source_skill):
|
|
306
318
|
if not required.is_file():
|
|
307
|
-
raise PrepareError(
|
|
319
|
+
raise PrepareError(
|
|
320
|
+
f"required okstra template or source skill missing: {required}.{_INSTALL_HINT}"
|
|
321
|
+
)
|
|
308
322
|
if not project_root.is_dir():
|
|
309
323
|
raise PrepareError(f"project root not found: {project_root}")
|
|
310
324
|
if not inp.brief_path.is_file():
|
|
@@ -329,7 +343,11 @@ def prepare_task_bundle(inp: PrepareInputs) -> PrepareOutputs:
|
|
|
329
343
|
try:
|
|
330
344
|
upsert_project_json(project_root, inp.project_id)
|
|
331
345
|
except ResolverError as exc:
|
|
332
|
-
|
|
346
|
+
# Surface the project_root in the prefix so the user can tell which
|
|
347
|
+
# registration failed when multiple projects are in play. The full
|
|
348
|
+
# underlying ResolverError text (which carries remediation guidance)
|
|
349
|
+
# is preserved by the `: {exc}` suffix and the `raise ... from exc`.
|
|
350
|
+
raise PrepareError(f"project.json upsert failed for {project_root}: {exc}") from exc
|
|
333
351
|
|
|
334
352
|
# ---- workers resolution ----
|
|
335
353
|
profile_workers_csv = ",".join(resolve_profile_workers(profile_file))
|
|
@@ -75,9 +75,12 @@ def resolve_project_root(*, explicit_root: str = "",
|
|
|
75
75
|
if git_top is not None:
|
|
76
76
|
return git_top.resolve()
|
|
77
77
|
raise ResolverError(
|
|
78
|
-
"
|
|
79
|
-
"--project-root
|
|
80
|
-
"
|
|
78
|
+
"could not resolve PROJECT_ROOT from cwd. "
|
|
79
|
+
"Pass --project-root <abs-path>, "
|
|
80
|
+
"run from inside a project (a directory with .project-docs/okstra/project.json at or above cwd), "
|
|
81
|
+
"or run from inside a git working tree. "
|
|
82
|
+
"(PROJECT_ROOT 를 해석할 수 없습니다 — --project-root 를 명시하거나, "
|
|
83
|
+
"프로젝트 루트 또는 그 하위에서 실행하거나, git 작업 트리 안에서 실행해 주십시오.)")
|
|
81
84
|
|
|
82
85
|
|
|
83
86
|
def upsert_project_json(project_root: Path, project_id: str, *,
|
|
@@ -100,13 +103,20 @@ def upsert_project_json(project_root: Path, project_id: str, *,
|
|
|
100
103
|
data = json.loads(target.read_text())
|
|
101
104
|
except (OSError, json.JSONDecodeError) as exc:
|
|
102
105
|
raise ResolverError(
|
|
103
|
-
f"project.json
|
|
106
|
+
f"failed to read project.json at {target}: {exc} "
|
|
107
|
+
f"(project.json 을 읽을 수 없습니다.) "
|
|
108
|
+
f"If the file is corrupted, delete it and re-run 'okstra setup --project-id <id>'."
|
|
109
|
+
) from exc
|
|
104
110
|
existing_id = str(data.get("projectId") or "")
|
|
105
111
|
if existing_id and existing_id != project_id:
|
|
106
112
|
raise ResolverError(
|
|
107
|
-
f"projectId
|
|
108
|
-
f"
|
|
109
|
-
f"
|
|
113
|
+
f"projectId mismatch: existing project.json has {existing_id!r} "
|
|
114
|
+
f"but the supplied argument is {project_id!r}. "
|
|
115
|
+
f"okstra allows only one projectId per PROJECT_ROOT. "
|
|
116
|
+
f"To fix: re-run with --project-id {existing_id!r} to keep the existing registration, "
|
|
117
|
+
f"or manually delete {target} if you intend to re-register this directory "
|
|
118
|
+
f"under a different id. "
|
|
119
|
+
f"(projectId 불일치: 한 PROJECT_ROOT 에는 하나의 projectId 만 허용됩니다.)")
|
|
110
120
|
result = {
|
|
111
121
|
"projectId": project_id,
|
|
112
122
|
"projectRoot": abs_root,
|
package/src/check-project.mjs
CHANGED
|
@@ -103,10 +103,15 @@ export async function run(args) {
|
|
|
103
103
|
);
|
|
104
104
|
|
|
105
105
|
if (probe.code !== 0) {
|
|
106
|
+
const raw = probe.stderr.trim() || probe.stdout.trim();
|
|
106
107
|
emit(opts, {
|
|
107
108
|
ok: false,
|
|
108
109
|
stage: "python",
|
|
109
|
-
reason:
|
|
110
|
+
reason:
|
|
111
|
+
`python invocation failed: ${raw}. ` +
|
|
112
|
+
"This usually means the okstra runtime is stale or missing — " +
|
|
113
|
+
"run 'okstra doctor' to diagnose, then 'okstra ensure-installed' " +
|
|
114
|
+
"to repair.",
|
|
110
115
|
});
|
|
111
116
|
return 1;
|
|
112
117
|
}
|
package/src/setup.mjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { promises as fs } from "node:fs";
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
3
|
import { createInterface } from "node:readline";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { resolve as resolvePath } from "node:path";
|
|
4
6
|
import { resolvePaths } from "./paths.mjs";
|
|
5
7
|
|
|
6
8
|
const USAGE = `okstra setup — register the current project with okstra
|
|
@@ -192,8 +194,51 @@ export async function run(args) {
|
|
|
192
194
|
try {
|
|
193
195
|
resolved = await resolveProjectRoot(paths, opts.projectRoot);
|
|
194
196
|
} catch (err) {
|
|
197
|
+
if (err.code === "RESOLVER") {
|
|
198
|
+
const cwd = resolvePath(process.cwd());
|
|
199
|
+
const home = resolvePath(homedir());
|
|
200
|
+
const inHome = cwd === home;
|
|
201
|
+
process.stderr.write(
|
|
202
|
+
"error: 'okstra setup' registers the CURRENT directory as an okstra project,\n" +
|
|
203
|
+
" but no project root could be resolved from here.\n" +
|
|
204
|
+
` cwd: ${cwd}\n` +
|
|
205
|
+
(inHome
|
|
206
|
+
? " (this looks like your home directory — setup is project-level, not machine-level;\n" +
|
|
207
|
+
" machine-level install is 'okstra install', which you've likely already done.)\n"
|
|
208
|
+
: "") +
|
|
209
|
+
"\nFix one of:\n" +
|
|
210
|
+
" 1. cd into the project you want to register, then re-run:\n" +
|
|
211
|
+
" cd <your project> && okstra setup --project-id <id>\n" +
|
|
212
|
+
" 2. pass an explicit path:\n" +
|
|
213
|
+
" okstra setup --project-root <abs-path> --project-id <id>\n" +
|
|
214
|
+
" 3. run from inside any git working tree (the toplevel becomes PROJECT_ROOT).\n" +
|
|
215
|
+
`\n(underlying error: ${err.message})\n`,
|
|
216
|
+
);
|
|
217
|
+
return 2;
|
|
218
|
+
}
|
|
219
|
+
// Non-RESOLVER path: typically python invocation failure (PYTHONPATH wrong,
|
|
220
|
+
// ~/.okstra missing, python3 not on PATH, okstra_project module missing).
|
|
221
|
+
// The user can't fix this by adjusting setup arguments — it's a runtime
|
|
222
|
+
// health issue, not a PROJECT_ROOT issue. Reword accordingly.
|
|
223
|
+
const looksLikePythonFailure = /python invocation failed|ModuleNotFoundError|No module named/.test(
|
|
224
|
+
err.message,
|
|
225
|
+
);
|
|
226
|
+
if (looksLikePythonFailure) {
|
|
227
|
+
process.stderr.write(
|
|
228
|
+
"error: 'okstra setup' could not start because the okstra runtime is not\n" +
|
|
229
|
+
" reachable from this process. This is almost always a stale or\n" +
|
|
230
|
+
" incomplete install, not a problem with your setup arguments.\n" +
|
|
231
|
+
"\nFix:\n" +
|
|
232
|
+
" 1. run 'okstra doctor' to see exactly what is missing\n" +
|
|
233
|
+
" 2. run 'okstra ensure-installed' (or 'npx -y okstra@latest install')\n" +
|
|
234
|
+
" to repair the runtime\n" +
|
|
235
|
+
" 3. retry: okstra setup --project-id <id>\n" +
|
|
236
|
+
`\n(underlying error: ${err.message})\n`,
|
|
237
|
+
);
|
|
238
|
+
return 1;
|
|
239
|
+
}
|
|
195
240
|
process.stderr.write(`error: could not resolve PROJECT_ROOT: ${err.message}\n`);
|
|
196
|
-
return
|
|
241
|
+
return 1;
|
|
197
242
|
}
|
|
198
243
|
const { projectRoot, projectJsonPath } = resolved;
|
|
199
244
|
|