@neotx/cli 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/LICENSE +21 -0
  2. package/dist/agents-Y6LREFXP.js +58 -0
  3. package/dist/agents-Y6LREFXP.js.map +1 -0
  4. package/dist/chunk-CP54H7WA.js +85 -0
  5. package/dist/chunk-CP54H7WA.js.map +1 -0
  6. package/dist/chunk-EZAJLAUF.js +40 -0
  7. package/dist/chunk-EZAJLAUF.js.map +1 -0
  8. package/dist/chunk-TNJOG54I.js +16 -0
  9. package/dist/chunk-TNJOG54I.js.map +1 -0
  10. package/dist/chunk-YQIWMDXL.js +33 -0
  11. package/dist/chunk-YQIWMDXL.js.map +1 -0
  12. package/dist/cost-DNGKT4UC.js +134 -0
  13. package/dist/cost-DNGKT4UC.js.map +1 -0
  14. package/dist/daemon/supervisor-worker.js +28 -0
  15. package/dist/daemon/supervisor-worker.js.map +1 -0
  16. package/dist/daemon/worker.js +95 -0
  17. package/dist/daemon/worker.js.map +1 -0
  18. package/dist/doctor-CPVIT7IP.js +198 -0
  19. package/dist/doctor-CPVIT7IP.js.map +1 -0
  20. package/dist/index.js +24 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/init-YNSPTCA3.js +74 -0
  23. package/dist/init-YNSPTCA3.js.map +1 -0
  24. package/dist/logs-AWNAMMJC.js +200 -0
  25. package/dist/logs-AWNAMMJC.js.map +1 -0
  26. package/dist/mcp-LC5VU65M.js +217 -0
  27. package/dist/mcp-LC5VU65M.js.map +1 -0
  28. package/dist/repos-GI6F72NO.js +111 -0
  29. package/dist/repos-GI6F72NO.js.map +1 -0
  30. package/dist/run-KIU2ZE72.js +231 -0
  31. package/dist/run-KIU2ZE72.js.map +1 -0
  32. package/dist/runs-CHA2JM5K.js +176 -0
  33. package/dist/runs-CHA2JM5K.js.map +1 -0
  34. package/dist/supervise-7ZITWRSL.js +298 -0
  35. package/dist/supervise-7ZITWRSL.js.map +1 -0
  36. package/dist/tui-W2FHMMMN.js +489 -0
  37. package/dist/tui-W2FHMMMN.js.map +1 -0
  38. package/package.json +53 -0
@@ -0,0 +1,176 @@
1
+ import {
2
+ loadRunsFiltered,
3
+ resolveRepoFilter
4
+ } from "./chunk-CP54H7WA.js";
5
+ import {
6
+ printError,
7
+ printJson,
8
+ printTable
9
+ } from "./chunk-YQIWMDXL.js";
10
+
11
+ // src/commands/runs.ts
12
+ import { defineCommand } from "citty";
13
+ function formatDuration(ms) {
14
+ if (ms < 1e3) return `${ms}ms`;
15
+ return `${(ms / 1e3).toFixed(1)}s`;
16
+ }
17
+ function totalCost(run) {
18
+ return Object.values(run.steps).reduce((sum, s) => sum + s.costUsd, 0);
19
+ }
20
+ function totalDuration(run) {
21
+ return Object.values(run.steps).reduce((sum, s) => sum + s.durationMs, 0);
22
+ }
23
+ function shortId(runId) {
24
+ return runId.slice(0, 8);
25
+ }
26
+ function showRunDetail(match, short) {
27
+ if (short) {
28
+ console.log(`${match.runId} ${match.status} $${totalCost(match).toFixed(4)}`);
29
+ for (const [name, step] of Object.entries(match.steps)) {
30
+ const out = typeof step.output === "string" ? step.output.slice(0, 200) : "";
31
+ console.log(` ${name}: ${step.status} ${step.agent} ${out}`);
32
+ }
33
+ return;
34
+ }
35
+ console.log(`Run: ${match.runId}`);
36
+ console.log(`Status: ${match.status}`);
37
+ console.log(`Repo: ${match.repo}`);
38
+ console.log(`Prompt: ${match.prompt}`);
39
+ if (match.branch) console.log(`Branch: ${match.branch}`);
40
+ console.log(`Cost: $${totalCost(match).toFixed(4)}`);
41
+ console.log(`Duration: ${formatDuration(totalDuration(match))}`);
42
+ console.log(`Created: ${match.createdAt}`);
43
+ console.log("");
44
+ for (const [name, step] of Object.entries(match.steps)) {
45
+ console.log(`Step: ${name}`);
46
+ console.log(` Agent: ${step.agent}`);
47
+ console.log(` Status: ${step.status}`);
48
+ console.log(` Cost: $${step.costUsd.toFixed(4)}`);
49
+ console.log(` Duration: ${formatDuration(step.durationMs)}`);
50
+ if (step.error) console.log(` Error: ${step.error}`);
51
+ if (step.output) {
52
+ const out = typeof step.output === "string" ? step.output : JSON.stringify(step.output);
53
+ console.log(` Output: ${out}`);
54
+ }
55
+ }
56
+ }
57
+ function listRuns(runs, short) {
58
+ if (short) {
59
+ for (const r of runs) {
60
+ const agent = Object.values(r.steps)[0]?.agent ?? "?";
61
+ console.log(
62
+ `${shortId(r.runId)} ${r.status.padEnd(9)} ${agent.padEnd(18)} $${totalCost(r).toFixed(4).padStart(8)} ${formatDuration(totalDuration(r)).padStart(7)}`
63
+ );
64
+ }
65
+ return;
66
+ }
67
+ if (runs.length === 0) {
68
+ console.log("No runs found.");
69
+ return;
70
+ }
71
+ printTable(
72
+ ["RUN", "STATUS", "AGENT", "COST", "DURATION", "BRANCH"],
73
+ runs.map((r) => [
74
+ shortId(r.runId),
75
+ r.status,
76
+ Object.values(r.steps)[0]?.agent ?? "unknown",
77
+ `$${totalCost(r).toFixed(4)}`,
78
+ formatDuration(totalDuration(r)),
79
+ r.branch?.replace("feat/run-", "").slice(0, 8) ?? "-"
80
+ ])
81
+ );
82
+ }
83
+ var runs_default = defineCommand({
84
+ meta: {
85
+ name: "runs",
86
+ description: "List runs or show details of a specific run"
87
+ },
88
+ args: {
89
+ runId: {
90
+ type: "positional",
91
+ description: "Run ID to show details (omit to list all runs)",
92
+ required: false
93
+ },
94
+ all: {
95
+ type: "boolean",
96
+ description: "Show runs from all repos",
97
+ default: false
98
+ },
99
+ repo: {
100
+ type: "string",
101
+ description: "Filter by repo name or path"
102
+ },
103
+ last: {
104
+ type: "string",
105
+ description: "Show only the last N runs"
106
+ },
107
+ status: {
108
+ type: "string",
109
+ description: "Filter by status: completed, failed, running"
110
+ },
111
+ short: {
112
+ type: "boolean",
113
+ description: "Compact output for supervisor agents (saves tokens)",
114
+ default: false
115
+ },
116
+ output: {
117
+ type: "string",
118
+ description: "Output format: json"
119
+ }
120
+ },
121
+ async run({ args }) {
122
+ const jsonOutput = args.output === "json";
123
+ const filter = await resolveRepoFilter({ all: args.all, repo: args.repo });
124
+ let runs = await loadRunsFiltered(filter);
125
+ if (runs.length === 0) {
126
+ if (!jsonOutput) {
127
+ printError("No runs found. Run 'neo run <agent>' first.");
128
+ } else {
129
+ printJson([]);
130
+ }
131
+ return;
132
+ }
133
+ if (args.runId) {
134
+ const match = runs.find(
135
+ (r) => r.runId === args.runId || r.runId.startsWith(args.runId)
136
+ );
137
+ if (!match) {
138
+ printError(`Run "${args.runId}" not found.`);
139
+ process.exitCode = 1;
140
+ return;
141
+ }
142
+ if (jsonOutput) {
143
+ printJson(match);
144
+ return;
145
+ }
146
+ showRunDetail(match, args.short);
147
+ return;
148
+ }
149
+ if (args.status) {
150
+ runs = runs.filter((r) => r.status === args.status);
151
+ }
152
+ if (args.last) {
153
+ runs = runs.slice(0, Number(args.last));
154
+ }
155
+ if (jsonOutput) {
156
+ printJson(
157
+ runs.map((r) => ({
158
+ runId: r.runId,
159
+ status: r.status,
160
+ repo: r.repo,
161
+ agent: Object.values(r.steps)[0]?.agent ?? "unknown",
162
+ costUsd: totalCost(r),
163
+ durationMs: totalDuration(r),
164
+ branch: r.branch,
165
+ updatedAt: r.updatedAt
166
+ }))
167
+ );
168
+ return;
169
+ }
170
+ listRuns(runs, args.short);
171
+ }
172
+ });
173
+ export {
174
+ runs_default as default
175
+ };
176
+ //# sourceMappingURL=runs-CHA2JM5K.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/runs.ts"],"sourcesContent":["import type { PersistedRun } from \"@neotx/core\";\nimport { defineCommand } from \"citty\";\nimport { printError, printJson, printTable } from \"../output.js\";\nimport { loadRunsFiltered, resolveRepoFilter } from \"../repo-filter.js\";\n\nfunction formatDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n return `${(ms / 1000).toFixed(1)}s`;\n}\n\nfunction totalCost(run: PersistedRun): number {\n return Object.values(run.steps).reduce((sum, s) => sum + s.costUsd, 0);\n}\n\nfunction totalDuration(run: PersistedRun): number {\n return Object.values(run.steps).reduce((sum, s) => sum + s.durationMs, 0);\n}\n\nfunction shortId(runId: string): string {\n return runId.slice(0, 8);\n}\n\nfunction showRunDetail(match: PersistedRun, short: boolean): void {\n if (short) {\n console.log(`${match.runId} ${match.status} $${totalCost(match).toFixed(4)}`);\n for (const [name, step] of Object.entries(match.steps)) {\n const out = typeof step.output === \"string\" ? step.output.slice(0, 200) : \"\";\n console.log(` ${name}: ${step.status} ${step.agent} ${out}`);\n }\n return;\n }\n\n console.log(`Run: ${match.runId}`);\n console.log(`Status: ${match.status}`);\n console.log(`Repo: ${match.repo}`);\n console.log(`Prompt: ${match.prompt}`);\n if (match.branch) console.log(`Branch: ${match.branch}`);\n console.log(`Cost: $${totalCost(match).toFixed(4)}`);\n console.log(`Duration: ${formatDuration(totalDuration(match))}`);\n console.log(`Created: ${match.createdAt}`);\n console.log(\"\");\n for (const [name, step] of Object.entries(match.steps)) {\n console.log(`Step: ${name}`);\n console.log(` Agent: ${step.agent}`);\n console.log(` Status: ${step.status}`);\n console.log(` Cost: $${step.costUsd.toFixed(4)}`);\n console.log(` Duration: ${formatDuration(step.durationMs)}`);\n if (step.error) console.log(` Error: ${step.error}`);\n if (step.output) {\n const out = typeof step.output === \"string\" ? step.output : JSON.stringify(step.output);\n console.log(` Output: ${out}`);\n }\n }\n}\n\nfunction listRuns(runs: PersistedRun[], short: boolean): void {\n if (short) {\n for (const r of runs) {\n const agent = Object.values(r.steps)[0]?.agent ?? \"?\";\n console.log(\n `${shortId(r.runId)} ${r.status.padEnd(9)} ${agent.padEnd(18)} $${totalCost(r).toFixed(4).padStart(8)} ${formatDuration(totalDuration(r)).padStart(7)}`,\n );\n }\n return;\n }\n\n if (runs.length === 0) {\n console.log(\"No runs found.\");\n return;\n }\n\n printTable(\n [\"RUN\", \"STATUS\", \"AGENT\", \"COST\", \"DURATION\", \"BRANCH\"],\n runs.map((r) => [\n shortId(r.runId),\n r.status,\n Object.values(r.steps)[0]?.agent ?? \"unknown\",\n `$${totalCost(r).toFixed(4)}`,\n formatDuration(totalDuration(r)),\n r.branch?.replace(\"feat/run-\", \"\").slice(0, 8) ?? \"-\",\n ]),\n );\n}\n\nexport default defineCommand({\n meta: {\n name: \"runs\",\n description: \"List runs or show details of a specific run\",\n },\n args: {\n runId: {\n type: \"positional\",\n description: \"Run ID to show details (omit to list all runs)\",\n required: false,\n },\n all: {\n type: \"boolean\",\n description: \"Show runs from all repos\",\n default: false,\n },\n repo: {\n type: \"string\",\n description: \"Filter by repo name or path\",\n },\n last: {\n type: \"string\",\n description: \"Show only the last N runs\",\n },\n status: {\n type: \"string\",\n description: \"Filter by status: completed, failed, running\",\n },\n short: {\n type: \"boolean\",\n description: \"Compact output for supervisor agents (saves tokens)\",\n default: false,\n },\n output: {\n type: \"string\",\n description: \"Output format: json\",\n },\n },\n async run({ args }) {\n const jsonOutput = args.output === \"json\";\n const filter = await resolveRepoFilter({ all: args.all, repo: args.repo });\n let runs = await loadRunsFiltered(filter);\n\n if (runs.length === 0) {\n if (!jsonOutput) {\n printError(\"No runs found. Run 'neo run <agent>' first.\");\n } else {\n printJson([]);\n }\n return;\n }\n\n // If a runId is given (full or prefix), show details\n if (args.runId) {\n const match = runs.find(\n (r) => r.runId === args.runId || r.runId.startsWith(args.runId as string),\n );\n if (!match) {\n printError(`Run \"${args.runId}\" not found.`);\n process.exitCode = 1;\n return;\n }\n\n if (jsonOutput) {\n printJson(match);\n return;\n }\n\n showRunDetail(match, args.short);\n return;\n }\n\n // List mode\n if (args.status) {\n runs = runs.filter((r) => r.status === args.status);\n }\n\n if (args.last) {\n runs = runs.slice(0, Number(args.last));\n }\n\n if (jsonOutput) {\n printJson(\n runs.map((r) => ({\n runId: r.runId,\n status: r.status,\n repo: r.repo,\n agent: Object.values(r.steps)[0]?.agent ?? \"unknown\",\n costUsd: totalCost(r),\n durationMs: totalDuration(r),\n branch: r.branch,\n updatedAt: r.updatedAt,\n })),\n );\n return;\n }\n\n listRuns(runs, args.short);\n },\n});\n"],"mappings":";;;;;;;;;;;AACA,SAAS,qBAAqB;AAI9B,SAAS,eAAe,IAAoB;AAC1C,MAAI,KAAK,IAAM,QAAO,GAAG,EAAE;AAC3B,SAAO,IAAI,KAAK,KAAM,QAAQ,CAAC,CAAC;AAClC;AAEA,SAAS,UAAU,KAA2B;AAC5C,SAAO,OAAO,OAAO,IAAI,KAAK,EAAE,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,SAAS,CAAC;AACvE;AAEA,SAAS,cAAc,KAA2B;AAChD,SAAO,OAAO,OAAO,IAAI,KAAK,EAAE,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,YAAY,CAAC;AAC1E;AAEA,SAAS,QAAQ,OAAuB;AACtC,SAAO,MAAM,MAAM,GAAG,CAAC;AACzB;AAEA,SAAS,cAAc,OAAqB,OAAsB;AAChE,MAAI,OAAO;AACT,YAAQ,IAAI,GAAG,MAAM,KAAK,IAAI,MAAM,MAAM,KAAK,UAAU,KAAK,EAAE,QAAQ,CAAC,CAAC,EAAE;AAC5E,eAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,MAAM,KAAK,GAAG;AACtD,YAAM,MAAM,OAAO,KAAK,WAAW,WAAW,KAAK,OAAO,MAAM,GAAG,GAAG,IAAI;AAC1E,cAAQ,IAAI,KAAK,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,IAAI,GAAG,EAAE;AAAA,IAC9D;AACA;AAAA,EACF;AAEA,UAAQ,IAAI,aAAa,MAAM,KAAK,EAAE;AACtC,UAAQ,IAAI,aAAa,MAAM,MAAM,EAAE;AACvC,UAAQ,IAAI,aAAa,MAAM,IAAI,EAAE;AACrC,UAAQ,IAAI,aAAa,MAAM,MAAM,EAAE;AACvC,MAAI,MAAM,OAAQ,SAAQ,IAAI,aAAa,MAAM,MAAM,EAAE;AACzD,UAAQ,IAAI,cAAc,UAAU,KAAK,EAAE,QAAQ,CAAC,CAAC,EAAE;AACvD,UAAQ,IAAI,aAAa,eAAe,cAAc,KAAK,CAAC,CAAC,EAAE;AAC/D,UAAQ,IAAI,aAAa,MAAM,SAAS,EAAE;AAC1C,UAAQ,IAAI,EAAE;AACd,aAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,MAAM,KAAK,GAAG;AACtD,YAAQ,IAAI,SAAS,IAAI,EAAE;AAC3B,YAAQ,IAAI,eAAe,KAAK,KAAK,EAAE;AACvC,YAAQ,IAAI,eAAe,KAAK,MAAM,EAAE;AACxC,YAAQ,IAAI,gBAAgB,KAAK,QAAQ,QAAQ,CAAC,CAAC,EAAE;AACrD,YAAQ,IAAI,eAAe,eAAe,KAAK,UAAU,CAAC,EAAE;AAC5D,QAAI,KAAK,MAAO,SAAQ,IAAI,eAAe,KAAK,KAAK,EAAE;AACvD,QAAI,KAAK,QAAQ;AACf,YAAM,MAAM,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS,KAAK,UAAU,KAAK,MAAM;AACtF,cAAQ,IAAI,eAAe,GAAG,EAAE;AAAA,IAClC;AAAA,EACF;AACF;AAEA,SAAS,SAAS,MAAsB,OAAsB;AAC5D,MAAI,OAAO;AACT,eAAW,KAAK,MAAM;AACpB,YAAM,QAAQ,OAAO,OAAO,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS;AAClD,cAAQ;AAAA,QACN,GAAG,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,OAAO,CAAC,CAAC,IAAI,MAAM,OAAO,EAAE,CAAC,KAAK,UAAU,CAAC,EAAE,QAAQ,CAAC,EAAE,SAAS,CAAC,CAAC,IAAI,eAAe,cAAc,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;AAAA,MACvJ;AAAA,IACF;AACA;AAAA,EACF;AAEA,MAAI,KAAK,WAAW,GAAG;AACrB,YAAQ,IAAI,gBAAgB;AAC5B;AAAA,EACF;AAEA;AAAA,IACE,CAAC,OAAO,UAAU,SAAS,QAAQ,YAAY,QAAQ;AAAA,IACvD,KAAK,IAAI,CAAC,MAAM;AAAA,MACd,QAAQ,EAAE,KAAK;AAAA,MACf,EAAE;AAAA,MACF,OAAO,OAAO,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS;AAAA,MACpC,IAAI,UAAU,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,MAC3B,eAAe,cAAc,CAAC,CAAC;AAAA,MAC/B,EAAE,QAAQ,QAAQ,aAAa,EAAE,EAAE,MAAM,GAAG,CAAC,KAAK;AAAA,IACpD,CAAC;AAAA,EACH;AACF;AAEA,IAAO,eAAQ,cAAc;AAAA,EAC3B,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,IACJ,OAAO;AAAA,MACL,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,IACZ;AAAA,IACA,KAAK;AAAA,MACH,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,IACA,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,IACA,OAAO;AAAA,MACL,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,EACF;AAAA,EACA,MAAM,IAAI,EAAE,KAAK,GAAG;AAClB,UAAM,aAAa,KAAK,WAAW;AACnC,UAAM,SAAS,MAAM,kBAAkB,EAAE,KAAK,KAAK,KAAK,MAAM,KAAK,KAAK,CAAC;AACzE,QAAI,OAAO,MAAM,iBAAiB,MAAM;AAExC,QAAI,KAAK,WAAW,GAAG;AACrB,UAAI,CAAC,YAAY;AACf,mBAAW,6CAA6C;AAAA,MAC1D,OAAO;AACL,kBAAU,CAAC,CAAC;AAAA,MACd;AACA;AAAA,IACF;AAGA,QAAI,KAAK,OAAO;AACd,YAAM,QAAQ,KAAK;AAAA,QACjB,CAAC,MAAM,EAAE,UAAU,KAAK,SAAS,EAAE,MAAM,WAAW,KAAK,KAAe;AAAA,MAC1E;AACA,UAAI,CAAC,OAAO;AACV,mBAAW,QAAQ,KAAK,KAAK,cAAc;AAC3C,gBAAQ,WAAW;AACnB;AAAA,MACF;AAEA,UAAI,YAAY;AACd,kBAAU,KAAK;AACf;AAAA,MACF;AAEA,oBAAc,OAAO,KAAK,KAAK;AAC/B;AAAA,IACF;AAGA,QAAI,KAAK,QAAQ;AACf,aAAO,KAAK,OAAO,CAAC,MAAM,EAAE,WAAW,KAAK,MAAM;AAAA,IACpD;AAEA,QAAI,KAAK,MAAM;AACb,aAAO,KAAK,MAAM,GAAG,OAAO,KAAK,IAAI,CAAC;AAAA,IACxC;AAEA,QAAI,YAAY;AACd;AAAA,QACE,KAAK,IAAI,CAAC,OAAO;AAAA,UACf,OAAO,EAAE;AAAA,UACT,QAAQ,EAAE;AAAA,UACV,MAAM,EAAE;AAAA,UACR,OAAO,OAAO,OAAO,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS;AAAA,UAC3C,SAAS,UAAU,CAAC;AAAA,UACpB,YAAY,cAAc,CAAC;AAAA,UAC3B,QAAQ,EAAE;AAAA,UACV,WAAW,EAAE;AAAA,QACf,EAAE;AAAA,MACJ;AACA;AAAA,IACF;AAEA,aAAS,MAAM,KAAK,KAAK;AAAA,EAC3B;AACF,CAAC;","names":[]}
@@ -0,0 +1,298 @@
1
+ import {
2
+ printError,
3
+ printSuccess
4
+ } from "./chunk-YQIWMDXL.js";
5
+
6
+ // src/commands/supervise.ts
7
+ import {
8
+ getSupervisorDir,
9
+ getSupervisorInboxPath,
10
+ getSupervisorLockPath,
11
+ getSupervisorStatePath,
12
+ loadGlobalConfig,
13
+ supervisorDaemonStateSchema
14
+ } from "@neotx/core";
15
+ import { defineCommand } from "citty";
16
+ import { spawn } from "child_process";
17
+ import { randomUUID } from "crypto";
18
+ import { closeSync, existsSync, openSync } from "fs";
19
+ import { appendFile, mkdir, readFile, rm } from "fs/promises";
20
+ import path from "path";
21
+ import { fileURLToPath } from "url";
22
+
23
+ // src/tmux.ts
24
+ import { execFile, spawnSync } from "child_process";
25
+ import { promisify } from "util";
26
+ var execFileAsync = promisify(execFile);
27
+ async function isTmuxInstalled() {
28
+ try {
29
+ await execFileAsync("tmux", ["-V"]);
30
+ return true;
31
+ } catch {
32
+ return false;
33
+ }
34
+ }
35
+ async function tmuxSessionExists(name) {
36
+ try {
37
+ await execFileAsync("tmux", ["has-session", "-t", name]);
38
+ return true;
39
+ } catch {
40
+ return false;
41
+ }
42
+ }
43
+ async function tmuxNewSession(name, command, args, cwd) {
44
+ await execFileAsync("tmux", ["new-session", "-d", "-s", name, "-c", cwd, command, ...args]);
45
+ await execFileAsync("tmux", ["set-option", "-t", name, "remain-on-exit", "on"]);
46
+ }
47
+ async function tmuxKill(name) {
48
+ await execFileAsync("tmux", ["kill-session", "-t", name]);
49
+ }
50
+
51
+ // src/commands/supervise.ts
52
+ var DEFAULT_NAME = "supervisor";
53
+ async function readState(name) {
54
+ const statePath = getSupervisorStatePath(name);
55
+ if (!existsSync(statePath)) return null;
56
+ try {
57
+ const raw = await readFile(statePath, "utf-8");
58
+ return supervisorDaemonStateSchema.parse(JSON.parse(raw));
59
+ } catch {
60
+ return null;
61
+ }
62
+ }
63
+ function isProcessAlive(pid) {
64
+ try {
65
+ process.kill(pid, 0);
66
+ return true;
67
+ } catch {
68
+ return false;
69
+ }
70
+ }
71
+ async function isDaemonRunning(name) {
72
+ const state = await readState(name);
73
+ if (!state || state.status === "stopped") return null;
74
+ if (!isProcessAlive(state.pid)) return null;
75
+ return state;
76
+ }
77
+ async function handleStatus(name) {
78
+ const state = await isDaemonRunning(name);
79
+ if (!state) {
80
+ console.log(`No supervisor daemon running (name: ${name}).`);
81
+ return;
82
+ }
83
+ printSuccess(`Supervisor "${name}" running`);
84
+ console.log(` PID: ${state.pid}`);
85
+ console.log(` Port: ${state.port}`);
86
+ console.log(` Session: ${state.sessionId}`);
87
+ console.log(` Started: ${state.startedAt}`);
88
+ console.log(` Heartbeats: ${state.heartbeatCount}`);
89
+ if (state.lastHeartbeat) {
90
+ console.log(` Last beat: ${state.lastHeartbeat}`);
91
+ }
92
+ console.log(` Cost today: $${state.todayCostUsd?.toFixed(2) ?? "0.00"}`);
93
+ console.log(` Cost total: $${state.totalCostUsd?.toFixed(2) ?? "0.00"}`);
94
+ console.log(` Status: ${state.status}`);
95
+ console.log("");
96
+ console.log(` Health: curl localhost:${state.port}/health`);
97
+ console.log(" Attach: neo supervise --attach");
98
+ console.log(" Stop: neo supervise --kill");
99
+ }
100
+ async function handleKill(name) {
101
+ const state = await isDaemonRunning(name);
102
+ if (!state) {
103
+ printError(`No supervisor daemon running (name: ${name}).`);
104
+ const lockPath2 = getSupervisorLockPath(name);
105
+ if (existsSync(lockPath2)) {
106
+ await rm(lockPath2, { force: true });
107
+ }
108
+ process.exitCode = 1;
109
+ return;
110
+ }
111
+ const pid = state.pid;
112
+ try {
113
+ process.kill(pid, "SIGTERM");
114
+ printSuccess(`Sent SIGTERM to supervisor "${name}" (PID ${pid})`);
115
+ } catch {
116
+ printError(`Failed to send signal to PID ${pid}. Cleaning up.`);
117
+ const lockPath2 = getSupervisorLockPath(name);
118
+ await rm(lockPath2, { force: true });
119
+ return;
120
+ }
121
+ const deadline = Date.now() + 1e4;
122
+ while (Date.now() < deadline) {
123
+ await new Promise((r) => setTimeout(r, 500));
124
+ if (!isProcessAlive(pid)) {
125
+ printSuccess("Daemon stopped.");
126
+ return;
127
+ }
128
+ }
129
+ try {
130
+ process.kill(pid, "SIGKILL");
131
+ printSuccess(`Daemon did not exit in time \u2014 sent SIGKILL (PID ${pid}).`);
132
+ } catch {
133
+ }
134
+ const lockPath = getSupervisorLockPath(name);
135
+ await rm(lockPath, { force: true });
136
+ const tmuxName = `neo-${name}`;
137
+ const tmuxExists = await tmuxSessionExists(tmuxName);
138
+ if (tmuxExists) {
139
+ await tmuxKill(tmuxName);
140
+ }
141
+ }
142
+ async function startDaemon(name, useTmux) {
143
+ const running = await isDaemonRunning(name);
144
+ if (running) {
145
+ printError(`Supervisor "${name}" is already running (PID ${running.pid}).`);
146
+ printError("Use --kill first, or --attach to connect.");
147
+ process.exitCode = 1;
148
+ return;
149
+ }
150
+ const lockPath = getSupervisorLockPath(name);
151
+ if (existsSync(lockPath)) {
152
+ await rm(lockPath, { force: true });
153
+ }
154
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
155
+ const workerPath = path.join(__dirname, "daemon", "supervisor-worker.js");
156
+ const packageRoot = path.resolve(__dirname, "..");
157
+ if (useTmux) {
158
+ const tmuxAvailable = await isTmuxInstalled();
159
+ if (!tmuxAvailable) {
160
+ printError("tmux not found. Install: brew install tmux");
161
+ printError("Or use --daemon to run without tmux.");
162
+ process.exitCode = 1;
163
+ return;
164
+ }
165
+ const tmuxName = `neo-${name}`;
166
+ const exists = await tmuxSessionExists(tmuxName);
167
+ if (exists) {
168
+ await tmuxKill(tmuxName);
169
+ }
170
+ await tmuxNewSession(tmuxName, "node", [workerPath, name], packageRoot);
171
+ const config = await loadGlobalConfig();
172
+ printSuccess(`Supervisor "${name}" started in tmux session neo-${name}`);
173
+ console.log(` Port: ${config.supervisor.port}`);
174
+ console.log(` Health: curl localhost:${config.supervisor.port}/health`);
175
+ console.log(` Webhook: curl -X POST localhost:${config.supervisor.port}/webhook -d '{}'`);
176
+ console.log(` Logs: ${getSupervisorDir(name)}/daemon.log`);
177
+ console.log(` Attach: neo supervise --attach`);
178
+ console.log(` Status: neo supervise --status`);
179
+ console.log(` Stop: neo supervise --kill`);
180
+ } else {
181
+ const logDir = getSupervisorDir(name);
182
+ await mkdir(logDir, { recursive: true });
183
+ const logFd = openSync(path.join(logDir, "daemon.log"), "a");
184
+ const child = spawn(process.execPath, [workerPath, name], {
185
+ detached: true,
186
+ stdio: ["ignore", logFd, logFd],
187
+ cwd: packageRoot
188
+ });
189
+ child.unref();
190
+ closeSync(logFd);
191
+ const config = await loadGlobalConfig();
192
+ printSuccess(`Supervisor "${name}" started (PID ${child.pid})`);
193
+ console.log(` Port: ${config.supervisor.port}`);
194
+ console.log(` Health: curl localhost:${config.supervisor.port}/health`);
195
+ console.log(` Webhook: curl -X POST localhost:${config.supervisor.port}/webhook -d '{}'`);
196
+ console.log(` Logs: ${getSupervisorDir(name)}/daemon.log`);
197
+ console.log(` Status: neo supervise --status`);
198
+ console.log(` Stop: neo supervise --kill`);
199
+ }
200
+ }
201
+ async function handleAttach(name) {
202
+ const running = await isDaemonRunning(name);
203
+ if (!running) {
204
+ printError(`No supervisor daemon running (name: ${name}).`);
205
+ printError("Start with: neo supervise");
206
+ process.exitCode = 1;
207
+ return;
208
+ }
209
+ const { renderSupervisorTui } = await import("./tui-W2FHMMMN.js");
210
+ await renderSupervisorTui(name);
211
+ }
212
+ async function handleMessage(name, text) {
213
+ const running = await isDaemonRunning(name);
214
+ if (!running) {
215
+ printError(`No supervisor daemon running (name: ${name}).`);
216
+ process.exitCode = 1;
217
+ return;
218
+ }
219
+ const inboxPath = getSupervisorInboxPath(name);
220
+ const message = {
221
+ id: randomUUID(),
222
+ from: "api",
223
+ text,
224
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
225
+ };
226
+ await appendFile(inboxPath, `${JSON.stringify(message)}
227
+ `, "utf-8");
228
+ printSuccess(`Message sent to supervisor "${name}".`);
229
+ }
230
+ var supervise_default = defineCommand({
231
+ meta: {
232
+ name: "supervise",
233
+ description: "Manage the autonomous supervisor daemon"
234
+ },
235
+ args: {
236
+ name: {
237
+ type: "string",
238
+ description: "Supervisor instance name",
239
+ default: DEFAULT_NAME
240
+ },
241
+ status: {
242
+ type: "boolean",
243
+ description: "Show supervisor status",
244
+ default: false
245
+ },
246
+ kill: {
247
+ type: "boolean",
248
+ description: "Stop the running supervisor",
249
+ default: false
250
+ },
251
+ daemon: {
252
+ type: "boolean",
253
+ description: "Start daemon without tmux (detached process)",
254
+ default: false
255
+ },
256
+ attach: {
257
+ type: "boolean",
258
+ description: "Open the TUI for a running supervisor",
259
+ default: false
260
+ },
261
+ message: {
262
+ type: "string",
263
+ description: "Send a message to the supervisor inbox"
264
+ }
265
+ },
266
+ async run({ args }) {
267
+ const name = args.name;
268
+ if (args.status) {
269
+ await handleStatus(name);
270
+ return;
271
+ }
272
+ if (args.kill) {
273
+ await handleKill(name);
274
+ return;
275
+ }
276
+ if (args.attach) {
277
+ await handleAttach(name);
278
+ return;
279
+ }
280
+ if (args.message) {
281
+ await handleMessage(name, args.message);
282
+ return;
283
+ }
284
+ const alreadyRunning = await isDaemonRunning(name);
285
+ if (!alreadyRunning) {
286
+ await startDaemon(name, !args.daemon);
287
+ await new Promise((r) => setTimeout(r, 1e3));
288
+ }
289
+ if (!args.daemon) {
290
+ const { renderSupervisorTui } = await import("./tui-W2FHMMMN.js");
291
+ await renderSupervisorTui(name);
292
+ }
293
+ }
294
+ });
295
+ export {
296
+ supervise_default as default
297
+ };
298
+ //# sourceMappingURL=supervise-7ZITWRSL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/supervise.ts","../src/tmux.ts"],"sourcesContent":["import {\n getSupervisorDir,\n getSupervisorInboxPath,\n getSupervisorLockPath,\n getSupervisorStatePath,\n loadGlobalConfig,\n type SupervisorDaemonState,\n supervisorDaemonStateSchema,\n} from \"@neotx/core\";\nimport { defineCommand } from \"citty\";\nimport { spawn } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { closeSync, existsSync, openSync } from \"node:fs\";\nimport { appendFile, mkdir, readFile, rm } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { printError, printSuccess } from \"../output.js\";\nimport { isTmuxInstalled, tmuxKill, tmuxNewSession, tmuxSessionExists } from \"../tmux.js\";\n\nconst DEFAULT_NAME = \"supervisor\";\n\nasync function readState(name: string): Promise<SupervisorDaemonState | null> {\n const statePath = getSupervisorStatePath(name);\n if (!existsSync(statePath)) return null;\n try {\n const raw = await readFile(statePath, \"utf-8\");\n return supervisorDaemonStateSchema.parse(JSON.parse(raw));\n } catch {\n return null;\n }\n}\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function isDaemonRunning(name: string): Promise<SupervisorDaemonState | null> {\n const state = await readState(name);\n if (!state || state.status === \"stopped\") return null;\n if (!isProcessAlive(state.pid)) return null;\n return state;\n}\n\nasync function handleStatus(name: string): Promise<void> {\n const state = await isDaemonRunning(name);\n if (!state) {\n console.log(`No supervisor daemon running (name: ${name}).`);\n return;\n }\n\n printSuccess(`Supervisor \"${name}\" running`);\n console.log(` PID: ${state.pid}`);\n console.log(` Port: ${state.port}`);\n console.log(` Session: ${state.sessionId}`);\n console.log(` Started: ${state.startedAt}`);\n console.log(` Heartbeats: ${state.heartbeatCount}`);\n if (state.lastHeartbeat) {\n console.log(` Last beat: ${state.lastHeartbeat}`);\n }\n console.log(` Cost today: $${state.todayCostUsd?.toFixed(2) ?? \"0.00\"}`);\n console.log(` Cost total: $${state.totalCostUsd?.toFixed(2) ?? \"0.00\"}`);\n console.log(` Status: ${state.status}`);\n console.log(\"\");\n console.log(` Health: curl localhost:${state.port}/health`);\n console.log(\" Attach: neo supervise --attach\");\n console.log(\" Stop: neo supervise --kill\");\n}\n\nasync function handleKill(name: string): Promise<void> {\n const state = await isDaemonRunning(name);\n if (!state) {\n printError(`No supervisor daemon running (name: ${name}).`);\n\n // Clean up stale lock if exists\n const lockPath = getSupervisorLockPath(name);\n if (existsSync(lockPath)) {\n await rm(lockPath, { force: true });\n }\n process.exitCode = 1;\n return;\n }\n\n // Send SIGTERM for graceful shutdown, then SIGKILL after 10s\n const pid = state.pid;\n try {\n process.kill(pid, \"SIGTERM\");\n printSuccess(`Sent SIGTERM to supervisor \"${name}\" (PID ${pid})`);\n } catch {\n printError(`Failed to send signal to PID ${pid}. Cleaning up.`);\n const lockPath = getSupervisorLockPath(name);\n await rm(lockPath, { force: true });\n return;\n }\n\n // Wait up to 10s for graceful exit, then force kill\n const deadline = Date.now() + 10_000;\n while (Date.now() < deadline) {\n await new Promise((r) => setTimeout(r, 500));\n if (!isProcessAlive(pid)) {\n printSuccess(\"Daemon stopped.\");\n return;\n }\n }\n\n // Force kill\n try {\n process.kill(pid, \"SIGKILL\");\n printSuccess(`Daemon did not exit in time — sent SIGKILL (PID ${pid}).`);\n } catch {\n // Already dead\n }\n\n // Clean up lock\n const lockPath = getSupervisorLockPath(name);\n await rm(lockPath, { force: true });\n\n // Also kill tmux session if it exists\n const tmuxName = `neo-${name}`;\n const tmuxExists = await tmuxSessionExists(tmuxName);\n if (tmuxExists) {\n await tmuxKill(tmuxName);\n }\n}\n\nasync function startDaemon(name: string, useTmux: boolean): Promise<void> {\n const running = await isDaemonRunning(name);\n if (running) {\n printError(`Supervisor \"${name}\" is already running (PID ${running.pid}).`);\n printError(\"Use --kill first, or --attach to connect.\");\n process.exitCode = 1;\n return;\n }\n\n // Clean up stale lock\n const lockPath = getSupervisorLockPath(name);\n if (existsSync(lockPath)) {\n await rm(lockPath, { force: true });\n }\n\n // Resolve the worker script path and package root (for module resolution)\n const __dirname = path.dirname(fileURLToPath(import.meta.url));\n const workerPath = path.join(__dirname, \"daemon\", \"supervisor-worker.js\");\n const packageRoot = path.resolve(__dirname, \"..\");\n\n if (useTmux) {\n const tmuxAvailable = await isTmuxInstalled();\n if (!tmuxAvailable) {\n printError(\"tmux not found. Install: brew install tmux\");\n printError(\"Or use --daemon to run without tmux.\");\n process.exitCode = 1;\n return;\n }\n\n const tmuxName = `neo-${name}`;\n const exists = await tmuxSessionExists(tmuxName);\n if (exists) {\n await tmuxKill(tmuxName);\n }\n\n // Launch via tmux so it persists after terminal closes\n await tmuxNewSession(tmuxName, \"node\", [workerPath, name], packageRoot);\n\n const config = await loadGlobalConfig();\n printSuccess(`Supervisor \"${name}\" started in tmux session neo-${name}`);\n console.log(` Port: ${config.supervisor.port}`);\n console.log(` Health: curl localhost:${config.supervisor.port}/health`);\n console.log(` Webhook: curl -X POST localhost:${config.supervisor.port}/webhook -d '{}'`);\n console.log(` Logs: ${getSupervisorDir(name)}/daemon.log`);\n console.log(` Attach: neo supervise --attach`);\n console.log(` Status: neo supervise --status`);\n console.log(` Stop: neo supervise --kill`);\n } else {\n // Spawn as detached child process with stdio to log file\n const logDir = getSupervisorDir(name);\n await mkdir(logDir, { recursive: true });\n const logFd = openSync(path.join(logDir, \"daemon.log\"), \"a\");\n const child = spawn(process.execPath, [workerPath, name], {\n detached: true,\n stdio: [\"ignore\", logFd, logFd],\n cwd: packageRoot,\n });\n child.unref();\n closeSync(logFd);\n\n const config = await loadGlobalConfig();\n printSuccess(`Supervisor \"${name}\" started (PID ${child.pid})`);\n console.log(` Port: ${config.supervisor.port}`);\n console.log(` Health: curl localhost:${config.supervisor.port}/health`);\n console.log(` Webhook: curl -X POST localhost:${config.supervisor.port}/webhook -d '{}'`);\n console.log(` Logs: ${getSupervisorDir(name)}/daemon.log`);\n console.log(` Status: neo supervise --status`);\n console.log(` Stop: neo supervise --kill`);\n }\n}\n\nasync function handleAttach(name: string): Promise<void> {\n const running = await isDaemonRunning(name);\n if (!running) {\n printError(`No supervisor daemon running (name: ${name}).`);\n printError(\"Start with: neo supervise\");\n process.exitCode = 1;\n return;\n }\n\n const { renderSupervisorTui } = await import(\"../tui/index.js\");\n await renderSupervisorTui(name);\n}\n\nasync function handleMessage(name: string, text: string): Promise<void> {\n const running = await isDaemonRunning(name);\n if (!running) {\n printError(`No supervisor daemon running (name: ${name}).`);\n process.exitCode = 1;\n return;\n }\n\n const inboxPath = getSupervisorInboxPath(name);\n const message = {\n id: randomUUID(),\n from: \"api\" as const,\n text,\n timestamp: new Date().toISOString(),\n };\n\n await appendFile(inboxPath, `${JSON.stringify(message)}\\n`, \"utf-8\");\n printSuccess(`Message sent to supervisor \"${name}\".`);\n}\n\nexport default defineCommand({\n meta: {\n name: \"supervise\",\n description: \"Manage the autonomous supervisor daemon\",\n },\n args: {\n name: {\n type: \"string\",\n description: \"Supervisor instance name\",\n default: DEFAULT_NAME,\n },\n status: {\n type: \"boolean\",\n description: \"Show supervisor status\",\n default: false,\n },\n kill: {\n type: \"boolean\",\n description: \"Stop the running supervisor\",\n default: false,\n },\n daemon: {\n type: \"boolean\",\n description: \"Start daemon without tmux (detached process)\",\n default: false,\n },\n attach: {\n type: \"boolean\",\n description: \"Open the TUI for a running supervisor\",\n default: false,\n },\n message: {\n type: \"string\",\n description: \"Send a message to the supervisor inbox\",\n },\n },\n async run({ args }) {\n const name = args.name;\n\n if (args.status) {\n await handleStatus(name);\n return;\n }\n\n if (args.kill) {\n await handleKill(name);\n return;\n }\n\n if (args.attach) {\n await handleAttach(name);\n return;\n }\n\n if (args.message) {\n await handleMessage(name, args.message);\n return;\n }\n\n // Default: start daemon + open TUI\n const alreadyRunning = await isDaemonRunning(name);\n if (!alreadyRunning) {\n await startDaemon(name, !args.daemon);\n // Give daemon a moment to initialize\n await new Promise((r) => setTimeout(r, 1_000));\n }\n\n // Open TUI unless --daemon (headless mode)\n if (!args.daemon) {\n const { renderSupervisorTui } = await import(\"../tui/index.js\");\n await renderSupervisorTui(name);\n }\n },\n});\n","import { execFile, spawnSync } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\n/** Check if tmux binary is available. */\nexport async function isTmuxInstalled(): Promise<boolean> {\n try {\n await execFileAsync(\"tmux\", [\"-V\"]);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Get tmux version string, or null if not installed. */\nexport async function getTmuxVersion(): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync(\"tmux\", [\"-V\"]);\n return stdout.trim();\n } catch {\n return null;\n }\n}\n\n/** Check if a tmux session with the given name exists. */\nexport async function tmuxSessionExists(name: string): Promise<boolean> {\n try {\n await execFileAsync(\"tmux\", [\"has-session\", \"-t\", name]);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Create a new detached tmux session running the given command.\n * Sets remain-on-exit so the pane stays alive when the process exits. */\nexport async function tmuxNewSession(\n name: string,\n command: string,\n args: string[],\n cwd: string,\n): Promise<void> {\n await execFileAsync(\"tmux\", [\"new-session\", \"-d\", \"-s\", name, \"-c\", cwd, command, ...args]);\n // Keep the pane alive when the process exits so we can respawn it\n await execFileAsync(\"tmux\", [\"set-option\", \"-t\", name, \"remain-on-exit\", \"on\"]);\n}\n\n/** Check if the first pane in the session has a dead process. */\nexport async function tmuxPaneDead(name: string): Promise<boolean> {\n try {\n const { stdout } = await execFileAsync(\"tmux\", [\n \"list-panes\",\n \"-t\",\n name,\n \"-F\",\n \"#{pane_dead}\",\n ]);\n return stdout.trim() === \"1\";\n } catch {\n return false;\n }\n}\n\n/** Respawn the dead pane in a session with a new command. */\nexport async function tmuxRespawnPane(\n name: string,\n command: string,\n args: string[],\n): Promise<void> {\n await execFileAsync(\"tmux\", [\"respawn-pane\", \"-t\", name, \"-k\", command, ...args]);\n}\n\n/** Attach the current terminal to an existing tmux session. */\nexport function tmuxAttach(name: string): void {\n spawnSync(\"tmux\", [\"attach-session\", \"-t\", name], { stdio: \"inherit\" });\n}\n\n/** Kill a tmux session by name. */\nexport async function tmuxKill(name: string): Promise<void> {\n await execFileAsync(\"tmux\", [\"kill-session\", \"-t\", name]);\n}\n\nexport interface TmuxSessionInfo {\n created: string;\n windows: number;\n}\n\n/** Get session info, or null if the session does not exist. */\nexport async function tmuxSessionInfo(name: string): Promise<TmuxSessionInfo | null> {\n try {\n const { stdout } = await execFileAsync(\"tmux\", [\n \"list-sessions\",\n \"-F\",\n \"#{session_created} #{session_windows}\",\n \"-f\",\n `#{==:#{session_name},${name}}`,\n ]);\n const line = stdout.trim();\n if (!line) return null;\n\n const [timestamp, windows] = line.split(\" \");\n const epoch = Number(timestamp);\n return {\n created: Number.isNaN(epoch) ? \"unknown\" : new Date(epoch * 1000).toISOString(),\n windows: Number(windows) || 1,\n };\n } catch {\n return null;\n }\n}\n"],"mappings":";;;;;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,OACK;AACP,SAAS,qBAAqB;AAC9B,SAAS,aAAa;AACtB,SAAS,kBAAkB;AAC3B,SAAS,WAAW,YAAY,gBAAgB;AAChD,SAAS,YAAY,OAAO,UAAU,UAAU;AAChD,OAAO,UAAU;AACjB,SAAS,qBAAqB;;;ACf9B,SAAS,UAAU,iBAAiB;AACpC,SAAS,iBAAiB;AAE1B,IAAM,gBAAgB,UAAU,QAAQ;AAGxC,eAAsB,kBAAoC;AACxD,MAAI;AACF,UAAM,cAAc,QAAQ,CAAC,IAAI,CAAC;AAClC,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAaA,eAAsB,kBAAkB,MAAgC;AACtE,MAAI;AACF,UAAM,cAAc,QAAQ,CAAC,eAAe,MAAM,IAAI,CAAC;AACvD,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAIA,eAAsB,eACpB,MACA,SACA,MACA,KACe;AACf,QAAM,cAAc,QAAQ,CAAC,eAAe,MAAM,MAAM,MAAM,MAAM,KAAK,SAAS,GAAG,IAAI,CAAC;AAE1F,QAAM,cAAc,QAAQ,CAAC,cAAc,MAAM,MAAM,kBAAkB,IAAI,CAAC;AAChF;AAiCA,eAAsB,SAAS,MAA6B;AAC1D,QAAM,cAAc,QAAQ,CAAC,gBAAgB,MAAM,IAAI,CAAC;AAC1D;;;AD9DA,IAAM,eAAe;AAErB,eAAe,UAAU,MAAqD;AAC5E,QAAM,YAAY,uBAAuB,IAAI;AAC7C,MAAI,CAAC,WAAW,SAAS,EAAG,QAAO;AACnC,MAAI;AACF,UAAM,MAAM,MAAM,SAAS,WAAW,OAAO;AAC7C,WAAO,4BAA4B,MAAM,KAAK,MAAM,GAAG,CAAC;AAAA,EAC1D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,eAAe,KAAsB;AAC5C,MAAI;AACF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,gBAAgB,MAAqD;AAClF,QAAM,QAAQ,MAAM,UAAU,IAAI;AAClC,MAAI,CAAC,SAAS,MAAM,WAAW,UAAW,QAAO;AACjD,MAAI,CAAC,eAAe,MAAM,GAAG,EAAG,QAAO;AACvC,SAAO;AACT;AAEA,eAAe,aAAa,MAA6B;AACvD,QAAM,QAAQ,MAAM,gBAAgB,IAAI;AACxC,MAAI,CAAC,OAAO;AACV,YAAQ,IAAI,uCAAuC,IAAI,IAAI;AAC3D;AAAA,EACF;AAEA,eAAa,eAAe,IAAI,WAAW;AAC3C,UAAQ,IAAI,iBAAiB,MAAM,GAAG,EAAE;AACxC,UAAQ,IAAI,iBAAiB,MAAM,IAAI,EAAE;AACzC,UAAQ,IAAI,iBAAiB,MAAM,SAAS,EAAE;AAC9C,UAAQ,IAAI,iBAAiB,MAAM,SAAS,EAAE;AAC9C,UAAQ,IAAI,iBAAiB,MAAM,cAAc,EAAE;AACnD,MAAI,MAAM,eAAe;AACvB,YAAQ,IAAI,iBAAiB,MAAM,aAAa,EAAE;AAAA,EACpD;AACA,UAAQ,IAAI,kBAAkB,MAAM,cAAc,QAAQ,CAAC,KAAK,MAAM,EAAE;AACxE,UAAQ,IAAI,kBAAkB,MAAM,cAAc,QAAQ,CAAC,KAAK,MAAM,EAAE;AACxE,UAAQ,IAAI,iBAAiB,MAAM,MAAM,EAAE;AAC3C,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,8BAA8B,MAAM,IAAI,SAAS;AAC7D,UAAQ,IAAI,oCAAoC;AAChD,UAAQ,IAAI,kCAAkC;AAChD;AAEA,eAAe,WAAW,MAA6B;AACrD,QAAM,QAAQ,MAAM,gBAAgB,IAAI;AACxC,MAAI,CAAC,OAAO;AACV,eAAW,uCAAuC,IAAI,IAAI;AAG1D,UAAMA,YAAW,sBAAsB,IAAI;AAC3C,QAAI,WAAWA,SAAQ,GAAG;AACxB,YAAM,GAAGA,WAAU,EAAE,OAAO,KAAK,CAAC;AAAA,IACpC;AACA,YAAQ,WAAW;AACnB;AAAA,EACF;AAGA,QAAM,MAAM,MAAM;AAClB,MAAI;AACF,YAAQ,KAAK,KAAK,SAAS;AAC3B,iBAAa,+BAA+B,IAAI,UAAU,GAAG,GAAG;AAAA,EAClE,QAAQ;AACN,eAAW,gCAAgC,GAAG,gBAAgB;AAC9D,UAAMA,YAAW,sBAAsB,IAAI;AAC3C,UAAM,GAAGA,WAAU,EAAE,OAAO,KAAK,CAAC;AAClC;AAAA,EACF;AAGA,QAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,SAAO,KAAK,IAAI,IAAI,UAAU;AAC5B,UAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,GAAG,CAAC;AAC3C,QAAI,CAAC,eAAe,GAAG,GAAG;AACxB,mBAAa,iBAAiB;AAC9B;AAAA,IACF;AAAA,EACF;AAGA,MAAI;AACF,YAAQ,KAAK,KAAK,SAAS;AAC3B,iBAAa,wDAAmD,GAAG,IAAI;AAAA,EACzE,QAAQ;AAAA,EAER;AAGA,QAAM,WAAW,sBAAsB,IAAI;AAC3C,QAAM,GAAG,UAAU,EAAE,OAAO,KAAK,CAAC;AAGlC,QAAM,WAAW,OAAO,IAAI;AAC5B,QAAM,aAAa,MAAM,kBAAkB,QAAQ;AACnD,MAAI,YAAY;AACd,UAAM,SAAS,QAAQ;AAAA,EACzB;AACF;AAEA,eAAe,YAAY,MAAc,SAAiC;AACxE,QAAM,UAAU,MAAM,gBAAgB,IAAI;AAC1C,MAAI,SAAS;AACX,eAAW,eAAe,IAAI,6BAA6B,QAAQ,GAAG,IAAI;AAC1E,eAAW,2CAA2C;AACtD,YAAQ,WAAW;AACnB;AAAA,EACF;AAGA,QAAM,WAAW,sBAAsB,IAAI;AAC3C,MAAI,WAAW,QAAQ,GAAG;AACxB,UAAM,GAAG,UAAU,EAAE,OAAO,KAAK,CAAC;AAAA,EACpC;AAGA,QAAM,YAAY,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AAC7D,QAAM,aAAa,KAAK,KAAK,WAAW,UAAU,sBAAsB;AACxE,QAAM,cAAc,KAAK,QAAQ,WAAW,IAAI;AAEhD,MAAI,SAAS;AACX,UAAM,gBAAgB,MAAM,gBAAgB;AAC5C,QAAI,CAAC,eAAe;AAClB,iBAAW,4CAA4C;AACvD,iBAAW,sCAAsC;AACjD,cAAQ,WAAW;AACnB;AAAA,IACF;AAEA,UAAM,WAAW,OAAO,IAAI;AAC5B,UAAM,SAAS,MAAM,kBAAkB,QAAQ;AAC/C,QAAI,QAAQ;AACV,YAAM,SAAS,QAAQ;AAAA,IACzB;AAGA,UAAM,eAAe,UAAU,QAAQ,CAAC,YAAY,IAAI,GAAG,WAAW;AAEtE,UAAM,SAAS,MAAM,iBAAiB;AACtC,iBAAa,eAAe,IAAI,iCAAiC,IAAI,EAAE;AACvE,YAAQ,IAAI,eAAe,OAAO,WAAW,IAAI,EAAE;AACnD,YAAQ,IAAI,8BAA8B,OAAO,WAAW,IAAI,SAAS;AACzE,YAAQ,IAAI,sCAAsC,OAAO,WAAW,IAAI,kBAAkB;AAC1F,YAAQ,IAAI,eAAe,iBAAiB,IAAI,CAAC,aAAa;AAC9D,YAAQ,IAAI,oCAAoC;AAChD,YAAQ,IAAI,oCAAoC;AAChD,YAAQ,IAAI,kCAAkC;AAAA,EAChD,OAAO;AAEL,UAAM,SAAS,iBAAiB,IAAI;AACpC,UAAM,MAAM,QAAQ,EAAE,WAAW,KAAK,CAAC;AACvC,UAAM,QAAQ,SAAS,KAAK,KAAK,QAAQ,YAAY,GAAG,GAAG;AAC3D,UAAM,QAAQ,MAAM,QAAQ,UAAU,CAAC,YAAY,IAAI,GAAG;AAAA,MACxD,UAAU;AAAA,MACV,OAAO,CAAC,UAAU,OAAO,KAAK;AAAA,MAC9B,KAAK;AAAA,IACP,CAAC;AACD,UAAM,MAAM;AACZ,cAAU,KAAK;AAEf,UAAM,SAAS,MAAM,iBAAiB;AACtC,iBAAa,eAAe,IAAI,kBAAkB,MAAM,GAAG,GAAG;AAC9D,YAAQ,IAAI,eAAe,OAAO,WAAW,IAAI,EAAE;AACnD,YAAQ,IAAI,8BAA8B,OAAO,WAAW,IAAI,SAAS;AACzE,YAAQ,IAAI,sCAAsC,OAAO,WAAW,IAAI,kBAAkB;AAC1F,YAAQ,IAAI,eAAe,iBAAiB,IAAI,CAAC,aAAa;AAC9D,YAAQ,IAAI,oCAAoC;AAChD,YAAQ,IAAI,kCAAkC;AAAA,EAChD;AACF;AAEA,eAAe,aAAa,MAA6B;AACvD,QAAM,UAAU,MAAM,gBAAgB,IAAI;AAC1C,MAAI,CAAC,SAAS;AACZ,eAAW,uCAAuC,IAAI,IAAI;AAC1D,eAAW,2BAA2B;AACtC,YAAQ,WAAW;AACnB;AAAA,EACF;AAEA,QAAM,EAAE,oBAAoB,IAAI,MAAM,OAAO,mBAAiB;AAC9D,QAAM,oBAAoB,IAAI;AAChC;AAEA,eAAe,cAAc,MAAc,MAA6B;AACtE,QAAM,UAAU,MAAM,gBAAgB,IAAI;AAC1C,MAAI,CAAC,SAAS;AACZ,eAAW,uCAAuC,IAAI,IAAI;AAC1D,YAAQ,WAAW;AACnB;AAAA,EACF;AAEA,QAAM,YAAY,uBAAuB,IAAI;AAC7C,QAAM,UAAU;AAAA,IACd,IAAI,WAAW;AAAA,IACf,MAAM;AAAA,IACN;AAAA,IACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,EACpC;AAEA,QAAM,WAAW,WAAW,GAAG,KAAK,UAAU,OAAO,CAAC;AAAA,GAAM,OAAO;AACnE,eAAa,+BAA+B,IAAI,IAAI;AACtD;AAEA,IAAO,oBAAQ,cAAc;AAAA,EAC3B,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,IACJ,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,EACF;AAAA,EACA,MAAM,IAAI,EAAE,KAAK,GAAG;AAClB,UAAM,OAAO,KAAK;AAElB,QAAI,KAAK,QAAQ;AACf,YAAM,aAAa,IAAI;AACvB;AAAA,IACF;AAEA,QAAI,KAAK,MAAM;AACb,YAAM,WAAW,IAAI;AACrB;AAAA,IACF;AAEA,QAAI,KAAK,QAAQ;AACf,YAAM,aAAa,IAAI;AACvB;AAAA,IACF;AAEA,QAAI,KAAK,SAAS;AAChB,YAAM,cAAc,MAAM,KAAK,OAAO;AACtC;AAAA,IACF;AAGA,UAAM,iBAAiB,MAAM,gBAAgB,IAAI;AACjD,QAAI,CAAC,gBAAgB;AACnB,YAAM,YAAY,MAAM,CAAC,KAAK,MAAM;AAEpC,YAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,GAAK,CAAC;AAAA,IAC/C;AAGA,QAAI,CAAC,KAAK,QAAQ;AAChB,YAAM,EAAE,oBAAoB,IAAI,MAAM,OAAO,mBAAiB;AAC9D,YAAM,oBAAoB,IAAI;AAAA,IAChC;AAAA,EACF;AACF,CAAC;","names":["lockPath"]}