otacon 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +101 -64
- package/dist/cli/browser.js +55 -0
- package/dist/cli/browser.js.map +1 -0
- package/dist/cli/commands/clean.js +3 -2
- package/dist/cli/commands/clean.js.map +1 -1
- package/dist/cli/commands/config.js +62 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/doctor.js +41 -21
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/install.js +53 -30
- package/dist/cli/commands/install.js.map +1 -1
- package/dist/cli/commands/open.js +14 -14
- package/dist/cli/commands/open.js.map +1 -1
- package/dist/cli/commands/start.js +1 -22
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/install/assets.js +35 -43
- package/dist/cli/install/assets.js.map +1 -1
- package/dist/cli/install/locations.js +15 -25
- package/dist/cli/install/locations.js.map +1 -1
- package/dist/cli/main.js +6 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/daemon/app.js +281 -54
- package/dist/daemon/app.js.map +1 -1
- package/dist/daemon/approve.js +49 -11
- package/dist/daemon/approve.js.map +1 -1
- package/dist/daemon/store.js +39 -2
- package/dist/daemon/store.js.map +1 -1
- package/dist/daemon/threads.js +11 -0
- package/dist/daemon/threads.js.map +1 -1
- package/dist/daemon/ui.js +3 -0
- package/dist/daemon/ui.js.map +1 -1
- package/dist/shared/config.js +290 -45
- package/dist/shared/config.js.map +1 -1
- package/dist/shared/paths.js +33 -5
- package/dist/shared/paths.js.map +1 -1
- package/dist/shared/types.js +6 -2
- package/dist/shared/types.js.map +1 -1
- package/dist/shared/version.js +1 -1
- package/dist/ui/assets/{arc-HhPfdCPZ.js → arc-KT3ZnaMp.js} +1 -1
- package/dist/ui/assets/architecture-7EHR7CIX-Cw3I1lil.js +1 -0
- package/dist/ui/assets/{architectureDiagram-3BPJPVTR-D2PIxGOb.js → architectureDiagram-3BPJPVTR-DLu0UM7N.js} +1 -1
- package/dist/ui/assets/{blockDiagram-GPEHLZMM-DQ3Dn17h.js → blockDiagram-GPEHLZMM-B8wApEWC.js} +1 -1
- package/dist/ui/assets/{c4Diagram-AAUBKEIU-DxITrQgS.js → c4Diagram-AAUBKEIU-BNS5gmQS.js} +1 -1
- package/dist/ui/assets/channel-CkOta24Z.js +1 -0
- package/dist/ui/assets/{chunk-2J33WTMH-Du1JoPx5.js → chunk-2J33WTMH-CTY2etwY.js} +1 -1
- package/dist/ui/assets/{chunk-3OPIFGDE-Dn7x2Yqf.js → chunk-3OPIFGDE-DZM4Sz84.js} +1 -1
- package/dist/ui/assets/{chunk-4BX2VUAB-DVnrE-4n.js → chunk-4BX2VUAB-sGwrrXIO.js} +1 -1
- package/dist/ui/assets/{chunk-55IACEB6-BAhFAimA.js → chunk-55IACEB6-CGlNp76o.js} +1 -1
- package/dist/ui/assets/{chunk-5ZQYHXKU-0hEZptem.js → chunk-5ZQYHXKU-5zebJ3jW.js} +1 -1
- package/dist/ui/assets/{chunk-727SXJPM-C1FN_cI3.js → chunk-727SXJPM-DelmUpvy.js} +1 -1
- package/dist/ui/assets/{chunk-AQP2D5EJ-A656OBd4.js → chunk-AQP2D5EJ-DMVzBf3M.js} +1 -1
- package/dist/ui/assets/{chunk-BSJP7CBP-D8oMbjm8.js → chunk-BSJP7CBP-CZHrcpSu.js} +1 -1
- package/dist/ui/assets/{chunk-CSCIHK7Q-DjIL8GLi.js → chunk-CSCIHK7Q-C1efTp0O.js} +1 -1
- package/dist/ui/assets/{chunk-FMBD7UC4-Otblfqvz.js → chunk-FMBD7UC4-B6axGwgn.js} +1 -1
- package/dist/ui/assets/{chunk-KSCS5N6A-BOjTvm3H.js → chunk-KSCS5N6A-DSaxbrm0.js} +1 -1
- package/dist/ui/assets/{chunk-L5ZTLDWV-CaTLaw6L.js → chunk-L5ZTLDWV-D9ZKdVGx.js} +1 -1
- package/dist/ui/assets/{chunk-LZXEDZCA-Dq5p7qrD.js → chunk-LZXEDZCA-DI5_1s00.js} +2 -2
- package/dist/ui/assets/{chunk-ND2GUHAM-jZ_NNnWi.js → chunk-ND2GUHAM-DQQ4RVLE.js} +1 -1
- package/dist/ui/assets/{chunk-NZK2D7GU-U_7l_sCh.js → chunk-NZK2D7GU-9zJJaDpb.js} +1 -1
- package/dist/ui/assets/{chunk-O5CBEL6O-MewqqNB7.js → chunk-O5CBEL6O-DUOshAt2.js} +1 -1
- package/dist/ui/assets/chunk-QZHKN3VN-DqRxzBM_.js +1 -0
- package/dist/ui/assets/chunk-WU5MYG2G-B1Mk3aBp.js +1 -0
- package/dist/ui/assets/{chunk-XPW4576I-D5ArxNEF.js → chunk-XPW4576I-DQVL_GAl.js} +1 -1
- package/dist/ui/assets/classDiagram-4FO5ZUOK-BH-5P4jH.js +1 -0
- package/dist/ui/assets/classDiagram-v2-Q7XG4LA2-BH-5P4jH.js +1 -0
- package/dist/ui/assets/{cose-bilkent-S5V4N54A-PFXzf7WV.js → cose-bilkent-S5V4N54A-C7m3VlSW.js} +1 -1
- package/dist/ui/assets/{dagre-BM42HDAG-xrCfjZuZ.js → dagre-BM42HDAG-CoU_T6EY.js} +1 -1
- package/dist/ui/assets/{diagram-2AECGRRQ-BFf-cyKY.js → diagram-2AECGRRQ-C_R7oNKE.js} +1 -1
- package/dist/ui/assets/{diagram-5GNKFQAL-kNPV4NfV.js → diagram-5GNKFQAL-UhE2W3Yi.js} +1 -1
- package/dist/ui/assets/{diagram-KO2AKTUF-ByC1IUwG.js → diagram-KO2AKTUF-D4KZCRld.js} +1 -1
- package/dist/ui/assets/{diagram-LMA3HP47-DZIJMPK0.js → diagram-LMA3HP47-CsOe8-S6.js} +1 -1
- package/dist/ui/assets/{diagram-OG6HWLK6-CSDED9A-.js → diagram-OG6HWLK6-Bkbs2V54.js} +1 -1
- package/dist/ui/assets/{dist-YwjsDswi.js → dist-BcowSnUl.js} +1 -1
- package/dist/ui/assets/{erDiagram-TEJ5UH35-yuzvjE6J.js → erDiagram-TEJ5UH35-DJXsykZz.js} +1 -1
- package/dist/ui/assets/eventmodeling-FCH6USID-DSDI1f5T.js +1 -0
- package/dist/ui/assets/{flowDiagram-I6XJVG4X-ApPtVyYM.js → flowDiagram-I6XJVG4X-Chguj9Xz.js} +1 -1
- package/dist/ui/assets/{ganttDiagram-6RSMTGT7-BeMLXtAr.js → ganttDiagram-6RSMTGT7-DXdpFesp.js} +1 -1
- package/dist/ui/assets/{gitGraph-WXDBUCRP-JmTTBa7j.js → gitGraph-WXDBUCRP-Doq1CcxB.js} +1 -1
- package/dist/ui/assets/{gitGraphDiagram-PVQCEYII-Cjjnjs71.js → gitGraphDiagram-PVQCEYII-uxGwHEPv.js} +1 -1
- package/dist/ui/assets/index-BsTJ9Ul_.css +1 -0
- package/dist/ui/assets/index-D-TSanrw.js +11 -0
- package/dist/ui/assets/{info-J43DQDTF-8vZ3gome.js → info-J43DQDTF-CgWT_d3M.js} +1 -1
- package/dist/ui/assets/{infoDiagram-5YYISTIA-CnMk1cA-.js → infoDiagram-5YYISTIA-B3oDA2Ct.js} +1 -1
- package/dist/ui/assets/{ishikawaDiagram-YF4QCWOH-Bl8z6huD.js → ishikawaDiagram-YF4QCWOH-C6l0lvC3.js} +1 -1
- package/dist/ui/assets/{journeyDiagram-JHISSGLW-DYIVfMpS.js → journeyDiagram-JHISSGLW-COf53NwC.js} +1 -1
- package/dist/ui/assets/{kanban-definition-UN3LZRKU-BnR0ZzOz.js → kanban-definition-UN3LZRKU-DaOPRBld.js} +1 -1
- package/dist/ui/assets/{line-DcBdQit6.js → line-new3jLu3.js} +1 -1
- package/dist/ui/assets/{linear-HKjRHFAO.js → linear-yA22knFB.js} +1 -1
- package/dist/ui/assets/{mermaid-parser.core-DkYXrPlA.js → mermaid-parser.core-D8JVCOKU.js} +2 -2
- package/dist/ui/assets/{mermaid.core-BmkfCI3b.js → mermaid.core-BCrPyVBK.js} +3 -3
- package/dist/ui/assets/{mindmap-definition-RKZ34NQL-sIAd4nDi.js → mindmap-definition-RKZ34NQL-CVcJTWsW.js} +1 -1
- package/dist/ui/assets/{packet-YPE3B663-BxbxcfXN.js → packet-YPE3B663-DlSwpK-G.js} +1 -1
- package/dist/ui/assets/{pie-LRSECV5Y-BJxazjNs.js → pie-LRSECV5Y-CyMpbo4C.js} +1 -1
- package/dist/ui/assets/{pieDiagram-4H26LBE5-BiOhc9GR.js → pieDiagram-4H26LBE5-Dy7day5R.js} +1 -1
- package/dist/ui/assets/{plan-view-CH6NzUDb.js → plan-view-CE2ha0qY.js} +3 -3
- package/dist/ui/assets/{quadrantDiagram-W4KKPZXB-CVyHbWgo.js → quadrantDiagram-W4KKPZXB-CVjVgbaQ.js} +1 -1
- package/dist/ui/assets/{radar-GUYGQ44K-D9ohbnbV.js → radar-GUYGQ44K-DLPfv0jT.js} +1 -1
- package/dist/ui/assets/{requirementDiagram-4Y6WPE33-Ba24_hqc.js → requirementDiagram-4Y6WPE33-y_0KOdN8.js} +1 -1
- package/dist/ui/assets/{sankeyDiagram-5OEKKPKP-CxD4wiPL.js → sankeyDiagram-5OEKKPKP-8T3b7meL.js} +1 -1
- package/dist/ui/assets/{sequenceDiagram-3UESZ5HK-7qA7lD61.js → sequenceDiagram-3UESZ5HK-Cn8DZiEr.js} +1 -1
- package/dist/ui/assets/{src-IM8AE8MK.js → src-BieOuieI.js} +1 -1
- package/dist/ui/assets/{stateDiagram-AJRCARHV-DNElRCuH.js → stateDiagram-AJRCARHV-nPEVGd3E.js} +1 -1
- package/dist/ui/assets/stateDiagram-v2-BHNVJYJU-CKrff-KJ.js +1 -0
- package/dist/ui/assets/{timeline-definition-PNZ67QCA-ChYC4Grd.js → timeline-definition-PNZ67QCA-Dj_qK0VJ.js} +1 -1
- package/dist/ui/assets/{treeView-BLDUP644-Il0KnMi_.js → treeView-BLDUP644-G5Bsebqu.js} +1 -1
- package/dist/ui/assets/{treemap-LRROVOQU-CIiKcdRo.js → treemap-LRROVOQU-anUEJzTb.js} +1 -1
- package/dist/ui/assets/{vennDiagram-CIIHVFJN-Ulhkum9i.js → vennDiagram-CIIHVFJN-D71ne3dS.js} +1 -1
- package/dist/ui/assets/{wardley-L42UT6IY-BNd4ljz7.js → wardley-L42UT6IY-DrJilmE_.js} +1 -1
- package/dist/ui/assets/{wardleyDiagram-YWT4CUSO-BicXxh84.js → wardleyDiagram-YWT4CUSO-B66G4ayp.js} +1 -1
- package/dist/ui/assets/{xychartDiagram-2RQKCTM6-Duf-m_th.js → xychartDiagram-2RQKCTM6-CReSRxNG.js} +1 -1
- package/dist/ui/index.html +2 -2
- package/package.json +1 -1
- package/dist/ui/assets/architecture-7EHR7CIX-BPLblcyi.js +0 -1
- package/dist/ui/assets/channel-ipcU8ZNI.js +0 -1
- package/dist/ui/assets/chunk-QZHKN3VN-DzGPH44B.js +0 -1
- package/dist/ui/assets/chunk-WU5MYG2G-DyEIVjoo.js +0 -1
- package/dist/ui/assets/classDiagram-4FO5ZUOK-Byg2Hl9D.js +0 -1
- package/dist/ui/assets/classDiagram-v2-Q7XG4LA2-Byg2Hl9D.js +0 -1
- package/dist/ui/assets/eventmodeling-FCH6USID-CZR4eNG-.js +0 -1
- package/dist/ui/assets/index-BFQVRcSI.js +0 -11
- package/dist/ui/assets/index-Bj_kTrwP.css +0 -1
- package/dist/ui/assets/stateDiagram-v2-BHNVJYJU-D6qTYpY3.js +0 -1
package/README.md
CHANGED
|
@@ -1,88 +1,125 @@
|
|
|
1
|
-
<
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://github.com/user-attachments/assets/18796111-63d7-4df6-a2ba-b95f132eabd3" alt="otacon" width="720">
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
plan modes with one CLI protocol: schema'd concise plans, anchored comments and
|
|
5
|
-
questions from any device (phone included, over Tailscale), revision diffs against
|
|
6
|
-
what you last reviewed, and a mandatory grill-me interview phase before any plan
|
|
7
|
-
reaches review. Approval produces a committed plan artifact for a future implementer
|
|
8
|
-
skill (`snake`) to execute.
|
|
5
|
+
<h3 align="center">Stop rubber-stamping your agent's plans</h3>
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://www.npmjs.com/package/otacon"><img src="https://img.shields.io/npm/v/otacon.svg" alt="npm version"></a>
|
|
9
|
+
<a href="https://www.npmjs.com/package/otacon"><img src="https://img.shields.io/node/v/otacon.svg" alt="node"></a>
|
|
10
|
+
<a href="LICENSE"><img src="https://img.shields.io/npm/l/otacon.svg" alt="license"></a>
|
|
11
|
+
</p>
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
<p align="center">
|
|
14
|
+
<a href="#installation"><b>Installation</b></a> ·
|
|
15
|
+
<a href="#get-started"><b>Get started</b></a> ·
|
|
16
|
+
<a href="#why-otacon"><b>Why Otacon</b></a> ·
|
|
17
|
+
<a href="docs/PHONE-ACCESS.md"><b>Phone access</b></a>
|
|
18
|
+
</p>
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
<br/>
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
Otacon replaces your coding agent's native plan mode with a review surface you'll actually use. Your agent (Claude Code, Codex, or OpenCode) interviews you until it understands the goal, drafts a concise plan with the discipline of an engineering design doc, and hands you a real place to comment, ask, and diff revisions, then sign off before a line of code is written.
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
20
25
|
|
|
21
26
|
```sh
|
|
22
|
-
npm install -g otacon
|
|
23
|
-
otacon install --all # agent wrappers; or --agent claude|codex|opencode
|
|
24
|
-
otacon install --agent claude --hooks # also register the Claude Code Stop hook
|
|
25
|
-
otacon doctor # verify: node, daemon boots, wrappers, Tailscale
|
|
27
|
+
npm install -g otacon
|
|
26
28
|
```
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
Claude Code: `~/.claude/skills/otacon/SKILL.md` (+ the Stop hook script at
|
|
30
|
-
`~/.claude/hooks/otacon-stop.sh`); Codex: a marked block in `~/.codex/AGENTS.md`;
|
|
31
|
-
OpenCode: `~/.config/opencode/skills/otacon/SKILL.md`. Wrappers are managed files:
|
|
32
|
-
reinstalls overwrite them (outside-the-markers content in Codex's shared file
|
|
33
|
-
survives). `--hooks` merges the Stop hook into `~/.claude/settings.json` additively
|
|
34
|
-
and idempotently, backing the file up first. The daemon is never started by hand —
|
|
35
|
-
any `otacon` command auto-spawns it.
|
|
36
|
-
|
|
37
|
-
Per-repo setup: **none.** The first `otacon start` in a repo creates `.otacon/` and
|
|
38
|
-
gitignores it. Approved plans land committed in `docs/plans/`. `otacon clean` archives
|
|
39
|
-
ended sessions' working state to `.otacon/archive/`.
|
|
30
|
+
## Get started
|
|
40
31
|
|
|
41
|
-
|
|
32
|
+
**Install the skill into your agent.** This drops the Otacon skill into the agent's skill
|
|
33
|
+
folder so it knows how to run a review:
|
|
42
34
|
|
|
43
35
|
```sh
|
|
44
|
-
|
|
36
|
+
otacon install --all # all three agents
|
|
37
|
+
otacon install --agent claude # or just one: claude, codex, or opencode
|
|
45
38
|
```
|
|
46
39
|
|
|
47
|
-
|
|
40
|
+
**Plan a feature.** In your agent, run `/otacon` (or just ask it to plan something with
|
|
41
|
+
Otacon). It interviews you to lock down intent, drafts the plan, and hands you a local
|
|
42
|
+
review URL.
|
|
48
43
|
|
|
49
|
-
|
|
50
|
-
|
|
44
|
+
**Review and sign off.** Open the URL: answer the interview, leave inline comments, ask
|
|
45
|
+
questions, and diff revisions in the browser, or [from your phone](docs/PHONE-ACCESS.md).
|
|
51
46
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
47
|
+
When the plan is ready, choose how it ships:
|
|
48
|
+
|
|
49
|
+
- **Save**: the approved plan lands in your home archive (`~/.otacon/sessions/`) plus a copy in the project (`.otacon/plans/` by default; set `plans.dir` to `docs/plans` to group it with your tracked plans). Commit the project copy if you want it in git.
|
|
50
|
+
- **Implement**: the same agent builds it in an isolated git worktree, phase by phase, and opens a PR.
|
|
51
|
+
|
|
52
|
+
## Why Otacon
|
|
53
|
+
|
|
54
|
+
Native plan mode hands you a wall of terminal text without fully clarifying your intent, and asks you to bless it. When you share your feedback, the agent sends back the full plan again. Re-reviewing the next revision costs as much as the first read.
|
|
55
|
+
|
|
56
|
+
The native plan also mixes low-level implementation detail with high-level design. Serious engineering orgs don't work that way. They sign off on the interface, the blast radius, and the behavior, dig into the implementation only where it matters, and treat review as a back-and-forth rather than a one-shot blessing. Otacon brings that discipline to coding agents.
|
|
57
|
+
|
|
58
|
+
<table>
|
|
59
|
+
<tr>
|
|
60
|
+
<td width="50%" valign="top">
|
|
61
|
+
|
|
62
|
+
#### 📄 Plans you actually read
|
|
63
|
+
|
|
64
|
+
A wall of prose is easy to skim and impossible to vet. Otacon plans are modeled on the
|
|
65
|
+
design docs strong eng orgs actually review. They lead with the high-level interface and
|
|
66
|
+
the impact, fold the code-level detail into collapsible sections, and put visuals where
|
|
67
|
+
they carry weight.
|
|
68
|
+
|
|
69
|
+
</td>
|
|
70
|
+
<td width="50%" valign="top">
|
|
71
|
+
|
|
72
|
+
#### 💬 Comment, don't rubber-stamp
|
|
73
|
+
|
|
74
|
+
Select any passage and leave an inline comment. Your note is
|
|
75
|
+
captured and routed to the agent without breaking your reading flow. Comments batch into
|
|
76
|
+
**one** clean revision with a changelog. Need a
|
|
77
|
+
clarification, not a change? **Quick Ask** gets you an instant answer without touching the
|
|
78
|
+
plan. And each revision lands as a diff that shows only what changed since you last looked,
|
|
79
|
+
so you never dig through a wall of terminal text to find it.
|
|
80
|
+
|
|
81
|
+
</td>
|
|
82
|
+
</tr>
|
|
83
|
+
<tr>
|
|
84
|
+
<td width="50%" valign="top">
|
|
85
|
+
|
|
86
|
+
#### 🎙️ It interviews you first
|
|
87
|
+
|
|
88
|
+
Otacon grills
|
|
89
|
+
you before it writes a word of the plan. It interviews until you're aligned, then drafts. Every
|
|
90
|
+
decision traces back to the answer that produced it, and the interview ships
|
|
91
|
+
with the approved plan, so the _why_ is never lost.
|
|
92
|
+
|
|
93
|
+
</td>
|
|
94
|
+
<td width="50%" valign="top">
|
|
95
|
+
|
|
96
|
+
#### 📱 Review from your phone
|
|
59
97
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
98
|
+
The five minutes before you hit the road shouldn't block your agent. Reviews run over
|
|
99
|
+
Tailscale, so you can continue the review, comment, and sign off from your phone. Because it's your own tailnet, your plans never leave your own devices.
|
|
100
|
+
[Phone setup →](docs/PHONE-ACCESS.md)
|
|
63
101
|
|
|
64
|
-
|
|
102
|
+
</td>
|
|
103
|
+
</tr>
|
|
104
|
+
<tr>
|
|
105
|
+
<td width="50%" valign="top">
|
|
65
106
|
|
|
66
|
-
|
|
67
|
-
devices, and the tailnet is the auth:
|
|
107
|
+
#### 🚀 From approved plan to shipped PR
|
|
68
108
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
tailnet URL actually serves, and prints the HTTPS URL with `verified: true`.
|
|
74
|
-
Bookmark it on the phone.
|
|
75
|
-
4. Keep the Mac awake while a plan is in review: `caffeinate -i`.
|
|
109
|
+
Approval shouldn't be where the rigor ends. **Approve & Implement** carries the plan
|
|
110
|
+
straight into the build inside an isolated git worktree: the same agent walks the phases
|
|
111
|
+
with a fresh subagent per phase,
|
|
112
|
+
then opens a PR.
|
|
76
113
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
instead of handing you a dead URL. (Just enabled HTTPS? The cert can take a minute to
|
|
80
|
-
provision; re-run `expose`.)
|
|
114
|
+
</td>
|
|
115
|
+
<td width="50%" valign="top">
|
|
81
116
|
|
|
82
|
-
|
|
83
|
-
launcher — a wrapper script that runs the app-bundle binary (a bare symlink crashes).
|
|
84
|
-
otacon finds the app-bundle binary on its own either way.
|
|
117
|
+
#### 🔒 Private & free by construction
|
|
85
118
|
|
|
86
|
-
|
|
119
|
+
The daemon, CLI, and UI never call an LLM. All the intelligence runs in your existing
|
|
120
|
+
subscription-backed agent session, so Otacon adds **zero API spend** of its own. It's
|
|
121
|
+
local-first, so your plans stay on your machines.
|
|
87
122
|
|
|
88
|
-
|
|
123
|
+
</td>
|
|
124
|
+
</tr>
|
|
125
|
+
</table>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// Launch a URL in the user's default browser for `otacon open` / `otacon config`
|
|
2
|
+
// (DESIGN.md §6, DECISIONS.md "open and config launch the browser"). Both run on
|
|
3
|
+
// the human's machine and the whole point of these two verbs is "show me the
|
|
4
|
+
// page", so they spawn the browser instead of printing the URL.
|
|
5
|
+
//
|
|
6
|
+
// The launch is best-effort and detached: a missing opener (ENOENT), a non-GUI
|
|
7
|
+
// host, or a slow browser must never fail the command, throw out of the CLI's
|
|
8
|
+
// JSON-on-stdout contract, or stall an agent that ran it. OTACON_NO_BROWSER
|
|
9
|
+
// suppresses the launch and prints the URL as one JSON line instead. That is the
|
|
10
|
+
// seam headless hosts (CI, the e2e scripts) and any agent that wants to parse the
|
|
11
|
+
// URL use to get the old print-only behavior back.
|
|
12
|
+
import { spawn } from "node:child_process";
|
|
13
|
+
import { notice, printJson } from "./output.js";
|
|
14
|
+
/** The platform's "open this URL with the default app" command + args. */
|
|
15
|
+
function opener(url) {
|
|
16
|
+
switch (process.platform) {
|
|
17
|
+
case "darwin":
|
|
18
|
+
return { command: "open", args: [url] };
|
|
19
|
+
case "win32":
|
|
20
|
+
// `start` is a cmd builtin; the empty "" is its window-title argument, so a
|
|
21
|
+
// URL carrying spaces/`&` isn't swallowed as the title instead of the URL.
|
|
22
|
+
return { command: "cmd", args: ["/c", "start", "", url] };
|
|
23
|
+
default:
|
|
24
|
+
return { command: "xdg-open", args: [url] };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** Fire the default browser at `url`, detached; never throws (see header). */
|
|
28
|
+
export function openInBrowser(url) {
|
|
29
|
+
const { command, args } = opener(url);
|
|
30
|
+
try {
|
|
31
|
+
const child = spawn(command, args, { detached: true, stdio: "ignore" });
|
|
32
|
+
// Without a listener an ENOENT (no opener on PATH) would surface as an
|
|
33
|
+
// uncaught error event; swallow it. The stderr notice still carries the URL.
|
|
34
|
+
child.on("error", () => { });
|
|
35
|
+
child.unref();
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// spawn can also throw synchronously; the URL is still in the notice.
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Deliver a URL the way `open`/`config` do: launch the browser and print a stderr
|
|
43
|
+
* notice carrying the link (a clickable fallback when the launch is a no-op).
|
|
44
|
+
* Under OTACON_NO_BROWSER it falls back to the print-only contract (one JSON line
|
|
45
|
+
* on stdout) for headless hosts, the e2e scripts, and URL-parsing agents.
|
|
46
|
+
*/
|
|
47
|
+
export function openOrPrint(url, payload) {
|
|
48
|
+
if (process.env.OTACON_NO_BROWSER) {
|
|
49
|
+
printJson(payload);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
notice(`opening ${url}`);
|
|
53
|
+
openInBrowser(url);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/cli/browser.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,iFAAiF;AACjF,6EAA6E;AAC7E,gEAAgE;AAChE,EAAE;AACF,+EAA+E;AAC/E,8EAA8E;AAC9E,4EAA4E;AAC5E,iFAAiF;AACjF,kFAAkF;AAClF,mDAAmD;AAEnD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEhD,0EAA0E;AAC1E,SAAS,MAAM,CAAC,GAAW;IACzB,QAAQ,OAAO,CAAC,QAAQ,EAAE,CAAC;QACzB,KAAK,QAAQ;YACX,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1C,KAAK,OAAO;YACV,4EAA4E;YAC5E,2EAA2E;YAC3E,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC;QAC5D;YACE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;IAChD,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QACxE,uEAAuE;QACvE,6EAA6E;QAC7E,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC5B,KAAK,CAAC,KAAK,EAAE,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,sEAAsE;IACxE,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,OAAgC;IACvE,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC;QAClC,SAAS,CAAC,OAAO,CAAC,CAAC;QACnB,OAAO;IACT,CAAC;IACD,MAAM,CAAC,WAAW,GAAG,EAAE,CAAC,CAAC;IACzB,aAAa,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC"}
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
// calls DELETE /api/sessions/:id; the daemon deregisters the session and
|
|
4
4
|
// archives its .otacon/<id>/ dir to .otacon/archive/<id>/, reporting the
|
|
5
5
|
// destination as `archivedTo` (the review UI drives the same route — terminal
|
|
6
|
-
// archives, non-terminal hard-deletes).
|
|
7
|
-
// are never touched (DECISIONS.md "clean: daemon
|
|
6
|
+
// archives, non-terminal hard-deletes). The home archive (~/.otacon/sessions/)
|
|
7
|
+
// and any Save-time project copy are never touched (DECISIONS.md "clean: daemon
|
|
8
|
+
// deregisters and archives").
|
|
8
9
|
import { parseArgs } from "node:util";
|
|
9
10
|
import { TERMINAL_STATUSES } from "../../shared/types.js";
|
|
10
11
|
import { api, ensureDaemon } from "../client.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clean.js","sourceRoot":"","sources":["../../../src/cli/commands/clean.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,4EAA4E;AAC5E,yEAAyE;AACzE,yEAAyE;AACzE,8EAA8E;AAC9E,
|
|
1
|
+
{"version":3,"file":"clean.js","sourceRoot":"","sources":["../../../src/cli/commands/clean.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,4EAA4E;AAC5E,yEAAyE;AACzE,yEAAyE;AACzE,8EAA8E;AAC9E,+EAA+E;AAC/E,gFAAgF;AAChF,8BAA8B;AAE9B,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEvE,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAc;IAC/C,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;QAC3B,IAAI,EAAE,IAAI;QACV,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;KACtD,CAAC,CAAC;IACH,MAAM,YAAY,EAAE,CAAC;IACrB,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC;IACtC,wEAAwE;IACxE,6EAA6E;IAC7E,8EAA8E;IAC9E,yEAAyE;IACzE,mDAAmD;IACnD,MAAM,OAAO,GAAG,CAAC,MAAM,YAAY,EAAE,CAAC,CAAC,MAAM,CAC3C,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAC3F,CAAC;IAEF,MAAM,OAAO,GAAkF,EAAE,CAAC;IAClG,KAAK,MAAM,OAAO,IAAI,OAAO,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,QAAQ,EAAE,iBAAiB,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QACpE,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,MAAM,CAAC,YAAY,OAAO,CAAC,EAAE,KAAK,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACnE,SAAS;QACX,CAAC;QACD,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC;QAC5C,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAC/C,MAAM,CAAC,GAAG,OAAO,CAAC,EAAE,KAAK,OAAO,wCAAwC,CAAC,CAAC;QAC5E,CAAC;QACD,6EAA6E;QAC7E,MAAM,UAAU,GAAI,QAAQ,CAAC,IAAI,CAAC,UAAwC,IAAI,IAAI,CAAC;QACnF,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;IAC9F,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,yBAAyB,IAAI,cAAc,CAAC,CAAC;IAClG,CAAC;IACD,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACjC,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// otacon config [open] | config get <key> (DESIGN.md §6, §16).
|
|
2
|
+
//
|
|
3
|
+
// otacon config open the Settings web UI in the browser. Inside a
|
|
4
|
+
// git repo the URL carries `?repo=<repo root>` so the screen defaults to
|
|
5
|
+
// Project scope for this repo; outside any repo it is the bare `/settings`
|
|
6
|
+
// (User scope). Like `otacon open`, it launches the browser; OTACON_NO_BROWSER
|
|
7
|
+
// prints the URL instead (DECISIONS.md "open and config launch the browser").
|
|
8
|
+
// otacon config get <key> read-only: resolve the merged effective value of
|
|
9
|
+
// one dotted key (`worktree.dir`, `budgets.summaryLines`, …) from the config
|
|
10
|
+
// files via loadConfig and print it. No daemon: it reads config directly so
|
|
11
|
+
// the agent implement loop can consume `worktree.dir` (DECISIONS.md
|
|
12
|
+
// "read-only `config get`"). Editing config stays UI-only.
|
|
13
|
+
import { CONFIG_SCHEMA, loadConfig } from "../../shared/config.js";
|
|
14
|
+
import { openOrPrint } from "../browser.js";
|
|
15
|
+
import { baseUrl, ensureDaemon } from "../client.js";
|
|
16
|
+
import { fail, printJson, usageError } from "../output.js";
|
|
17
|
+
import { findRepoRoot, realpathOr } from "../session.js";
|
|
18
|
+
/** Every valid dotted key, derived from the one schema source of truth. */
|
|
19
|
+
const KNOWN_KEYS = new Set(CONFIG_SCHEMA.map((field) => `${field.section}.${field.key}`));
|
|
20
|
+
export async function configCommand(argv) {
|
|
21
|
+
const sub = argv[0];
|
|
22
|
+
if (sub === "get")
|
|
23
|
+
return configGet(argv.slice(1));
|
|
24
|
+
// No sub-form, or the explicit `open` verb: open the Settings web UI.
|
|
25
|
+
if (sub === undefined || sub === "open")
|
|
26
|
+
return configOpen();
|
|
27
|
+
usageError("usage: otacon config [open] | otacon config get <key>");
|
|
28
|
+
}
|
|
29
|
+
/** Launch the Settings web UI in the browser (mirrors `otacon open`). */
|
|
30
|
+
async function configOpen() {
|
|
31
|
+
await ensureDaemon();
|
|
32
|
+
// Inside a git repo, default the Settings screen to this repo's Project scope
|
|
33
|
+
// via ?repo=; outside any repo there is no project target, so open User scope.
|
|
34
|
+
const repoRoot = findRepoRoot(realpathOr(process.cwd()));
|
|
35
|
+
const url = repoRoot === undefined
|
|
36
|
+
? `${baseUrl()}/settings`
|
|
37
|
+
: `${baseUrl()}/settings?repo=${encodeURIComponent(repoRoot)}`;
|
|
38
|
+
openOrPrint(url, { ok: true, url, ...(repoRoot === undefined ? {} : { repo: repoRoot }) });
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
/** Read-only merged lookup of one dotted config key. */
|
|
42
|
+
function configGet(args) {
|
|
43
|
+
const key = args[0];
|
|
44
|
+
if (key === undefined || args.length > 1) {
|
|
45
|
+
usageError("otacon config get takes exactly one <key> (e.g. worktree.dir)");
|
|
46
|
+
}
|
|
47
|
+
if (!KNOWN_KEYS.has(key)) {
|
|
48
|
+
fail("E_UNKNOWN_KEY", `unknown config key ${key}; valid keys: ${[...KNOWN_KEYS].join(", ")}`);
|
|
49
|
+
}
|
|
50
|
+
// Resolve against the cwd repo's merged config when inside a repo, else the
|
|
51
|
+
// defaults←user layers alone — exactly what the runtime would see here.
|
|
52
|
+
const repoRoot = findRepoRoot(realpathOr(process.cwd()));
|
|
53
|
+
const config = loadConfig(repoRoot);
|
|
54
|
+
const [section, leaf] = key.split(".");
|
|
55
|
+
// `key` passed the CONFIG_SCHEMA check above, so section/leaf name a real
|
|
56
|
+
// config field; the unknown hop is the schema-driven section→leaf indexing
|
|
57
|
+
// (same shape overlayConfig uses) rather than a per-section union.
|
|
58
|
+
const value = config[section][leaf];
|
|
59
|
+
printJson({ ok: true, key, value });
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/cli/commands/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,31 +7,41 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
7
7
|
import { parseArgs } from "node:util";
|
|
8
8
|
import { otaconPort } from "../../shared/paths.js";
|
|
9
9
|
import { ensureDaemon } from "../client.js";
|
|
10
|
-
import {
|
|
11
|
-
import { claudeHookScriptPath, claudeSkillPath,
|
|
10
|
+
import { MANAGED_MARKER } from "../install/assets.js";
|
|
11
|
+
import { claudeHookScriptPath, claudeSkillPath, codexSkillPath, opencodeSkillPath, settingsRegisterStopHook, } from "../install/locations.js";
|
|
12
12
|
import { findTailscale, tailscaleStatus } from "../install/tailscale.js";
|
|
13
13
|
import { CliError, printJson } from "../output.js";
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return
|
|
17
|
-
? { name, status: "ok", detail: path }
|
|
18
|
-
: {
|
|
19
|
-
name,
|
|
20
|
-
status: "warn",
|
|
21
|
-
detail: `wrapper not installed at ${path}; run otacon install --agent ${name.replace("wrapper-", "")}`,
|
|
22
|
-
};
|
|
14
|
+
import { findRepoRoot } from "../session.js";
|
|
15
|
+
function wrapperPresent(path, marker) {
|
|
16
|
+
return existsSync(path) && readFileSync(path, "utf8").includes(marker);
|
|
23
17
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
// A wrapper is the otacon protocol skill (the SKILL.md `otacon install` writes); it's
|
|
19
|
+
// optional, so absence is a warn, never a failure. When run inside a repo, accept the
|
|
20
|
+
// wrapper at EITHER the user path or the project path so a `--project` install doesn't
|
|
21
|
+
// trip a spurious "not installed" warning — report whichever scope satisfied it.
|
|
22
|
+
export function wrapperCheck(name, candidates, marker) {
|
|
23
|
+
const hit = candidates.find((c) => wrapperPresent(c.path, marker));
|
|
24
|
+
if (hit)
|
|
25
|
+
return { name, status: "ok", detail: `${hit.path} (${hit.scope})` };
|
|
26
|
+
const agent = name.replace("wrapper-", "");
|
|
27
|
+
const looked = candidates.map((c) => c.path).join(" and ");
|
|
28
|
+
const projectHint = candidates.some((c) => c.scope === "project")
|
|
29
|
+
? " or add --project to install it into this repo"
|
|
30
|
+
: "";
|
|
29
31
|
return {
|
|
30
32
|
name,
|
|
31
33
|
status: "warn",
|
|
32
|
-
detail:
|
|
34
|
+
detail: `otacon protocol skill not found for ${agent} (looked in ${looked}); run \`otacon install --agent ${agent}\`${projectHint}`,
|
|
33
35
|
};
|
|
34
36
|
}
|
|
37
|
+
// The Stop hook is optional — a belt-and-suspenders guard on top of the skill's
|
|
38
|
+
// never-end-your-turn rule, not a required piece. Confirm it when wired up, but
|
|
39
|
+
// never flag its absence (return undefined → omitted from the report, no warning).
|
|
40
|
+
function stopHookCheck() {
|
|
41
|
+
if (!settingsRegisterStopHook())
|
|
42
|
+
return undefined;
|
|
43
|
+
return { name: "stop-hook", status: "ok", detail: claudeHookScriptPath() };
|
|
44
|
+
}
|
|
35
45
|
function tailscaleCheck() {
|
|
36
46
|
const name = "tailscale";
|
|
37
47
|
const bin = findTailscale();
|
|
@@ -74,10 +84,20 @@ export async function doctorCommand(argv) {
|
|
|
74
84
|
detail: error instanceof CliError ? `${error.code}: ${error.message}` : String(error),
|
|
75
85
|
});
|
|
76
86
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
87
|
+
// When in a git repo, also accept a project-scope wrapper (otacon install --project)
|
|
88
|
+
// so a committed `.claude`/`.codex`/`.opencode` doesn't read as "not installed".
|
|
89
|
+
const projectRoot = findRepoRoot(process.cwd());
|
|
90
|
+
const project = projectRoot === undefined ? undefined : { kind: "project", root: projectRoot };
|
|
91
|
+
const candidates = (skillPath) => [
|
|
92
|
+
{ path: skillPath(), scope: "user" },
|
|
93
|
+
...(project ? [{ path: skillPath(project), scope: "project" }] : []),
|
|
94
|
+
];
|
|
95
|
+
checks.push(wrapperCheck("wrapper-claude", candidates(claudeSkillPath), MANAGED_MARKER));
|
|
96
|
+
checks.push(wrapperCheck("wrapper-codex", candidates(codexSkillPath), MANAGED_MARKER));
|
|
97
|
+
checks.push(wrapperCheck("wrapper-opencode", candidates(opencodeSkillPath), MANAGED_MARKER));
|
|
98
|
+
const stopHook = stopHookCheck();
|
|
99
|
+
if (stopHook)
|
|
100
|
+
checks.push(stopHook);
|
|
81
101
|
checks.push(tailscaleCheck());
|
|
82
102
|
const ok = checks.every((c) => c.status !== "fail");
|
|
83
103
|
printJson({ ok, checks });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,8EAA8E;AAC9E,2EAA2E;AAC3E,8EAA8E;AAC9E,6EAA6E;AAE7E,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -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
|
|
5
|
-
//
|
|
6
|
-
//
|
|
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 {
|
|
12
|
-
import { claudeHookScriptPath, claudeSettingsPath, claudeSkillPath,
|
|
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
|
-
|
|
23
|
-
writeManaged(
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
29
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
105
|
-
|
|
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":"AAAA,+EAA+E;AAC/E,+EAA+E;AAC/E,6EAA6E;AAC7E,
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/cli/commands/install.ts"],"names":[],"mappings":"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"}
|