otacon 0.1.1 → 0.1.3

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 (128) hide show
  1. package/README.md +101 -64
  2. package/dist/cli/browser.js +55 -0
  3. package/dist/cli/browser.js.map +1 -0
  4. package/dist/cli/client.js +11 -0
  5. package/dist/cli/client.js.map +1 -1
  6. package/dist/cli/commands/clean.js +3 -2
  7. package/dist/cli/commands/clean.js.map +1 -1
  8. package/dist/cli/commands/config.js +62 -0
  9. package/dist/cli/commands/config.js.map +1 -0
  10. package/dist/cli/commands/doctor.js +41 -21
  11. package/dist/cli/commands/doctor.js.map +1 -1
  12. package/dist/cli/commands/install.js +53 -30
  13. package/dist/cli/commands/install.js.map +1 -1
  14. package/dist/cli/commands/open.js +14 -14
  15. package/dist/cli/commands/open.js.map +1 -1
  16. package/dist/cli/commands/start.js +8 -22
  17. package/dist/cli/commands/start.js.map +1 -1
  18. package/dist/cli/commands/update.js +76 -0
  19. package/dist/cli/commands/update.js.map +1 -0
  20. package/dist/cli/install/assets.js +35 -43
  21. package/dist/cli/install/assets.js.map +1 -1
  22. package/dist/cli/install/locations.js +15 -25
  23. package/dist/cli/install/locations.js.map +1 -1
  24. package/dist/cli/main.js +10 -1
  25. package/dist/cli/main.js.map +1 -1
  26. package/dist/cli/update.js +195 -0
  27. package/dist/cli/update.js.map +1 -0
  28. package/dist/daemon/app.js +281 -54
  29. package/dist/daemon/app.js.map +1 -1
  30. package/dist/daemon/approve.js +49 -11
  31. package/dist/daemon/approve.js.map +1 -1
  32. package/dist/daemon/store.js +39 -2
  33. package/dist/daemon/store.js.map +1 -1
  34. package/dist/daemon/threads.js +11 -0
  35. package/dist/daemon/threads.js.map +1 -1
  36. package/dist/daemon/ui.js +9 -1
  37. package/dist/daemon/ui.js.map +1 -1
  38. package/dist/shared/config.js +301 -45
  39. package/dist/shared/config.js.map +1 -1
  40. package/dist/shared/paths.js +41 -5
  41. package/dist/shared/paths.js.map +1 -1
  42. package/dist/shared/types.js +6 -2
  43. package/dist/shared/types.js.map +1 -1
  44. package/dist/shared/version.js +1 -1
  45. package/dist/ui/assets/{arc-HhPfdCPZ.js → arc-Cp3sPd_U.js} +1 -1
  46. package/dist/ui/assets/architecture-7EHR7CIX-BbwstElO.js +1 -0
  47. package/dist/ui/assets/{architectureDiagram-3BPJPVTR-D2PIxGOb.js → architectureDiagram-3BPJPVTR-C4F3heWP.js} +1 -1
  48. package/dist/ui/assets/{blockDiagram-GPEHLZMM-DQ3Dn17h.js → blockDiagram-GPEHLZMM-DmJoG8ky.js} +1 -1
  49. package/dist/ui/assets/{c4Diagram-AAUBKEIU-DxITrQgS.js → c4Diagram-AAUBKEIU-BDEf52Jp.js} +1 -1
  50. package/dist/ui/assets/channel-BMK3JFRf.js +1 -0
  51. package/dist/ui/assets/{chunk-2J33WTMH-Du1JoPx5.js → chunk-2J33WTMH-Dh_UFriv.js} +1 -1
  52. package/dist/ui/assets/{chunk-3OPIFGDE-Dn7x2Yqf.js → chunk-3OPIFGDE-c66RlAN8.js} +1 -1
  53. package/dist/ui/assets/{chunk-4BX2VUAB-DVnrE-4n.js → chunk-4BX2VUAB-CrGJaCCg.js} +1 -1
  54. package/dist/ui/assets/{chunk-55IACEB6-BAhFAimA.js → chunk-55IACEB6-BvwqEeyq.js} +1 -1
  55. package/dist/ui/assets/{chunk-5ZQYHXKU-0hEZptem.js → chunk-5ZQYHXKU-BfF2IfQe.js} +1 -1
  56. package/dist/ui/assets/{chunk-727SXJPM-C1FN_cI3.js → chunk-727SXJPM-DOEUwc9I.js} +1 -1
  57. package/dist/ui/assets/{chunk-AQP2D5EJ-A656OBd4.js → chunk-AQP2D5EJ-CVf2xV2Z.js} +1 -1
  58. package/dist/ui/assets/{chunk-BSJP7CBP-D8oMbjm8.js → chunk-BSJP7CBP-D_EbTWTC.js} +1 -1
  59. package/dist/ui/assets/{chunk-CSCIHK7Q-DjIL8GLi.js → chunk-CSCIHK7Q-CkxTSMAM.js} +1 -1
  60. package/dist/ui/assets/{chunk-FMBD7UC4-Otblfqvz.js → chunk-FMBD7UC4-DVShhFc7.js} +1 -1
  61. package/dist/ui/assets/{chunk-KSCS5N6A-BOjTvm3H.js → chunk-KSCS5N6A-DnHEEYpq.js} +1 -1
  62. package/dist/ui/assets/{chunk-L5ZTLDWV-CaTLaw6L.js → chunk-L5ZTLDWV-B_gjyajS.js} +1 -1
  63. package/dist/ui/assets/{chunk-LZXEDZCA-Dq5p7qrD.js → chunk-LZXEDZCA-Bsf7basG.js} +2 -2
  64. package/dist/ui/assets/{chunk-ND2GUHAM-jZ_NNnWi.js → chunk-ND2GUHAM-DGepGb8_.js} +1 -1
  65. package/dist/ui/assets/{chunk-NZK2D7GU-U_7l_sCh.js → chunk-NZK2D7GU-BJIlh-gB.js} +1 -1
  66. package/dist/ui/assets/{chunk-O5CBEL6O-MewqqNB7.js → chunk-O5CBEL6O-cdVbOOCs.js} +1 -1
  67. package/dist/ui/assets/chunk-QZHKN3VN-DLNUTn7U.js +1 -0
  68. package/dist/ui/assets/chunk-WU5MYG2G-ipH3YPcA.js +1 -0
  69. package/dist/ui/assets/{chunk-XPW4576I-D5ArxNEF.js → chunk-XPW4576I-DPW39hNO.js} +1 -1
  70. package/dist/ui/assets/classDiagram-4FO5ZUOK-CvIMLlSD.js +1 -0
  71. package/dist/ui/assets/classDiagram-v2-Q7XG4LA2-CvIMLlSD.js +1 -0
  72. package/dist/ui/assets/{cose-bilkent-S5V4N54A-PFXzf7WV.js → cose-bilkent-S5V4N54A-DmMsC6om.js} +1 -1
  73. package/dist/ui/assets/{dagre-BM42HDAG-xrCfjZuZ.js → dagre-BM42HDAG-BmVr7T7Z.js} +1 -1
  74. package/dist/ui/assets/{diagram-2AECGRRQ-BFf-cyKY.js → diagram-2AECGRRQ-e0VnXEyj.js} +1 -1
  75. package/dist/ui/assets/{diagram-5GNKFQAL-kNPV4NfV.js → diagram-5GNKFQAL-SCJGYE6m.js} +1 -1
  76. package/dist/ui/assets/{diagram-KO2AKTUF-ByC1IUwG.js → diagram-KO2AKTUF-DDUZO1Mj.js} +1 -1
  77. package/dist/ui/assets/{diagram-LMA3HP47-DZIJMPK0.js → diagram-LMA3HP47-5x1ypf6a.js} +1 -1
  78. package/dist/ui/assets/{diagram-OG6HWLK6-CSDED9A-.js → diagram-OG6HWLK6-3nDhrQ20.js} +1 -1
  79. package/dist/ui/assets/{dist-YwjsDswi.js → dist-NEinnePC.js} +1 -1
  80. package/dist/ui/assets/{erDiagram-TEJ5UH35-yuzvjE6J.js → erDiagram-TEJ5UH35-BNvwSDNZ.js} +1 -1
  81. package/dist/ui/assets/eventmodeling-FCH6USID-BeFWDbla.js +1 -0
  82. package/dist/ui/assets/{flowDiagram-I6XJVG4X-ApPtVyYM.js → flowDiagram-I6XJVG4X-Bt_wDUhb.js} +1 -1
  83. package/dist/ui/assets/{ganttDiagram-6RSMTGT7-BeMLXtAr.js → ganttDiagram-6RSMTGT7-DVcJ0rNX.js} +1 -1
  84. package/dist/ui/assets/{gitGraph-WXDBUCRP-JmTTBa7j.js → gitGraph-WXDBUCRP-CO_SyAgP.js} +1 -1
  85. package/dist/ui/assets/{gitGraphDiagram-PVQCEYII-Cjjnjs71.js → gitGraphDiagram-PVQCEYII-oDyO3lWI.js} +1 -1
  86. package/dist/ui/assets/index-CJJIQ0dr.css +1 -0
  87. package/dist/ui/assets/index-Dh5CsH24.js +11 -0
  88. package/dist/ui/assets/{info-J43DQDTF-8vZ3gome.js → info-J43DQDTF-Bn17NS7h.js} +1 -1
  89. package/dist/ui/assets/{infoDiagram-5YYISTIA-CnMk1cA-.js → infoDiagram-5YYISTIA-HG1opLLT.js} +1 -1
  90. package/dist/ui/assets/{ishikawaDiagram-YF4QCWOH-Bl8z6huD.js → ishikawaDiagram-YF4QCWOH-Di_yQwi8.js} +1 -1
  91. package/dist/ui/assets/{journeyDiagram-JHISSGLW-DYIVfMpS.js → journeyDiagram-JHISSGLW-DZtHvLeE.js} +1 -1
  92. package/dist/ui/assets/{kanban-definition-UN3LZRKU-BnR0ZzOz.js → kanban-definition-UN3LZRKU-B_RCx3Km.js} +1 -1
  93. package/dist/ui/assets/{line-DcBdQit6.js → line-DenX-zXQ.js} +1 -1
  94. package/dist/ui/assets/{linear-HKjRHFAO.js → linear-dly_ngoq.js} +1 -1
  95. package/dist/ui/assets/{mermaid-parser.core-DkYXrPlA.js → mermaid-parser.core-CRmtm0s9.js} +2 -2
  96. package/dist/ui/assets/{mermaid.core-BmkfCI3b.js → mermaid.core-C_3KVfpx.js} +3 -3
  97. package/dist/ui/assets/{mindmap-definition-RKZ34NQL-sIAd4nDi.js → mindmap-definition-RKZ34NQL-wdzSyYO6.js} +1 -1
  98. package/dist/ui/assets/{packet-YPE3B663-BxbxcfXN.js → packet-YPE3B663-tUyFmR11.js} +1 -1
  99. package/dist/ui/assets/{pie-LRSECV5Y-BJxazjNs.js → pie-LRSECV5Y-Cel48VVp.js} +1 -1
  100. package/dist/ui/assets/{pieDiagram-4H26LBE5-BiOhc9GR.js → pieDiagram-4H26LBE5-B55ypWtu.js} +1 -1
  101. package/dist/ui/assets/{plan-view-CH6NzUDb.js → plan-view-CMoo3_gE.js} +3 -3
  102. package/dist/ui/assets/{quadrantDiagram-W4KKPZXB-CVyHbWgo.js → quadrantDiagram-W4KKPZXB-9WcKQV0a.js} +1 -1
  103. package/dist/ui/assets/{radar-GUYGQ44K-D9ohbnbV.js → radar-GUYGQ44K-w5pk53Vr.js} +1 -1
  104. package/dist/ui/assets/{requirementDiagram-4Y6WPE33-Ba24_hqc.js → requirementDiagram-4Y6WPE33-CzE82fXz.js} +1 -1
  105. package/dist/ui/assets/{sankeyDiagram-5OEKKPKP-CxD4wiPL.js → sankeyDiagram-5OEKKPKP-DSGO39je.js} +1 -1
  106. package/dist/ui/assets/{sequenceDiagram-3UESZ5HK-7qA7lD61.js → sequenceDiagram-3UESZ5HK-BKSDDr0S.js} +1 -1
  107. package/dist/ui/assets/{src-IM8AE8MK.js → src-JXBGgRt-.js} +1 -1
  108. package/dist/ui/assets/{stateDiagram-AJRCARHV-DNElRCuH.js → stateDiagram-AJRCARHV-DZHYA9aj.js} +1 -1
  109. package/dist/ui/assets/stateDiagram-v2-BHNVJYJU-DnAfDlvZ.js +1 -0
  110. package/dist/ui/assets/{timeline-definition-PNZ67QCA-ChYC4Grd.js → timeline-definition-PNZ67QCA-WqJFw7aE.js} +1 -1
  111. package/dist/ui/assets/{treeView-BLDUP644-Il0KnMi_.js → treeView-BLDUP644-DoIQYMiz.js} +1 -1
  112. package/dist/ui/assets/{treemap-LRROVOQU-CIiKcdRo.js → treemap-LRROVOQU-BA9si_Mo.js} +1 -1
  113. package/dist/ui/assets/{vennDiagram-CIIHVFJN-Ulhkum9i.js → vennDiagram-CIIHVFJN-BvWRUfFr.js} +1 -1
  114. package/dist/ui/assets/{wardley-L42UT6IY-BNd4ljz7.js → wardley-L42UT6IY-Cf9PU44t.js} +1 -1
  115. package/dist/ui/assets/{wardleyDiagram-YWT4CUSO-BicXxh84.js → wardleyDiagram-YWT4CUSO-CGuxl7AU.js} +1 -1
  116. package/dist/ui/assets/{xychartDiagram-2RQKCTM6-Duf-m_th.js → xychartDiagram-2RQKCTM6-CNteNXpe.js} +1 -1
  117. package/dist/ui/index.html +2 -2
  118. package/package.json +1 -1
  119. package/dist/ui/assets/architecture-7EHR7CIX-BPLblcyi.js +0 -1
  120. package/dist/ui/assets/channel-ipcU8ZNI.js +0 -1
  121. package/dist/ui/assets/chunk-QZHKN3VN-DzGPH44B.js +0 -1
  122. package/dist/ui/assets/chunk-WU5MYG2G-DyEIVjoo.js +0 -1
  123. package/dist/ui/assets/classDiagram-4FO5ZUOK-Byg2Hl9D.js +0 -1
  124. package/dist/ui/assets/classDiagram-v2-Q7XG4LA2-Byg2Hl9D.js +0 -1
  125. package/dist/ui/assets/eventmodeling-FCH6USID-CZR4eNG-.js +0 -1
  126. package/dist/ui/assets/index-BFQVRcSI.js +0 -11
  127. package/dist/ui/assets/index-Bj_kTrwP.css +0 -1
  128. package/dist/ui/assets/stateDiagram-v2-BHNVJYJU-D6qTYpY3.js +0 -1
@@ -1,38 +1,44 @@
1
1
  // otacon install --agent claude|codex|opencode [--agent …] | --all [--hooks] —
2
2
  // write the protocol wrapper into each agent's skill location (DESIGN.md §16).
3
3
  // Pure file writes — no daemon needed. Wrappers are managed files: reinstall
4
- // overwrites them (Codex: only the marked block inside its shared AGENTS.md).
5
- // --hooks additionally registers the Claude Code Stop hook in
6
- // ~/.claude/settings.json merged additively and idempotently, with a backup
7
- // before the first change, never clobbering what cannot be parsed.
4
+ // overwrites them wholesale. --hooks additionally registers the Claude Code Stop
5
+ // hook in ~/.claude/settings.json merged additively and idempotently, with a
6
+ // backup before the first change, never clobbering what cannot be parsed.
8
7
  import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
9
8
  import { dirname } from "node:path";
10
9
  import { parseArgs } from "node:util";
11
- import { CODEX_BEGIN, CODEX_END, codexBlock, skillMd, STOP_HOOK_SCRIPT } from "../install/assets.js";
12
- import { claudeHookScriptPath, claudeSettingsPath, claudeSkillPath, codexAgentsPath, mergeStopHook, opencodeSkillPath, settingsRegisterStopHook, upsertMarkedBlock, } from "../install/locations.js";
10
+ import { skillMd, STOP_HOOK_SCRIPT } from "../install/assets.js";
11
+ import { claudeHookScriptPath, claudeSettingsPath, claudeSkillPath, codexSkillPath, mergeStopHook, opencodeSkillPath, settingsRegisterStopHook, } from "../install/locations.js";
13
12
  import { fail, notice, printJson, usageError } from "../output.js";
13
+ import { findRepoRoot } from "../session.js";
14
14
  const AGENTS = ["claude", "codex", "opencode"];
15
15
  function writeManaged(path, content) {
16
16
  mkdirSync(dirname(path), { recursive: true });
17
17
  writeFileSync(path, content);
18
18
  }
19
- function installAgent(agent) {
19
+ function installAgent(agent, scope) {
20
20
  switch (agent) {
21
21
  case "claude": {
22
- writeManaged(claudeSkillPath(), skillMd());
23
- writeManaged(claudeHookScriptPath(), STOP_HOOK_SCRIPT);
24
- chmodSync(claudeHookScriptPath(), 0o755);
25
- return { agent, files: [claudeSkillPath(), claudeHookScriptPath()] };
22
+ const skill = claudeSkillPath(scope);
23
+ writeManaged(skill, skillMd());
24
+ // The Stop hook script lives in the user home only — it is never written at
25
+ // project scope (DECISIONS.md "Stop hook deferred at project scope"), so a
26
+ // committed `.claude/` ships an inert skill wrapper, never a hook pointing at
27
+ // a script teammates may not have. `--hooks --project` is rejected upstream.
28
+ if (scope.kind === "user") {
29
+ writeManaged(claudeHookScriptPath(), STOP_HOOK_SCRIPT);
30
+ chmodSync(claudeHookScriptPath(), 0o755);
31
+ return { agent, files: [skill, claudeHookScriptPath()] };
32
+ }
33
+ return { agent, files: [skill] };
26
34
  }
27
35
  case "codex": {
28
- const path = codexAgentsPath();
29
- const existing = existsSync(path) ? readFileSync(path, "utf8") : "";
30
- writeManaged(path, upsertMarkedBlock(existing, codexBlock(), CODEX_BEGIN, CODEX_END));
31
- return { agent, files: [path] };
36
+ writeManaged(codexSkillPath(scope), skillMd());
37
+ return { agent, files: [codexSkillPath(scope)] };
32
38
  }
33
39
  case "opencode": {
34
- writeManaged(opencodeSkillPath(), skillMd());
35
- return { agent, files: [opencodeSkillPath()] };
40
+ writeManaged(opencodeSkillPath(scope), skillMd());
41
+ return { agent, files: [opencodeSkillPath(scope)] };
36
42
  }
37
43
  }
38
44
  }
@@ -65,19 +71,14 @@ function applyStopHook() {
65
71
  notice(`registered the otacon Stop hook in ${path}`);
66
72
  return { registered: true, command, settings: path, ...(backup ? { backup } : {}) };
67
73
  }
68
- /** Without --hooks: report the current state and offer the flag (DESIGN.md §16). */
74
+ // Without --hooks: report registration state without nagging (DESIGN.md §16). The
75
+ // Stop hook is optional, so its absence is neither warned about nor "offered" — the
76
+ // JSON still factually carries `registered` for anyone who wants to wire it up.
69
77
  function offerStopHook() {
70
- const path = claudeSettingsPath();
71
- const registered = settingsRegisterStopHook();
72
- if (!registered) {
73
- notice("Stop hook not registered — run `otacon install --agent claude --hooks` to add it to " +
74
- `${path} (merged additively, existing settings preserved, backup written first)`);
75
- }
76
78
  return {
77
- registered,
79
+ registered: settingsRegisterStopHook(),
78
80
  command: claudeHookScriptPath(),
79
- settings: path,
80
- ...(registered ? {} : { hint: "re-run with --hooks to register the Stop hook" }),
81
+ settings: claudeSettingsPath(),
81
82
  };
82
83
  }
83
84
  export async function installCommand(argv) {
@@ -87,6 +88,7 @@ export async function installCommand(argv) {
87
88
  agent: { type: "string", multiple: true },
88
89
  all: { type: "boolean", default: false },
89
90
  hooks: { type: "boolean", default: false },
91
+ project: { type: "boolean", default: false },
90
92
  },
91
93
  });
92
94
  const picked = values.all ? [...AGENTS] : (values.agent ?? []);
@@ -101,13 +103,34 @@ export async function installCommand(argv) {
101
103
  if (values.hooks && !agents.includes("claude")) {
102
104
  usageError("--hooks registers the Claude Code Stop hook; include --agent claude (or --all)");
103
105
  }
104
- const installed = agents.map(installAgent);
105
- const hooks = agents.includes("claude")
106
+ // The Stop hook is a user-level Claude Code registration; it is never installed at
107
+ // project scope (DECISIONS.md "Stop hook deferred at project scope"), so the two
108
+ // flags are mutually exclusive rather than silently picking one.
109
+ if (values.hooks && values.project) {
110
+ usageError("--hooks installs a user-level Stop hook and cannot be combined with --project; run --hooks without --project");
111
+ }
112
+ // --project resolves the install base to the current git repo root so the
113
+ // wrappers can be committed and shared; outside any repo it is a hard error
114
+ // (DECISIONS.md "`--project` resolves to the git repo root").
115
+ let scope = { kind: "user" };
116
+ if (values.project) {
117
+ const cwd = process.cwd();
118
+ const root = findRepoRoot(cwd);
119
+ if (root === undefined) {
120
+ usageError(`otacon install --project must run inside a git repo; none found at ${cwd}`);
121
+ }
122
+ scope = { kind: "project", root };
123
+ }
124
+ const installed = agents.map((agent) => installAgent(agent, scope));
125
+ // The Stop hook report is user-only: at project scope --hooks is rejected, and
126
+ // offerStopHook() would read the user ~/.claude/settings.json — misleading for a
127
+ // project install — so the entire hooks branch is gated on user scope.
128
+ const hooks = scope.kind === "user" && agents.includes("claude")
106
129
  ? values.hooks
107
130
  ? applyStopHook()
108
131
  : offerStopHook()
109
132
  : undefined;
110
- printJson({ ok: true, installed, ...(hooks ? { hooks } : {}) });
133
+ printJson({ ok: true, scope: scope.kind, installed, ...(hooks ? { hooks } : {}) });
111
134
  return 0;
112
135
  }
113
136
  //# sourceMappingURL=install.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/cli/commands/install.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/cli/commands/install.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,14 @@
1
- // otacon open [--session id] print the review URL (DESIGN.md §6, human
2
- // convenience). Print, never launch: agents also run this, and stdout is the
3
- // contract (DECISIONS.md "open prints, never launches a browser"). With no
4
- // resolvable session the index URL is the answer, not an error — reading is
5
- // never the wrong screen; the never-guess rule guards writes, not looks.
1
+ // otacon open [--session id]: launch the review URL in the browser (DESIGN.md
2
+ // §6, human convenience). It runs on the human's machine and the verb means "show
3
+ // me the page", so it spawns the browser; OTACON_NO_BROWSER prints the URL as JSON
4
+ // instead, for headless hosts and URL-parsing agents (DECISIONS.md "open and
5
+ // config launch the browser"). With no resolvable session the index URL is the
6
+ // answer, not an error; reading is never the wrong screen, and the never-guess
7
+ // rule guards writes, not looks.
6
8
  import { parseArgs } from "node:util";
9
+ import { openOrPrint } from "../browser.js";
7
10
  import { baseUrl, ensureDaemon } from "../client.js";
8
- import { CliError, notice, printJson } from "../output.js";
11
+ import { CliError, notice } from "../output.js";
9
12
  import { listSessions, realpathOr, resolveSession } from "../session.js";
10
13
  export async function openCommand(argv) {
11
14
  const { values } = parseArgs({
@@ -16,12 +19,8 @@ export async function openCommand(argv) {
16
19
  const sessions = await listSessions();
17
20
  try {
18
21
  const session = resolveSession(sessions, values.session, realpathOr(process.cwd()));
19
- printJson({
20
- ok: true,
21
- session: session.id,
22
- title: session.title,
23
- url: `${baseUrl()}/s/${session.id}`,
24
- });
22
+ const url = `${baseUrl()}/s/${session.id}`;
23
+ openOrPrint(url, { ok: true, session: session.id, title: session.title, url });
25
24
  }
26
25
  catch (error) {
27
26
  // An explicit --session that fails to resolve is a real refusal; implicit
@@ -29,8 +28,9 @@ export async function openCommand(argv) {
29
28
  // the index, which lists everything.
30
29
  if (!(error instanceof CliError) || values.session !== undefined)
31
30
  throw error;
32
- notice(`${error.message} printing the index URL`);
33
- printJson({ ok: true, url: `${baseUrl()}/` });
31
+ notice(`${error.message}; using the index`);
32
+ const url = `${baseUrl()}/`;
33
+ openOrPrint(url, { ok: true, url });
34
34
  }
35
35
  return 0;
36
36
  }
@@ -1 +1 @@
1
- {"version":3,"file":"open.js","sourceRoot":"","sources":["../../../src/cli/commands/open.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,6EAA6E;AAC7E,2EAA2E;AAC3E,4EAA4E;AAC5E,yEAAyE;AAEzE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEzE,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAc;IAC9C,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;QAC3B,IAAI,EAAE,IAAI;QACV,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;KACzC,CAAC,CAAC;IACH,MAAM,YAAY,EAAE,CAAC;IACrB,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAC;IACtC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACpF,SAAS,CAAC;YACR,EAAE,EAAE,IAAI;YACR,OAAO,EAAE,OAAO,CAAC,EAAE;YACnB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,GAAG,EAAE,GAAG,OAAO,EAAE,MAAM,OAAO,CAAC,EAAE,EAAE;SACpC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,0EAA0E;QAC1E,wEAAwE;QACxE,qCAAqC;QACrC,IAAI,CAAC,CAAC,KAAK,YAAY,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS;YAAE,MAAM,KAAK,CAAC;QAC9E,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;QACpD,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
1
+ {"version":3,"file":"open.js","sourceRoot":"","sources":["../../../src/cli/commands/open.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,kFAAkF;AAClF,mFAAmF;AACnF,6EAA6E;AAC7E,+EAA+E;AAC/E,+EAA+E;AAC/E,iCAAiC;AAEjC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEzE,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAc;IAC9C,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;QAC3B,IAAI,EAAE,IAAI;QACV,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;KACzC,CAAC,CAAC;IACH,MAAM,YAAY,EAAE,CAAC;IACrB,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAC;IACtC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACpF,MAAM,GAAG,GAAG,GAAG,OAAO,EAAE,MAAM,OAAO,CAAC,EAAE,EAAE,CAAC;QAC3C,WAAW,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IACjF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,0EAA0E;QAC1E,wEAAwE;QACxE,qCAAqC;QACrC,IAAI,CAAC,CAAC,KAAK,YAAY,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS;YAAE,MAAM,KAAK,CAAC;QAC9E,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;QAC5C,MAAM,GAAG,GAAG,GAAG,OAAO,EAAE,GAAG,CAAC;QAC5B,WAAW,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -1,14 +1,18 @@
1
1
  // otacon start --title <t> [--quick] — mint and register a session (DESIGN.md
2
- // §6, §16): POST /api/sessions, append .otacon/ to the repo's .gitignore if
3
- // missing (with a notice), print the session id and review URL. No local
2
+ // §6, §16): POST /api/sessions, print the session id and review URL. No local
4
3
  // session pointer — the daemon registry is the single source of truth (§7).
5
- import { appendFileSync, existsSync, readFileSync } from "node:fs";
6
- import { join } from "node:path";
7
4
  import { parseArgs } from "node:util";
8
5
  import { api, baseUrl, ensureDaemon } from "../client.js";
9
6
  import { fail, notice, printJson, usageError } from "../output.js";
10
7
  import { currentBranch, findRepoRoot, realpathOr } from "../session.js";
8
+ import { maybeAutoUpdate } from "../update.js";
11
9
  export async function startCommand(argv) {
10
+ // Pre-session auto-update gate (DESIGN.md §16): on a newer published version
11
+ // this self-updates and re-execs `start` with the original argv, so the flags
12
+ // below are reconstructed exactly; in every other case it returns and we
13
+ // proceed on the installed version. Must run before ensureDaemon so the
14
+ // re-exec's version handshake restarts the stale daemon.
15
+ await maybeAutoUpdate(argv);
12
16
  const { values } = parseArgs({
13
17
  args: argv,
14
18
  options: { title: { type: "string" }, quick: { type: "boolean", default: false } },
@@ -34,8 +38,6 @@ export async function startCommand(argv) {
34
38
  fail("E_INTERNAL", `session create failed: ${JSON.stringify(created.body)}`, undefined, 2);
35
39
  }
36
40
  const session = created.body;
37
- if (gitRoot !== undefined)
38
- ensureGitignore(gitRoot);
39
41
  printJson({
40
42
  ok: true,
41
43
  session: session.id,
@@ -47,20 +49,4 @@ export async function startCommand(argv) {
47
49
  });
48
50
  return 0;
49
51
  }
50
- /** First start in a repo appends .otacon/ to .gitignore, with a notice (DESIGN.md §16). */
51
- export function ensureGitignore(repo) {
52
- const path = join(repo, ".gitignore");
53
- const existing = existsSync(path) ? readFileSync(path, "utf8") : "";
54
- const covered = existing
55
- .split("\n")
56
- .some((line) => /^\/?\.otacon\/?$/.test(line.trim()));
57
- if (covered)
58
- return;
59
- // Match the file's own line endings — appending LF to a CRLF file would
60
- // leave it with mixed endings.
61
- const eol = existing.includes("\r\n") ? "\r\n" : "\n";
62
- const separator = existing === "" || existing.endsWith("\n") ? "" : eol;
63
- appendFileSync(path, `${separator}.otacon/${eol}`);
64
- notice(`appended .otacon/ to ${path} (working state stays out of git, DESIGN.md §12)`);
65
- }
66
52
  //# sourceMappingURL=start.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"start.js","sourceRoot":"","sources":["../../../src/cli/commands/start.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"start.js","sourceRoot":"","sources":["../../../src/cli/commands/start.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,8EAA8E;AAC9E,4EAA4E;AAE5E,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAc;IAC/C,6EAA6E;IAC7E,8EAA8E;IAC9E,yEAAyE;IACzE,wEAAwE;IACxE,yDAAyD;IACzD,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;IAE5B,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;QAC3B,IAAI,EAAE,IAAI;QACV,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;KACnF,CAAC,CAAC;IACH,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAC7D,UAAU,CAAC,mCAAmC,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,0EAA0E;QAC1E,MAAM,CAAC,GAAG,GAAG,4DAA4D,CAAC,CAAC;IAC7E,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,IAAI,GAAG,CAAC;IAE5B,MAAM,YAAY,EAAE,CAAC;IACrB,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,eAAe,EAAE;QACjD,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,IAAI;QACJ,MAAM,EAAE,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC;QACvD,KAAK,EAAE,MAAM,CAAC,KAAK,KAAK,IAAI;KAC7B,CAAC,CAAC;IACH,IAAI,OAAO,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC3B,IAAI,CAAC,YAAY,EAAE,0BAA0B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;IAC7F,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAkC,CAAC;IAE3D,SAAS,CAAC;QACR,EAAE,EAAE,IAAI;QACR,OAAO,EAAE,OAAO,CAAC,EAAE;QACnB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,IAAI;QACJ,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,GAAG,EAAE,GAAG,OAAO,EAAE,MAAM,OAAO,CAAC,EAAE,EAAE;KACpC,CAAC,CAAC;IACH,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1,76 @@
1
+ // otacon update [--check] — the manual/forced upgrade command (DESIGN.md §6,
2
+ // §16). It deliberately bypasses the auto-update gate's two suppressors: it
3
+ // ignores the 1h throttle (the user asked NOW) and `update.auto:false` (an
4
+ // explicit command overrides a config that only governs the implicit start-time
5
+ // check). It still fails open on a registry blip and never escalates to sudo —
6
+ // it shares `runNpmUpdate` with the start-time gate, so the install behavior is
7
+ // identical (D12, plan docs/plans/2026-06-19-auto-update-outdated-version.md).
8
+ //
9
+ // --check report current/latest/outdated and exit; never installs (a dry run
10
+ // for "am I behind?", and the only safe mode in CI / pinned shops).
11
+ //
12
+ // stdout is the usual single JSON line; npm's own progress and our notices go to
13
+ // stderr. Exit 0 on every reported outcome except an attempted-but-failed
14
+ // install, which is the one expected exit-1 failure (the manual command to run
15
+ // is on stderr).
16
+ import { parseArgs } from "node:util";
17
+ import { VERSION } from "../../shared/version.js";
18
+ import { isSourceRun } from "../client.js";
19
+ import { notice, printJson } from "../output.js";
20
+ import { fetchLatest, isNewer, runNpmUpdate } from "../update.js";
21
+ const REAL_DEPS = {
22
+ fetch: fetchLatest,
23
+ runNpmUpdate,
24
+ sourceRun: isSourceRun,
25
+ };
26
+ export async function updateCommand(argv, deps = REAL_DEPS) {
27
+ const { values } = parseArgs({
28
+ args: argv,
29
+ options: { check: { type: "boolean", default: false } },
30
+ });
31
+ // Dev-run refusal (D6): a source checkout has no global package to update.
32
+ if (deps.sourceRun()) {
33
+ notice("running otacon from a source checkout; nothing to update");
34
+ printJson({ ok: true, source: true, version: VERSION });
35
+ return 0;
36
+ }
37
+ // Fail-open (D5): a transient registry blip is not a hard error — report that
38
+ // we couldn't check and exit 0, exactly as the start-time gate proceeds.
39
+ const latest = await deps.fetch();
40
+ if (latest === undefined) {
41
+ notice("could not reach the npm registry to check for updates; try again later");
42
+ printJson({ ok: true, current: VERSION, latest: null, outdated: false });
43
+ return 0;
44
+ }
45
+ const outdated = isNewer(latest, VERSION);
46
+ // --check never installs: it's the dry run.
47
+ if (values.check === true) {
48
+ printJson({ ok: true, current: VERSION, latest, outdated });
49
+ return 0;
50
+ }
51
+ // Already current: nothing to do.
52
+ if (!outdated) {
53
+ printJson({ ok: true, current: VERSION, latest, outdated: false, updated: false });
54
+ return 0;
55
+ }
56
+ // Outdated: install. On failure this is the one expected exit-1 path.
57
+ if (!deps.runNpmUpdate(latest).ok) {
58
+ notice("auto-update failed; run: npm install -g otacon@latest");
59
+ printJson({
60
+ ok: false,
61
+ error: { code: "E_UPDATE_FAILED", message: "npm install -g otacon@latest failed" },
62
+ });
63
+ return 1;
64
+ }
65
+ // Success. This process is STILL the old code (the binary was swapped under
66
+ // it), so we do NOT restart the daemon here: ensureDaemon from this old CLI
67
+ // would see daemon.version === this process's (old) VERSION and find no
68
+ // mismatch, so it could not pull the new version anyway. The new daemon (and
69
+ // the open tabs' self-heal) come up on the NEXT `otacon` invocation, which
70
+ // runs the freshly-installed binary and trips the version handshake. We report
71
+ // that accurately rather than claim a restart that didn't happen (D12).
72
+ notice(`updated otacon ${VERSION} → ${latest}; the daemon and any open tabs update on your next otacon command`);
73
+ printJson({ ok: true, updated: true, from: VERSION, to: latest });
74
+ return 0;
75
+ }
76
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../../src/cli/commands/update.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,12 @@
1
1
  // The wrapper content `otacon install` writes (DESIGN.md §16) — this is the
2
2
  // product-critical text that teaches an agent the whole protocol: the §6 full
3
3
  // loop, §8 grill discipline, and §13 "never end your turn". One protocol card,
4
- // three destinations: Claude Code and OpenCode get it as a SKILL.md; Codex gets
5
- // it as a marker-delimited block inside its shared ~/.codex/AGENTS.md. Plus the
6
- // Stop hook shell script (§13). Wrappers are managed files: reinstall
7
- // overwrites them wholesale (DECISIONS.md "Wrappers are managed files").
4
+ // three destinations Claude Code, Codex, and OpenCode each get it as a
5
+ // SKILL.md in their own skills dir. Plus the Stop hook shell script (§13).
6
+ // Wrappers are managed files: reinstall overwrites them wholesale (DECISIONS.md
7
+ // "Wrappers are managed files").
8
8
  /** Present in every wrapper this tool owns; doctor greps for it. */
9
9
  export const MANAGED_MARKER = 'managed by `otacon install`';
10
- export const CODEX_BEGIN = '<!-- BEGIN OTACON — managed by `otacon install`; content inside these markers is overwritten on reinstall -->';
11
- export const CODEX_END = '<!-- END OTACON -->';
12
10
  /**
13
11
  * The protocol card — §6 full loop (start-first) + §8 grill discipline + §13
14
12
  * failure habits — parametrized by the command prefix so one source feeds both
@@ -27,7 +25,7 @@ machine-readable error you can fix (read the JSON); exit 2 = you invoked it wron
27
25
 
28
26
  1. \`${cmd} start --title <kebab-title>\` **first, before you research** — it mints
29
27
  the session and prints the review URL. Tell the user to open it (\`${cmd} open\`
30
- prints it again) so they can watch the whole thing from the first second.
28
+ launches it in their browser) so they can watch the whole thing from the first second.
31
29
  \`--quick\` skips the interview — only when the user explicitly asks.
32
30
  2. **Research the codebase**, narrating as you go with
33
31
  \`${cmd} progress "<what you're doing>"\` — call it whenever you start a chunk of
@@ -59,18 +57,23 @@ machine-readable error you can fix (read the JSON); exit 2 = you invoked it wron
59
57
  - \`comments\` → revise plan.md; write \`resolutions.json\` as
60
58
  \`{"changelog":"what changed","threads":{"t1":"how you resolved it"}}\` with
61
59
  one reply per comment thread; \`${cmd} submit --resolutions resolutions.json\`
62
- (loop on lint errors); park again.
60
+ (loop on lint errors); park again. A \`comments\` batch with \`"final":true\` is
61
+ the reviewer's **comment & approve**: resolve every thread the usual way, but
62
+ your next clean submit **finalizes** — you'll get \`approved\` (which may carry
63
+ \`implement:true\`), not another review round. So fold them all in, submit, then
64
+ park and handle the \`approved\` that follows (do NOT expect more comments).
63
65
  - \`question\` → \`${cmd} answer <q-id> --body "..."\` (or \`--file\`); park again. A
64
66
  \`question\` may carry \`replyTo\` (a follow-up on an earlier question) — skim that
65
67
  thread's prior turns for context, but still answer the new \`q<n>\`.
66
68
  - \`answer\` → use it and continue; park again whenever you are waiting.
67
69
  - \`timeout\` → park again immediately. A timeout is NEVER completion.
68
- - \`approved\` → \`git add\` + commit the plan file at the printed \`path\`. Plain
69
- \`approved\` (no \`implement\`) → print a one-line summary and STOP. \`approved\`
70
- **with \`implement:true\`** → after committing, enter the **Implement loop**
71
- (below) — do NOT stop; the session is now \`implementing\`.
70
+ - \`approved\` → the plan is saved at \`path\`. Plain \`approved\` (Save, no
71
+ \`implement\`) → print a one-line summary naming where it was saved (\`path\`),
72
+ then STOP. \`approved\` **with \`implement:true\`** → read the plan at \`path\` to
73
+ guide the build and enter the **Implement loop** (below) — do NOT stop; the
74
+ session is now \`implementing\`.
72
75
  - \`deleted\` → the user deleted this session in the review UI. It is over:
73
- STOP. There is no approved plan and nothing to commit.
76
+ STOP. There is no approved plan.
74
77
  6. **Never end your turn while the session is open.** Nothing to do = park in
75
78
  \`${cmd} wait\` again. Confused, crashed, or compacted? \`${cmd} status\` returns
76
79
  the open session, revision, and pending events — resume the loop from it.
@@ -80,7 +83,7 @@ machine-readable error you can fix (read the JSON); exit 2 = you invoked it wron
80
83
  - \`${cmd} start --title <t> [--quick]\` · \`${cmd} progress "<note>"\` ·
81
84
  \`${cmd} ask ...\` · \`${cmd} wait --timeout 540\` · \`${cmd} submit [--resolutions f]\` ·
82
85
  \`${cmd} answer <q> --body "..."\` · \`${cmd} implement-done [--pr <url>] [--failed]\` ·
83
- \`${cmd} status\` · \`${cmd} open\`
86
+ \`${cmd} status\` · \`${cmd} open\` · \`${cmd} config [get <key>]\`
84
87
 
85
88
  ## Implement loop (on \`approved\` with \`implement:true\`)
86
89
 
@@ -88,10 +91,14 @@ You are the **orchestrator**: you only coordinate and narrate
88
91
  (\`${cmd} progress\` at each checkpoint) — every phase's real work runs in a fresh
89
92
  native subagent (Task tool) so your own context stays lean.
90
93
 
91
- 1. **Setup.** Commit the plan file at the event \`path\` (exactly as plain Approve),
92
- then \`git worktree add .otacon/worktrees/<slug> -b otacon/impl-<slug>\` off that
93
- commit (\`.otacon/\` is gitignored). \`${cmd} progress\` each checkpoint throughout.
94
- 2. **Per phase, in order** (read the phases from the committed plan):
94
+ 1. **Setup.** On Implement the plan lives only in the home archive at the event
95
+ \`path\` (read the phases from there). Branch off the repo's current default branch
96
+ HEAD: create the
97
+ worktree under the configured \`worktree.dir\`
98
+ (\`${cmd} config get worktree.dir\` — default \`~/.otacon/worktrees\`, outside the repo):
99
+ \`git worktree add <worktree.dir>/<slug> -b otacon/impl-<slug>\` (off the default
100
+ branch). \`${cmd} progress\` each checkpoint throughout.
101
+ 2. **Per phase, in order** (read the phases from the home plan at the event \`path\`):
95
102
  - \`${cmd} progress "phase N — implementing"\`; spawn an **implement+test**
96
103
  subagent (Task tool) scoped to that phase's Goal/Files/Verification — it
97
104
  implements and runs the phase Verification plus the repo gates.
@@ -102,14 +109,10 @@ native subagent (Task tool) so your own context stays lean.
102
109
  review still flags, or a subagent is stuck) → on the FIRST blocker,
103
110
  \`${cmd} ask\` with options \`retry|skip|abort|guidance\`, park in \`${cmd} wait\`,
104
111
  and act on the answer. No auto-retry.
105
- 3. **Finish.** On success, \`git mv\` the committed plan (the \`approved\` event's
106
- \`path\`) into \`docs/plans/archive/\` and commit it on the impl branch, so the
107
- archived plan rides along in the PR (it only takes effect on the default branch
108
- when the PR merges). Then \`gh pr create\` against the default branch (PR body =
109
- the plan summary + the per-phase log; fall back to the local branch + path when
110
- there is no remote), then \`${cmd} implement-done --pr <url>\`. On abort, skip the
111
- archive move (leave the plan in \`docs/plans/\` so it stays active) and run
112
- \`${cmd} implement-done --failed\`.
112
+ 3. **Finish.** On success, open a PR against the default branch with \`gh pr create\`
113
+ (PR body = the plan summary + the per-phase log; fall back to the local branch +
114
+ path when there is no remote), then \`${cmd} implement-done --pr <url>\`. On abort,
115
+ run \`${cmd} implement-done --failed\`.
113
116
 
114
117
  While \`implementing\` the Stop hook still keeps you on the line — never end the turn
115
118
  until \`implement-done\`.
@@ -184,11 +187,11 @@ than a sentence — never as decoration.
184
187
  while the session runs.
185
188
  `;
186
189
  }
187
- /** ~/.claude/skills/otacon/SKILL.md and the OpenCode equivalent (same format). */
190
+ /** The SKILL.md every agent's skills dir gets (Claude, Codex, OpenCode same format). */
188
191
  export function skillMd() {
189
192
  return `---
190
193
  name: otacon
191
- description: Plan a feature through an otacon review session — grill interview, schema'd plan, phone review with anchored comments, approved committed artifact. Use when the user asks to plan something with otacon, types /otacon, or wants a reviewed implementation plan before coding. Replaces native plan mode.
194
+ description: Plan a feature through an otacon review session — grill interview, schema'd plan, phone review with anchored comments, approved plan saved to a home archive (and your project on Save). Use when the user asks to plan something with otacon, types /otacon, or wants a reviewed implementation plan before coding. Replaces native plan mode.
192
195
  ---
193
196
 
194
197
  <!-- ${MANAGED_MARKER} — reinstall overwrites this file; the spec lives in otacon's DESIGN.md -->
@@ -197,18 +200,6 @@ description: Plan a feature through an otacon review session — grill interview
197
200
 
198
201
  ${protocolCard('otacon')}`;
199
202
  }
200
- /** The marker-delimited block upserted into ~/.codex/AGENTS.md. */
201
- export function codexBlock() {
202
- return `${CODEX_BEGIN}
203
-
204
- # Otacon plan sessions
205
-
206
- When the user asks you to plan a feature "with otacon" (or to run a plan
207
- review), follow this protocol exactly.
208
-
209
- ${protocolCard('otacon')}
210
- ${CODEX_END}`;
211
- }
212
203
  /**
213
204
  * THIS repo's dogfood wrapper — the committed \`.claude/skills/otacon/SKILL.md\`
214
205
  * (DESIGN.md §16). It is the same protocol card as \`skillMd()\`, but with the
@@ -221,7 +212,7 @@ ${CODEX_END}`;
221
212
  export function dogfoodSkillMd() {
222
213
  return `---
223
214
  name: otacon
224
- description: Plan a feature for THIS repo through an otacon review session — grill interview, schema'd plan, browser/phone review with anchored comments, approved committed artifact. Use when the user asks to plan something with otacon, types /otacon, or wants a reviewed implementation plan before coding. Replaces native plan mode. Dogfoods otacon on its own development.
215
+ description: Plan a feature for THIS repo through an otacon review session — grill interview, schema'd plan, browser/phone review with anchored comments, approved plan saved to a home archive (and your project on Save). Use when the user asks to plan something with otacon, types /otacon, or wants a reviewed implementation plan before coding. Replaces native plan mode. Dogfoods otacon on its own development.
225
216
  ---
226
217
 
227
218
  <!-- Generated from src/cli/install/assets.ts (dogfoodSkillMd) — do NOT hand-edit;
@@ -234,8 +225,9 @@ This repo **is** otacon. You plan features for it by running otacon's own CLI fr
234
225
  source via the \`./bin/otacon\` shim, so every command below exercises the code in
235
226
  this checkout. That shim runs the CLI from \`src/\` via bun — no build needed; it
236
227
  always reflects current source. The daemon auto-spawns from source on the first
237
- command. Working state lives in the gitignored \`.otacon/\`; the approved plan is
238
- committed to \`docs/plans/\`.
228
+ command. Working state lives in \`.otacon/\`; the approved plan is archived in the
229
+ home store (\`~/.otacon/sessions/<id>/\`) and, on Save, copied into the repo under
230
+ \`plans.dir\` (default \`.otacon/plans\`).
239
231
 
240
232
  After editing **daemon** source (\`src/daemon/**\`) mid-session, restart the running
241
233
  daemon so your change loads: \`./bin/otacon restart\` (the next command respawns it
@@ -1 +1 @@
1
- {"version":3,"file":"assets.js","sourceRoot":"","sources":["../../../src/cli/install/assets.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,8EAA8E;AAC9E,+EAA+E;AAC/E,gFAAgF;AAChF,gFAAgF;AAChF,sEAAsE;AACtE,yEAAyE;AAEzE,oEAAoE;AACpE,MAAM,CAAC,MAAM,cAAc,GAAG,6BAA6B,CAAC;AAE5D,MAAM,CAAC,MAAM,WAAW,GACtB,+GAA+G,CAAC;AAClH,MAAM,CAAC,MAAM,SAAS,GAAG,qBAAqB,CAAC;AAE/C;;;;;;;GAOG;AACH,SAAS,YAAY,CAAC,GAAW;IAC/B,OAAO;qCAC4B,GAAG;;;;;;OAMjC,GAAG;wEAC8D,GAAG;;;;OAIpE,GAAG;;;;;;;;;;SAUD,GAAG;;;;;eAKG,GAAG;;;;8BAIY,GAAG;;;OAG1B,GAAG;;iCAEuB,GAAG;;;;uCAIG,GAAG;;wBAElB,GAAG;;;;;;;;;;;;OAYpB,GAAG,qDAAqD,GAAG;;;;;MAK5D,GAAG,sCAAsC,GAAG;MAC5C,GAAG,kBAAkB,GAAG,6BAA6B,GAAG;MACxD,GAAG,kCAAkC,GAAG;MACxC,GAAG,iBAAiB,GAAG;;;;;KAKxB,GAAG;;;;;4CAKoC,GAAG;;SAEtC,GAAG;;;;;;;;SAQH,GAAG,gEAAgE,GAAG;;;;;;;iCAO9C,GAAG;;OAE7B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wDAsE8C,GAAG;;;CAG1D,CAAC;AACF,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,OAAO;IACrB,OAAO;;;;;OAKF,cAAc;;;;EAInB,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;AAC3B,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,UAAU;IACxB,OAAO,GAAG,WAAW;;;;;;;EAOrB,YAAY,CAAC,QAAQ,CAAC;EACtB,SAAS,EAAE,CAAC;AACd,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BP,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;AACjC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;uBACT,cAAc;;;;;;;;;;;;;;;;;;;;;CAqBpC,CAAC"}
1
+ {"version":3,"file":"assets.js","sourceRoot":"","sources":["../../../src/cli/install/assets.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,8EAA8E;AAC9E,+EAA+E;AAC/E,yEAAyE;AACzE,2EAA2E;AAC3E,gFAAgF;AAChF,iCAAiC;AAEjC,oEAAoE;AACpE,MAAM,CAAC,MAAM,cAAc,GAAG,6BAA6B,CAAC;AAE5D;;;;;;;GAOG;AACH,SAAS,YAAY,CAAC,GAAW;IAC/B,OAAO;qCAC4B,GAAG;;;;;;OAMjC,GAAG;wEAC8D,GAAG;;;;OAIpE,GAAG;;;;;;;;;;SAUD,GAAG;;;;;eAKG,GAAG;;;;8BAIY,GAAG;;;OAG1B,GAAG;;iCAEuB,GAAG;;;;uCAIG,GAAG;;;;;;wBAMlB,GAAG;;;;;;;;;;;;;OAapB,GAAG,qDAAqD,GAAG;;;;;MAK5D,GAAG,sCAAsC,GAAG;MAC5C,GAAG,kBAAkB,GAAG,6BAA6B,GAAG;MACxD,GAAG,kCAAkC,GAAG;MACxC,GAAG,iBAAiB,GAAG,eAAe,GAAG;;;;;KAK1C,GAAG;;;;;;;QAOA,GAAG;;gBAEK,GAAG;;SAEV,GAAG;;;;;;;;SAQH,GAAG,gEAAgE,GAAG;;;;2CAIpC,GAAG;WACnC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wDAsE0C,GAAG;;;CAG1D,CAAC;AACF,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,OAAO;IACrB,OAAO;;;;;OAKF,cAAc;;;;EAInB,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;AAC3B,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8BP,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;AACjC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;uBACT,cAAc;;;;;;;;;;;;;;;;;;;;;CAqBpC,CAAC"}
@@ -5,8 +5,9 @@
5
5
  import { readFileSync } from "node:fs";
6
6
  import { homedir } from "node:os";
7
7
  import { join } from "node:path";
8
- export function claudeSkillPath() {
9
- return join(homedir(), ".claude", "skills", "otacon", "SKILL.md");
8
+ export function claudeSkillPath(scope = { kind: "user" }) {
9
+ const base = scope.kind === "project" ? scope.root : homedir();
10
+ return join(base, ".claude", "skills", "otacon", "SKILL.md");
10
11
  }
11
12
  /** The Stop hook script install writes; settings.json references it by this path. */
12
13
  export function claudeHookScriptPath() {
@@ -15,30 +16,19 @@ export function claudeHookScriptPath() {
15
16
  export function claudeSettingsPath() {
16
17
  return join(homedir(), ".claude", "settings.json");
17
18
  }
18
- /** Codex's global instructions file ($CODEX_HOME, default ~/.codex). */
19
- export function codexAgentsPath() {
20
- return join(process.env.CODEX_HOME ?? join(homedir(), ".codex"), "AGENTS.md");
19
+ /** Codex's skills dir user: $CODEX_HOME (default ~/.codex); project: <root>/.codex. */
20
+ export function codexSkillPath(scope = { kind: "user" }) {
21
+ const base = scope.kind === "project"
22
+ ? join(scope.root, ".codex")
23
+ : (process.env.CODEX_HOME ?? join(homedir(), ".codex"));
24
+ return join(base, "skills", "otacon", "SKILL.md");
21
25
  }
22
- /** OpenCode's global skills dir ($XDG_CONFIG_HOME, default ~/.config). */
23
- export function opencodeSkillPath() {
24
- return join(process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config"), "opencode", "skills", "otacon", "SKILL.md");
25
- }
26
- /**
27
- * Replace the marker-delimited block in `existing` with `block` (which carries
28
- * its own begin/end lines), or append it when no markers are present. User
29
- * content outside the markers survives byte-for-byte; re-running with the same
30
- * block is a fixpoint (the idempotent-reinstall contract).
31
- */
32
- export function upsertMarkedBlock(existing, block, begin, end) {
33
- const from = existing.indexOf(begin);
34
- const to = existing.indexOf(end);
35
- if (from !== -1 && to !== -1 && to > from) {
36
- return existing.slice(0, from) + block + existing.slice(to + end.length);
37
- }
38
- if (existing.trim() === "")
39
- return `${block}\n`;
40
- const separator = existing.endsWith("\n") ? "\n" : "\n\n";
41
- return `${existing}${separator}${block}\n`;
26
+ /** OpenCode's skills dir — user: $XDG_CONFIG_HOME/opencode (default ~/.config); project: <root>/.opencode. */
27
+ export function opencodeSkillPath(scope = { kind: "user" }) {
28
+ const base = scope.kind === "project"
29
+ ? join(scope.root, ".opencode")
30
+ : join(process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config"), "opencode");
31
+ return join(base, "skills", "otacon", "SKILL.md");
42
32
  }
43
33
  /**
44
34
  * Whether ~/.claude/settings.json currently registers the otacon Stop hook