otacon 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +88 -0
  3. package/dist/cli/client.js +188 -0
  4. package/dist/cli/client.js.map +1 -0
  5. package/dist/cli/commands/answer.js +63 -0
  6. package/dist/cli/commands/answer.js.map +1 -0
  7. package/dist/cli/commands/ask.js +117 -0
  8. package/dist/cli/commands/ask.js.map +1 -0
  9. package/dist/cli/commands/clean.js +48 -0
  10. package/dist/cli/commands/clean.js.map +1 -0
  11. package/dist/cli/commands/doctor.js +86 -0
  12. package/dist/cli/commands/doctor.js.map +1 -0
  13. package/dist/cli/commands/expose.js +104 -0
  14. package/dist/cli/commands/expose.js.map +1 -0
  15. package/dist/cli/commands/implement-done.js +53 -0
  16. package/dist/cli/commands/implement-done.js.map +1 -0
  17. package/dist/cli/commands/install.js +113 -0
  18. package/dist/cli/commands/install.js.map +1 -0
  19. package/dist/cli/commands/open.js +37 -0
  20. package/dist/cli/commands/open.js.map +1 -0
  21. package/dist/cli/commands/progress.js +45 -0
  22. package/dist/cli/commands/progress.js.map +1 -0
  23. package/dist/cli/commands/start.js +66 -0
  24. package/dist/cli/commands/start.js.map +1 -0
  25. package/dist/cli/commands/status.js +44 -0
  26. package/dist/cli/commands/status.js.map +1 -0
  27. package/dist/cli/commands/submit.js +64 -0
  28. package/dist/cli/commands/submit.js.map +1 -0
  29. package/dist/cli/commands/wait.js +66 -0
  30. package/dist/cli/commands/wait.js.map +1 -0
  31. package/dist/cli/install/assets.js +285 -0
  32. package/dist/cli/install/assets.js.map +1 -0
  33. package/dist/cli/install/locations.js +92 -0
  34. package/dist/cli/install/locations.js.map +1 -0
  35. package/dist/cli/install/tailscale.js +39 -0
  36. package/dist/cli/install/tailscale.js.map +1 -0
  37. package/dist/cli/main.js +73 -0
  38. package/dist/cli/main.js.map +1 -0
  39. package/dist/cli/output.js +39 -0
  40. package/dist/cli/output.js.map +1 -0
  41. package/dist/cli/session.js +77 -0
  42. package/dist/cli/session.js.map +1 -0
  43. package/dist/daemon/activity.js +56 -0
  44. package/dist/daemon/activity.js.map +1 -0
  45. package/dist/daemon/anchor.js +143 -0
  46. package/dist/daemon/anchor.js.map +1 -0
  47. package/dist/daemon/app.js +1081 -0
  48. package/dist/daemon/app.js.map +1 -0
  49. package/dist/daemon/approve.js +71 -0
  50. package/dist/daemon/approve.js.map +1 -0
  51. package/dist/daemon/desktop-notify.js +69 -0
  52. package/dist/daemon/desktop-notify.js.map +1 -0
  53. package/dist/daemon/diff.js +187 -0
  54. package/dist/daemon/diff.js.map +1 -0
  55. package/dist/daemon/linter/index.js +19 -0
  56. package/dist/daemon/linter/index.js.map +1 -0
  57. package/dist/daemon/linter/parse.js +350 -0
  58. package/dist/daemon/linter/parse.js.map +1 -0
  59. package/dist/daemon/linter/rules.js +359 -0
  60. package/dist/daemon/linter/rules.js.map +1 -0
  61. package/dist/daemon/main.js +48 -0
  62. package/dist/daemon/main.js.map +1 -0
  63. package/dist/daemon/notify.js +23 -0
  64. package/dist/daemon/notify.js.map +1 -0
  65. package/dist/daemon/presence.js +37 -0
  66. package/dist/daemon/presence.js.map +1 -0
  67. package/dist/daemon/queue.js +160 -0
  68. package/dist/daemon/queue.js.map +1 -0
  69. package/dist/daemon/store.js +393 -0
  70. package/dist/daemon/store.js.map +1 -0
  71. package/dist/daemon/threads.js +153 -0
  72. package/dist/daemon/threads.js.map +1 -0
  73. package/dist/daemon/transcript.js +89 -0
  74. package/dist/daemon/transcript.js.map +1 -0
  75. package/dist/daemon/ui.js +175 -0
  76. package/dist/daemon/ui.js.map +1 -0
  77. package/dist/shared/config.js +93 -0
  78. package/dist/shared/config.js.map +1 -0
  79. package/dist/shared/gwt.js +69 -0
  80. package/dist/shared/gwt.js.map +1 -0
  81. package/dist/shared/paths.js +67 -0
  82. package/dist/shared/paths.js.map +1 -0
  83. package/dist/shared/question-spec.js +44 -0
  84. package/dist/shared/question-spec.js.map +1 -0
  85. package/dist/shared/types.js +35 -0
  86. package/dist/shared/types.js.map +1 -0
  87. package/dist/shared/version.js +5 -0
  88. package/dist/shared/version.js.map +1 -0
  89. package/dist/ui/assets/arc-HhPfdCPZ.js +1 -0
  90. package/dist/ui/assets/architecture-7EHR7CIX-BPLblcyi.js +1 -0
  91. package/dist/ui/assets/architectureDiagram-3BPJPVTR-D2PIxGOb.js +36 -0
  92. package/dist/ui/assets/array-BifhSqXX.js +1 -0
  93. package/dist/ui/assets/blockDiagram-GPEHLZMM-DQ3Dn17h.js +132 -0
  94. package/dist/ui/assets/c4Diagram-AAUBKEIU-DxITrQgS.js +10 -0
  95. package/dist/ui/assets/channel-ipcU8ZNI.js +1 -0
  96. package/dist/ui/assets/chunk-2J33WTMH-Du1JoPx5.js +1 -0
  97. package/dist/ui/assets/chunk-3OPIFGDE-Dn7x2Yqf.js +62 -0
  98. package/dist/ui/assets/chunk-4BX2VUAB-DVnrE-4n.js +1 -0
  99. package/dist/ui/assets/chunk-55IACEB6-BAhFAimA.js +1 -0
  100. package/dist/ui/assets/chunk-5ZQYHXKU-0hEZptem.js +2 -0
  101. package/dist/ui/assets/chunk-727SXJPM-C1FN_cI3.js +206 -0
  102. package/dist/ui/assets/chunk-AQP2D5EJ-A656OBd4.js +231 -0
  103. package/dist/ui/assets/chunk-BSJP7CBP-D8oMbjm8.js +1 -0
  104. package/dist/ui/assets/chunk-CSCIHK7Q-DjIL8GLi.js +122 -0
  105. package/dist/ui/assets/chunk-FMBD7UC4-Otblfqvz.js +15 -0
  106. package/dist/ui/assets/chunk-KSCS5N6A-BOjTvm3H.js +10 -0
  107. package/dist/ui/assets/chunk-L5ZTLDWV-CaTLaw6L.js +1 -0
  108. package/dist/ui/assets/chunk-LZXEDZCA-Dq5p7qrD.js +2 -0
  109. package/dist/ui/assets/chunk-ND2GUHAM-jZ_NNnWi.js +1 -0
  110. package/dist/ui/assets/chunk-NNHCCRGN-DlpIbxXb.js +159 -0
  111. package/dist/ui/assets/chunk-NZK2D7GU-U_7l_sCh.js +1 -0
  112. package/dist/ui/assets/chunk-O5CBEL6O-MewqqNB7.js +70 -0
  113. package/dist/ui/assets/chunk-QZHKN3VN-DzGPH44B.js +1 -0
  114. package/dist/ui/assets/chunk-WU5MYG2G-DyEIVjoo.js +1 -0
  115. package/dist/ui/assets/chunk-XPW4576I-D5ArxNEF.js +32 -0
  116. package/dist/ui/assets/classDiagram-4FO5ZUOK-Byg2Hl9D.js +1 -0
  117. package/dist/ui/assets/classDiagram-v2-Q7XG4LA2-Byg2Hl9D.js +1 -0
  118. package/dist/ui/assets/cose-bilkent-S5V4N54A-PFXzf7WV.js +1 -0
  119. package/dist/ui/assets/cytoscape.esm-h6BdjjI9.js +321 -0
  120. package/dist/ui/assets/dagre-BM42HDAG-xrCfjZuZ.js +4 -0
  121. package/dist/ui/assets/dagre-Bx709z4p.js +1 -0
  122. package/dist/ui/assets/defaultLocale-C8Fc0cco.js +1 -0
  123. package/dist/ui/assets/diagram-2AECGRRQ-BFf-cyKY.js +43 -0
  124. package/dist/ui/assets/diagram-5GNKFQAL-kNPV4NfV.js +10 -0
  125. package/dist/ui/assets/diagram-KO2AKTUF-ByC1IUwG.js +3 -0
  126. package/dist/ui/assets/diagram-LMA3HP47-DZIJMPK0.js +24 -0
  127. package/dist/ui/assets/diagram-OG6HWLK6-CSDED9A-.js +24 -0
  128. package/dist/ui/assets/dist-YwjsDswi.js +1 -0
  129. package/dist/ui/assets/erDiagram-TEJ5UH35-yuzvjE6J.js +85 -0
  130. package/dist/ui/assets/eventmodeling-FCH6USID-CZR4eNG-.js +1 -0
  131. package/dist/ui/assets/flowDiagram-I6XJVG4X-ApPtVyYM.js +162 -0
  132. package/dist/ui/assets/ganttDiagram-6RSMTGT7-BeMLXtAr.js +292 -0
  133. package/dist/ui/assets/gitGraph-WXDBUCRP-JmTTBa7j.js +1 -0
  134. package/dist/ui/assets/gitGraphDiagram-PVQCEYII-Cjjnjs71.js +106 -0
  135. package/dist/ui/assets/graphlib-B8gBHxth.js +1 -0
  136. package/dist/ui/assets/index-BFQVRcSI.js +11 -0
  137. package/dist/ui/assets/index-Bj_kTrwP.css +1 -0
  138. package/dist/ui/assets/info-J43DQDTF-8vZ3gome.js +1 -0
  139. package/dist/ui/assets/infoDiagram-5YYISTIA-CnMk1cA-.js +2 -0
  140. package/dist/ui/assets/init-D6jRqBbL.js +1 -0
  141. package/dist/ui/assets/ishikawaDiagram-YF4QCWOH-Bl8z6huD.js +70 -0
  142. package/dist/ui/assets/journeyDiagram-JHISSGLW-DYIVfMpS.js +139 -0
  143. package/dist/ui/assets/kanban-definition-UN3LZRKU-BnR0ZzOz.js +89 -0
  144. package/dist/ui/assets/katex-Vhh-h91d.js +257 -0
  145. package/dist/ui/assets/line-DcBdQit6.js +1 -0
  146. package/dist/ui/assets/linear-HKjRHFAO.js +1 -0
  147. package/dist/ui/assets/mermaid-parser.core-DkYXrPlA.js +4 -0
  148. package/dist/ui/assets/mermaid.core-BmkfCI3b.js +9 -0
  149. package/dist/ui/assets/mindmap-definition-RKZ34NQL-sIAd4nDi.js +96 -0
  150. package/dist/ui/assets/ordinal-hYBb2elL.js +1 -0
  151. package/dist/ui/assets/otacon-DPXGiaVj.svg +11 -0
  152. package/dist/ui/assets/packet-YPE3B663-BxbxcfXN.js +1 -0
  153. package/dist/ui/assets/path-BWPyau1x.js +1 -0
  154. package/dist/ui/assets/pie-LRSECV5Y-BJxazjNs.js +1 -0
  155. package/dist/ui/assets/pieDiagram-4H26LBE5-BiOhc9GR.js +30 -0
  156. package/dist/ui/assets/plan-view-CH6NzUDb.js +74 -0
  157. package/dist/ui/assets/purify.es-CDvCXckx.js +3 -0
  158. package/dist/ui/assets/quadrantDiagram-W4KKPZXB-CVyHbWgo.js +7 -0
  159. package/dist/ui/assets/radar-GUYGQ44K-D9ohbnbV.js +1 -0
  160. package/dist/ui/assets/requirementDiagram-4Y6WPE33-Ba24_hqc.js +84 -0
  161. package/dist/ui/assets/rough.esm-CSKSodPl.js +1 -0
  162. package/dist/ui/assets/sankeyDiagram-5OEKKPKP-CxD4wiPL.js +40 -0
  163. package/dist/ui/assets/sequenceDiagram-3UESZ5HK-7qA7lD61.js +162 -0
  164. package/dist/ui/assets/src-IM8AE8MK.js +1 -0
  165. package/dist/ui/assets/stateDiagram-AJRCARHV-DNElRCuH.js +1 -0
  166. package/dist/ui/assets/stateDiagram-v2-BHNVJYJU-D6qTYpY3.js +1 -0
  167. package/dist/ui/assets/timeline-definition-PNZ67QCA-ChYC4Grd.js +120 -0
  168. package/dist/ui/assets/treeView-BLDUP644-Il0KnMi_.js +1 -0
  169. package/dist/ui/assets/treemap-LRROVOQU-CIiKcdRo.js +1 -0
  170. package/dist/ui/assets/vennDiagram-CIIHVFJN-Ulhkum9i.js +34 -0
  171. package/dist/ui/assets/wardley-L42UT6IY-BNd4ljz7.js +1 -0
  172. package/dist/ui/assets/wardleyDiagram-YWT4CUSO-BicXxh84.js +78 -0
  173. package/dist/ui/assets/xychartDiagram-2RQKCTM6-Duf-m_th.js +7 -0
  174. package/dist/ui/index.html +20 -0
  175. package/package.json +66 -0
@@ -0,0 +1,66 @@
1
+ // otacon wait [--timeout 540] [--session id] — the parked wait (DESIGN.md §6):
2
+ // long-poll the session's queue and print exactly one event as JSON, exit 0
3
+ // ({"event":"timeout"} included — re-parking is the agent's normal loop).
4
+ //
5
+ // The deadline is fixed once at entry; each iteration re-ensures the daemon
6
+ // (a cheap health probe when it is up, a respawn + handshake after a crash)
7
+ // and parks for min(remaining, 240s). A connection failure mid-park therefore
8
+ // re-parks transparently until the overall deadline — a daemon restart is
9
+ // invisible to the agent. The 240s slice stays under undici's 300s
10
+ // response-headers timeout (DECISIONS.md "wait parks in slices").
11
+ import { parseArgs } from "node:util";
12
+ import { api, ensureDaemon, sleep } from "../client.js";
13
+ import { CliError, fail, printJson, usageError } from "../output.js";
14
+ import { listSessions, realpathOr, resolveSession } from "../session.js";
15
+ const MAX_PARK_SECONDS = 240;
16
+ const RESPONSE_GRACE_MS = 10_000;
17
+ const RETRY_DELAY_MS = 250;
18
+ export async function waitCommand(argv) {
19
+ const { values } = parseArgs({
20
+ args: argv,
21
+ options: { timeout: { type: "string", default: "540" }, session: { type: "string" } },
22
+ });
23
+ const timeoutSeconds = Number(values.timeout);
24
+ if (!Number.isFinite(timeoutSeconds) || timeoutSeconds <= 0) {
25
+ usageError("--timeout must be a positive number of seconds");
26
+ }
27
+ await ensureDaemon();
28
+ const session = resolveSession(await listSessions(), values.session, realpathOr(process.cwd()));
29
+ const deadline = Date.now() + timeoutSeconds * 1000;
30
+ for (;;) {
31
+ const remainingMs = deadline - Date.now();
32
+ if (remainingMs <= 0)
33
+ break;
34
+ try {
35
+ await ensureDaemon();
36
+ const parkSeconds = Math.min(Math.ceil(remainingMs / 1000), MAX_PARK_SECONDS);
37
+ const response = await api("GET", `/api/sessions/${session.id}/events?wait=${parkSeconds}`, undefined,
38
+ // Guard a wedged connection; generous because the daemon owns the clock.
39
+ AbortSignal.timeout(Math.min(remainingMs, parkSeconds * 1000) + RESPONSE_GRACE_MS));
40
+ if (response.status === 404) {
41
+ fail("E_UNKNOWN_SESSION", `daemon no longer knows session ${session.id}: ${JSON.stringify(response.body)}`);
42
+ }
43
+ if (response.status !== 200) {
44
+ // A daemon 500 is not "unknown session" — surface it as what it is.
45
+ fail("E_INTERNAL", `wait failed: ${JSON.stringify(response.body)}`, undefined, 2);
46
+ }
47
+ if (response.body.event === "timeout")
48
+ continue; // re-park
49
+ printJson(response.body);
50
+ return 0;
51
+ }
52
+ catch (error) {
53
+ // Only a dead/wedged connection (daemon killed or restarting) is
54
+ // retryable: back off, then the loop re-ensures the daemon and re-parks
55
+ // (queued events survive on disk). Everything else — ensureDaemon
56
+ // refusals, 404s, programming errors — propagates instead of being
57
+ // silently retried until the deadline.
58
+ if (!(error instanceof CliError) || error.code !== "E_DAEMON_DOWN")
59
+ throw error;
60
+ await sleep(RETRY_DELAY_MS);
61
+ }
62
+ }
63
+ printJson({ event: "timeout" });
64
+ return 0;
65
+ }
66
+ //# sourceMappingURL=wait.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wait.js","sourceRoot":"","sources":["../../../src/cli/commands/wait.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,285 @@
1
+ // The wrapper content `otacon install` writes (DESIGN.md §16) — this is the
2
+ // product-critical text that teaches an agent the whole protocol: the §6 full
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").
8
+ /** Present in every wrapper this tool owns; doctor greps for it. */
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
+ /**
13
+ * The protocol card — §6 full loop (start-first) + §8 grill discipline + §13
14
+ * failure habits — parametrized by the command prefix so one source feeds both
15
+ * wrappers (D7): `otacon` for what `otacon install` writes into any repo,
16
+ * `./bin/otacon` for this repo's dogfood (run-from-source). The only thing that
17
+ * varies between the two is `cmd`; the protocol text is identical, so a change
18
+ * here lands in both at once.
19
+ */
20
+ function protocolCard(cmd) {
21
+ return `Run plan reviews through the otacon CLI instead of your native plan mode. The
22
+ user reviews in a browser. Every \`${cmd}\`
23
+ command prints exactly one JSON line on stdout. Exit 0 = proceed; exit 1 = a
24
+ machine-readable error you can fix (read the JSON); exit 2 = you invoked it wrong.
25
+
26
+ ## The loop
27
+
28
+ 1. \`${cmd} start --title <kebab-title>\` **first, before you research** — it mints
29
+ 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.
31
+ \`--quick\` skips the interview — only when the user explicitly asks.
32
+ 2. **Research the codebase**, narrating as you go with
33
+ \`${cmd} progress "<what you're doing>"\` — call it whenever you start a chunk of
34
+ work the user can't otherwise see (reading a module, drafting, revising). It is
35
+ a non-blocking one-liner that feeds the live activity log and the draft chip; no
36
+ answer comes back, so never park on it. Read enough to propose answers, not
37
+ collect questions.
38
+ 3. **Grill** (mandatory unless --quick): Interview me relentlessly about every
39
+ aspect of this plan until we reach a shared understanding. Walk down each branch
40
+ of the design tree, resolving dependencies between decisions one-by-one. For
41
+ each question, provide your recommended answer. Explore the code before asking.
42
+ Never ask what the code can answer.
43
+ - \`${cmd} ask --question "..." --options "A|B|C" --recommend A\` — always lead
44
+ with your recommended answer. \`--multi\` for multi-select; omit \`--options\`
45
+ for free text. The user can always answer with free-form custom text instead
46
+ of (or alongside) the chips, so frame options as a starting point, not a cage.
47
+ - Independent questions whose answers don't shape each other? Post them in one
48
+ call: \`${cmd} ask --batch questions.json\` (or \`--batch -\` for stdin) — a JSON
49
+ array of the same specs (\`{question, options?, recommend?, multi?}\`). They land
50
+ as ordinary cards; loop \`wait\` to collect each answer. Dependent questions
51
+ still go one at a time.
52
+ - Park for the answer: \`${cmd} wait --timeout 540\` (set the Bash tool timeout
53
+ to 600000 ms). The answer arrives as \`{"event":"answer","question":"q<n>",...}\`.
54
+ 4. **Draft** the plan at \`.otacon/<session>/plan.md\` in the schema below, then
55
+ \`${cmd} submit\`. On exit 1, fix every reported lint issue and resubmit until
56
+ accepted.
57
+ 5. **Review loop** — park in \`${cmd} wait --timeout 540\` (Bash timeout 600000 ms)
58
+ and handle the one event it prints:
59
+ - \`comments\` → revise plan.md; write \`resolutions.json\` as
60
+ \`{"changelog":"what changed","threads":{"t1":"how you resolved it"}}\` with
61
+ one reply per comment thread; \`${cmd} submit --resolutions resolutions.json\`
62
+ (loop on lint errors); park again.
63
+ - \`question\` → \`${cmd} answer <q-id> --body "..."\` (or \`--file\`); park again. A
64
+ \`question\` may carry \`replyTo\` (a follow-up on an earlier question) — skim that
65
+ thread's prior turns for context, but still answer the new \`q<n>\`.
66
+ - \`answer\` → use it and continue; park again whenever you are waiting.
67
+ - \`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\`.
72
+ - \`deleted\` → the user deleted this session in the review UI. It is over:
73
+ STOP. There is no approved plan and nothing to commit.
74
+ 6. **Never end your turn while the session is open.** Nothing to do = park in
75
+ \`${cmd} wait\` again. Confused, crashed, or compacted? \`${cmd} status\` returns
76
+ the open session, revision, and pending events — resume the loop from it.
77
+
78
+ ## CLI quick reference
79
+
80
+ - \`${cmd} start --title <t> [--quick]\` · \`${cmd} progress "<note>"\` ·
81
+ \`${cmd} ask ...\` · \`${cmd} wait --timeout 540\` · \`${cmd} submit [--resolutions f]\` ·
82
+ \`${cmd} answer <q> --body "..."\` · \`${cmd} implement-done [--pr <url>] [--failed]\` ·
83
+ \`${cmd} status\` · \`${cmd} open\`
84
+
85
+ ## Implement loop (on \`approved\` with \`implement:true\`)
86
+
87
+ You are the **orchestrator**: you only coordinate and narrate
88
+ (\`${cmd} progress\` at each checkpoint) — every phase's real work runs in a fresh
89
+ native subagent (Task tool) so your own context stays lean.
90
+
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):
95
+ - \`${cmd} progress "phase N — implementing"\`; spawn an **implement+test**
96
+ subagent (Task tool) scoped to that phase's Goal/Files/Verification — it
97
+ implements and runs the phase Verification plus the repo gates.
98
+ - spawn a **separate** \`/code-review --fix\` subagent on the phase's working
99
+ diff; it applies findings; re-review. (\`/code-review\` effort is config — start
100
+ moderate so false positives don't become needless pauses.)
101
+ - **clean + green** → commit the phase and continue. **Blocked** (tests stay red,
102
+ review still flags, or a subagent is stuck) → on the FIRST blocker,
103
+ \`${cmd} ask\` with options \`retry|skip|abort|guidance\`, park in \`${cmd} wait\`,
104
+ 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\`.
113
+
114
+ While \`implementing\` the Stop hook still keeps you on the line — never end the turn
115
+ until \`implement-done\`.
116
+
117
+ ## Plan schema (linted on submit)
118
+
119
+ Frontmatter (\`title\`, \`session\`, \`revision\`, \`status\`, \`created\`), then these
120
+ H2 sections in order — the five required ones plus optional review-altitude
121
+ sections slotted in place (include them when the change warrants; skip them on
122
+ trivial plans): \`## Summary\` (≤5 lines, lead with a diagram — see below) ·
123
+ *(optional)* \`## Contract\` (≤12 lines —
124
+ the interface surface the reviewer signs off instead of reading code: inputs,
125
+ outputs, types, errors; one signature fence is fine under the 1-fence rule) ·
126
+ \`## Decisions\` (entries ≤3 lines, \`- D<n>: ... ← q<n>\` citing the grill answer
127
+ that produced it, or \`[assumed]\`) · *(optional)* \`## Impact\` (≤10 lines — blast
128
+ radius: the upstream modules this plan leans on and the downstream modules it can
129
+ break; a dependency mermaid is fine under the 1-fence rule) · \`## Phases\`
130
+ (\`### Phase <n> — <name>\`, each with \`Goal:\` ≤3 lines, \`Files:\` list,
131
+ \`Verification:\` ≤3 lines plus an optional \`\`\`gwt scenario block — see below,
132
+ optional collapsible \`#### Details\` block) ·
133
+ \`## Risks\` (≤5 items, ≤2 lines each) ·
134
+ \`## Open Questions\`. Mermaid / code / \`before\`+\`after\` fences are budget-exempt,
135
+ max one per read-path section; the markdown-native review visuals below share a
136
+ separate per-section cap. Details may elaborate on the read path, never
137
+ introduce new scope.
138
+
139
+ **Lead with a diagram.** Put a \`\`\`mermaid state / sequence / flow diagram right
140
+ under the \`## Summary\` headline — strongly recommended on ~90% of plans, so the
141
+ reviewer grasps the change's shape before reading prose. Keep the headline as the ≤5-line
142
+ Summary.
143
+
144
+ ## Visuals — prefer them over prose where they carry the information
145
+
146
+ Four markdown-native primitives the review UI styles. They degrade to readable
147
+ markdown if rendering fails, and a comment can anchor to one specific risk, row,
148
+ or callout.
149
+
150
+ - **Callouts** — a blockquote whose first line is a type marker
151
+ (\`[!risk]\`, \`[!note]\`, \`[!decision]\`, \`[!assumption]\`). Risks and
152
+ assumptions SHOULD be callouts, not bullets buried in prose:
153
+ > [!risk]
154
+ > The JWT cutover locks out sessions issued before it.
155
+ - **Decision matrix** — a GFM table comparing options, the chosen row led by a
156
+ \`✓\`. A Decisions section weighing 2+ options SHOULD use a matrix:
157
+ | Pick | Option | Tradeoff |
158
+ | ---- | ------ | ------------------------------- |
159
+ | ✓ | RS256 | rotate keys without redeploy |
160
+ | | HS256 | shared secret on every verifier |
161
+ - **Scope pills** — inline tags \`[new]\` \`[breaking]\` \`[risky]\` \`[deletes]\`
162
+ for flagging scope mid-sentence ("adds a [new] issuer; [breaking] cookie removal").
163
+ - **Behavioral assertions** — a \`\`\`gwt fence inside a phase's \`Verification\`
164
+ holding one or more Given/When/Then scenarios (blank line between scenarios;
165
+ \`And\`/\`But\` continue a clause). They render as scenario cards that double as
166
+ the human's approve checklist (Test-Driven Review), so write the observable
167
+ behavior the reviewer signs off, not the test code:
168
+ \`\`\`gwt
169
+ Given a plan with no Contract section
170
+ When the agent submits it
171
+ Then the lint passes and review opens
172
+ \`\`\`
173
+ Capped at 6 scenarios per block; must sit under \`Verification\`.
174
+
175
+ Callouts and matrices are budget-exempt but capped (default 2 per read-path
176
+ section); pills are free. Reach for a visual when it carries the point better
177
+ than a sentence — never as decoration.
178
+
179
+ ## Rules
180
+
181
+ - Never use native plan mode, AskUserQuestion, or any built-in question UI while
182
+ the session is open — every question goes through \`${cmd} ask\`.
183
+ - Long review or build ahead? Remind the user to keep the Mac awake: \`caffeinate -i\`
184
+ while the session runs.
185
+ `;
186
+ }
187
+ /** ~/.claude/skills/otacon/SKILL.md and the OpenCode equivalent (same format). */
188
+ export function skillMd() {
189
+ return `---
190
+ 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.
192
+ ---
193
+
194
+ <!-- ${MANAGED_MARKER} — reinstall overwrites this file; the spec lives in otacon's DESIGN.md -->
195
+
196
+ # Otacon plan session protocol
197
+
198
+ ${protocolCard('otacon')}`;
199
+ }
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
+ /**
213
+ * THIS repo's dogfood wrapper — the committed \`.claude/skills/otacon/SKILL.md\`
214
+ * (DESIGN.md §16). It is the same protocol card as \`skillMd()\`, but with the
215
+ * \`./bin/otacon\` run-from-source command prefix and a repo preamble (run from
216
+ * source, restart after daemon edits). Generated from this function and never
217
+ * hand-edited; \`assets.test.ts\` asserts the committed file equals this output,
218
+ * so a protocol change that updates the card but forgets to regenerate the
219
+ * dogfood file fails CI (D7).
220
+ */
221
+ export function dogfoodSkillMd() {
222
+ return `---
223
+ 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.
225
+ ---
226
+
227
+ <!-- Generated from src/cli/install/assets.ts (dogfoodSkillMd) — do NOT hand-edit;
228
+ assets.test.ts guards that this file equals that output. Regenerate after any
229
+ protocol change. -->
230
+
231
+ # Otacon plan session protocol (dogfooding this repo)
232
+
233
+ This repo **is** otacon. You plan features for it by running otacon's own CLI from
234
+ source via the \`./bin/otacon\` shim, so every command below exercises the code in
235
+ this checkout. That shim runs the CLI from \`src/\` via bun — no build needed; it
236
+ 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/\`.
239
+
240
+ After editing **daemon** source (\`src/daemon/**\`) mid-session, restart the running
241
+ daemon so your change loads: \`./bin/otacon restart\` (the next command respawns it
242
+ from current source). Use \`./bin/otacon restart\`, not a raw curl to a fixed port —
243
+ in a git worktree the shim runs the daemon on a derived port, and \`restart\` always
244
+ targets the one this checkout talks to. CLI/linter/parser edits need no restart.
245
+
246
+ The spec these commands implement is otacon's own DESIGN.md (§6 loop, §8 grill, §13
247
+ failure habits); the canonical wrapper text lives in \`src/cli/install/assets.ts\`.
248
+
249
+ ---
250
+
251
+ ${protocolCard('./bin/otacon')}`;
252
+ }
253
+ /**
254
+ * The Claude Code Stop hook (DESIGN.md §13): blocks ending the turn while an
255
+ * open otacon session exists in the cwd's repo. Plain sh, fast, fail-open —
256
+ * any failure (daemon down, curl missing, no match) allows the stop. With no
257
+ * local pointer, the open session is found by scanning the daemon registry for
258
+ * a non-terminal session whose repo equals the cwd's git root (DESIGN.md §7) —
259
+ * `implementing` still blocks (the build is live); only the terminal states
260
+ * (approved/implemented/implement_failed) let the agent end its turn.
261
+ */
262
+ export const STOP_HOOK_SCRIPT = `#!/bin/sh
263
+ # otacon Stop hook — ${MANAGED_MARKER}; reinstall overwrites this file.
264
+ # Blocks Claude Code from ending its turn while the cwd's repo has an open
265
+ # otacon plan session (DESIGN.md §13). Fail-open by design: when anything here
266
+ # fails (daemon unreachable, curl missing, no match), the stop is allowed.
267
+ input=$(cat 2>/dev/null) || input=""
268
+ cwd=$(printf '%s' "$input" | sed -n 's/.*"cwd"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p')
269
+ [ -n "$cwd" ] || cwd=$PWD
270
+ root=$(git -C "$cwd" rev-parse --show-toplevel 2>/dev/null) || root=$cwd
271
+ root=$(cd "$root" 2>/dev/null && pwd -P) || exit 0
272
+ port=\${OTACON_PORT:-4747}
273
+ list=$(curl -fsS --max-time 2 "http://127.0.0.1:$port/api/sessions" 2>/dev/null) || exit 0
274
+ # Split the compact registry array one session-object per line, keep this repo's
275
+ # open (non-terminal) sessions, take the first id. The repo match is exact: the
276
+ # pattern includes the closing quote of the JSON value. Terminal statuses
277
+ # (approved/implemented/implement_failed) are over -- drop them so a finished
278
+ # build no longer traps the agent, while an in-flight implementing still blocks.
279
+ sid=$(printf '%s' "$list" | sed 's/},{/}\\
280
+ {/g' | grep -F "\\"repo\\":\\"$root\\"" | grep -vE '"status":"(approved|implemented|implement_failed)"' | sed -n '1s/.*"id":"\\([^"]*\\)".*/\\1/p')
281
+ [ -n "$sid" ] || exit 0
282
+ printf '{"decision":"block","reason":"otacon plan session %s is still open — run otacon wait --timeout 540 (Bash timeout 600000 ms) and keep handling events until the plan is approved; run otacon status to re-orient."}\\n' "$sid"
283
+ exit 0
284
+ `;
285
+ //# sourceMappingURL=assets.js.map
@@ -0,0 +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"}
@@ -0,0 +1,92 @@
1
+ // Where each agent reads its wrapper from (DESIGN.md §16; DECISIONS.md
2
+ // "Wrapper destinations per agent"), plus the merge/registration helpers
3
+ // install and doctor share. homedir() honors $HOME, which is what keeps the
4
+ // install e2e hermetic under a temp HOME.
5
+ import { readFileSync } from "node:fs";
6
+ import { homedir } from "node:os";
7
+ import { join } from "node:path";
8
+ export function claudeSkillPath() {
9
+ return join(homedir(), ".claude", "skills", "otacon", "SKILL.md");
10
+ }
11
+ /** The Stop hook script install writes; settings.json references it by this path. */
12
+ export function claudeHookScriptPath() {
13
+ return join(homedir(), ".claude", "hooks", "otacon-stop.sh");
14
+ }
15
+ export function claudeSettingsPath() {
16
+ return join(homedir(), ".claude", "settings.json");
17
+ }
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");
21
+ }
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`;
42
+ }
43
+ /**
44
+ * Whether ~/.claude/settings.json currently registers the otacon Stop hook
45
+ * (install's offer path and doctor's check). Missing or unparseable settings
46
+ * read as "not registered" — only --hooks treats unparseable as an error.
47
+ */
48
+ export function settingsRegisterStopHook() {
49
+ try {
50
+ const raw = JSON.parse(readFileSync(claudeSettingsPath(), "utf8"));
51
+ return stopHookRegistered(raw?.hooks?.Stop, claudeHookScriptPath());
52
+ }
53
+ catch {
54
+ return false;
55
+ }
56
+ }
57
+ /** True when some Stop matcher entry already runs `command`. */
58
+ export function stopHookRegistered(stop, command) {
59
+ if (!Array.isArray(stop))
60
+ return false;
61
+ return stop.some((entry) => {
62
+ const hooks = entry?.hooks;
63
+ return (Array.isArray(hooks) &&
64
+ hooks.some((h) => h?.command === command));
65
+ });
66
+ }
67
+ /**
68
+ * Additively merge the Stop hook entry into a parsed settings.json: every
69
+ * existing key (and every existing Stop matcher) is preserved; an entry already
70
+ * running `command` makes this a no-op. Returns undefined when the existing
71
+ * structure has a shape we refuse to rewrite (hooks or hooks.Stop not
72
+ * object/array) — never clobber what we cannot faithfully merge.
73
+ */
74
+ export function mergeStopHook(raw, command) {
75
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw))
76
+ return undefined;
77
+ const settings = raw;
78
+ const hooks = settings.hooks ?? {};
79
+ if (hooks === null || typeof hooks !== "object" || Array.isArray(hooks))
80
+ return undefined;
81
+ const stop = hooks.Stop ?? [];
82
+ if (!Array.isArray(stop))
83
+ return undefined;
84
+ if (stopHookRegistered(stop, command))
85
+ return { settings, changed: false };
86
+ const entry = { matcher: "", hooks: [{ type: "command", command }] };
87
+ return {
88
+ settings: { ...settings, hooks: { ...hooks, Stop: [...stop, entry] } },
89
+ changed: true,
90
+ };
91
+ }
92
+ //# sourceMappingURL=locations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locations.js","sourceRoot":"","sources":["../../../src/cli/install/locations.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,yEAAyE;AACzE,4EAA4E;AAC5E,0CAA0C;AAE1C,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,UAAU,eAAe;IAC7B,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;AACpE,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,oBAAoB;IAClC,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;AACrD,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,eAAe;IAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,EAAE,WAAW,CAAC,CAAC;AAChF,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,iBAAiB;IAC/B,OAAO,IAAI,CACT,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,EACzD,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,UAAU,CACX,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAgB,EAChB,KAAa,EACb,KAAa,EACb,GAAW;IAEX,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACrC,MAAM,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,IAAI,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC;QAC1C,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,GAAG,KAAK,IAAI,CAAC;IAChD,MAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IAC1D,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK,IAAI,CAAC;AAC7C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB;IACtC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,EAAE,EAAE,MAAM,CAAC,CAEhE,CAAC;QACF,OAAO,kBAAkB,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC,CAAC;IACtE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,kBAAkB,CAAC,IAAa,EAAE,OAAe;IAC/D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;QACzB,MAAM,KAAK,GAAI,KAAoC,EAAE,KAAK,CAAC;QAC3D,OAAO,CACL,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YACpB,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAE,CAAkC,EAAE,OAAO,KAAK,OAAO,CAAC,CAC5E,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAOD;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,GAAY,EAAE,OAAe;IACzD,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IACpF,MAAM,QAAQ,GAAG,GAA8B,CAAC;IAChD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC;IACnC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1F,MAAM,IAAI,GAAI,KAAiC,CAAC,IAAI,IAAI,EAAE,CAAC;IAC3D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAC3C,IAAI,kBAAkB,CAAC,IAAI,EAAE,OAAO,CAAC;QAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC3E,MAAM,KAAK,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IACrE,OAAO;QACL,QAAQ,EAAE,EAAE,GAAG,QAAQ,EAAE,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE;QACtE,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC"}
@@ -0,0 +1,39 @@
1
+ // Best-effort Tailscale discovery shared by doctor and expose (DESIGN.md §11,
2
+ // §16). OTACON_TAILSCALE pins the binary (hermetic tests; nonstandard
3
+ // installs) and is authoritative when set; otherwise PATH, then the macOS app
4
+ // bundle's embedded CLI (DECISIONS.md "doctor/expose automation boundary").
5
+ import { execFileSync } from "node:child_process";
6
+ const MAC_APP_BIN = "/Applications/Tailscale.app/Contents/MacOS/Tailscale";
7
+ export function findTailscale() {
8
+ const override = process.env.OTACON_TAILSCALE;
9
+ const candidates = override !== undefined && override !== "" ? [override] : ["tailscale", MAC_APP_BIN];
10
+ for (const bin of candidates) {
11
+ try {
12
+ execFileSync(bin, ["version"], { stdio: ["ignore", "pipe", "ignore"] });
13
+ return bin;
14
+ }
15
+ catch {
16
+ // not this one
17
+ }
18
+ }
19
+ return undefined;
20
+ }
21
+ export function tailscaleStatus(bin) {
22
+ try {
23
+ const raw = JSON.parse(execFileSync(bin, ["status", "--json"], {
24
+ encoding: "utf8",
25
+ stdio: ["ignore", "pipe", "pipe"],
26
+ }));
27
+ const dns = raw?.Self?.DNSName;
28
+ return {
29
+ backendState: typeof raw?.BackendState === "string" ? raw.BackendState : "unknown",
30
+ ...(typeof dns === "string" && dns !== ""
31
+ ? { dnsName: dns.replace(/\.$/, "") }
32
+ : {}),
33
+ };
34
+ }
35
+ catch {
36
+ return undefined;
37
+ }
38
+ }
39
+ //# sourceMappingURL=tailscale.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tailscale.js","sourceRoot":"","sources":["../../../src/cli/install/tailscale.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,sEAAsE;AACtE,8EAA8E;AAC9E,4EAA4E;AAE5E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,WAAW,GAAG,sDAAsD,CAAC;AAE3E,MAAM,UAAU,aAAa;IAC3B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC9C,MAAM,UAAU,GAAG,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACvG,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,YAAY,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;YACxE,OAAO,GAAG,CAAC;QACb,CAAC;QAAC,MAAM,CAAC;YACP,eAAe;QACjB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AASD,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CACpB,YAAY,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE;YACtC,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;SAClC,CAAC,CACyD,CAAC;QAC9D,MAAM,GAAG,GAAG,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC;QAC/B,OAAO;YACL,YAAY,EAAE,OAAO,GAAG,EAAE,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS;YAClF,GAAG,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,EAAE;gBACvC,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE;gBACrC,CAAC,CAAC,EAAE,CAAC;SACR,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env node
2
+ // otacon CLI dispatch (DESIGN.md §6). stdout carries exactly one JSON line per
3
+ // invocation; notices go to stderr; exit 0 success / 1 expected failure /
4
+ // 2 usage or internal error (src/cli/output.ts).
5
+ import { answerCommand } from "./commands/answer.js";
6
+ import { askCommand } from "./commands/ask.js";
7
+ import { cleanCommand } from "./commands/clean.js";
8
+ import { doctorCommand } from "./commands/doctor.js";
9
+ import { exposeCommand } from "./commands/expose.js";
10
+ import { implementDoneCommand } from "./commands/implement-done.js";
11
+ import { installCommand } from "./commands/install.js";
12
+ import { openCommand } from "./commands/open.js";
13
+ import { progressCommand } from "./commands/progress.js";
14
+ import { startCommand } from "./commands/start.js";
15
+ import { statusCommand } from "./commands/status.js";
16
+ import { submitCommand } from "./commands/submit.js";
17
+ import { waitCommand } from "./commands/wait.js";
18
+ import { CliError, printJson } from "./output.js";
19
+ const USAGE = "usage: otacon <start|submit|wait|ask|answer|progress|implement-done|status|open|clean|install|doctor|expose> [options]";
20
+ async function dispatch(command, argv) {
21
+ switch (command) {
22
+ case "start":
23
+ return startCommand(argv);
24
+ case "submit":
25
+ return submitCommand(argv);
26
+ case "wait":
27
+ return waitCommand(argv);
28
+ case "ask":
29
+ return askCommand(argv);
30
+ case "answer":
31
+ return answerCommand(argv);
32
+ case "progress":
33
+ return progressCommand(argv);
34
+ case "implement-done":
35
+ return implementDoneCommand(argv);
36
+ case "status":
37
+ return statusCommand(argv);
38
+ case "open":
39
+ return openCommand(argv);
40
+ case "clean":
41
+ return cleanCommand(argv);
42
+ case "install":
43
+ return installCommand(argv);
44
+ case "doctor":
45
+ return doctorCommand(argv);
46
+ case "expose":
47
+ return exposeCommand(argv);
48
+ default:
49
+ throw new CliError("E_USAGE", USAGE, 2);
50
+ }
51
+ }
52
+ const isParseArgsError = (error) => error instanceof Error &&
53
+ (error.code?.startsWith("ERR_PARSE_ARGS") ?? false);
54
+ /** Exit only after queued stdout writes flush (stdout may be a pipe). */
55
+ function exit(code) {
56
+ process.stdout.write("", () => process.exit(code));
57
+ }
58
+ dispatch(process.argv[2], process.argv.slice(3)).then((code) => exit(code), (error) => {
59
+ if (error instanceof CliError) {
60
+ printJson(error.toPayload());
61
+ exit(error.exitCode);
62
+ }
63
+ else if (isParseArgsError(error)) {
64
+ printJson({ ok: false, error: { code: "E_USAGE", message: `${error.message}; ${USAGE}` } });
65
+ exit(2);
66
+ }
67
+ else {
68
+ const message = error instanceof Error ? error.message : String(error);
69
+ printJson({ ok: false, error: { code: "E_INTERNAL", message } });
70
+ exit(2);
71
+ }
72
+ });
73
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ // JSON-only stdout discipline for the otacon CLI (DESIGN.md §6): every command
2
+ // prints exactly one JSON line on stdout — the machine-readable result a coding
3
+ // agent parses as its Bash tool output — and human-facing notices go to stderr.
4
+ //
5
+ // Exit codes: 0 success (including {"event":"timeout"}, DESIGN.md §6), 1
6
+ // expected failure the agent can act on (lint reject, ambiguous session, port
7
+ // conflict), 2 usage or internal error.
8
+ /** A machine-readable command failure; main.ts prints the payload and exits. */
9
+ export class CliError extends Error {
10
+ code;
11
+ exitCode;
12
+ extra;
13
+ constructor(code, message, exitCode = 1, extra = {}) {
14
+ super(message);
15
+ this.code = code;
16
+ this.exitCode = exitCode;
17
+ this.extra = extra;
18
+ this.name = "CliError";
19
+ }
20
+ toPayload() {
21
+ return { ok: false, error: { code: this.code, message: this.message, ...this.extra } };
22
+ }
23
+ }
24
+ /** Throw an expected failure (exit 1 unless told otherwise). */
25
+ export function fail(code, message, extra, exitCode = 1) {
26
+ throw new CliError(code, message, exitCode, extra);
27
+ }
28
+ export function usageError(message) {
29
+ throw new CliError("E_USAGE", message, 2);
30
+ }
31
+ /** The one stdout write a command makes. */
32
+ export function printJson(value) {
33
+ process.stdout.write(`${JSON.stringify(value)}\n`);
34
+ }
35
+ /** Human-facing notice; never stdout, which agents parse. */
36
+ export function notice(message) {
37
+ process.stderr.write(`otacon: ${message}\n`);
38
+ }
39
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,gFAAgF;AAChF,gFAAgF;AAChF,EAAE;AACF,yEAAyE;AACzE,8EAA8E;AAC9E,wCAAwC;AAIxC,gFAAgF;AAChF,MAAM,OAAO,QAAS,SAAQ,KAAK;IAEtB;IAEA;IACA;IAJX,YACW,IAAY,EACrB,OAAe,EACN,WAAqB,CAAC,EACtB,QAAiC,EAAE;QAE5C,KAAK,CAAC,OAAO,CAAC,CAAC;QALN,SAAI,GAAJ,IAAI,CAAQ;QAEZ,aAAQ,GAAR,QAAQ,CAAc;QACtB,UAAK,GAAL,KAAK,CAA8B;QAG5C,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;IAED,SAAS;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;IACzF,CAAC;CACF;AAED,gEAAgE;AAChE,MAAM,UAAU,IAAI,CAClB,IAAY,EACZ,OAAe,EACf,KAA+B,EAC/B,WAAqB,CAAC;IAEtB,MAAM,IAAI,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,MAAM,IAAI,QAAQ,CAAC,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,SAAS,CAAC,KAAc;IACtC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACrD,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,MAAM,CAAC,OAAe;IACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,OAAO,IAAI,CAAC,CAAC;AAC/C,CAAC"}