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.
- package/README.md +101 -64
- package/dist/cli/browser.js +55 -0
- package/dist/cli/browser.js.map +1 -0
- package/dist/cli/client.js +11 -0
- package/dist/cli/client.js.map +1 -1
- 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 +8 -22
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/update.js +76 -0
- package/dist/cli/commands/update.js.map +1 -0
- 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 +10 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/update.js +195 -0
- package/dist/cli/update.js.map +1 -0
- 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 +9 -1
- package/dist/daemon/ui.js.map +1 -1
- package/dist/shared/config.js +301 -45
- package/dist/shared/config.js.map +1 -1
- package/dist/shared/paths.js +41 -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-Cp3sPd_U.js} +1 -1
- package/dist/ui/assets/architecture-7EHR7CIX-BbwstElO.js +1 -0
- package/dist/ui/assets/{architectureDiagram-3BPJPVTR-D2PIxGOb.js → architectureDiagram-3BPJPVTR-C4F3heWP.js} +1 -1
- package/dist/ui/assets/{blockDiagram-GPEHLZMM-DQ3Dn17h.js → blockDiagram-GPEHLZMM-DmJoG8ky.js} +1 -1
- package/dist/ui/assets/{c4Diagram-AAUBKEIU-DxITrQgS.js → c4Diagram-AAUBKEIU-BDEf52Jp.js} +1 -1
- package/dist/ui/assets/channel-BMK3JFRf.js +1 -0
- package/dist/ui/assets/{chunk-2J33WTMH-Du1JoPx5.js → chunk-2J33WTMH-Dh_UFriv.js} +1 -1
- package/dist/ui/assets/{chunk-3OPIFGDE-Dn7x2Yqf.js → chunk-3OPIFGDE-c66RlAN8.js} +1 -1
- package/dist/ui/assets/{chunk-4BX2VUAB-DVnrE-4n.js → chunk-4BX2VUAB-CrGJaCCg.js} +1 -1
- package/dist/ui/assets/{chunk-55IACEB6-BAhFAimA.js → chunk-55IACEB6-BvwqEeyq.js} +1 -1
- package/dist/ui/assets/{chunk-5ZQYHXKU-0hEZptem.js → chunk-5ZQYHXKU-BfF2IfQe.js} +1 -1
- package/dist/ui/assets/{chunk-727SXJPM-C1FN_cI3.js → chunk-727SXJPM-DOEUwc9I.js} +1 -1
- package/dist/ui/assets/{chunk-AQP2D5EJ-A656OBd4.js → chunk-AQP2D5EJ-CVf2xV2Z.js} +1 -1
- package/dist/ui/assets/{chunk-BSJP7CBP-D8oMbjm8.js → chunk-BSJP7CBP-D_EbTWTC.js} +1 -1
- package/dist/ui/assets/{chunk-CSCIHK7Q-DjIL8GLi.js → chunk-CSCIHK7Q-CkxTSMAM.js} +1 -1
- package/dist/ui/assets/{chunk-FMBD7UC4-Otblfqvz.js → chunk-FMBD7UC4-DVShhFc7.js} +1 -1
- package/dist/ui/assets/{chunk-KSCS5N6A-BOjTvm3H.js → chunk-KSCS5N6A-DnHEEYpq.js} +1 -1
- package/dist/ui/assets/{chunk-L5ZTLDWV-CaTLaw6L.js → chunk-L5ZTLDWV-B_gjyajS.js} +1 -1
- package/dist/ui/assets/{chunk-LZXEDZCA-Dq5p7qrD.js → chunk-LZXEDZCA-Bsf7basG.js} +2 -2
- package/dist/ui/assets/{chunk-ND2GUHAM-jZ_NNnWi.js → chunk-ND2GUHAM-DGepGb8_.js} +1 -1
- package/dist/ui/assets/{chunk-NZK2D7GU-U_7l_sCh.js → chunk-NZK2D7GU-BJIlh-gB.js} +1 -1
- package/dist/ui/assets/{chunk-O5CBEL6O-MewqqNB7.js → chunk-O5CBEL6O-cdVbOOCs.js} +1 -1
- package/dist/ui/assets/chunk-QZHKN3VN-DLNUTn7U.js +1 -0
- package/dist/ui/assets/chunk-WU5MYG2G-ipH3YPcA.js +1 -0
- package/dist/ui/assets/{chunk-XPW4576I-D5ArxNEF.js → chunk-XPW4576I-DPW39hNO.js} +1 -1
- package/dist/ui/assets/classDiagram-4FO5ZUOK-CvIMLlSD.js +1 -0
- package/dist/ui/assets/classDiagram-v2-Q7XG4LA2-CvIMLlSD.js +1 -0
- package/dist/ui/assets/{cose-bilkent-S5V4N54A-PFXzf7WV.js → cose-bilkent-S5V4N54A-DmMsC6om.js} +1 -1
- package/dist/ui/assets/{dagre-BM42HDAG-xrCfjZuZ.js → dagre-BM42HDAG-BmVr7T7Z.js} +1 -1
- package/dist/ui/assets/{diagram-2AECGRRQ-BFf-cyKY.js → diagram-2AECGRRQ-e0VnXEyj.js} +1 -1
- package/dist/ui/assets/{diagram-5GNKFQAL-kNPV4NfV.js → diagram-5GNKFQAL-SCJGYE6m.js} +1 -1
- package/dist/ui/assets/{diagram-KO2AKTUF-ByC1IUwG.js → diagram-KO2AKTUF-DDUZO1Mj.js} +1 -1
- package/dist/ui/assets/{diagram-LMA3HP47-DZIJMPK0.js → diagram-LMA3HP47-5x1ypf6a.js} +1 -1
- package/dist/ui/assets/{diagram-OG6HWLK6-CSDED9A-.js → diagram-OG6HWLK6-3nDhrQ20.js} +1 -1
- package/dist/ui/assets/{dist-YwjsDswi.js → dist-NEinnePC.js} +1 -1
- package/dist/ui/assets/{erDiagram-TEJ5UH35-yuzvjE6J.js → erDiagram-TEJ5UH35-BNvwSDNZ.js} +1 -1
- package/dist/ui/assets/eventmodeling-FCH6USID-BeFWDbla.js +1 -0
- package/dist/ui/assets/{flowDiagram-I6XJVG4X-ApPtVyYM.js → flowDiagram-I6XJVG4X-Bt_wDUhb.js} +1 -1
- package/dist/ui/assets/{ganttDiagram-6RSMTGT7-BeMLXtAr.js → ganttDiagram-6RSMTGT7-DVcJ0rNX.js} +1 -1
- package/dist/ui/assets/{gitGraph-WXDBUCRP-JmTTBa7j.js → gitGraph-WXDBUCRP-CO_SyAgP.js} +1 -1
- package/dist/ui/assets/{gitGraphDiagram-PVQCEYII-Cjjnjs71.js → gitGraphDiagram-PVQCEYII-oDyO3lWI.js} +1 -1
- package/dist/ui/assets/index-CJJIQ0dr.css +1 -0
- package/dist/ui/assets/index-Dh5CsH24.js +11 -0
- package/dist/ui/assets/{info-J43DQDTF-8vZ3gome.js → info-J43DQDTF-Bn17NS7h.js} +1 -1
- package/dist/ui/assets/{infoDiagram-5YYISTIA-CnMk1cA-.js → infoDiagram-5YYISTIA-HG1opLLT.js} +1 -1
- package/dist/ui/assets/{ishikawaDiagram-YF4QCWOH-Bl8z6huD.js → ishikawaDiagram-YF4QCWOH-Di_yQwi8.js} +1 -1
- package/dist/ui/assets/{journeyDiagram-JHISSGLW-DYIVfMpS.js → journeyDiagram-JHISSGLW-DZtHvLeE.js} +1 -1
- package/dist/ui/assets/{kanban-definition-UN3LZRKU-BnR0ZzOz.js → kanban-definition-UN3LZRKU-B_RCx3Km.js} +1 -1
- package/dist/ui/assets/{line-DcBdQit6.js → line-DenX-zXQ.js} +1 -1
- package/dist/ui/assets/{linear-HKjRHFAO.js → linear-dly_ngoq.js} +1 -1
- package/dist/ui/assets/{mermaid-parser.core-DkYXrPlA.js → mermaid-parser.core-CRmtm0s9.js} +2 -2
- package/dist/ui/assets/{mermaid.core-BmkfCI3b.js → mermaid.core-C_3KVfpx.js} +3 -3
- package/dist/ui/assets/{mindmap-definition-RKZ34NQL-sIAd4nDi.js → mindmap-definition-RKZ34NQL-wdzSyYO6.js} +1 -1
- package/dist/ui/assets/{packet-YPE3B663-BxbxcfXN.js → packet-YPE3B663-tUyFmR11.js} +1 -1
- package/dist/ui/assets/{pie-LRSECV5Y-BJxazjNs.js → pie-LRSECV5Y-Cel48VVp.js} +1 -1
- package/dist/ui/assets/{pieDiagram-4H26LBE5-BiOhc9GR.js → pieDiagram-4H26LBE5-B55ypWtu.js} +1 -1
- package/dist/ui/assets/{plan-view-CH6NzUDb.js → plan-view-CMoo3_gE.js} +3 -3
- package/dist/ui/assets/{quadrantDiagram-W4KKPZXB-CVyHbWgo.js → quadrantDiagram-W4KKPZXB-9WcKQV0a.js} +1 -1
- package/dist/ui/assets/{radar-GUYGQ44K-D9ohbnbV.js → radar-GUYGQ44K-w5pk53Vr.js} +1 -1
- package/dist/ui/assets/{requirementDiagram-4Y6WPE33-Ba24_hqc.js → requirementDiagram-4Y6WPE33-CzE82fXz.js} +1 -1
- package/dist/ui/assets/{sankeyDiagram-5OEKKPKP-CxD4wiPL.js → sankeyDiagram-5OEKKPKP-DSGO39je.js} +1 -1
- package/dist/ui/assets/{sequenceDiagram-3UESZ5HK-7qA7lD61.js → sequenceDiagram-3UESZ5HK-BKSDDr0S.js} +1 -1
- package/dist/ui/assets/{src-IM8AE8MK.js → src-JXBGgRt-.js} +1 -1
- package/dist/ui/assets/{stateDiagram-AJRCARHV-DNElRCuH.js → stateDiagram-AJRCARHV-DZHYA9aj.js} +1 -1
- package/dist/ui/assets/stateDiagram-v2-BHNVJYJU-DnAfDlvZ.js +1 -0
- package/dist/ui/assets/{timeline-definition-PNZ67QCA-ChYC4Grd.js → timeline-definition-PNZ67QCA-WqJFw7aE.js} +1 -1
- package/dist/ui/assets/{treeView-BLDUP644-Il0KnMi_.js → treeView-BLDUP644-DoIQYMiz.js} +1 -1
- package/dist/ui/assets/{treemap-LRROVOQU-CIiKcdRo.js → treemap-LRROVOQU-BA9si_Mo.js} +1 -1
- package/dist/ui/assets/{vennDiagram-CIIHVFJN-Ulhkum9i.js → vennDiagram-CIIHVFJN-BvWRUfFr.js} +1 -1
- package/dist/ui/assets/{wardley-L42UT6IY-BNd4ljz7.js → wardley-L42UT6IY-Cf9PU44t.js} +1 -1
- package/dist/ui/assets/{wardleyDiagram-YWT4CUSO-BicXxh84.js → wardleyDiagram-YWT4CUSO-CGuxl7AU.js} +1 -1
- package/dist/ui/assets/{xychartDiagram-2RQKCTM6-Duf-m_th.js → xychartDiagram-2RQKCTM6-CNteNXpe.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
|
@@ -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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"}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
// otacon open [--session id]
|
|
2
|
-
// convenience).
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
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
|
|
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
|
-
|
|
20
|
-
|
|
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}
|
|
33
|
-
|
|
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,
|
|
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,
|
|
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":"AAAA,8EAA8E;AAC9E,
|
|
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
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
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
|
-
|
|
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\` →
|
|
69
|
-
\`
|
|
70
|
-
**with \`implement:true\`** →
|
|
71
|
-
(below) — do NOT stop; the
|
|
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
|
|
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.**
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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,
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
/**
|
|
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
|
|
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
|
|
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
|
|
238
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
|
19
|
-
export function
|
|
20
|
-
|
|
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
|
|
23
|
-
export function opencodeSkillPath() {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|