@iowarp/clio-coder 0.3.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/CHANGELOG.md +407 -0
- package/CODE_OF_CONDUCT.md +21 -0
- package/CONTRIBUTING.md +224 -0
- package/LICENSE +202 -0
- package/NOTICE +9 -0
- package/README.md +798 -0
- package/SECURITY.md +72 -0
- package/assets/clio-coder-logo-128.webp +0 -0
- package/damage-control-rules.yaml +419 -0
- package/dist/acp-UMLFVA3F.js +92 -0
- package/dist/agents-Q4MYPMUW.js +91 -0
- package/dist/auth-O6HYIJ6J.js +521 -0
- package/dist/chunk-262G75JS.js +35 -0
- package/dist/chunk-26BZQOAD.js +1281 -0
- package/dist/chunk-2J63S4SF.js +508 -0
- package/dist/chunk-3DANZDGR.js +717 -0
- package/dist/chunk-4UQA7NCT.js +29 -0
- package/dist/chunk-527KG6XR.js +497 -0
- package/dist/chunk-5LDRNKX2.js +1063 -0
- package/dist/chunk-5N2FG33Q.js +25 -0
- package/dist/chunk-67MTHP2E.js +135 -0
- package/dist/chunk-6CWDTGUC.js +20 -0
- package/dist/chunk-7BHLZB3A.js +2115 -0
- package/dist/chunk-7RBKDI66.js +348 -0
- package/dist/chunk-AMFR5YA3.js +541 -0
- package/dist/chunk-BBUH4VAA.js +1224 -0
- package/dist/chunk-BYEU76JP.js +899 -0
- package/dist/chunk-CLJ5HLUD.js +458 -0
- package/dist/chunk-D5YD55AR.js +116 -0
- package/dist/chunk-DXQNI4PC.js +61 -0
- package/dist/chunk-E3NYWENM.js +1004 -0
- package/dist/chunk-GNGDQYDU.js +34688 -0
- package/dist/chunk-GOTUR54M.js +9 -0
- package/dist/chunk-HBU5MTAM.js +41 -0
- package/dist/chunk-HMYNFFY4.js +28 -0
- package/dist/chunk-JPOWPFCU.js +1010 -0
- package/dist/chunk-JWHCJDCI.js +1215 -0
- package/dist/chunk-KBR4MZZR.js +41 -0
- package/dist/chunk-KKKPTZLM.js +93 -0
- package/dist/chunk-ME6DNWIU.js +66 -0
- package/dist/chunk-NI4DEJMC.js +88 -0
- package/dist/chunk-O4EJEDHO.js +659 -0
- package/dist/chunk-PIDUD6M2.js +31 -0
- package/dist/chunk-PS4PFJQP.js +29459 -0
- package/dist/chunk-QV47YRF4.js +48 -0
- package/dist/chunk-RQDWMVRB.js +279 -0
- package/dist/chunk-TFSSEXL6.js +136 -0
- package/dist/chunk-TKHQ4DGZ.js +8290 -0
- package/dist/chunk-TPOCL34A.js +2876 -0
- package/dist/chunk-UGYAX5YI.js +565 -0
- package/dist/chunk-UHTSULZS.js +461 -0
- package/dist/chunk-UU3R62TT.js +128 -0
- package/dist/chunk-UWIJNAOB.js +3906 -0
- package/dist/chunk-VOO7NYPP.js +914 -0
- package/dist/chunk-VPAWTYLY.js +117 -0
- package/dist/chunk-WD6AJM35.js +1216 -0
- package/dist/chunk-X3BR7HWV.js +115 -0
- package/dist/chunk-X3NE4WVW.js +120 -0
- package/dist/chunk-XNISANGE.js +1395 -0
- package/dist/chunk-XV4ZJ6ZM.js +3177 -0
- package/dist/cli/index.js +236 -0
- package/dist/clio-KIQ5SNDS.js +53 -0
- package/dist/components-JVHMUBEB.js +653 -0
- package/dist/config-ZFCDBMDC.js +372 -0
- package/dist/configure-G4E3A2PG.js +27 -0
- package/dist/context-CDXTP2MP.js +293 -0
- package/dist/context-E3KIFVXI.js +185 -0
- package/dist/context-clear-3F4PLXOS.js +102 -0
- package/dist/context-index-Q7YSYTR3.js +106 -0
- package/dist/docs-YIETIWZI.js +280 -0
- package/dist/doctor-M5HJJZOL.js +61 -0
- package/dist/domains/agents/builtins/architect.md +33 -0
- package/dist/domains/agents/builtins/coder.md +31 -0
- package/dist/domains/agents/builtins/context-bootstrap.md +38 -0
- package/dist/domains/agents/builtins/debugger.md +30 -0
- package/dist/domains/agents/builtins/documenter.md +31 -0
- package/dist/domains/agents/builtins/git-master.md +30 -0
- package/dist/domains/agents/builtins/provenance.md +30 -0
- package/dist/domains/agents/builtins/researcher.md +71 -0
- package/dist/domains/agents/builtins/scout.md +42 -0
- package/dist/domains/agents/builtins/tester.md +31 -0
- package/dist/domains/agents/builtins/verifier.md +30 -0
- package/dist/domains/agents/builtins/wiki-writer.md +41 -0
- package/dist/eval-B3KZZESM.js +2674 -0
- package/dist/evidence-V67CHM35.js +233 -0
- package/dist/evolve-YDZSUQYA.js +518 -0
- package/dist/extensions-SRG7XCAH.js +207 -0
- package/dist/fleet-CA2CRTVG.js +760 -0
- package/dist/fleet-preflight-CLIAX7YR.js +21 -0
- package/dist/init-2OZDJE2D.js +227 -0
- package/dist/memory-3PIQQAKX.js +207 -0
- package/dist/models-DY35XI7Y.js +237 -0
- package/dist/paths-5OMXW7Z4.js +57 -0
- package/dist/preload-KZVHET2B.js +11 -0
- package/dist/reset-PIFYNOS3.js +216 -0
- package/dist/run-3VSPP24F.js +735 -0
- package/dist/share-D36RQCXM.js +241 -0
- package/dist/skills-F2MRLELY.js +445 -0
- package/dist/skills-eval-E2ZTW4PL.js +932 -0
- package/dist/targets-DZMEZAH4.js +977 -0
- package/dist/trace-7NYCUI2J.js +250 -0
- package/dist/uninstall-AD3JWHBB.js +322 -0
- package/dist/upgrade-WYYBKGDY.js +301 -0
- package/dist/usage-ULIDAGFF.js +755 -0
- package/dist/version-ROZ6CZKH.js +16 -0
- package/dist/wiki-generate-PKFIX6OB.js +377 -0
- package/dist/worker/entry.js +1739 -0
- package/docs/README.md +93 -0
- package/docs/acp.md +120 -0
- package/docs/alcf-provider.md +72 -0
- package/docs/architecture.md +172 -0
- package/docs/artifact-versions.md +54 -0
- package/docs/built-in-agents.md +265 -0
- package/docs/capacity-and-scheduling.md +97 -0
- package/docs/commands-and-modes.md +554 -0
- package/docs/config-knobs-audit.md +115 -0
- package/docs/configuration-and-targets.md +812 -0
- package/docs/context-engine.md +236 -0
- package/docs/dispatch-architecture-rationale.md +126 -0
- package/docs/documentation-coverage.md +46 -0
- package/docs/documentation-guide.md +166 -0
- package/docs/environment-variables.md +105 -0
- package/docs/eval-runner.md +205 -0
- package/docs/evals-internal.md +298 -0
- package/docs/evidence-and-memory.md +243 -0
- package/docs/evolution.md +143 -0
- package/docs/exit-codes-and-output.md +74 -0
- package/docs/extensions-and-sharing.md +306 -0
- package/docs/fleet-demo-runbook.md +179 -0
- package/docs/fleet-dispatch.md +591 -0
- package/docs/glossary.md +75 -0
- package/docs/html/agents_blueprint.html +936 -0
- package/docs/html/alcf_blueprint.html +324 -0
- package/docs/html/architecture_blueprint.html +850 -0
- package/docs/html/commands_blueprint.html +794 -0
- package/docs/html/config_knobs_audit_blueprint.html +178 -0
- package/docs/html/configuration_blueprint.html +1080 -0
- package/docs/html/context_blueprint.html +603 -0
- package/docs/html/documentation_blueprint.html +832 -0
- package/docs/html/environment_blueprint.html +404 -0
- package/docs/html/eval_blueprint.html +743 -0
- package/docs/html/evals_internal_blueprint.html +190 -0
- package/docs/html/evolution_blueprint.html +674 -0
- package/docs/html/extensions_blueprint.html +2065 -0
- package/docs/html/fleet_dispatch_blueprint.html +286 -0
- package/docs/html/index.html +919 -0
- package/docs/html/lifecycle_blueprint.html +723 -0
- package/docs/html/memory_blueprint.html +699 -0
- package/docs/html/middleware_blueprint.html +664 -0
- package/docs/html/models_blueprint.html +2366 -0
- package/docs/html/observability_blueprint.html +683 -0
- package/docs/html/provider_adapter_blueprint.html +245 -0
- package/docs/html/safety_blueprint.html +1386 -0
- package/docs/html/shared.css +571 -0
- package/docs/html/shared.js +143 -0
- package/docs/html/skills_blueprint.html +671 -0
- package/docs/html/soak_blueprint.html +182 -0
- package/docs/html/tool_usage_blueprint.html +350 -0
- package/docs/html/tools_blueprint.html +2249 -0
- package/docs/html/trace_blueprint.html +235 -0
- package/docs/html/tui_design_blueprint.html +314 -0
- package/docs/html/validation_blueprint.html +961 -0
- package/docs/html/worker_dispatch_blueprint.html +231 -0
- package/docs/installation-and-lifecycle.md +308 -0
- package/docs/middleware-and-components.md +148 -0
- package/docs/model-catalog.md +189 -0
- package/docs/observability.md +233 -0
- package/docs/proactive-memory.md +452 -0
- package/docs/prompt-envelope-and-tools.md +142 -0
- package/docs/provider-adapter-cookbook.md +148 -0
- package/docs/release-cut-checklist.md +138 -0
- package/docs/safety-model.md +357 -0
- package/docs/scientific-validation.md +105 -0
- package/docs/session-lifecycle.md +156 -0
- package/docs/skills-marketplace.md +46 -0
- package/docs/tool-usage.md +527 -0
- package/docs/trace-store.md +132 -0
- package/docs/troubleshooting.md +33 -0
- package/docs/tui-design.md +239 -0
- package/docs/worker-dispatch-mechanics.md +242 -0
- package/package.json +132 -0
- package/skills/README.md +408 -0
- package/skills/git/commit-crafting/SKILL.md +79 -0
- package/skills/git/commit-crafting/evals.md +92 -0
- package/skills/git/create-pr/SKILL.md +116 -0
- package/skills/git/create-pr/evals.md +114 -0
- package/skills/git/investigate-issue/SKILL.md +139 -0
- package/skills/git/investigate-issue/evals.md +94 -0
- package/skills/git/resolve-merge-conflicts/SKILL.md +96 -0
- package/skills/git/resolve-merge-conflicts/evals.md +58 -0
- package/skills/git/review-changes/SKILL.md +103 -0
- package/skills/git/review-changes/evals.md +85 -0
- package/skills/git/worktree-create/SKILL.md +92 -0
- package/skills/git/worktree-create/evals.md +97 -0
- package/skills/git/worktree-create/references/worktree-setup.md +66 -0
- package/skills/git/worktree-merge/SKILL.md +95 -0
- package/skills/git/worktree-merge/evals.md +114 -0
- package/skills/skill-marketplace.json +261 -0
- package/skills/workflow/cut-it/SKILL.md +86 -0
- package/skills/workflow/cut-it/evals.md +42 -0
- package/src/domains/agents/builtins/architect.md +33 -0
- package/src/domains/agents/builtins/coder.md +31 -0
- package/src/domains/agents/builtins/context-bootstrap.md +38 -0
- package/src/domains/agents/builtins/debugger.md +30 -0
- package/src/domains/agents/builtins/documenter.md +31 -0
- package/src/domains/agents/builtins/git-master.md +30 -0
- package/src/domains/agents/builtins/provenance.md +30 -0
- package/src/domains/agents/builtins/researcher.md +71 -0
- package/src/domains/agents/builtins/scout.md +42 -0
- package/src/domains/agents/builtins/tester.md +31 -0
- package/src/domains/agents/builtins/verifier.md +30 -0
- package/src/domains/agents/builtins/wiki-writer.md +41 -0
- package/src/domains/agents/fleets/build-review.md +34 -0
- package/src/domains/agents/fleets/build-test.md +35 -0
- package/src/domains/agents/fleets/sdlc.md +86 -0
- package/src/domains/prompts/fragments/identity/clio-worker.md +11 -0
- package/src/domains/prompts/fragments/identity/clio.md +26 -0
- package/src/domains/prompts/fragments/operating/contract.md +64 -0
- package/src/domains/prompts/fragments/safety/auto-edit.md +14 -0
- package/src/domains/prompts/fragments/safety/full-auto.md +14 -0
- package/src/domains/prompts/fragments/safety/read-only.md +13 -0
- package/src/domains/prompts/fragments/safety/suggest.md +13 -0
- package/src/domains/prompts/fragments/wiki/page.md +75 -0
- package/src/domains/prompts/fragments/wiki/plan.md +48 -0
- package/src/domains/providers/models/cloud-models/alcf.yaml +40 -0
- package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +993 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GUARDRAIL_ENV_VARS,
|
|
3
|
+
resolveGuardrail
|
|
4
|
+
} from "./chunk-UHTSULZS.js";
|
|
5
|
+
|
|
6
|
+
// src/cli/internal-dispatch.ts
|
|
7
|
+
function armInternalDispatchDeadline(dispatch, runId, label, env = process.env, maxTimeoutMs) {
|
|
8
|
+
const configuredTimeoutMs = resolveGuardrail("internalDispatchTimeoutMs", env);
|
|
9
|
+
const timeoutMs = maxTimeoutMs === void 0 ? configuredTimeoutMs : Math.min(configuredTimeoutMs, Math.max(1, maxTimeoutMs));
|
|
10
|
+
const productCapped = timeoutMs < configuredTimeoutMs;
|
|
11
|
+
let fired = false;
|
|
12
|
+
const timer = setTimeout(() => {
|
|
13
|
+
fired = true;
|
|
14
|
+
try {
|
|
15
|
+
dispatch.abort(runId, { cause: "timeout", detail: `${label} timed out after ${timeoutMs}ms` });
|
|
16
|
+
} catch {
|
|
17
|
+
}
|
|
18
|
+
}, timeoutMs);
|
|
19
|
+
return {
|
|
20
|
+
timedOut: () => fired,
|
|
21
|
+
clear: () => clearTimeout(timer),
|
|
22
|
+
message: () => productCapped ? `${label} exceeded its ${Math.round(timeoutMs / 1e3)}s latency ceiling and was aborted.` : `${label} timed out after ${Math.round(timeoutMs / 1e3)}s and was aborted. Raise guardrails.internalDispatchTimeoutMs (env ${GUARDRAIL_ENV_VARS.internalDispatchTimeoutMs}) for slower targets.`
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export {
|
|
27
|
+
armInternalDispatchDeadline
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=chunk-4UQA7NCT.js.map
|
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
import {
|
|
2
|
+
readLayeredSettings
|
|
3
|
+
} from "./chunk-UU3R62TT.js";
|
|
4
|
+
import {
|
|
5
|
+
BusChannels,
|
|
6
|
+
getSharedBus
|
|
7
|
+
} from "./chunk-D5YD55AR.js";
|
|
8
|
+
import {
|
|
9
|
+
formatSettingsFailure,
|
|
10
|
+
readSettings,
|
|
11
|
+
settingsPath,
|
|
12
|
+
updateSettings
|
|
13
|
+
} from "./chunk-JWHCJDCI.js";
|
|
14
|
+
|
|
15
|
+
// src/core/termination.ts
|
|
16
|
+
var DEFAULT_SHUTDOWN_HOOK_MS = 500;
|
|
17
|
+
var SIGNAL_EXIT_CODES = {
|
|
18
|
+
SIGHUP: 129,
|
|
19
|
+
SIGINT: 130,
|
|
20
|
+
SIGTERM: 143
|
|
21
|
+
};
|
|
22
|
+
function resolveShutdownHookBudgetMs() {
|
|
23
|
+
const raw = process.env.CLIO_CODER_SHUTDOWN_HOOK_MS;
|
|
24
|
+
if (raw === void 0) return DEFAULT_SHUTDOWN_HOOK_MS;
|
|
25
|
+
const parsed = Number.parseInt(raw, 10);
|
|
26
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return DEFAULT_SHUTDOWN_HOOK_MS;
|
|
27
|
+
return parsed;
|
|
28
|
+
}
|
|
29
|
+
async function runWithBudget(op, budgetMs, onError) {
|
|
30
|
+
let timer;
|
|
31
|
+
const timeout = new Promise((resolve) => {
|
|
32
|
+
timer = setTimeout(() => resolve("timeout"), budgetMs);
|
|
33
|
+
});
|
|
34
|
+
try {
|
|
35
|
+
const done = Promise.resolve().then(() => op()).then(() => "done").catch((err) => {
|
|
36
|
+
onError?.(err);
|
|
37
|
+
return "done";
|
|
38
|
+
});
|
|
39
|
+
const outcome = await Promise.race([done, timeout]);
|
|
40
|
+
return outcome === "done";
|
|
41
|
+
} finally {
|
|
42
|
+
if (timer) clearTimeout(timer);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
var TerminationCoordinator = class {
|
|
46
|
+
phase = "idle";
|
|
47
|
+
drainHooks = [];
|
|
48
|
+
terminateHooks = [];
|
|
49
|
+
persistHooks = [];
|
|
50
|
+
exitCode = 0;
|
|
51
|
+
started = false;
|
|
52
|
+
signalHandler = null;
|
|
53
|
+
getPhase() {
|
|
54
|
+
return this.phase;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The process exit code this shutdown will use. Set before any hook runs,
|
|
58
|
+
* so a hook sealing terminal accounting records the same status the process
|
|
59
|
+
* reports (130 for SIGINT, 143 for SIGTERM).
|
|
60
|
+
*/
|
|
61
|
+
getExitCode() {
|
|
62
|
+
return this.exitCode;
|
|
63
|
+
}
|
|
64
|
+
onDrain(hook) {
|
|
65
|
+
this.drainHooks.push(hook);
|
|
66
|
+
}
|
|
67
|
+
onTerminate(hook) {
|
|
68
|
+
this.terminateHooks.push(hook);
|
|
69
|
+
}
|
|
70
|
+
onPersist(hook) {
|
|
71
|
+
this.persistHooks.push(hook);
|
|
72
|
+
}
|
|
73
|
+
async shutdown(code = 0) {
|
|
74
|
+
if (this.started) return;
|
|
75
|
+
this.started = true;
|
|
76
|
+
this.exitCode = code;
|
|
77
|
+
const bus = getSharedBus();
|
|
78
|
+
const debug = process.env.CLIO_CODER_DEBUG_SHUTDOWN === "1";
|
|
79
|
+
const budgetMs = resolveShutdownHookBudgetMs();
|
|
80
|
+
const mark = debug ? process.hrtime.bigint() : 0n;
|
|
81
|
+
const log = (msg) => {
|
|
82
|
+
if (!debug) return;
|
|
83
|
+
const ms = Number(process.hrtime.bigint() - mark) / 1e6;
|
|
84
|
+
process.stderr.write(`[clio:shutdown] +${ms.toFixed(1)}ms ${msg}
|
|
85
|
+
`);
|
|
86
|
+
};
|
|
87
|
+
this.phase = "draining";
|
|
88
|
+
bus.emit(BusChannels.ShutdownRequested, { phase: this.phase });
|
|
89
|
+
log("drain:start");
|
|
90
|
+
await this.runHooks(this.drainHooks, "drain", budgetMs, log);
|
|
91
|
+
log("drain:end");
|
|
92
|
+
bus.emit(BusChannels.ShutdownDrained, {});
|
|
93
|
+
this.phase = "terminating";
|
|
94
|
+
log("terminate:start");
|
|
95
|
+
await this.runHooks(this.terminateHooks, "terminate", budgetMs, log);
|
|
96
|
+
log("terminate:end");
|
|
97
|
+
bus.emit(BusChannels.ShutdownTerminated, {});
|
|
98
|
+
this.phase = "persisting";
|
|
99
|
+
log("persist:start");
|
|
100
|
+
await this.runHooks(this.persistHooks, "persist", budgetMs, log);
|
|
101
|
+
log("persist:end");
|
|
102
|
+
bus.emit(BusChannels.ShutdownPersisted, {});
|
|
103
|
+
this.phase = "exiting";
|
|
104
|
+
bus.emit(BusChannels.SessionEnd, { exitCode: this.exitCode });
|
|
105
|
+
log("process.exit");
|
|
106
|
+
process.exit(this.exitCode);
|
|
107
|
+
}
|
|
108
|
+
async runHooks(hooks, phase, budgetMs, log) {
|
|
109
|
+
for (let i = 0; i < hooks.length; i++) {
|
|
110
|
+
const hook = hooks[i];
|
|
111
|
+
if (!hook) continue;
|
|
112
|
+
const t0 = process.hrtime.bigint();
|
|
113
|
+
const completed = await runWithBudget(hook, budgetMs, (err) => {
|
|
114
|
+
console.error("[clio:termination] hook failed:", err);
|
|
115
|
+
});
|
|
116
|
+
const dt = Number(process.hrtime.bigint() - t0) / 1e6;
|
|
117
|
+
if (!completed) {
|
|
118
|
+
process.stderr.write(
|
|
119
|
+
`[clio:termination] ${phase}[${i}] exceeded ${budgetMs}ms budget; abandoning and continuing shutdown
|
|
120
|
+
`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
log(` ${phase}[${i}] ${dt.toFixed(1)}ms${completed ? "" : " (timed out)"}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* SIGHUP is here for the same reason as SIGTERM. Without a listener Node
|
|
128
|
+
* takes its default action and the process dies with no shutdown at all,
|
|
129
|
+
* which on a TUI session means the terminal is never given back. Exit codes
|
|
130
|
+
* follow the 128+signal convention.
|
|
131
|
+
*/
|
|
132
|
+
installSignalHandlers() {
|
|
133
|
+
if (this.signalHandler) return;
|
|
134
|
+
const handler = (signal) => {
|
|
135
|
+
process.stderr.write(`
|
|
136
|
+
Clio Coder: received ${signal}, shutting down...
|
|
137
|
+
`);
|
|
138
|
+
void this.shutdown(SIGNAL_EXIT_CODES[signal] ?? 143);
|
|
139
|
+
};
|
|
140
|
+
this.signalHandler = handler;
|
|
141
|
+
process.once("SIGINT", handler);
|
|
142
|
+
process.once("SIGTERM", handler);
|
|
143
|
+
process.once("SIGHUP", handler);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Hand SIGINT to a foreground owner and return the call that takes it back.
|
|
147
|
+
*
|
|
148
|
+
* Boot arms this coordinator before any interactive surface exists, and Node
|
|
149
|
+
* runs signal listeners in registration order, so a TUI that merely added its
|
|
150
|
+
* own listener would lose every first press to a shutdown already underway.
|
|
151
|
+
* One owner holds the interrupt at a time and the transfer is explicit.
|
|
152
|
+
* SIGTERM is not part of the handover; it is never an interactive gesture.
|
|
153
|
+
*/
|
|
154
|
+
releaseInterruptOwnership() {
|
|
155
|
+
const handler = this.signalHandler;
|
|
156
|
+
if (!handler) return () => {
|
|
157
|
+
};
|
|
158
|
+
process.off("SIGINT", handler);
|
|
159
|
+
let restored = false;
|
|
160
|
+
return () => {
|
|
161
|
+
if (restored) return;
|
|
162
|
+
restored = true;
|
|
163
|
+
process.once("SIGINT", handler);
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
var coordinator = null;
|
|
168
|
+
function getTerminationCoordinator() {
|
|
169
|
+
if (!coordinator) coordinator = new TerminationCoordinator();
|
|
170
|
+
return coordinator;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// src/core/domain-loader.ts
|
|
174
|
+
async function loadDomains(modules) {
|
|
175
|
+
const order = topoSort(modules);
|
|
176
|
+
const contracts = /* @__PURE__ */ new Map();
|
|
177
|
+
const extensions = /* @__PURE__ */ new Map();
|
|
178
|
+
const loaded = [];
|
|
179
|
+
const failed = [];
|
|
180
|
+
const bus = getSharedBus();
|
|
181
|
+
const context = {
|
|
182
|
+
bus,
|
|
183
|
+
getContract(dep) {
|
|
184
|
+
return contracts.get(dep);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
for (const name of order) {
|
|
188
|
+
const mod = modules.find((m) => m.manifest.name === name);
|
|
189
|
+
if (!mod) continue;
|
|
190
|
+
try {
|
|
191
|
+
const bundle = await mod.createExtension(context);
|
|
192
|
+
await bundle.extension.start();
|
|
193
|
+
extensions.set(name, bundle.extension);
|
|
194
|
+
contracts.set(name, bundle.contract);
|
|
195
|
+
loaded.push(name);
|
|
196
|
+
bus.emit(BusChannels.DomainLoaded, { name });
|
|
197
|
+
} catch (error) {
|
|
198
|
+
failed.push({ name, error });
|
|
199
|
+
bus.emit(BusChannels.DomainFailed, { name, error });
|
|
200
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
201
|
+
process.stderr.write(`[clio:domain] load failed: ${name}: ${message}
|
|
202
|
+
`);
|
|
203
|
+
throw new DomainLoadError(name, error);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const stop = async () => {
|
|
207
|
+
const debug = process.env.CLIO_CODER_DEBUG_SHUTDOWN === "1";
|
|
208
|
+
const budgetMs = resolveShutdownHookBudgetMs();
|
|
209
|
+
for (const name of [...loaded].reverse()) {
|
|
210
|
+
const ext = extensions.get(name);
|
|
211
|
+
if (!ext?.stop) continue;
|
|
212
|
+
const stopFn = ext.stop.bind(ext);
|
|
213
|
+
const t0 = debug ? process.hrtime.bigint() : 0n;
|
|
214
|
+
const completed = await runWithBudget(stopFn, budgetMs, (err) => {
|
|
215
|
+
console.error(`[clio:domain-loader] ${name}.stop() failed:`, err);
|
|
216
|
+
});
|
|
217
|
+
if (!completed) {
|
|
218
|
+
process.stderr.write(`[clio:domain-loader] ${name}.stop() exceeded ${budgetMs}ms budget; abandoning
|
|
219
|
+
`);
|
|
220
|
+
}
|
|
221
|
+
if (debug) {
|
|
222
|
+
const dt = Number(process.hrtime.bigint() - t0) / 1e6;
|
|
223
|
+
process.stderr.write(`[clio:shutdown] domain.${name} ${dt.toFixed(1)}ms${completed ? "" : " (timed out)"}
|
|
224
|
+
`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
const getContract = (name) => {
|
|
229
|
+
return contracts.get(name);
|
|
230
|
+
};
|
|
231
|
+
return { loaded, failed, getContract, stop };
|
|
232
|
+
}
|
|
233
|
+
function topoSort(modules) {
|
|
234
|
+
const names = new Set(modules.map((m) => m.manifest.name));
|
|
235
|
+
const unresolved = [];
|
|
236
|
+
for (const m of modules) {
|
|
237
|
+
for (const dep of m.manifest.dependsOn) {
|
|
238
|
+
if (!names.has(dep)) unresolved.push(`${m.manifest.name} -> ${dep}`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (unresolved.length > 0) {
|
|
242
|
+
throw new DomainLoadError("topo", new Error(`Unresolved dependencies: ${unresolved.join(", ")}`));
|
|
243
|
+
}
|
|
244
|
+
const order = [];
|
|
245
|
+
const visited = /* @__PURE__ */ new Set();
|
|
246
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
247
|
+
const visit = (name) => {
|
|
248
|
+
if (visited.has(name)) return;
|
|
249
|
+
if (visiting.has(name)) {
|
|
250
|
+
throw new DomainLoadError("topo", new Error(`Cycle detected at ${name}`));
|
|
251
|
+
}
|
|
252
|
+
visiting.add(name);
|
|
253
|
+
const mod = modules.find((m) => m.manifest.name === name);
|
|
254
|
+
if (mod) {
|
|
255
|
+
for (const dep of mod.manifest.dependsOn) visit(dep);
|
|
256
|
+
}
|
|
257
|
+
visiting.delete(name);
|
|
258
|
+
visited.add(name);
|
|
259
|
+
order.push(name);
|
|
260
|
+
};
|
|
261
|
+
for (const m of modules) visit(m.manifest.name);
|
|
262
|
+
return order;
|
|
263
|
+
}
|
|
264
|
+
var DomainLoadError = class extends Error {
|
|
265
|
+
constructor(domain, cause) {
|
|
266
|
+
super(`Domain '${domain}' failed to load: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
267
|
+
this.domain = domain;
|
|
268
|
+
this.cause = cause;
|
|
269
|
+
this.name = "DomainLoadError";
|
|
270
|
+
}
|
|
271
|
+
domain;
|
|
272
|
+
cause;
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
// src/domains/config/agent-namespace.ts
|
|
276
|
+
function assertAgentIdNamespace(nativeRecipes, acpDelegates) {
|
|
277
|
+
const native = new Set(nativeRecipes.map((recipe) => recipe.id));
|
|
278
|
+
const collision = acpDelegates.find((delegate) => native.has(delegate.id));
|
|
279
|
+
if (collision !== void 0) {
|
|
280
|
+
throw new Error(
|
|
281
|
+
`agent id collision: native recipe '${collision.id}' and ACP delegation agent '${collision.id}' share one namespace`
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// src/domains/config/classify.ts
|
|
287
|
+
var HOT_RELOAD_FIELDS = /* @__PURE__ */ new Set(["theme", "keybindings", "autonomy", "modelSelector"]);
|
|
288
|
+
var NEXT_TURN_FIELDS = /* @__PURE__ */ new Set([
|
|
289
|
+
"identity",
|
|
290
|
+
"targets",
|
|
291
|
+
"orchestrator.target",
|
|
292
|
+
"orchestrator.model",
|
|
293
|
+
"orchestrator.thinkingLevel",
|
|
294
|
+
"background.target",
|
|
295
|
+
"background.model",
|
|
296
|
+
"background.thinkingLevel",
|
|
297
|
+
"memory",
|
|
298
|
+
"workers.default.target",
|
|
299
|
+
"workers.default.model",
|
|
300
|
+
"workers.default.thinkingLevel",
|
|
301
|
+
"workers.profiles",
|
|
302
|
+
"workers.agentBindings",
|
|
303
|
+
"workers.maxRetries",
|
|
304
|
+
"workers.onPermission",
|
|
305
|
+
"fleet",
|
|
306
|
+
"routing",
|
|
307
|
+
"scope",
|
|
308
|
+
"budget.sessionCeilingUsd",
|
|
309
|
+
"defaults",
|
|
310
|
+
"terminal",
|
|
311
|
+
"skills",
|
|
312
|
+
"delegation",
|
|
313
|
+
"compaction",
|
|
314
|
+
"retry"
|
|
315
|
+
]);
|
|
316
|
+
var RESTART_REQUIRED_FIELDS = /* @__PURE__ */ new Set(["budget.concurrency", "runtimePlugins"]);
|
|
317
|
+
function matchesPrefix(path, fields) {
|
|
318
|
+
if (fields.has(path)) return true;
|
|
319
|
+
for (const field of fields) {
|
|
320
|
+
if (path.startsWith(`${field}.`)) return true;
|
|
321
|
+
}
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
function diffSettings(prev, next) {
|
|
325
|
+
const changed = collectChangedPaths(prev, next);
|
|
326
|
+
const diff = { hotReload: [], nextTurn: [], restartRequired: [] };
|
|
327
|
+
for (const p of changed) {
|
|
328
|
+
if (matchesPrefix(p, HOT_RELOAD_FIELDS)) diff.hotReload.push(p);
|
|
329
|
+
else if (matchesPrefix(p, NEXT_TURN_FIELDS)) diff.nextTurn.push(p);
|
|
330
|
+
else if (matchesPrefix(p, RESTART_REQUIRED_FIELDS)) diff.restartRequired.push(p);
|
|
331
|
+
else {
|
|
332
|
+
diff.restartRequired.push(p);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return diff;
|
|
336
|
+
}
|
|
337
|
+
function collectChangedPaths(a, b, prefix = "") {
|
|
338
|
+
if (Object.is(a, b)) return [];
|
|
339
|
+
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) {
|
|
340
|
+
return [prefix || "(root)"];
|
|
341
|
+
}
|
|
342
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
343
|
+
const paths = [];
|
|
344
|
+
for (const k of keys) {
|
|
345
|
+
const nextPrefix = prefix ? `${prefix}.${k}` : k;
|
|
346
|
+
const av = a[k];
|
|
347
|
+
const bv = b[k];
|
|
348
|
+
paths.push(...collectChangedPaths(av, bv, nextPrefix));
|
|
349
|
+
}
|
|
350
|
+
return paths;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// src/domains/config/watcher.ts
|
|
354
|
+
import { watch } from "node:fs";
|
|
355
|
+
import { basename, dirname } from "node:path";
|
|
356
|
+
function startConfigWatcher(cb) {
|
|
357
|
+
const path = settingsPath();
|
|
358
|
+
const settingsFile = basename(path);
|
|
359
|
+
let watcher = null;
|
|
360
|
+
let debounceTimer = null;
|
|
361
|
+
try {
|
|
362
|
+
watcher = watch(dirname(path), { persistent: false }, (_event, filename) => {
|
|
363
|
+
if (filename !== null && filename !== settingsFile) return;
|
|
364
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
365
|
+
debounceTimer = setTimeout(() => {
|
|
366
|
+
cb({ at: Date.now() });
|
|
367
|
+
}, 80);
|
|
368
|
+
});
|
|
369
|
+
} catch (err) {
|
|
370
|
+
console.error("[clio:config] watcher setup failed:", err);
|
|
371
|
+
}
|
|
372
|
+
return {
|
|
373
|
+
stop() {
|
|
374
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
375
|
+
watcher?.close();
|
|
376
|
+
watcher = null;
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// src/domains/config/extension.ts
|
|
382
|
+
function createConfigBundle(context) {
|
|
383
|
+
let watcher = null;
|
|
384
|
+
let snapshot = null;
|
|
385
|
+
let reloadFailure = null;
|
|
386
|
+
const listeners = /* @__PURE__ */ new Map([
|
|
387
|
+
["hotReload", /* @__PURE__ */ new Set()],
|
|
388
|
+
["nextTurn", /* @__PURE__ */ new Set()],
|
|
389
|
+
["restartRequired", /* @__PURE__ */ new Set()]
|
|
390
|
+
]);
|
|
391
|
+
function assertAgentNamespace(settings) {
|
|
392
|
+
const agents = context.getContract("agents");
|
|
393
|
+
if (agents) assertAgentIdNamespace(agents.list(), settings.delegation.agents);
|
|
394
|
+
}
|
|
395
|
+
function dispatch(kind, payload) {
|
|
396
|
+
const bus = context.bus;
|
|
397
|
+
const channel = kind === "hotReload" ? BusChannels.ConfigHotReload : kind === "nextTurn" ? BusChannels.ConfigNextTurn : BusChannels.ConfigRestartRequired;
|
|
398
|
+
bus.emit(channel, payload);
|
|
399
|
+
for (const listener of listeners.get(kind) ?? []) {
|
|
400
|
+
try {
|
|
401
|
+
listener(payload);
|
|
402
|
+
} catch (err) {
|
|
403
|
+
console.error(`[clio:config] listener for ${kind} threw:`, err);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
function publishReloadFailure(message) {
|
|
408
|
+
if (reloadFailure === message) return;
|
|
409
|
+
reloadFailure = message;
|
|
410
|
+
context.bus.emit(BusChannels.ConfigReloadFailed, { message });
|
|
411
|
+
}
|
|
412
|
+
function onWatcherFire() {
|
|
413
|
+
let next;
|
|
414
|
+
try {
|
|
415
|
+
readSettings();
|
|
416
|
+
next = readLayeredSettings(process.cwd()).settings;
|
|
417
|
+
} catch (err) {
|
|
418
|
+
publishReloadFailure(formatSettingsFailure(err));
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
const prev = snapshot;
|
|
422
|
+
try {
|
|
423
|
+
assertAgentNamespace(next);
|
|
424
|
+
} catch (err) {
|
|
425
|
+
publishReloadFailure(formatSettingsFailure(err));
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
publishReloadFailure(null);
|
|
429
|
+
snapshot = next;
|
|
430
|
+
if (!prev) return;
|
|
431
|
+
const diff = diffSettings(prev, next);
|
|
432
|
+
if (diff.hotReload.length > 0) dispatch("hotReload", { diff, settings: next });
|
|
433
|
+
if (diff.nextTurn.length > 0) dispatch("nextTurn", { diff, settings: next });
|
|
434
|
+
if (diff.restartRequired.length > 0) dispatch("restartRequired", { diff, settings: next });
|
|
435
|
+
}
|
|
436
|
+
const extension = {
|
|
437
|
+
async start() {
|
|
438
|
+
readSettings();
|
|
439
|
+
snapshot = readLayeredSettings(process.cwd()).settings;
|
|
440
|
+
watcher = startConfigWatcher(() => onWatcherFire());
|
|
441
|
+
},
|
|
442
|
+
async stop() {
|
|
443
|
+
watcher?.stop();
|
|
444
|
+
watcher = null;
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
const contract = {
|
|
448
|
+
get() {
|
|
449
|
+
if (!snapshot) throw new Error("config domain not started");
|
|
450
|
+
return snapshot;
|
|
451
|
+
},
|
|
452
|
+
set(next) {
|
|
453
|
+
contract.update?.(() => next);
|
|
454
|
+
},
|
|
455
|
+
update(mutate) {
|
|
456
|
+
if (!snapshot) throw new Error("config domain not started");
|
|
457
|
+
const previous = snapshot;
|
|
458
|
+
const candidate = structuredClone(previous);
|
|
459
|
+
mutate(candidate);
|
|
460
|
+
assertAgentNamespace(candidate);
|
|
461
|
+
updateSettings(mutate);
|
|
462
|
+
const normalized = readLayeredSettings(process.cwd()).settings;
|
|
463
|
+
snapshot = normalized;
|
|
464
|
+
const diff = diffSettings(previous, normalized);
|
|
465
|
+
if (diff.hotReload.length > 0) dispatch("hotReload", { diff, settings: normalized });
|
|
466
|
+
if (diff.nextTurn.length > 0) dispatch("nextTurn", { diff, settings: normalized });
|
|
467
|
+
if (diff.restartRequired.length > 0) dispatch("restartRequired", { diff, settings: normalized });
|
|
468
|
+
},
|
|
469
|
+
onChange(kind, listener) {
|
|
470
|
+
listeners.get(kind)?.add(listener);
|
|
471
|
+
return () => {
|
|
472
|
+
listeners.get(kind)?.delete(listener);
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
return { extension, contract };
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// src/domains/config/manifest.ts
|
|
480
|
+
var ConfigManifest = {
|
|
481
|
+
name: "config",
|
|
482
|
+
dependsOn: []
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
// src/domains/config/index.ts
|
|
486
|
+
var ConfigDomainModule = {
|
|
487
|
+
manifest: ConfigManifest,
|
|
488
|
+
createExtension: createConfigBundle
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
export {
|
|
492
|
+
getTerminationCoordinator,
|
|
493
|
+
loadDomains,
|
|
494
|
+
assertAgentIdNamespace,
|
|
495
|
+
ConfigDomainModule
|
|
496
|
+
};
|
|
497
|
+
//# sourceMappingURL=chunk-527KG6XR.js.map
|