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.
- package/LICENSE +21 -0
- package/README.md +88 -0
- package/dist/cli/client.js +188 -0
- package/dist/cli/client.js.map +1 -0
- package/dist/cli/commands/answer.js +63 -0
- package/dist/cli/commands/answer.js.map +1 -0
- package/dist/cli/commands/ask.js +117 -0
- package/dist/cli/commands/ask.js.map +1 -0
- package/dist/cli/commands/clean.js +48 -0
- package/dist/cli/commands/clean.js.map +1 -0
- package/dist/cli/commands/doctor.js +86 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/expose.js +104 -0
- package/dist/cli/commands/expose.js.map +1 -0
- package/dist/cli/commands/implement-done.js +53 -0
- package/dist/cli/commands/implement-done.js.map +1 -0
- package/dist/cli/commands/install.js +113 -0
- package/dist/cli/commands/install.js.map +1 -0
- package/dist/cli/commands/open.js +37 -0
- package/dist/cli/commands/open.js.map +1 -0
- package/dist/cli/commands/progress.js +45 -0
- package/dist/cli/commands/progress.js.map +1 -0
- package/dist/cli/commands/start.js +66 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/commands/status.js +44 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/submit.js +64 -0
- package/dist/cli/commands/submit.js.map +1 -0
- package/dist/cli/commands/wait.js +66 -0
- package/dist/cli/commands/wait.js.map +1 -0
- package/dist/cli/install/assets.js +285 -0
- package/dist/cli/install/assets.js.map +1 -0
- package/dist/cli/install/locations.js +92 -0
- package/dist/cli/install/locations.js.map +1 -0
- package/dist/cli/install/tailscale.js +39 -0
- package/dist/cli/install/tailscale.js.map +1 -0
- package/dist/cli/main.js +73 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/output.js +39 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/session.js +77 -0
- package/dist/cli/session.js.map +1 -0
- package/dist/daemon/activity.js +56 -0
- package/dist/daemon/activity.js.map +1 -0
- package/dist/daemon/anchor.js +143 -0
- package/dist/daemon/anchor.js.map +1 -0
- package/dist/daemon/app.js +1081 -0
- package/dist/daemon/app.js.map +1 -0
- package/dist/daemon/approve.js +71 -0
- package/dist/daemon/approve.js.map +1 -0
- package/dist/daemon/desktop-notify.js +69 -0
- package/dist/daemon/desktop-notify.js.map +1 -0
- package/dist/daemon/diff.js +187 -0
- package/dist/daemon/diff.js.map +1 -0
- package/dist/daemon/linter/index.js +19 -0
- package/dist/daemon/linter/index.js.map +1 -0
- package/dist/daemon/linter/parse.js +350 -0
- package/dist/daemon/linter/parse.js.map +1 -0
- package/dist/daemon/linter/rules.js +359 -0
- package/dist/daemon/linter/rules.js.map +1 -0
- package/dist/daemon/main.js +48 -0
- package/dist/daemon/main.js.map +1 -0
- package/dist/daemon/notify.js +23 -0
- package/dist/daemon/notify.js.map +1 -0
- package/dist/daemon/presence.js +37 -0
- package/dist/daemon/presence.js.map +1 -0
- package/dist/daemon/queue.js +160 -0
- package/dist/daemon/queue.js.map +1 -0
- package/dist/daemon/store.js +393 -0
- package/dist/daemon/store.js.map +1 -0
- package/dist/daemon/threads.js +153 -0
- package/dist/daemon/threads.js.map +1 -0
- package/dist/daemon/transcript.js +89 -0
- package/dist/daemon/transcript.js.map +1 -0
- package/dist/daemon/ui.js +175 -0
- package/dist/daemon/ui.js.map +1 -0
- package/dist/shared/config.js +93 -0
- package/dist/shared/config.js.map +1 -0
- package/dist/shared/gwt.js +69 -0
- package/dist/shared/gwt.js.map +1 -0
- package/dist/shared/paths.js +67 -0
- package/dist/shared/paths.js.map +1 -0
- package/dist/shared/question-spec.js +44 -0
- package/dist/shared/question-spec.js.map +1 -0
- package/dist/shared/types.js +35 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/shared/version.js +5 -0
- package/dist/shared/version.js.map +1 -0
- package/dist/ui/assets/arc-HhPfdCPZ.js +1 -0
- package/dist/ui/assets/architecture-7EHR7CIX-BPLblcyi.js +1 -0
- package/dist/ui/assets/architectureDiagram-3BPJPVTR-D2PIxGOb.js +36 -0
- package/dist/ui/assets/array-BifhSqXX.js +1 -0
- package/dist/ui/assets/blockDiagram-GPEHLZMM-DQ3Dn17h.js +132 -0
- package/dist/ui/assets/c4Diagram-AAUBKEIU-DxITrQgS.js +10 -0
- package/dist/ui/assets/channel-ipcU8ZNI.js +1 -0
- package/dist/ui/assets/chunk-2J33WTMH-Du1JoPx5.js +1 -0
- package/dist/ui/assets/chunk-3OPIFGDE-Dn7x2Yqf.js +62 -0
- package/dist/ui/assets/chunk-4BX2VUAB-DVnrE-4n.js +1 -0
- package/dist/ui/assets/chunk-55IACEB6-BAhFAimA.js +1 -0
- package/dist/ui/assets/chunk-5ZQYHXKU-0hEZptem.js +2 -0
- package/dist/ui/assets/chunk-727SXJPM-C1FN_cI3.js +206 -0
- package/dist/ui/assets/chunk-AQP2D5EJ-A656OBd4.js +231 -0
- package/dist/ui/assets/chunk-BSJP7CBP-D8oMbjm8.js +1 -0
- package/dist/ui/assets/chunk-CSCIHK7Q-DjIL8GLi.js +122 -0
- package/dist/ui/assets/chunk-FMBD7UC4-Otblfqvz.js +15 -0
- package/dist/ui/assets/chunk-KSCS5N6A-BOjTvm3H.js +10 -0
- package/dist/ui/assets/chunk-L5ZTLDWV-CaTLaw6L.js +1 -0
- package/dist/ui/assets/chunk-LZXEDZCA-Dq5p7qrD.js +2 -0
- package/dist/ui/assets/chunk-ND2GUHAM-jZ_NNnWi.js +1 -0
- package/dist/ui/assets/chunk-NNHCCRGN-DlpIbxXb.js +159 -0
- package/dist/ui/assets/chunk-NZK2D7GU-U_7l_sCh.js +1 -0
- package/dist/ui/assets/chunk-O5CBEL6O-MewqqNB7.js +70 -0
- package/dist/ui/assets/chunk-QZHKN3VN-DzGPH44B.js +1 -0
- package/dist/ui/assets/chunk-WU5MYG2G-DyEIVjoo.js +1 -0
- package/dist/ui/assets/chunk-XPW4576I-D5ArxNEF.js +32 -0
- package/dist/ui/assets/classDiagram-4FO5ZUOK-Byg2Hl9D.js +1 -0
- package/dist/ui/assets/classDiagram-v2-Q7XG4LA2-Byg2Hl9D.js +1 -0
- package/dist/ui/assets/cose-bilkent-S5V4N54A-PFXzf7WV.js +1 -0
- package/dist/ui/assets/cytoscape.esm-h6BdjjI9.js +321 -0
- package/dist/ui/assets/dagre-BM42HDAG-xrCfjZuZ.js +4 -0
- package/dist/ui/assets/dagre-Bx709z4p.js +1 -0
- package/dist/ui/assets/defaultLocale-C8Fc0cco.js +1 -0
- package/dist/ui/assets/diagram-2AECGRRQ-BFf-cyKY.js +43 -0
- package/dist/ui/assets/diagram-5GNKFQAL-kNPV4NfV.js +10 -0
- package/dist/ui/assets/diagram-KO2AKTUF-ByC1IUwG.js +3 -0
- package/dist/ui/assets/diagram-LMA3HP47-DZIJMPK0.js +24 -0
- package/dist/ui/assets/diagram-OG6HWLK6-CSDED9A-.js +24 -0
- package/dist/ui/assets/dist-YwjsDswi.js +1 -0
- package/dist/ui/assets/erDiagram-TEJ5UH35-yuzvjE6J.js +85 -0
- package/dist/ui/assets/eventmodeling-FCH6USID-CZR4eNG-.js +1 -0
- package/dist/ui/assets/flowDiagram-I6XJVG4X-ApPtVyYM.js +162 -0
- package/dist/ui/assets/ganttDiagram-6RSMTGT7-BeMLXtAr.js +292 -0
- package/dist/ui/assets/gitGraph-WXDBUCRP-JmTTBa7j.js +1 -0
- package/dist/ui/assets/gitGraphDiagram-PVQCEYII-Cjjnjs71.js +106 -0
- package/dist/ui/assets/graphlib-B8gBHxth.js +1 -0
- package/dist/ui/assets/index-BFQVRcSI.js +11 -0
- package/dist/ui/assets/index-Bj_kTrwP.css +1 -0
- package/dist/ui/assets/info-J43DQDTF-8vZ3gome.js +1 -0
- package/dist/ui/assets/infoDiagram-5YYISTIA-CnMk1cA-.js +2 -0
- package/dist/ui/assets/init-D6jRqBbL.js +1 -0
- package/dist/ui/assets/ishikawaDiagram-YF4QCWOH-Bl8z6huD.js +70 -0
- package/dist/ui/assets/journeyDiagram-JHISSGLW-DYIVfMpS.js +139 -0
- package/dist/ui/assets/kanban-definition-UN3LZRKU-BnR0ZzOz.js +89 -0
- package/dist/ui/assets/katex-Vhh-h91d.js +257 -0
- package/dist/ui/assets/line-DcBdQit6.js +1 -0
- package/dist/ui/assets/linear-HKjRHFAO.js +1 -0
- package/dist/ui/assets/mermaid-parser.core-DkYXrPlA.js +4 -0
- package/dist/ui/assets/mermaid.core-BmkfCI3b.js +9 -0
- package/dist/ui/assets/mindmap-definition-RKZ34NQL-sIAd4nDi.js +96 -0
- package/dist/ui/assets/ordinal-hYBb2elL.js +1 -0
- package/dist/ui/assets/otacon-DPXGiaVj.svg +11 -0
- package/dist/ui/assets/packet-YPE3B663-BxbxcfXN.js +1 -0
- package/dist/ui/assets/path-BWPyau1x.js +1 -0
- package/dist/ui/assets/pie-LRSECV5Y-BJxazjNs.js +1 -0
- package/dist/ui/assets/pieDiagram-4H26LBE5-BiOhc9GR.js +30 -0
- package/dist/ui/assets/plan-view-CH6NzUDb.js +74 -0
- package/dist/ui/assets/purify.es-CDvCXckx.js +3 -0
- package/dist/ui/assets/quadrantDiagram-W4KKPZXB-CVyHbWgo.js +7 -0
- package/dist/ui/assets/radar-GUYGQ44K-D9ohbnbV.js +1 -0
- package/dist/ui/assets/requirementDiagram-4Y6WPE33-Ba24_hqc.js +84 -0
- package/dist/ui/assets/rough.esm-CSKSodPl.js +1 -0
- package/dist/ui/assets/sankeyDiagram-5OEKKPKP-CxD4wiPL.js +40 -0
- package/dist/ui/assets/sequenceDiagram-3UESZ5HK-7qA7lD61.js +162 -0
- package/dist/ui/assets/src-IM8AE8MK.js +1 -0
- package/dist/ui/assets/stateDiagram-AJRCARHV-DNElRCuH.js +1 -0
- package/dist/ui/assets/stateDiagram-v2-BHNVJYJU-D6qTYpY3.js +1 -0
- package/dist/ui/assets/timeline-definition-PNZ67QCA-ChYC4Grd.js +120 -0
- package/dist/ui/assets/treeView-BLDUP644-Il0KnMi_.js +1 -0
- package/dist/ui/assets/treemap-LRROVOQU-CIiKcdRo.js +1 -0
- package/dist/ui/assets/vennDiagram-CIIHVFJN-Ulhkum9i.js +34 -0
- package/dist/ui/assets/wardley-L42UT6IY-BNd4ljz7.js +1 -0
- package/dist/ui/assets/wardleyDiagram-YWT4CUSO-BicXxh84.js +78 -0
- package/dist/ui/assets/xychartDiagram-2RQKCTM6-Duf-m_th.js +7 -0
- package/dist/ui/index.html +20 -0
- package/package.json +66 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// otacon expose — configure phone access over Tailscale (DESIGN.md §11, §16):
|
|
2
|
+
// verify the tailscale CLI exists and is logged in, make sure the daemon is
|
|
3
|
+
// up, run `tailscale serve --bg` against the daemon port, then confirm the
|
|
4
|
+
// tailnet URL actually serves before printing it. Deliberately thin: install,
|
|
5
|
+
// login (`tailscale up`), and tailnet HTTPS enablement are interactive/
|
|
6
|
+
// account-level steps this command points at instead of automating (DECISIONS.md
|
|
7
|
+
// "doctor/expose automation boundary").
|
|
8
|
+
import { execFileSync } from "node:child_process";
|
|
9
|
+
import { parseArgs } from "node:util";
|
|
10
|
+
import { otaconPort } from "../../shared/paths.js";
|
|
11
|
+
import { ensureDaemon, sleep } from "../client.js";
|
|
12
|
+
import { fail, notice, printJson } from "../output.js";
|
|
13
|
+
import { findTailscale, tailscaleStatus } from "../install/tailscale.js";
|
|
14
|
+
const VERIFY_ATTEMPTS = 3;
|
|
15
|
+
const VERIFY_DELAY_MS = 2000;
|
|
16
|
+
const VERIFY_TIMEOUT_MS = 5000;
|
|
17
|
+
/**
|
|
18
|
+
* Confirm `tailscale serve` is actually serving the tailnet URL. `serve --bg`
|
|
19
|
+
* exits 0 the moment its config is written, but the HTTPS frontend resets every
|
|
20
|
+
* TLS handshake until the tailnet has HTTPS Certificates enabled — so a bare
|
|
21
|
+
* `ok:true` is a false positive (the phone just sees a dead URL). A real GET of
|
|
22
|
+
* `<url>api/health` is the only honest check. Failures (TLS reset, unresolved
|
|
23
|
+
* name, refused) reject fast, so a few bounded retries ride out cold-cert
|
|
24
|
+
* provisioning right after enablement without ever hanging the command.
|
|
25
|
+
*/
|
|
26
|
+
export async function verifyServing(url, opts = {}) {
|
|
27
|
+
const attempts = opts.attempts ?? VERIFY_ATTEMPTS;
|
|
28
|
+
const delayMs = opts.delayMs ?? VERIFY_DELAY_MS;
|
|
29
|
+
const timeoutMs = opts.timeoutMs ?? VERIFY_TIMEOUT_MS;
|
|
30
|
+
const healthUrl = new URL("api/health", url).toString();
|
|
31
|
+
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
32
|
+
try {
|
|
33
|
+
const res = await fetch(healthUrl, { signal: AbortSignal.timeout(timeoutMs) });
|
|
34
|
+
if (res.ok)
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// unreachable / TLS reset / DNS miss / timeout — retry or give up below
|
|
39
|
+
}
|
|
40
|
+
if (attempt < attempts - 1)
|
|
41
|
+
await sleep(delayMs);
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
/** Verification timing is env-overridable so the e2e stays fast and hermetic. */
|
|
46
|
+
function verifyOptsFromEnv() {
|
|
47
|
+
const num = (v) => {
|
|
48
|
+
if (v === undefined || v === "")
|
|
49
|
+
return undefined;
|
|
50
|
+
const n = Number(v);
|
|
51
|
+
return Number.isFinite(n) && n >= 0 ? n : undefined;
|
|
52
|
+
};
|
|
53
|
+
return {
|
|
54
|
+
attempts: num(process.env.OTACON_EXPOSE_VERIFY_ATTEMPTS),
|
|
55
|
+
delayMs: num(process.env.OTACON_EXPOSE_VERIFY_DELAY_MS),
|
|
56
|
+
timeoutMs: num(process.env.OTACON_EXPOSE_VERIFY_TIMEOUT_MS),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export async function exposeCommand(argv) {
|
|
60
|
+
parseArgs({ args: argv, options: {} });
|
|
61
|
+
const bin = findTailscale();
|
|
62
|
+
if (bin === undefined) {
|
|
63
|
+
fail("E_TAILSCALE_MISSING", "tailscale CLI not found — install Tailscale and log in first (DESIGN.md §11; README \"Phone access\"), or set OTACON_TAILSCALE to the binary");
|
|
64
|
+
}
|
|
65
|
+
const status = tailscaleStatus(bin);
|
|
66
|
+
if (status === undefined) {
|
|
67
|
+
fail("E_TAILSCALE_STATUS", `\`${bin} status --json\` failed — is the Tailscale daemon running?`);
|
|
68
|
+
}
|
|
69
|
+
if (status.backendState !== "Running") {
|
|
70
|
+
fail("E_TAILSCALE_NOT_RUNNING", `tailscale backend is ${status.backendState}; run \`tailscale up\` (log in), then retry`);
|
|
71
|
+
}
|
|
72
|
+
await ensureDaemon(); // something must be listening before we serve it
|
|
73
|
+
const port = otaconPort();
|
|
74
|
+
const target = `http://127.0.0.1:${port}`;
|
|
75
|
+
try {
|
|
76
|
+
execFileSync(bin, ["serve", "--bg", target], {
|
|
77
|
+
encoding: "utf8",
|
|
78
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
const stderr = error?.stderr;
|
|
83
|
+
const detail = typeof stderr === "string" && stderr.trim() !== "" ? stderr.trim() : String(error);
|
|
84
|
+
fail("E_TAILSCALE_SERVE", `\`tailscale serve --bg ${target}\` failed: ${detail} (HTTPS certificates may need enabling on the tailnet — DESIGN.md §11)`);
|
|
85
|
+
}
|
|
86
|
+
const url = status.dnsName !== undefined ? `https://${status.dnsName}/` : undefined;
|
|
87
|
+
if (url === undefined) {
|
|
88
|
+
notice("could not determine the tailnet DNS name; run `tailscale serve status` to find the URL");
|
|
89
|
+
printJson({ ok: true, target, port });
|
|
90
|
+
return 0;
|
|
91
|
+
}
|
|
92
|
+
// `serve --bg` succeeding only means the config was written — confirm the URL
|
|
93
|
+
// actually answers before handing it over (DECISIONS.md "expose verifies").
|
|
94
|
+
const verified = await verifyServing(url, verifyOptsFromEnv());
|
|
95
|
+
if (!verified) {
|
|
96
|
+
notice(`serve is configured but ${url} did not respond. The usual cause is that HTTPS ` +
|
|
97
|
+
"Certificates are not enabled for your tailnet — enable them (admin console → " +
|
|
98
|
+
"DNS → Enable HTTPS): https://login.tailscale.com/admin/dns , then retry. " +
|
|
99
|
+
"(Just enabled them? The cert may still be provisioning — give it a minute.)");
|
|
100
|
+
}
|
|
101
|
+
printJson({ ok: true, target, port, url, verified });
|
|
102
|
+
return 0;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=expose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expose.js","sourceRoot":"","sources":["../../../src/cli/commands/expose.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// otacon implement-done [--pr <url>] [--failed] [--session id] — the agent's
|
|
2
|
+
// build-outcome report for Approve & Implement (DESIGN.md §6, §12). Once the
|
|
3
|
+
// approved plan is built, the agent calls this to flip the session out of
|
|
4
|
+
// `implementing`: `--failed` → `implement_failed`, otherwise `implemented`
|
|
5
|
+
// (both terminal). `--pr` records the opened PR's URL so the home card can
|
|
6
|
+
// surface the link. Prints the daemon's {ok, session, status, prUrl}.
|
|
7
|
+
//
|
|
8
|
+
// The session must currently be `implementing`: a stray call (or a double
|
|
9
|
+
// report) surfaces the daemon's E_NOT_IMPLEMENTING as a clear CLI failure, not
|
|
10
|
+
// a crash — symmetrical with how the other mutating verbs translate a 409.
|
|
11
|
+
import { parseArgs } from "node:util";
|
|
12
|
+
import { api, ensureDaemon } from "../client.js";
|
|
13
|
+
import { fail, printJson } from "../output.js";
|
|
14
|
+
import { listSessions, realpathOr, resolveSession } from "../session.js";
|
|
15
|
+
export async function implementDoneCommand(argv) {
|
|
16
|
+
const { values } = parseArgs({
|
|
17
|
+
args: argv,
|
|
18
|
+
options: {
|
|
19
|
+
pr: { type: "string" },
|
|
20
|
+
failed: { type: "boolean", default: false },
|
|
21
|
+
session: { type: "string" },
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
// Omit absent keys: a bare `implement-done` posts {} (success), the daemon
|
|
25
|
+
// defaults to `implemented`. --failed and --pr are independent — an aborted
|
|
26
|
+
// build can still carry the PR of a partial branch if the agent opened one.
|
|
27
|
+
const payload = {
|
|
28
|
+
...(values.pr !== undefined ? { pr: values.pr } : {}),
|
|
29
|
+
...(values.failed === true ? { failed: true } : {}),
|
|
30
|
+
};
|
|
31
|
+
await ensureDaemon();
|
|
32
|
+
const session = resolveSession(await listSessions(), values.session, realpathOr(process.cwd()));
|
|
33
|
+
const response = await api("POST", `/api/sessions/${session.id}/implement-done`, payload);
|
|
34
|
+
if (response.status === 200) {
|
|
35
|
+
printJson(response.body);
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
const code = response.body.error?.code;
|
|
39
|
+
const message = response.body.error?.message;
|
|
40
|
+
if (response.status === 409) {
|
|
41
|
+
// Not implementing (never started, or already reported): surface the
|
|
42
|
+
// daemon's own code so the agent knows the build outcome was not recorded.
|
|
43
|
+
fail(code ?? "E_NOT_IMPLEMENTING", message ?? `session ${session.id} is not implementing`);
|
|
44
|
+
}
|
|
45
|
+
if (response.status === 404) {
|
|
46
|
+
fail("E_UNKNOWN_SESSION", `daemon no longer knows session ${session.id}`);
|
|
47
|
+
}
|
|
48
|
+
if (response.status === 400) {
|
|
49
|
+
fail("E_BAD_REQUEST", message ?? "daemon rejected the outcome report");
|
|
50
|
+
}
|
|
51
|
+
fail("E_INTERNAL", `implement-done failed: ${JSON.stringify(response.body)}`, undefined, 2);
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=implement-done.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"implement-done.js","sourceRoot":"","sources":["../../../src/cli/commands/implement-done.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,6EAA6E;AAC7E,0EAA0E;AAC1E,2EAA2E;AAC3E,2EAA2E;AAC3E,sEAAsE;AACtE,EAAE;AACF,0EAA0E;AAC1E,+EAA+E;AAC/E,2EAA2E;AAE3E,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEzE,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,IAAc;IACvD,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;QAC3B,IAAI,EAAE,IAAI;QACV,OAAO,EAAE;YACP,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACtB,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;YAC3C,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;SAC5B;KACF,CAAC,CAAC;IAEH,2EAA2E;IAC3E,4EAA4E;IAC5E,4EAA4E;IAC5E,MAAM,OAAO,GAAsC;QACjD,GAAG,CAAC,MAAM,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACpD,CAAC;IAEF,MAAM,YAAY,EAAE,CAAC;IACrB,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,YAAY,EAAE,EAAE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAEhG,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,iBAAiB,OAAO,CAAC,EAAE,iBAAiB,EAAE,OAAO,CAAC,CAAC;IAC1F,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACzB,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,IAAI,GAAI,QAAQ,CAAC,IAAI,CAAC,KAAuC,EAAE,IAAI,CAAC;IAC1E,MAAM,OAAO,GAAI,QAAQ,CAAC,IAAI,CAAC,KAA0C,EAAE,OAAO,CAAC;IACnF,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,qEAAqE;QACrE,2EAA2E;QAC3E,IAAI,CAAC,IAAI,IAAI,oBAAoB,EAAE,OAAO,IAAI,WAAW,OAAO,CAAC,EAAE,sBAAsB,CAAC,CAAC;IAC7F,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,IAAI,CAAC,mBAAmB,EAAE,kCAAkC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,IAAI,CAAC,eAAe,EAAE,OAAO,IAAI,oCAAoC,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,CAAC,YAAY,EAAE,0BAA0B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;AAC9F,CAAC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// otacon install --agent claude|codex|opencode [--agent …] | --all [--hooks] —
|
|
2
|
+
// write the protocol wrapper into each agent's skill location (DESIGN.md §16).
|
|
3
|
+
// Pure file writes — no daemon needed. Wrappers are managed files: reinstall
|
|
4
|
+
// overwrites them (Codex: only the marked block inside its shared AGENTS.md).
|
|
5
|
+
// --hooks additionally registers the Claude Code Stop hook in
|
|
6
|
+
// ~/.claude/settings.json — merged additively and idempotently, with a backup
|
|
7
|
+
// before the first change, never clobbering what cannot be parsed.
|
|
8
|
+
import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
9
|
+
import { dirname } from "node:path";
|
|
10
|
+
import { parseArgs } from "node:util";
|
|
11
|
+
import { CODEX_BEGIN, CODEX_END, codexBlock, skillMd, STOP_HOOK_SCRIPT } from "../install/assets.js";
|
|
12
|
+
import { claudeHookScriptPath, claudeSettingsPath, claudeSkillPath, codexAgentsPath, mergeStopHook, opencodeSkillPath, settingsRegisterStopHook, upsertMarkedBlock, } from "../install/locations.js";
|
|
13
|
+
import { fail, notice, printJson, usageError } from "../output.js";
|
|
14
|
+
const AGENTS = ["claude", "codex", "opencode"];
|
|
15
|
+
function writeManaged(path, content) {
|
|
16
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
17
|
+
writeFileSync(path, content);
|
|
18
|
+
}
|
|
19
|
+
function installAgent(agent) {
|
|
20
|
+
switch (agent) {
|
|
21
|
+
case "claude": {
|
|
22
|
+
writeManaged(claudeSkillPath(), skillMd());
|
|
23
|
+
writeManaged(claudeHookScriptPath(), STOP_HOOK_SCRIPT);
|
|
24
|
+
chmodSync(claudeHookScriptPath(), 0o755);
|
|
25
|
+
return { agent, files: [claudeSkillPath(), claudeHookScriptPath()] };
|
|
26
|
+
}
|
|
27
|
+
case "codex": {
|
|
28
|
+
const path = codexAgentsPath();
|
|
29
|
+
const existing = existsSync(path) ? readFileSync(path, "utf8") : "";
|
|
30
|
+
writeManaged(path, upsertMarkedBlock(existing, codexBlock(), CODEX_BEGIN, CODEX_END));
|
|
31
|
+
return { agent, files: [path] };
|
|
32
|
+
}
|
|
33
|
+
case "opencode": {
|
|
34
|
+
writeManaged(opencodeSkillPath(), skillMd());
|
|
35
|
+
return { agent, files: [opencodeSkillPath()] };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Register the Stop hook in ~/.claude/settings.json (additive, idempotent, backed up). */
|
|
40
|
+
function applyStopHook() {
|
|
41
|
+
const path = claudeSettingsPath();
|
|
42
|
+
const command = claudeHookScriptPath();
|
|
43
|
+
let raw = {};
|
|
44
|
+
if (existsSync(path)) {
|
|
45
|
+
try {
|
|
46
|
+
raw = JSON.parse(readFileSync(path, "utf8"));
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
fail("E_SETTINGS_UNREADABLE", `${path} is not valid JSON; fix it by hand — otacon never overwrites settings it cannot parse`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const merged = mergeStopHook(raw, command);
|
|
53
|
+
if (!merged) {
|
|
54
|
+
fail("E_SETTINGS_SHAPE", `${path} has a hooks/hooks.Stop shape otacon cannot merge into; add the Stop hook by hand (command: ${command})`);
|
|
55
|
+
}
|
|
56
|
+
if (!merged.changed)
|
|
57
|
+
return { registered: true, command, settings: path };
|
|
58
|
+
let backup;
|
|
59
|
+
if (existsSync(path)) {
|
|
60
|
+
backup = `${path}.otacon-backup-${Date.now()}`;
|
|
61
|
+
copyFileSync(path, backup);
|
|
62
|
+
notice(`backed up ${path} to ${backup}`);
|
|
63
|
+
}
|
|
64
|
+
writeManaged(path, `${JSON.stringify(merged.settings, null, 2)}\n`);
|
|
65
|
+
notice(`registered the otacon Stop hook in ${path}`);
|
|
66
|
+
return { registered: true, command, settings: path, ...(backup ? { backup } : {}) };
|
|
67
|
+
}
|
|
68
|
+
/** Without --hooks: report the current state and offer the flag (DESIGN.md §16). */
|
|
69
|
+
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
|
+
return {
|
|
77
|
+
registered,
|
|
78
|
+
command: claudeHookScriptPath(),
|
|
79
|
+
settings: path,
|
|
80
|
+
...(registered ? {} : { hint: "re-run with --hooks to register the Stop hook" }),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export async function installCommand(argv) {
|
|
84
|
+
const { values } = parseArgs({
|
|
85
|
+
args: argv,
|
|
86
|
+
options: {
|
|
87
|
+
agent: { type: "string", multiple: true },
|
|
88
|
+
all: { type: "boolean", default: false },
|
|
89
|
+
hooks: { type: "boolean", default: false },
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
const picked = values.all ? [...AGENTS] : (values.agent ?? []);
|
|
93
|
+
if (picked.length === 0) {
|
|
94
|
+
usageError("otacon install requires --agent claude|codex|opencode (repeatable) or --all");
|
|
95
|
+
}
|
|
96
|
+
const unknown = picked.find((a) => !AGENTS.includes(a));
|
|
97
|
+
if (unknown !== undefined) {
|
|
98
|
+
usageError(`unknown agent "${unknown}" — expected claude, codex, or opencode`);
|
|
99
|
+
}
|
|
100
|
+
const agents = [...new Set(picked)];
|
|
101
|
+
if (values.hooks && !agents.includes("claude")) {
|
|
102
|
+
usageError("--hooks registers the Claude Code Stop hook; include --agent claude (or --all)");
|
|
103
|
+
}
|
|
104
|
+
const installed = agents.map(installAgent);
|
|
105
|
+
const hooks = agents.includes("claude")
|
|
106
|
+
? values.hooks
|
|
107
|
+
? applyStopHook()
|
|
108
|
+
: offerStopHook()
|
|
109
|
+
: undefined;
|
|
110
|
+
printJson({ ok: true, installed, ...(hooks ? { hooks } : {}) });
|
|
111
|
+
return 0;
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/cli/commands/install.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// otacon open [--session id] — print the review URL (DESIGN.md §6, human
|
|
2
|
+
// convenience). Print, never launch: agents also run this, and stdout is the
|
|
3
|
+
// contract (DECISIONS.md "open prints, never launches a browser"). With no
|
|
4
|
+
// resolvable session the index URL is the answer, not an error — reading is
|
|
5
|
+
// never the wrong screen; the never-guess rule guards writes, not looks.
|
|
6
|
+
import { parseArgs } from "node:util";
|
|
7
|
+
import { baseUrl, ensureDaemon } from "../client.js";
|
|
8
|
+
import { CliError, notice, printJson } from "../output.js";
|
|
9
|
+
import { listSessions, realpathOr, resolveSession } from "../session.js";
|
|
10
|
+
export async function openCommand(argv) {
|
|
11
|
+
const { values } = parseArgs({
|
|
12
|
+
args: argv,
|
|
13
|
+
options: { session: { type: "string" } },
|
|
14
|
+
});
|
|
15
|
+
await ensureDaemon();
|
|
16
|
+
const sessions = await listSessions();
|
|
17
|
+
try {
|
|
18
|
+
const session = resolveSession(sessions, values.session, realpathOr(process.cwd()));
|
|
19
|
+
printJson({
|
|
20
|
+
ok: true,
|
|
21
|
+
session: session.id,
|
|
22
|
+
title: session.title,
|
|
23
|
+
url: `${baseUrl()}/s/${session.id}`,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
// An explicit --session that fails to resolve is a real refusal; implicit
|
|
28
|
+
// resolution failures (no session, ambiguity, stale pointer) degrade to
|
|
29
|
+
// the index, which lists everything.
|
|
30
|
+
if (!(error instanceof CliError) || values.session !== undefined)
|
|
31
|
+
throw error;
|
|
32
|
+
notice(`${error.message} — printing the index URL`);
|
|
33
|
+
printJson({ ok: true, url: `${baseUrl()}/` });
|
|
34
|
+
}
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=open.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open.js","sourceRoot":"","sources":["../../../src/cli/commands/open.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,6EAA6E;AAC7E,2EAA2E;AAC3E,4EAA4E;AAC5E,yEAAyE;AAEzE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEzE,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAc;IAC9C,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;QAC3B,IAAI,EAAE,IAAI;QACV,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;KACzC,CAAC,CAAC;IACH,MAAM,YAAY,EAAE,CAAC;IACrB,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAC;IACtC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACpF,SAAS,CAAC;YACR,EAAE,EAAE,IAAI;YACR,OAAO,EAAE,OAAO,CAAC,EAAE;YACnB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,GAAG,EAAE,GAAG,OAAO,EAAE,MAAM,OAAO,CAAC,EAAE,EAAE;SACpC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,0EAA0E;QAC1E,wEAAwE;QACxE,qCAAqC;QACrC,IAAI,CAAC,CAAC,KAAK,YAAY,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS;YAAE,MAAM,KAAK,CAAC;QAC9E,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;QACpD,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// otacon progress "<note>" [--session id] — narrate what you are doing
|
|
2
|
+
// (DESIGN.md §6, §8). Appends a timestamped note to the session's live activity
|
|
3
|
+
// feed so the review UI shows the agent at work during research and drafting,
|
|
4
|
+
// when no other command is firing. Non-blocking — it never parks; the agent
|
|
5
|
+
// calls it at checkpoints and keeps working. Prints {ok, session, note}.
|
|
6
|
+
//
|
|
7
|
+
// The note is taken from the positional argument(s) (joined) or --note; the
|
|
8
|
+
// daemon trims it to the configured max so long narration never fails.
|
|
9
|
+
import { parseArgs } from "node:util";
|
|
10
|
+
import { api, ensureDaemon } from "../client.js";
|
|
11
|
+
import { fail, printJson, usageError } from "../output.js";
|
|
12
|
+
import { listSessions, realpathOr, resolveSession } from "../session.js";
|
|
13
|
+
export async function progressCommand(argv) {
|
|
14
|
+
const { values, positionals } = parseArgs({
|
|
15
|
+
args: argv,
|
|
16
|
+
options: { session: { type: "string" }, note: { type: "string" } },
|
|
17
|
+
allowPositionals: true,
|
|
18
|
+
});
|
|
19
|
+
// The note is the positional remainder (`otacon progress reading auth`) or
|
|
20
|
+
// --note; positionals win nothing if --note is given.
|
|
21
|
+
const note = values.note ?? positionals.join(" ");
|
|
22
|
+
if (note.trim() === "") {
|
|
23
|
+
usageError('otacon progress requires a note: otacon progress "<what you are doing>"');
|
|
24
|
+
}
|
|
25
|
+
await ensureDaemon();
|
|
26
|
+
const session = resolveSession(await listSessions(), values.session, realpathOr(process.cwd()));
|
|
27
|
+
const response = await api("POST", `/api/sessions/${session.id}/progress`, { note });
|
|
28
|
+
if (response.status === 200) {
|
|
29
|
+
printJson(response.body);
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
const code = response.body.error?.code;
|
|
33
|
+
const message = response.body.error?.message;
|
|
34
|
+
if (response.status === 409) {
|
|
35
|
+
fail(code ?? "E_SESSION_OVER", message ?? `session ${session.id} is over`);
|
|
36
|
+
}
|
|
37
|
+
if (response.status === 404) {
|
|
38
|
+
fail("E_UNKNOWN_SESSION", `daemon no longer knows session ${session.id}`);
|
|
39
|
+
}
|
|
40
|
+
if (response.status === 400) {
|
|
41
|
+
fail("E_BAD_REQUEST", message ?? "daemon rejected the note");
|
|
42
|
+
}
|
|
43
|
+
fail("E_INTERNAL", `progress failed: ${JSON.stringify(response.body)}`, undefined, 2);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=progress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.js","sourceRoot":"","sources":["../../../src/cli/commands/progress.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,gFAAgF;AAChF,8EAA8E;AAC9E,4EAA4E;AAC5E,yEAAyE;AACzE,EAAE;AACF,4EAA4E;AAC5E,uEAAuE;AAEvE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEzE,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAc;IAClD,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;QACxC,IAAI,EAAE,IAAI;QACV,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QAClE,gBAAgB,EAAE,IAAI;KACvB,CAAC,CAAC;IACH,2EAA2E;IAC3E,sDAAsD;IACtD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClD,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACvB,UAAU,CAAC,yEAAyE,CAAC,CAAC;IACxF,CAAC;IAED,MAAM,YAAY,EAAE,CAAC;IACrB,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,YAAY,EAAE,EAAE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAEhG,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,iBAAiB,OAAO,CAAC,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACrF,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACzB,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,IAAI,GAAI,QAAQ,CAAC,IAAI,CAAC,KAAuC,EAAE,IAAI,CAAC;IAC1E,MAAM,OAAO,GAAI,QAAQ,CAAC,IAAI,CAAC,KAA0C,EAAE,OAAO,CAAC;IACnF,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI,IAAI,gBAAgB,EAAE,OAAO,IAAI,WAAW,OAAO,CAAC,EAAE,UAAU,CAAC,CAAC;IAC7E,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,IAAI,CAAC,mBAAmB,EAAE,kCAAkC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,IAAI,CAAC,eAAe,EAAE,OAAO,IAAI,0BAA0B,CAAC,CAAC;IAC/D,CAAC;IACD,IAAI,CAAC,YAAY,EAAE,oBAAoB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;AACxF,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// otacon start --title <t> [--quick] — mint and register a session (DESIGN.md
|
|
2
|
+
// §6, §16): POST /api/sessions, append .otacon/ to the repo's .gitignore if
|
|
3
|
+
// missing (with a notice), print the session id and review URL. No local
|
|
4
|
+
// 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
|
+
import { parseArgs } from "node:util";
|
|
8
|
+
import { api, baseUrl, ensureDaemon } from "../client.js";
|
|
9
|
+
import { fail, notice, printJson, usageError } from "../output.js";
|
|
10
|
+
import { currentBranch, findRepoRoot, realpathOr } from "../session.js";
|
|
11
|
+
export async function startCommand(argv) {
|
|
12
|
+
const { values } = parseArgs({
|
|
13
|
+
args: argv,
|
|
14
|
+
options: { title: { type: "string" }, quick: { type: "boolean", default: false } },
|
|
15
|
+
});
|
|
16
|
+
if (values.title === undefined || values.title.trim() === "") {
|
|
17
|
+
usageError("otacon start requires --title <t>");
|
|
18
|
+
}
|
|
19
|
+
const cwd = realpathOr(process.cwd());
|
|
20
|
+
const gitRoot = findRepoRoot(cwd);
|
|
21
|
+
if (gitRoot === undefined) {
|
|
22
|
+
// DECISIONS.md "`.otacon/` lives at the git repo root": non-git fallback.
|
|
23
|
+
notice(`${cwd} is not inside a git repository; using it as the repo root`);
|
|
24
|
+
}
|
|
25
|
+
const repo = gitRoot ?? cwd;
|
|
26
|
+
await ensureDaemon();
|
|
27
|
+
const created = await api("POST", "/api/sessions", {
|
|
28
|
+
title: values.title,
|
|
29
|
+
repo,
|
|
30
|
+
branch: gitRoot === undefined ? "" : currentBranch(cwd),
|
|
31
|
+
quick: values.quick === true,
|
|
32
|
+
});
|
|
33
|
+
if (created.status !== 201) {
|
|
34
|
+
fail("E_INTERNAL", `session create failed: ${JSON.stringify(created.body)}`, undefined, 2);
|
|
35
|
+
}
|
|
36
|
+
const session = created.body;
|
|
37
|
+
if (gitRoot !== undefined)
|
|
38
|
+
ensureGitignore(gitRoot);
|
|
39
|
+
printJson({
|
|
40
|
+
ok: true,
|
|
41
|
+
session: session.id,
|
|
42
|
+
title: session.title,
|
|
43
|
+
repo,
|
|
44
|
+
branch: session.branch,
|
|
45
|
+
quick: session.quick,
|
|
46
|
+
url: `${baseUrl()}/s/${session.id}`,
|
|
47
|
+
});
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
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
|
+
//# sourceMappingURL=start.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.js","sourceRoot":"","sources":["../../../src/cli/commands/start.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// otacon status [--all] — the crash/resume entry point (DESIGN.md §6): a
|
|
2
|
+
// brand-new agent session runs this to find its open session, current
|
|
3
|
+
// revision, and undelivered event count, then resumes the loop.
|
|
4
|
+
//
|
|
5
|
+
// Routing is registry-first (DESIGN.md §7): the daemon's registry says where
|
|
6
|
+
// every session's repo lives, so the default view is "sessions whose repo
|
|
7
|
+
// contains my cwd" — no local state needed, the registry is the source of truth.
|
|
8
|
+
import { sep } from "node:path";
|
|
9
|
+
import { parseArgs } from "node:util";
|
|
10
|
+
import { otaconPort } from "../../shared/paths.js";
|
|
11
|
+
import { api, ensureDaemon } from "../client.js";
|
|
12
|
+
import { printJson } from "../output.js";
|
|
13
|
+
import { realpathOr } from "../session.js";
|
|
14
|
+
function repoContains(repo, cwd) {
|
|
15
|
+
const root = realpathOr(repo);
|
|
16
|
+
return cwd === root || cwd.startsWith(root + sep);
|
|
17
|
+
}
|
|
18
|
+
export async function statusCommand(argv) {
|
|
19
|
+
const { values } = parseArgs({
|
|
20
|
+
args: argv,
|
|
21
|
+
options: { all: { type: "boolean", default: false } },
|
|
22
|
+
});
|
|
23
|
+
const daemon = await ensureDaemon();
|
|
24
|
+
const index = await api("GET", "/api/sessions");
|
|
25
|
+
const all = (index.body.sessions ?? []);
|
|
26
|
+
const cwd = realpathOr(process.cwd());
|
|
27
|
+
const relevant = values.all ? all : all.filter((s) => repoContains(s.repo, cwd));
|
|
28
|
+
// Detail adds revision + pendingEvents (the undelivered event count).
|
|
29
|
+
const details = await Promise.all(relevant.map((s) => api("GET", `/api/sessions/${s.id}`)));
|
|
30
|
+
const sessions = details.flatMap((detail) => {
|
|
31
|
+
// A session can vanish between index and detail (e.g. otacon clean);
|
|
32
|
+
// skip it rather than spreading the 404 error body into the report.
|
|
33
|
+
if (detail === undefined || detail.status !== 200)
|
|
34
|
+
return [];
|
|
35
|
+
return [detail.body];
|
|
36
|
+
});
|
|
37
|
+
printJson({
|
|
38
|
+
ok: true,
|
|
39
|
+
daemon: { version: daemon.version, pid: daemon.pid, port: otaconPort() },
|
|
40
|
+
sessions,
|
|
41
|
+
});
|
|
42
|
+
return 0;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/cli/commands/status.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,sEAAsE;AACtE,gEAAgE;AAChE,EAAE;AACF,6EAA6E;AAC7E,0EAA0E;AAC1E,iFAAiF;AAEjF,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C,SAAS,YAAY,CAAC,IAAY,EAAE,GAAW;IAC7C,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAc;IAChD,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,MAAM,GAAG,MAAM,YAAY,EAAE,CAAC;IACpC,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAsB,CAAC;IAC7D,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;IAEjF,sEAAsE;IACtE,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CACzD,CAAC;IACF,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;QAC1C,qEAAqE;QACrE,oEAAoE;QACpE,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,EAAE,CAAC;QAC7D,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;IACH,SAAS,CAAC;QACR,EAAE,EAAE,IAAI;QACR,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE;QACxE,QAAQ;KACT,CAAC,CAAC;IACH,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// otacon submit [plan.md] [--resolutions res.json] [--session id] — read the
|
|
2
|
+
// plan (default: .otacon/<session>/plan.md in the session's repo, DESIGN.md
|
|
3
|
+
// §4) and POST it for linting. A 422 prints the daemon's lint issues JSON and
|
|
4
|
+
// exits 1 so the agent fixes and resubmits (DESIGN.md §5). The resolutions
|
|
5
|
+
// file is the revision-accompaniment document (DESIGN.md §6):
|
|
6
|
+
// {"changelog": "...", "threads": {"t1": "reply", ...}} — required by L5 on
|
|
7
|
+
// resubmits after comment batches and on every revision ≥ 2.
|
|
8
|
+
import { readFileSync } from "node:fs";
|
|
9
|
+
import { resolve } from "node:path";
|
|
10
|
+
import { parseArgs } from "node:util";
|
|
11
|
+
import { planPath } from "../../shared/paths.js";
|
|
12
|
+
import { api, ensureDaemon } from "../client.js";
|
|
13
|
+
import { fail, printJson, usageError } from "../output.js";
|
|
14
|
+
import { listSessions, realpathOr, resolveSession } from "../session.js";
|
|
15
|
+
export async function submitCommand(argv) {
|
|
16
|
+
const { values, positionals } = parseArgs({
|
|
17
|
+
args: argv,
|
|
18
|
+
options: { resolutions: { type: "string" }, session: { type: "string" } },
|
|
19
|
+
allowPositionals: true,
|
|
20
|
+
});
|
|
21
|
+
if (positionals.length > 1)
|
|
22
|
+
usageError("otacon submit takes at most one plan path");
|
|
23
|
+
await ensureDaemon();
|
|
24
|
+
const session = resolveSession(await listSessions(), values.session, realpathOr(process.cwd()));
|
|
25
|
+
const path = positionals[0] !== undefined ? resolve(positionals[0]) : planPath(session.repo, session.id);
|
|
26
|
+
let plan;
|
|
27
|
+
try {
|
|
28
|
+
plan = readFileSync(path, "utf8");
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
fail("E_NO_PLAN", `cannot read plan file ${path}; write the plan there or pass its path`);
|
|
32
|
+
}
|
|
33
|
+
let resolutions;
|
|
34
|
+
if (values.resolutions !== undefined) {
|
|
35
|
+
try {
|
|
36
|
+
resolutions = JSON.parse(readFileSync(resolve(values.resolutions), "utf8"));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
fail("E_BAD_RESOLUTIONS", `cannot read ${values.resolutions} as JSON`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const response = await api("POST", `/api/sessions/${session.id}/submit`, { plan, resolutions });
|
|
43
|
+
if (response.status === 200 || response.status === 422) {
|
|
44
|
+
// 200: {ok,session,revision,status,warnings}. 422: {ok:false,errors,warnings}.
|
|
45
|
+
printJson(response.body);
|
|
46
|
+
return response.status === 200 ? 0 : 1;
|
|
47
|
+
}
|
|
48
|
+
if (response.status === 400) {
|
|
49
|
+
// A malformed resolutions shape (or empty plan) — the agent fixes its file.
|
|
50
|
+
const message = response.body?.error?.message;
|
|
51
|
+
fail("E_BAD_RESOLUTIONS", message ?? "daemon rejected the submit body");
|
|
52
|
+
}
|
|
53
|
+
if (response.status === 404) {
|
|
54
|
+
// The session vanished between resolution and submit — actionable, not internal.
|
|
55
|
+
fail("E_UNKNOWN_SESSION", `daemon no longer knows session ${session.id}`);
|
|
56
|
+
}
|
|
57
|
+
if (response.status === 409) {
|
|
58
|
+
// The session was approved (e.g. via --session to an ended one) — over.
|
|
59
|
+
const message = response.body?.error?.message;
|
|
60
|
+
fail("E_SESSION_OVER", message ?? `session ${session.id} is approved — the session is over`);
|
|
61
|
+
}
|
|
62
|
+
fail("E_INTERNAL", `submit failed: ${JSON.stringify(response.body)}`, undefined, 2);
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=submit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submit.js","sourceRoot":"","sources":["../../../src/cli/commands/submit.ts"],"names":[],"mappings":"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"}
|