okstra 0.34.1 → 0.36.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 +26 -16
- package/README.md +26 -16
- package/docs/kr/architecture.md +59 -45
- package/docs/kr/cli.md +61 -18
- package/docs/pr-template-usage.md +65 -0
- package/docs/project-structure-overview.md +358 -354
- package/docs/superpowers/plans/2026-05-12-ticket-id-in-reports.md +1 -1
- package/docs/superpowers/plans/2026-05-14-convergence-queue-pruning.md +1 -1
- package/docs/superpowers/plans/2026-05-17-dual-format-final-report.md +1 -1
- package/docs/superpowers/plans/2026-05-20-final-report-language.md +1501 -0
- package/docs/superpowers/plans/2026-05-20-implementation-planning-multi-stage.md +1267 -0
- package/docs/superpowers/plans/2026-05-20-okstra-run-prompt-sot-b1.md +1007 -0
- package/docs/superpowers/plans/2026-05-20-wizard-messages-json-sot.md +720 -0
- package/docs/superpowers/plans/2026-05-20-wizard-prompt-json-sot-a1.md +681 -0
- package/docs/superpowers/plans/2026-05-21-improvement-discovery-task-type.md +1691 -0
- package/docs/superpowers/specs/2026-05-20-final-report-language-design.md +383 -0
- package/docs/superpowers/specs/2026-05-20-implementation-planning-multi-stage-design.md +320 -0
- package/docs/superpowers/specs/2026-05-20-okstra-run-prompt-sot-design.md +299 -0
- package/docs/superpowers/specs/2026-05-21-improvement-discovery-task-type-design.md +335 -0
- package/docs/task-process/README.md +74 -0
- package/docs/task-process/common-flow.md +166 -0
- package/docs/task-process/error-analysis.md +101 -0
- package/docs/task-process/final-verification.md +167 -0
- package/docs/task-process/implementation-planning.md +128 -0
- package/docs/task-process/implementation.md +149 -0
- package/docs/task-process/release-handoff.md +206 -0
- package/docs/task-process/requirements-discovery.md +115 -0
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/SKILL.md +12 -2
- package/runtime/agents/workers/claude-worker.md +26 -0
- package/runtime/agents/workers/codex-worker.md +27 -1
- package/runtime/agents/workers/gemini-worker.md +27 -1
- package/runtime/agents/workers/report-writer-worker.md +8 -1
- package/runtime/bin/okstra-central.sh +6 -6
- package/runtime/bin/okstra-codex-exec.sh +49 -28
- package/runtime/bin/okstra-gemini-exec.sh +39 -21
- package/runtime/bin/okstra-render-final-report.py +13 -2
- package/runtime/bin/okstra-wrapper-status.py +155 -0
- package/runtime/bin/okstra.sh +2 -2
- package/runtime/prompts/profiles/_common-contract.md +11 -6
- package/runtime/prompts/profiles/error-analysis.md +3 -7
- package/runtime/prompts/profiles/implementation-planning.md +22 -21
- package/runtime/prompts/profiles/implementation.md +28 -11
- package/runtime/prompts/profiles/improvement-discovery.md +42 -0
- package/runtime/prompts/profiles/kr/_common-contract.md +92 -0
- package/runtime/prompts/profiles/kr/error-analysis.md +36 -0
- package/runtime/prompts/profiles/kr/final-verification.md +48 -0
- package/runtime/prompts/profiles/kr/implementation-planning.md +90 -0
- package/runtime/prompts/profiles/kr/implementation.md +144 -0
- package/runtime/prompts/profiles/kr/improvement-discovery.md +42 -0
- package/runtime/prompts/profiles/kr/release-handoff.md +104 -0
- package/runtime/prompts/profiles/kr/requirements-discovery.md +42 -0
- package/runtime/prompts/profiles/release-handoff.md +1 -1
- package/runtime/prompts/profiles/requirements-discovery.md +8 -12
- package/runtime/prompts/wizard/prompts.ko.json +230 -0
- package/runtime/python/lib/okstra/cli.sh +2 -49
- package/runtime/python/lib/okstra/globals.sh +21 -21
- package/runtime/python/lib/okstra/interactive.sh +7 -7
- package/runtime/python/okstra_ctl/clarification_items.py +3 -9
- package/runtime/python/okstra_ctl/consumers.py +53 -0
- package/runtime/python/okstra_ctl/final_report_schema.py +0 -7
- package/runtime/python/okstra_ctl/i18n.py +73 -0
- package/runtime/python/okstra_ctl/improvement_lenses.py +44 -0
- package/runtime/python/okstra_ctl/index.py +1 -1
- package/runtime/python/okstra_ctl/paths.py +23 -20
- package/runtime/python/okstra_ctl/render.py +147 -202
- package/runtime/python/okstra_ctl/render_final_report.py +53 -10
- package/runtime/python/okstra_ctl/run.py +292 -107
- package/runtime/python/okstra_ctl/run_context.py +22 -0
- package/runtime/python/okstra_ctl/seeding.py +186 -0
- package/runtime/python/okstra_ctl/wizard.py +348 -127
- package/runtime/python/okstra_ctl/workflow.py +21 -2
- package/runtime/python/okstra_ctl/worktree.py +54 -1
- package/runtime/python/okstra_project/resolver.py +4 -3
- package/runtime/python/okstra_token_usage/report.py +2 -2
- package/runtime/schemas/final-report-v1.0.schema.json +22 -16
- package/runtime/skills/okstra-brief/SKILL.md +124 -31
- package/runtime/skills/okstra-convergence/SKILL.md +2 -3
- package/runtime/skills/okstra-report-writer/SKILL.md +35 -15
- package/runtime/skills/okstra-run/SKILL.md +5 -4
- package/runtime/skills/okstra-schedule/SKILL.md +4 -4
- package/runtime/skills/okstra-setup/SKILL.md +27 -0
- package/runtime/skills/okstra-team-contract/SKILL.md +1 -1
- package/runtime/templates/okstra.CLAUDE.md +104 -0
- package/runtime/templates/reports/final-report.template.md +93 -98
- package/runtime/templates/reports/i18n/en.json +135 -0
- package/runtime/templates/reports/i18n/ko.json +135 -0
- package/runtime/templates/reports/implementation-planning-input.template.md +18 -0
- package/runtime/templates/reports/improvement-discovery-input.template.md +78 -0
- package/runtime/templates/reports/task-brief.template.md +2 -2
- package/runtime/validators/lib/fixtures.sh +30 -0
- package/runtime/validators/lib/runners.sh +1 -1
- package/runtime/validators/validate-implementation-plan-stages.py +211 -0
- package/runtime/validators/validate-run.py +121 -26
- package/runtime/validators/validate-workflow.sh +2 -2
- package/runtime/validators/validate_improvement_report.py +275 -0
- package/src/config.mjs +18 -0
- package/src/install.mjs +41 -14
- package/src/setup.mjs +133 -1
- package/src/uninstall.mjs +21 -1
package/src/install.mjs
CHANGED
|
@@ -15,6 +15,10 @@ const SETTINGS_TEMPLATE_SRC_REL = ["templates", "reports", "settings.template.js
|
|
|
15
15
|
// Destination under ~/.okstra/. Project-local .claude/settings.local.json symlinks here.
|
|
16
16
|
const SETTINGS_TEMPLATE_DST_REL = ["templates", "settings.local.json"];
|
|
17
17
|
|
|
18
|
+
// okstra-managed CLAUDE.md template. Per-project <PROJECT>/.project-docs/okstra/CLAUDE.md
|
|
19
|
+
// symlinks here; <PROJECT>/CLAUDE.md gets an `@.project-docs/okstra/CLAUDE.md` import line.
|
|
20
|
+
const CLAUDE_MD_TEMPLATE_REL = ["templates", "okstra.CLAUDE.md"];
|
|
21
|
+
|
|
18
22
|
const PYTHON_PACKAGES = ["okstra_project", "okstra_ctl", "okstra_token_usage", "okstra_vendor", "lib"];
|
|
19
23
|
const BIN_ENTRYPOINTS = [
|
|
20
24
|
"okstra.sh",
|
|
@@ -42,7 +46,7 @@ Usage:
|
|
|
42
46
|
Effect (copy mode):
|
|
43
47
|
${"$HOME"}/.okstra/lib/python <- runtime/python
|
|
44
48
|
${"$HOME"}/.okstra/bin <- runtime/bin
|
|
45
|
-
${"$HOME"}/.okstra/templates <- runtime/templates (report.css / report.js / *.template.md)
|
|
49
|
+
${"$HOME"}/.okstra/templates <- runtime/templates (report.css / report.js / *.template.md / okstra.CLAUDE.md)
|
|
46
50
|
${"$HOME"}/.okstra/templates/settings.local.json <- runtime/templates/reports/settings.template.json
|
|
47
51
|
${"$HOME"}/.claude/skills/<name> <- runtime/skills/<name> (per skill)
|
|
48
52
|
${"$HOME"}/.claude/agents/<worker>.md <- runtime/agents/workers/<worker>.md
|
|
@@ -54,6 +58,7 @@ Effect (link mode):
|
|
|
54
58
|
${"$HOME"}/.okstra/lib/python/<pkg> -> <repo>/scripts/<pkg> (symlink)
|
|
55
59
|
${"$HOME"}/.okstra/bin/<name>.sh -> <repo>/scripts/<name>.sh
|
|
56
60
|
${"$HOME"}/.okstra/templates/settings.local.json -> <repo>/templates/reports/settings.template.json
|
|
61
|
+
${"$HOME"}/.okstra/templates/okstra.CLAUDE.md -> <repo>/templates/okstra.CLAUDE.md
|
|
57
62
|
${"$HOME"}/.claude/skills/<name> -> <repo>/skills/<name> (symlink dir)
|
|
58
63
|
${"$HOME"}/.claude/agents/<worker>.md -> <repo>/agents/workers/<worker>.md
|
|
59
64
|
${"$HOME"}/.okstra/dev-link <- <repo> path stamp
|
|
@@ -64,6 +69,11 @@ project-local <project>/.claude/settings.local.json that okstra-setup
|
|
|
64
69
|
provisions, granting per-project Claude Code permissions for okstra
|
|
65
70
|
worker wrapper scripts without modifying the user's global settings.
|
|
66
71
|
|
|
72
|
+
The okstra.CLAUDE.md file is the symlink target referenced by every
|
|
73
|
+
project-local <project>/.project-docs/okstra/CLAUDE.md that okstra-setup provisions;
|
|
74
|
+
<project>/CLAUDE.md gets an "@.project-docs/okstra/CLAUDE.md" import block so Claude
|
|
75
|
+
Code automatically picks up the okstra runtime guidance.
|
|
76
|
+
|
|
67
77
|
Worker agent definitions are installed into ${"$HOME"}/.claude/agents/ so
|
|
68
78
|
that Claude Code's subagent discovery picks them up; they cannot live
|
|
69
79
|
inside the package alone because the harness only scans ~/.claude/agents/
|
|
@@ -245,7 +255,8 @@ async function installLinkMode(repoPath, paths, opts) {
|
|
|
245
255
|
const agentResult = await installAgentsLink(repoAbs, { dryRun, quiet });
|
|
246
256
|
await writeAgentsManifest(paths.home, agentResult.installed, { dryRun });
|
|
247
257
|
|
|
248
|
-
await
|
|
258
|
+
await installNamedTemplate(repoAbs, paths, { mode: "link", dryRun, quiet }, SETTINGS_TEMPLATE_DESCRIPTOR);
|
|
259
|
+
await installNamedTemplate(repoAbs, paths, { mode: "link", dryRun, quiet }, CLAUDE_MD_TEMPLATE_DESCRIPTOR);
|
|
249
260
|
|
|
250
261
|
if (!dryRun) {
|
|
251
262
|
await writeFileAtomic(join(paths.home, "dev-link"), repoAbs + "\n", 0o644);
|
|
@@ -395,13 +406,14 @@ async function installAgentsLink(repoAbs, opts) {
|
|
|
395
406
|
return { installed: names };
|
|
396
407
|
}
|
|
397
408
|
|
|
398
|
-
async function
|
|
409
|
+
async function installNamedTemplate(srcRoot, paths, opts, descriptor) {
|
|
399
410
|
const { mode, refresh = false, dryRun = false, quiet = false } = opts;
|
|
400
|
-
const
|
|
401
|
-
const
|
|
411
|
+
const { srcRel, dstRel, label } = descriptor;
|
|
412
|
+
const src = join(srcRoot, ...srcRel);
|
|
413
|
+
const dst = join(paths.home, ...dstRel);
|
|
402
414
|
|
|
403
415
|
if (!(await fileExists(src))) {
|
|
404
|
-
if (!quiet) process.stdout.write(`
|
|
416
|
+
if (!quiet) process.stdout.write(` ${label}: source missing — skipped (${src})\n`);
|
|
405
417
|
return { installed: false };
|
|
406
418
|
}
|
|
407
419
|
|
|
@@ -409,7 +421,7 @@ async function installSettingsTemplate(srcRoot, paths, opts) {
|
|
|
409
421
|
|
|
410
422
|
if (mode === "link") {
|
|
411
423
|
const action = await ensureSymlink(src, dst, { dryRun });
|
|
412
|
-
if (!quiet) process.stdout.write(`
|
|
424
|
+
if (!quiet) process.stdout.write(` ${label}: ${action} (${dst} -> ${src})\n`);
|
|
413
425
|
return { installed: action !== "skipped" };
|
|
414
426
|
}
|
|
415
427
|
|
|
@@ -426,7 +438,7 @@ async function installSettingsTemplate(srcRoot, paths, opts) {
|
|
|
426
438
|
}
|
|
427
439
|
|
|
428
440
|
if (!needsCopy) {
|
|
429
|
-
if (!quiet) process.stdout.write(`
|
|
441
|
+
if (!quiet) process.stdout.write(` ${label}: skipped (hash match)\n`);
|
|
430
442
|
return { installed: false };
|
|
431
443
|
}
|
|
432
444
|
|
|
@@ -436,10 +448,22 @@ async function installSettingsTemplate(srcRoot, paths, opts) {
|
|
|
436
448
|
const buf = await fs.readFile(src);
|
|
437
449
|
await writeFileAtomic(dst, buf, 0o644);
|
|
438
450
|
}
|
|
439
|
-
if (!quiet) process.stdout.write(`
|
|
451
|
+
if (!quiet) process.stdout.write(` ${label}: copied -> ${dst}\n`);
|
|
440
452
|
return { installed: true };
|
|
441
453
|
}
|
|
442
454
|
|
|
455
|
+
const SETTINGS_TEMPLATE_DESCRIPTOR = {
|
|
456
|
+
srcRel: SETTINGS_TEMPLATE_SRC_REL,
|
|
457
|
+
dstRel: SETTINGS_TEMPLATE_DST_REL,
|
|
458
|
+
label: "settings template",
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
const CLAUDE_MD_TEMPLATE_DESCRIPTOR = {
|
|
462
|
+
srcRel: CLAUDE_MD_TEMPLATE_REL,
|
|
463
|
+
dstRel: CLAUDE_MD_TEMPLATE_REL,
|
|
464
|
+
label: "claude.md template",
|
|
465
|
+
};
|
|
466
|
+
|
|
443
467
|
async function installSkillsCopy(runtimeRoot, opts) {
|
|
444
468
|
const { refresh, dryRun, quiet } = opts;
|
|
445
469
|
const srcRoot = join(runtimeRoot, "skills");
|
|
@@ -553,10 +577,11 @@ export async function runInstall(args) {
|
|
|
553
577
|
paths.bin,
|
|
554
578
|
{ refresh: opts.refresh, dryRun: opts.dryRun, mode: 0o755 },
|
|
555
579
|
);
|
|
556
|
-
// templates/ tree — report.css / report.js / *.template.md
|
|
557
|
-
// runtime by okstra-render-report-views.py
|
|
558
|
-
//
|
|
559
|
-
//
|
|
580
|
+
// templates/ tree — report.css / report.js / *.template.md / okstra.CLAUDE.md
|
|
581
|
+
// are consumed at runtime by okstra-render-report-views.py, final-report
|
|
582
|
+
// assembly, and the per-project .project-docs/okstra/CLAUDE.md symlink provisioned by
|
|
583
|
+
// setup. They are NOT covered by installNamedTemplate (which only handles
|
|
584
|
+
// the renamed settings.local.json sidecar), so without this step copy-mode
|
|
560
585
|
// installs miss every asset other than that single file. See
|
|
561
586
|
// okstra-render-report-views.py _TEMPLATES_DIRS for the lookup path.
|
|
562
587
|
const templatesResult = await copyTreeIfChanged(
|
|
@@ -588,7 +613,9 @@ export async function runInstall(args) {
|
|
|
588
613
|
const agentResult = await installAgentsCopy(runtimeRoot, opts);
|
|
589
614
|
await writeAgentsManifest(paths.home, agentResult.installed, { dryRun: opts.dryRun });
|
|
590
615
|
|
|
591
|
-
await
|
|
616
|
+
await installNamedTemplate(runtimeRoot, paths, { mode: "copy", ...opts }, SETTINGS_TEMPLATE_DESCRIPTOR);
|
|
617
|
+
// okstra.CLAUDE.md is already covered by the runtime/templates tree copy
|
|
618
|
+
// above (same src/dst path, no rename). No second call needed in copy mode.
|
|
592
619
|
|
|
593
620
|
if (!opts.dryRun) {
|
|
594
621
|
await writeFileAtomic(join(paths.home, "version"), paths.package + "\n", 0o644);
|
package/src/setup.mjs
CHANGED
|
@@ -293,9 +293,37 @@ export async function run(args) {
|
|
|
293
293
|
);
|
|
294
294
|
}
|
|
295
295
|
|
|
296
|
+
let claudeMd = { symlink: null, importInjected: false };
|
|
297
|
+
try {
|
|
298
|
+
claudeMd = await ensureProjectClaudeMd(projectRoot);
|
|
299
|
+
} catch (err) {
|
|
300
|
+
process.stderr.write(
|
|
301
|
+
`warning: failed to wire <PROJECT>/CLAUDE.md @ .project-docs/okstra/CLAUDE.md import — ` +
|
|
302
|
+
`Claude Code sessions in this project will not auto-load okstra guidance. (${err.message})\n`,
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
let agentsMdSymlink = null;
|
|
307
|
+
try {
|
|
308
|
+
agentsMdSymlink = await ensureProjectAgentsMd(projectRoot);
|
|
309
|
+
} catch (err) {
|
|
310
|
+
process.stderr.write(
|
|
311
|
+
`warning: failed to provision <PROJECT>/AGENTS.md symlink — ` +
|
|
312
|
+
`codex / aider sessions in this project will not auto-load okstra guidance. (${err.message})\n`,
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
296
316
|
process.stdout.write(
|
|
297
317
|
JSON.stringify(
|
|
298
|
-
{
|
|
318
|
+
{
|
|
319
|
+
ok: true,
|
|
320
|
+
...result,
|
|
321
|
+
projectJsonPath,
|
|
322
|
+
settingsLocalJson: settingsSymlink,
|
|
323
|
+
claudeMdSymlink: claudeMd.symlink,
|
|
324
|
+
claudeMdImportInjected: claudeMd.importInjected,
|
|
325
|
+
agentsMdSymlink,
|
|
326
|
+
},
|
|
299
327
|
null,
|
|
300
328
|
2,
|
|
301
329
|
) + "\n",
|
|
@@ -348,3 +376,107 @@ async function backupAndReplace(target, template) {
|
|
|
348
376
|
await fs.rename(target, backup);
|
|
349
377
|
await fs.symlink(template, target);
|
|
350
378
|
}
|
|
379
|
+
|
|
380
|
+
const CLAUDE_MD_TEMPLATE_PATH = join(homedir(), ".okstra", "templates", "okstra.CLAUDE.md");
|
|
381
|
+
const CLAUDE_MD_SYMLINK_REL = join(".project-docs", "okstra", "CLAUDE.md");
|
|
382
|
+
const CLAUDE_MD_IMPORT_LINE = "@.project-docs/okstra/CLAUDE.md";
|
|
383
|
+
const CLAUDE_MD_MARKER_BEGIN = "<!-- okstra:claude-md:begin (managed by okstra setup — do not edit) -->";
|
|
384
|
+
const CLAUDE_MD_MARKER_END = "<!-- okstra:claude-md:end -->";
|
|
385
|
+
|
|
386
|
+
async function ensureProjectClaudeMd(projectRoot) {
|
|
387
|
+
try {
|
|
388
|
+
await fs.access(CLAUDE_MD_TEMPLATE_PATH);
|
|
389
|
+
} catch {
|
|
390
|
+
return { symlink: null, importInjected: false };
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const symlink = await ensureClaudeMdSymlink(projectRoot);
|
|
394
|
+
const importInjected = await ensureClaudeMdImport(projectRoot);
|
|
395
|
+
return { symlink, importInjected };
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
async function ensureClaudeMdSymlink(projectRoot) {
|
|
399
|
+
const target = join(projectRoot, CLAUDE_MD_SYMLINK_REL);
|
|
400
|
+
await fs.mkdir(join(target, ".."), { recursive: true });
|
|
401
|
+
|
|
402
|
+
let existingStat;
|
|
403
|
+
try {
|
|
404
|
+
existingStat = await fs.lstat(target);
|
|
405
|
+
} catch {
|
|
406
|
+
existingStat = null;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (existingStat?.isSymbolicLink()) {
|
|
410
|
+
const current = await fs.readlink(target);
|
|
411
|
+
const resolved = current.startsWith("/") ? current : join(target, "..", current);
|
|
412
|
+
if (resolved === CLAUDE_MD_TEMPLATE_PATH) return target;
|
|
413
|
+
await backupAndReplace(target, CLAUDE_MD_TEMPLATE_PATH);
|
|
414
|
+
return target;
|
|
415
|
+
}
|
|
416
|
+
if (existingStat) {
|
|
417
|
+
await backupAndReplace(target, CLAUDE_MD_TEMPLATE_PATH);
|
|
418
|
+
return target;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
await fs.symlink(CLAUDE_MD_TEMPLATE_PATH, target);
|
|
422
|
+
return target;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
async function ensureClaudeMdImport(projectRoot) {
|
|
426
|
+
const claudeMdPath = join(projectRoot, "CLAUDE.md");
|
|
427
|
+
const block = `${CLAUDE_MD_MARKER_BEGIN}\n${CLAUDE_MD_IMPORT_LINE}\n${CLAUDE_MD_MARKER_END}\n`;
|
|
428
|
+
|
|
429
|
+
let existing;
|
|
430
|
+
try {
|
|
431
|
+
existing = await fs.readFile(claudeMdPath, "utf8");
|
|
432
|
+
} catch (err) {
|
|
433
|
+
if (err.code !== "ENOENT") throw err;
|
|
434
|
+
await fs.writeFile(claudeMdPath, block, { mode: 0o644 });
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (existing.includes(CLAUDE_MD_MARKER_BEGIN) && existing.includes(CLAUDE_MD_MARKER_END)) {
|
|
439
|
+
return false;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const separator = blockSeparatorFor(existing);
|
|
443
|
+
await fs.writeFile(claudeMdPath, existing + separator + block, { mode: 0o644 });
|
|
444
|
+
return true;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function blockSeparatorFor(existing) {
|
|
448
|
+
if (existing.length === 0) return "";
|
|
449
|
+
if (existing.endsWith("\n\n")) return "";
|
|
450
|
+
if (existing.endsWith("\n")) return "\n";
|
|
451
|
+
return "\n\n";
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
async function ensureProjectAgentsMd(projectRoot) {
|
|
455
|
+
try {
|
|
456
|
+
await fs.access(CLAUDE_MD_TEMPLATE_PATH);
|
|
457
|
+
} catch {
|
|
458
|
+
return null;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const target = join(projectRoot, "AGENTS.md");
|
|
462
|
+
|
|
463
|
+
let existingStat;
|
|
464
|
+
try {
|
|
465
|
+
existingStat = await fs.lstat(target);
|
|
466
|
+
} catch {
|
|
467
|
+
existingStat = null;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (existingStat?.isSymbolicLink()) {
|
|
471
|
+
const current = await fs.readlink(target);
|
|
472
|
+
const resolved = current.startsWith("/") ? current : join(target, "..", current);
|
|
473
|
+
if (resolved === CLAUDE_MD_TEMPLATE_PATH) return target;
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
if (existingStat) {
|
|
477
|
+
return null;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
await fs.symlink(CLAUDE_MD_TEMPLATE_PATH, target);
|
|
481
|
+
return target;
|
|
482
|
+
}
|
package/src/uninstall.mjs
CHANGED
|
@@ -11,14 +11,19 @@ const BIN_ENTRYPOINTS = [
|
|
|
11
11
|
"okstra-central.sh",
|
|
12
12
|
"okstra-token-usage.py",
|
|
13
13
|
"okstra-error-log.py",
|
|
14
|
+
"okstra-render-report-views.py",
|
|
15
|
+
"okstra-render-final-report.py",
|
|
16
|
+
"okstra-wrapper-status.py",
|
|
14
17
|
];
|
|
15
18
|
|
|
16
19
|
const FALLBACK_SKILL_NAMES = [
|
|
17
20
|
"okstra-setup",
|
|
21
|
+
"okstra-brief",
|
|
18
22
|
"okstra-run",
|
|
19
23
|
"okstra-status",
|
|
20
24
|
"okstra-history",
|
|
21
25
|
"okstra-schedule",
|
|
26
|
+
"okstra-logs",
|
|
22
27
|
"okstra-context-loader",
|
|
23
28
|
"okstra-team-contract",
|
|
24
29
|
"okstra-convergence",
|
|
@@ -44,7 +49,9 @@ const USAGE = `okstra uninstall — remove installed runtime from ~/.okstra, ~/.
|
|
|
44
49
|
Usage:
|
|
45
50
|
okstra uninstall Remove ~/.okstra/{lib, bin/<known>, version,
|
|
46
51
|
dev-link, installed-skills.json,
|
|
47
|
-
installed-agents.json
|
|
52
|
+
installed-agents.json,
|
|
53
|
+
templates/settings.local.json,
|
|
54
|
+
templates/okstra.CLAUDE.md} AND
|
|
48
55
|
~/.claude/skills/<name> AND
|
|
49
56
|
~/.claude/agents/<worker>.md for every
|
|
50
57
|
entry in the install manifests (fallback:
|
|
@@ -52,6 +59,12 @@ Usage:
|
|
|
52
59
|
Preserves user data: recent.jsonl,
|
|
53
60
|
active.jsonl, projects/, archive/,
|
|
54
61
|
state.json, .locks/
|
|
62
|
+
Per-project artifacts created by 'okstra setup'
|
|
63
|
+
(<PROJECT>/.project-docs/okstra/CLAUDE.md symlink,
|
|
64
|
+
<PROJECT>/CLAUDE.md import block,
|
|
65
|
+
<PROJECT>/AGENTS.md symlink,
|
|
66
|
+
<PROJECT>/.claude/settings.local.json symlink)
|
|
67
|
+
are NOT touched — remove them manually if needed.
|
|
55
68
|
okstra uninstall --purge Remove the entire ~/.okstra directory AND
|
|
56
69
|
~/.claude/skills/<okstra-*> AND
|
|
57
70
|
~/.claude/agents/<*-worker.md> (DESTRUCTIVE).
|
|
@@ -182,6 +195,13 @@ export async function runUninstall(args) {
|
|
|
182
195
|
await removePath(join(paths.home, AGENTS_MANIFEST_REL), opts);
|
|
183
196
|
|
|
184
197
|
await removePath(join(paths.home, "templates", "settings.local.json"), opts);
|
|
198
|
+
await removePath(join(paths.home, "templates", "okstra.CLAUDE.md"), opts);
|
|
199
|
+
// Per-project artifacts (<PROJECT>/.project-docs/okstra/CLAUDE.md symlink,
|
|
200
|
+
// <PROJECT>/AGENTS.md symlink, and the @.project-docs/okstra/CLAUDE.md import
|
|
201
|
+
// block inside <PROJECT>/CLAUDE.md) are NOT removed here — uninstall is
|
|
202
|
+
// machine-level and does not know which projects opted in. Symlinks will
|
|
203
|
+
// dangle until the user removes them manually or re-runs okstra install +
|
|
204
|
+
// okstra setup.
|
|
185
205
|
// Remove templates/ if now empty.
|
|
186
206
|
const templatesDir = join(paths.home, "templates");
|
|
187
207
|
if (await pathExists(templatesDir)) {
|