@iowarp/clio-coder 0.3.4 → 0.3.6
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 +37 -2
- package/CONTRIBUTING.md +6 -6
- package/README.md +2 -2
- package/dist/{acp-S5R4RR5B.js → acp-2BEHC4DL.js} +4 -4
- package/dist/{agents-P6DMMVZY.js → agents-LNNFTM53.js} +13 -11
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-2XCZLPKS.js → auth-KXXFI2VS.js} +6 -6
- package/dist/{chunk-YCWGATWI.js → chunk-24I7BN55.js} +2 -2
- package/dist/{chunk-EKMEHE4H.js → chunk-33YXPOE3.js} +2 -3
- package/dist/chunk-3BPUFZDL.js +37 -0
- package/dist/{chunk-WPQLXFOZ.js → chunk-43AOLP7E.js} +2 -2
- package/dist/{chunk-N4CZJQRK.js → chunk-5JGRAMKL.js} +4 -4
- package/dist/{chunk-BRXQQJFP.js → chunk-6US73PDB.js} +568 -47
- package/dist/{chunk-K6WL7QZT.js → chunk-6XXKFVSN.js} +2 -2
- package/dist/{chunk-QQK64KLB.js → chunk-CJUB2JJ2.js} +138 -20
- package/dist/{chunk-HV5X7OR2.js → chunk-CKXWIANG.js} +12 -12
- package/dist/{chunk-UZHIZC5S.js → chunk-CYQKWTG3.js} +61 -76
- package/dist/{chunk-QWU7ZBO7.js → chunk-DJVECN66.js} +204 -45
- package/dist/{chunk-ZWMF7253.js → chunk-E2ER4LJF.js} +304 -9
- package/dist/{chunk-7RXG6QRZ.js → chunk-EKY57CSP.js} +2 -75
- package/dist/{chunk-EDRHSCIE.js → chunk-EYPA3EGJ.js} +10 -2
- package/dist/{chunk-TTNYS3EA.js → chunk-G7MUEIGA.js} +1 -1
- package/dist/{chunk-BPGS2WCQ.js → chunk-GEYXPTRF.js} +2 -1
- package/dist/{chunk-BEY543CS.js → chunk-GOXNB3AO.js} +5 -2
- package/dist/{chunk-G4BMMOKF.js → chunk-HVDIIIQW.js} +2 -2
- package/dist/chunk-HWUFFB6L.js +83 -0
- package/dist/{chunk-35MKKU5R.js → chunk-K7T3E2SR.js} +15 -8
- package/dist/{chunk-VAWWTKDP.js → chunk-KHSFENX2.js} +2 -2
- package/dist/chunk-LCGCVYZ4.js +57 -0
- package/dist/{chunk-X6COSD2O.js → chunk-LYF7OHWH.js} +41 -14
- package/dist/{chunk-POHLU5DW.js → chunk-M6L6IDJG.js} +3 -3
- package/dist/{chunk-X4RCMKVQ.js → chunk-NDINPTJ4.js} +2 -2
- package/dist/{chunk-5M54SPOL.js → chunk-ODFEOB4F.js} +161 -5
- package/dist/{chunk-3JLKSKD7.js → chunk-OH3TOQTB.js} +5 -1
- package/dist/{chunk-MEQ45TQ4.js → chunk-PBTHKCPN.js} +18 -4
- package/dist/{chunk-ED4KHGC3.js → chunk-PPAMZ32Z.js} +9 -2
- package/dist/{chunk-QQL5RT5M.js → chunk-QM3F2GKX.js} +94 -36
- package/dist/{chunk-A2GZF7DC.js → chunk-QNQHSOLF.js} +4 -4
- package/dist/{chunk-KRPY7NTG.js → chunk-R46L2BIR.js} +3 -3
- package/dist/{chunk-BP4OYD6A.js → chunk-RY3LY4J5.js} +20 -2
- package/dist/{chunk-34475P3I.js → chunk-TSHXZTOQ.js} +5 -4
- package/dist/{chunk-VJWL6YS5.js → chunk-UUVG37B4.js} +2 -2
- package/dist/{chunk-2TZWSW76.js → chunk-WHGPSPT5.js} +2 -2
- package/dist/{chunk-TW3WDMVS.js → chunk-WHJYKASB.js} +2 -2
- package/dist/{chunk-YHZX5GEU.js → chunk-XAKHZX5N.js} +2 -2
- package/dist/{chunk-HXG4IURW.js → chunk-XE2VEJHX.js} +2 -2
- package/dist/{chunk-3HZ5RWN2.js → chunk-XF5N4U5A.js} +7 -6
- package/dist/{chunk-ZYKPLLNQ.js → chunk-XXQNGV4M.js} +590 -32
- package/dist/{chunk-4JUF2NNX.js → chunk-XYDYPRZI.js} +4 -4
- package/dist/{chunk-VMNQ6OZA.js → chunk-ZRGEBJ4T.js} +971 -794
- package/dist/{chunk-2LZI5CAG.js → chunk-ZXF4XRKW.js} +75 -33
- package/dist/{chunk-VSNATDE6.js → chunk-ZZMN5OM4.js} +2 -2
- package/dist/cli/index.js +31 -31
- package/dist/{clio-J5JIOIDS.js → clio-M2KGYUFZ.js} +2 -2
- package/dist/{code-nav-AXCXSBHX.js → code-nav-GQNL7XA6.js} +5 -5
- package/dist/codewiki/build-worker.js +4 -4
- package/dist/{components-KELWS457.js → components-5TTYYX6G.js} +3 -3
- package/dist/{config-OEBMIN2U.js → config-XUUYQIWO.js} +27 -25
- package/dist/{configure-PUQOSIXQ.js → configure-IHJ7YOMV.js} +7 -7
- package/dist/{context-URSXPBCK.js → context-74JLXAWD.js} +12 -12
- package/dist/{context-MGSE4Z2T.js → context-75MIWW3U.js} +24 -22
- package/dist/{context-EKDCKUUZ.js → context-ZQ7SIFJV.js} +8 -7
- package/dist/{context-clear-KDAJRNUK.js → context-clear-GYKWNUML.js} +24 -22
- package/dist/{context-index-BZ4UYMTC.js → context-index-SSR5ECNE.js} +3 -3
- package/dist/{context-working-set-SBKMPPI2.js → context-working-set-UX5KEP4J.js} +11 -10
- package/dist/{dispatch-runner-MSWN72NK.js → dispatch-runner-GIJBHNFL.js} +21 -20
- package/dist/{docs-2C2LTVT2.js → docs-6FZSCG5B.js} +3 -3
- package/dist/{doctor-7BSE27PJ.js → doctor-SVJ5BZCW.js} +4 -4
- package/dist/{eval-IZGDOO4H.js → eval-CG6LLBLD.js} +47 -232
- package/dist/{evidence-SR7WXB5B.js → evidence-ZYFIEN42.js} +19 -18
- package/dist/{evolve-K7VE2CBX.js → evolve-QGEXEMDW.js} +19 -18
- package/dist/{extensions-QVDOHDGJ.js → extensions-ADGNCJJD.js} +3 -3
- package/dist/{fleet-7XMJNQNF.js → fleet-S5R4ZOQY.js} +49 -30
- package/dist/{fleet-preflight-AQNAH644.js → fleet-preflight-BHSNPBMH.js} +2 -2
- package/dist/{init-JGNPAYXT.js → init-5DRU55YR.js} +31 -29
- package/dist/memory-7YKKR6UC.js +467 -0
- package/dist/{models-ZMMLFJNN.js → models-ZPOLRU2C.js} +10 -10
- package/dist/{monitor-2F3T5KHP.js → monitor-US5F5YGZ.js} +33 -18
- package/dist/{orchestrator-ORHT43JB.js → orchestrator-E2AL4T5N.js} +1092 -659
- package/dist/{paths-UXLN5YYZ.js → paths-E7KYAQWE.js} +3 -3
- package/dist/{reset-NXGTYNUO.js → reset-KZ652EK6.js} +3 -3
- package/dist/{run-RF4WJGMT.js → run-SRNBKDWD.js} +52 -40
- package/dist/{share-UT3W6E4M.js → share-CGZE33UP.js} +3 -3
- package/dist/{skills-PSACKC5Q.js → skills-S2X4DLY5.js} +4 -4
- package/dist/{skills-eval-WJSI55RZ.js → skills-eval-W2GGIC4R.js} +19 -18
- package/dist/{targets-PIIRAOYS.js → targets-54SWINWB.js} +14 -12
- package/dist/{terminal-lease-ULWXWNVY.js → terminal-lease-SAIF2OGY.js} +5 -4
- package/dist/{uninstall-FZCQCDKC.js → uninstall-BVLWXKBT.js} +3 -3
- package/dist/{upgrade-346TZ6AV.js → upgrade-JKAR27XC.js} +8 -8
- package/dist/{usage-6KKXR32N.js → usage-MSAWCLX4.js} +60 -27
- package/dist/{verifiers-4UUM6TEE.js → verifiers-NCBTHHN2.js} +60 -54
- package/dist/{wiki-generate-7STOCIFZ.js → wiki-generate-GUSOQ6ZP.js} +30 -28
- package/dist/worker/entry.js +69 -58
- package/dist/{workspace-G4ZWUIPR.js → workspace-ZJ6BFM3Q.js} +4 -4
- package/docs/README.md +3 -3
- package/docs/acp.md +1 -1
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +2 -2
- package/docs/artifact-placement.md +1 -2
- package/docs/artifact-versions.md +1 -1
- package/docs/built-in-agents.md +1 -1
- package/docs/capacity-and-scheduling.md +1 -1
- package/docs/commands-and-modes.md +9 -7
- package/docs/configuration-and-targets.md +12 -1
- package/docs/context-engine.md +4 -2
- package/docs/context-working-set.md +4 -4
- package/docs/development-pipeline.md +1 -1
- package/docs/documentation-coverage.md +3 -3
- package/docs/documentation-guide.md +2 -2
- package/docs/eval-runner.md +1 -1
- package/docs/evals-internal.md +4 -45
- package/docs/evidence-and-memory.md +67 -7
- package/docs/evolution.md +1 -1
- package/docs/exit-codes-and-output.md +1 -1
- package/docs/extensions-and-sharing.md +2 -2
- package/docs/fleet-dispatch.md +28 -2
- package/docs/installation-and-lifecycle.md +2 -2
- package/docs/middleware-and-components.md +19 -2
- package/docs/model-catalog.md +1 -1
- package/docs/observability.md +3 -3
- package/docs/proactive-memory.md +26 -16
- package/docs/prompt-envelope-and-tools.md +4 -2
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/release-cut-checklist.md +38 -35
- package/docs/safety-model.md +29 -7
- package/docs/scientific-validation.md +3 -3
- package/docs/session-lifecycle.md +1 -1
- package/docs/skills-marketplace.md +1 -1
- package/docs/tool-usage.md +2 -2
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +1 -1
- package/docs/tui-design.md +38 -4
- package/docs/worker-dispatch-mechanics.md +1 -1
- package/package.json +7 -4
- package/src/cli/agents.ts +2 -3
- package/src/cli/argv.ts +14 -1
- package/src/cli/fleet.ts +15 -0
- package/src/cli/index.ts +1 -1
- package/src/cli/memory.ts +272 -10
- package/src/cli/modes/json-stream.ts +2 -2
- package/src/cli/modes/print.ts +12 -1
- package/src/cli/run.ts +22 -2
- package/src/cli/targets.ts +12 -3
- package/src/cli/usage.ts +55 -7
- package/src/core/bus-events.ts +3 -0
- package/src/core/response-model-id.ts +134 -0
- package/src/core/toml.ts +62 -0
- package/src/core/workspace-files.ts +0 -1
- package/src/domains/agents/builtins/architect.md +1 -1
- package/src/domains/agents/catalog.ts +5 -4
- package/src/domains/agents/recipe.ts +54 -14
- package/src/domains/agents/result-contract.ts +7 -4
- package/src/domains/context/bootstrap.ts +36 -27
- package/src/domains/context/project-metadata.ts +19 -63
- package/src/domains/context/prompt-context.ts +8 -0
- package/src/domains/context/working-set/policies/index.ts +3 -4
- package/src/domains/dispatch/budget-envelope.ts +396 -0
- package/src/domains/dispatch/contract.ts +2 -0
- package/src/domains/dispatch/extension.ts +81 -27
- package/src/domains/dispatch/orphan-recovery.ts +1 -0
- package/src/domains/dispatch/receipt-integrity.ts +4 -0
- package/src/domains/dispatch/state.ts +1 -0
- package/src/domains/dispatch/types.ts +10 -3
- package/src/domains/dispatch/validation.ts +14 -0
- package/src/domains/dispatch/worker-spawn.ts +14 -3
- package/src/domains/eval/metrics/evidence.ts +0 -116
- package/src/domains/eval/metrics/invariants.ts +1 -1
- package/src/domains/eval/runners/clio-run.ts +1 -10
- package/src/domains/eval/runners/external-command.ts +2 -29
- package/src/domains/eval/schema/suite.ts +0 -7
- package/src/domains/eval/suites/run.ts +1 -7
- package/src/domains/memory/index.ts +22 -0
- package/src/domains/memory/operations.ts +58 -1
- package/src/domains/memory/promotion.ts +281 -0
- package/src/domains/memory/prompt-section.ts +25 -5
- package/src/domains/memory/proposal.ts +51 -7
- package/src/domains/memory/task-bank.ts +3 -2
- package/src/domains/memory/task-memory-handoff.ts +181 -24
- package/src/domains/memory/task-memory-policy.ts +3 -1
- package/src/domains/memory/types.ts +37 -0
- package/src/domains/memory/validate.ts +178 -0
- package/src/domains/middleware/memory-intervention.ts +35 -25
- package/src/domains/middleware/runtime.ts +6 -0
- package/src/domains/middleware/skills-reminder.ts +19 -4
- package/src/domains/middleware/stalled-turn.ts +43 -1
- package/src/domains/middleware/types.ts +10 -0
- package/src/domains/observability/contract.ts +6 -1
- package/src/domains/observability/cost.ts +20 -4
- package/src/domains/observability/extension.ts +2 -2
- package/src/domains/providers/index.ts +3 -0
- package/src/domains/providers/model-discovery.ts +9 -0
- package/src/domains/providers/runtime-resolution.ts +38 -1
- package/src/domains/providers/runtimes/common/probe-helpers.ts +97 -16
- package/src/domains/providers/types/context-window-slots.ts +18 -0
- package/src/domains/providers/types/runtime-descriptor.ts +3 -1
- package/src/domains/safety/call-target.ts +211 -14
- package/src/domains/safety/decision-presentation.ts +268 -0
- package/src/domains/safety/redaction.ts +73 -0
- package/src/domains/session/context-ledger.ts +10 -1
- package/src/domains/session/decision-board.ts +4 -0
- package/src/domains/session/entries.ts +3 -0
- package/src/domains/session/history.ts +68 -19
- package/src/domains/session/usage.ts +24 -7
- package/src/engine/acp/event-mapper.ts +7 -0
- package/src/engine/acp/server.ts +29 -2
- package/src/engine/apis/lmstudio.ts +25 -4
- package/src/engine/apis/openai-completions.ts +147 -22
- package/src/engine/claude/sdk-runtime.ts +8 -2
- package/src/engine/claude/tool-safety.ts +13 -0
- package/src/engine/loop-guard.ts +27 -3
- package/src/engine/worker-events.ts +4 -3
- package/src/engine/worker-runtime.ts +59 -54
- package/src/entry/orchestrator.ts +18 -1
- package/src/interactive/chat-loop-messages.ts +22 -0
- package/src/interactive/chat-loop.ts +13 -0
- package/src/interactive/chat-renderer.ts +19 -3
- package/src/interactive/clio-editor.ts +44 -7
- package/src/interactive/context-overlay.ts +43 -5
- package/src/interactive/cost-overlay.ts +39 -8
- package/src/interactive/dispatch-board.ts +212 -35
- package/src/interactive/footer/widgets.ts +13 -0
- package/src/interactive/interactive-application.ts +6 -1
- package/src/interactive/interactive-input-runtime.ts +11 -1
- package/src/interactive/interactive-presentation.ts +11 -1
- package/src/interactive/memory-overlay.ts +89 -4
- package/src/interactive/overlay-ask-user-lifecycle.ts +1 -1
- package/src/interactive/overlay-frame.ts +5 -2
- package/src/interactive/overlay-general-openers.ts +40 -1
- package/src/interactive/overlay-key-routing.ts +41 -1
- package/src/interactive/overlay-lifecycle.ts +11 -4
- package/src/interactive/overlay-permission-lifecycle.ts +23 -8
- package/src/interactive/overlay-transitions.ts +11 -0
- package/src/interactive/overlays/ask-user.ts +74 -30
- package/src/interactive/overlays/decisions.ts +3 -1
- package/src/interactive/permission-hint.ts +35 -0
- package/src/interactive/permission-overlay.ts +95 -45
- package/src/interactive/renderers/tool-execution.ts +19 -49
- package/src/interactive/session-last-turn.ts +8 -1
- package/src/interactive/session-usage-reseed.ts +36 -10
- package/src/interactive/slash-commands.ts +2 -2
- package/src/interactive/status/summary.ts +5 -0
- package/src/interactive/status/types.ts +5 -0
- package/src/interactive/terminal-lease.ts +1 -0
- package/src/interactive/turn-context.ts +96 -23
- package/src/interactive/turn-middleware.ts +1 -0
- package/src/interactive/turn-runtime.ts +37 -8
- package/src/interactive/turn-state.ts +3 -0
- package/src/interactive/worker-progress.ts +440 -0
- package/src/interactive/worker-stream.ts +51 -110
- package/src/tools/agent-tools.ts +28 -3
- package/src/tools/ask-user.ts +21 -1
- package/src/tools/context/index.ts +2 -2
- package/src/tools/dispatch-arguments.ts +8 -0
- package/src/tools/dispatch-event-text.ts +19 -0
- package/src/tools/dispatch.ts +24 -1
- package/src/tools/monitor.ts +15 -0
- package/src/tools/registry.ts +15 -5
- package/src/tools/result-disposition.ts +156 -0
- package/src/tools/result-shaping.ts +59 -1
- package/src/tools/verify/authoring.ts +55 -54
- package/src/tools/worker-evidence.ts +19 -0
- package/src/worker/spec-contract.ts +43 -3
- package/dist/chunk-EFADSJET.js +0 -18
- package/dist/memory-4ALKDJ4Q.js +0 -246
- package/src/domains/eval/metrics/chaos-stream.ts +0 -93
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/** What Clio directly observed about a provider response model id. */
|
|
2
|
+
export type ResponseModelIdObservation =
|
|
3
|
+
| { state: "reported"; reportedModelId: string }
|
|
4
|
+
| { state: "not-reported" }
|
|
5
|
+
| { state: "not-observed" }
|
|
6
|
+
| { state: "legacy-difference-only"; differingModelId: string | null };
|
|
7
|
+
|
|
8
|
+
export type MissingResponseModelIdObservation = "not-observed" | "legacy-difference-only";
|
|
9
|
+
|
|
10
|
+
/** Call counts grouped by the exact response model-id observation state. */
|
|
11
|
+
export interface ResponseModelIdObservationCounts {
|
|
12
|
+
reportedCalls: number;
|
|
13
|
+
notReportedCalls: number;
|
|
14
|
+
notObservedCalls: number;
|
|
15
|
+
legacyDifferenceOnlyCalls: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function emptyResponseModelIdObservationCounts(): ResponseModelIdObservationCounts {
|
|
19
|
+
return { reportedCalls: 0, notReportedCalls: 0, notObservedCalls: 0, legacyDifferenceOnlyCalls: 0 };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function addResponseModelIdObservationCount(
|
|
23
|
+
counts: ResponseModelIdObservationCounts,
|
|
24
|
+
observation: ResponseModelIdObservation,
|
|
25
|
+
calls = 1,
|
|
26
|
+
): void {
|
|
27
|
+
switch (observation.state) {
|
|
28
|
+
case "reported":
|
|
29
|
+
counts.reportedCalls += calls;
|
|
30
|
+
break;
|
|
31
|
+
case "not-reported":
|
|
32
|
+
counts.notReportedCalls += calls;
|
|
33
|
+
break;
|
|
34
|
+
case "not-observed":
|
|
35
|
+
counts.notObservedCalls += calls;
|
|
36
|
+
break;
|
|
37
|
+
case "legacy-difference-only":
|
|
38
|
+
counts.legacyDifferenceOnlyCalls += calls;
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function addResponseModelIdObservationCounts(
|
|
44
|
+
counts: ResponseModelIdObservationCounts,
|
|
45
|
+
additional: Readonly<ResponseModelIdObservationCounts>,
|
|
46
|
+
): void {
|
|
47
|
+
counts.reportedCalls += additional.reportedCalls;
|
|
48
|
+
counts.notReportedCalls += additional.notReportedCalls;
|
|
49
|
+
counts.notObservedCalls += additional.notObservedCalls;
|
|
50
|
+
counts.legacyDifferenceOnlyCalls += additional.legacyDifferenceOnlyCalls;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function responseModelIdObservationCountsLabel(counts: ResponseModelIdObservationCounts): string {
|
|
54
|
+
const parts: string[] = [];
|
|
55
|
+
if (counts.reportedCalls > 0) parts.push(`reported ${counts.reportedCalls}`);
|
|
56
|
+
if (counts.notReportedCalls > 0) parts.push(`not reported ${counts.notReportedCalls}`);
|
|
57
|
+
if (counts.notObservedCalls > 0) parts.push(`not observed ${counts.notObservedCalls}`);
|
|
58
|
+
if (counts.legacyDifferenceOnlyCalls > 0) parts.push(`legacy difference-only ${counts.legacyDifferenceOnlyCalls}`);
|
|
59
|
+
return parts.join(", ");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function nonEmptyString(value: unknown): string | null {
|
|
63
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function parsedObservation(value: unknown): ResponseModelIdObservation | null {
|
|
67
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return null;
|
|
68
|
+
const record = value as Record<string, unknown>;
|
|
69
|
+
switch (record.state) {
|
|
70
|
+
case "reported": {
|
|
71
|
+
const reportedModelId = nonEmptyString(record.reportedModelId);
|
|
72
|
+
return reportedModelId === null ? null : { state: "reported", reportedModelId };
|
|
73
|
+
}
|
|
74
|
+
case "not-reported":
|
|
75
|
+
return { state: "not-reported" };
|
|
76
|
+
case "not-observed":
|
|
77
|
+
return { state: "not-observed" };
|
|
78
|
+
case "legacy-difference-only":
|
|
79
|
+
return { state: "legacy-difference-only", differingModelId: nonEmptyString(record.differingModelId) };
|
|
80
|
+
default:
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Read the current observation shape and the short-lived #193 shape. A caller
|
|
87
|
+
* chooses how to label a missing field because a live message is not historical,
|
|
88
|
+
* while a persisted row without either shape predates model-id presence capture.
|
|
89
|
+
*/
|
|
90
|
+
export function responseModelIdObservationFromRecord(
|
|
91
|
+
record: Readonly<Record<string, unknown>>,
|
|
92
|
+
missing: MissingResponseModelIdObservation,
|
|
93
|
+
): ResponseModelIdObservation {
|
|
94
|
+
const current = parsedObservation(record.responseModelIdObservation);
|
|
95
|
+
if (current !== null) return current;
|
|
96
|
+
if (Object.hasOwn(record, "servedModel")) {
|
|
97
|
+
const reportedModelId = nonEmptyString(record.servedModel);
|
|
98
|
+
return reportedModelId === null ? { state: "not-reported" } : { state: "reported", reportedModelId };
|
|
99
|
+
}
|
|
100
|
+
if (missing === "not-observed") return { state: "not-observed" };
|
|
101
|
+
return { state: "legacy-difference-only", differingModelId: nonEmptyString(record.responseModel) };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Human vocabulary shared by usage, footer, and receipt projections. */
|
|
105
|
+
export function responseModelIdObservationLabel(observation: ResponseModelIdObservation): string {
|
|
106
|
+
switch (observation.state) {
|
|
107
|
+
case "reported":
|
|
108
|
+
return "reported";
|
|
109
|
+
case "not-reported":
|
|
110
|
+
return "not reported";
|
|
111
|
+
case "not-observed":
|
|
112
|
+
return "not observed";
|
|
113
|
+
case "legacy-difference-only":
|
|
114
|
+
return "legacy difference-only";
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Model id used for accounting without claiming more than the observation supports. */
|
|
119
|
+
export function attributedModelId(
|
|
120
|
+
observation: ResponseModelIdObservation,
|
|
121
|
+
requestedModelId: string,
|
|
122
|
+
differingResponseModelId: string | null,
|
|
123
|
+
): string {
|
|
124
|
+
switch (observation.state) {
|
|
125
|
+
case "reported":
|
|
126
|
+
return observation.reportedModelId;
|
|
127
|
+
case "not-reported":
|
|
128
|
+
return "unknown";
|
|
129
|
+
case "not-observed":
|
|
130
|
+
return differingResponseModelId ?? requestedModelId;
|
|
131
|
+
case "legacy-difference-only":
|
|
132
|
+
return observation.differingModelId ?? requestedModelId;
|
|
133
|
+
}
|
|
134
|
+
}
|
package/src/core/toml.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import type { TomlTable } from "smol-toml";
|
|
5
|
+
|
|
6
|
+
type SmolTomlModule = typeof import("smol-toml");
|
|
7
|
+
|
|
8
|
+
const require = createRequire(import.meta.url);
|
|
9
|
+
let parse: SmolTomlModule["parse"] | undefined;
|
|
10
|
+
|
|
11
|
+
function parser(): SmolTomlModule["parse"] {
|
|
12
|
+
parse ??= (require("smol-toml") as SmolTomlModule).parse;
|
|
13
|
+
return parse;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Parse one TOML document, returning no structure when the input is malformed. */
|
|
17
|
+
export function parseTomlDocument(raw: string): TomlTable | null {
|
|
18
|
+
try {
|
|
19
|
+
return parser()(raw);
|
|
20
|
+
} catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function isTomlTable(value: unknown): value is TomlTable {
|
|
26
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Resolve a structural table path from a parsed document. */
|
|
30
|
+
export function tomlTableAt(document: TomlTable, path: ReadonlyArray<string>): TomlTable | null {
|
|
31
|
+
let value: unknown = document;
|
|
32
|
+
for (const segment of path) {
|
|
33
|
+
if (!isTomlTable(value) || !Object.hasOwn(value, segment)) return null;
|
|
34
|
+
value = value[segment];
|
|
35
|
+
}
|
|
36
|
+
return isTomlTable(value) ? value : null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface TomlFileReader {
|
|
40
|
+
read(relativePath: string): TomlTable | null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Create an operation-scoped TOML reader. Each relative path is read and
|
|
45
|
+
* parsed at most once, including missing and malformed files.
|
|
46
|
+
*/
|
|
47
|
+
export function createTomlFileReader(root: string): TomlFileReader {
|
|
48
|
+
const documents = new Map<string, TomlTable | null>();
|
|
49
|
+
return {
|
|
50
|
+
read(relativePath) {
|
|
51
|
+
if (documents.has(relativePath)) return documents.get(relativePath) ?? null;
|
|
52
|
+
let document: TomlTable | null = null;
|
|
53
|
+
try {
|
|
54
|
+
document = parseTomlDocument(readFileSync(join(root, relativePath), "utf8"));
|
|
55
|
+
} catch {
|
|
56
|
+
document = null;
|
|
57
|
+
}
|
|
58
|
+
documents.set(relativePath, document);
|
|
59
|
+
return document;
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -11,7 +11,7 @@ category: plan
|
|
|
11
11
|
capabilityClass: artifact-write
|
|
12
12
|
latencyClass: deep
|
|
13
13
|
projectContextTier: bounded
|
|
14
|
-
budget: {toolCalls: 32, readReserve: 5, synthesis: true}
|
|
14
|
+
budget: {toolCalls: 32, readReserve: 5, synthesis: true, maximum: {toolCalls: 150, readReserve: 16}}
|
|
15
15
|
resultContract: {kind: architect-plan, path: .clio-coder/artifacts/PLAN.md}
|
|
16
16
|
tags: [architecture, boundaries, migration]
|
|
17
17
|
---
|
|
@@ -71,7 +71,9 @@ function fleetPromptPurpose(description: string): string {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
function fleetPromptLine(spec: AgentSpec): string {
|
|
74
|
-
const budget = spec.budget
|
|
74
|
+
const budget = spec.budget.maximum
|
|
75
|
+
? `${spec.budget.toolCalls}..${spec.budget.maximum.toolCalls} calls`
|
|
76
|
+
: `${spec.budget.toolCalls} calls`;
|
|
75
77
|
const purpose = fleetPromptPurpose(spec.description);
|
|
76
78
|
return `- ${spec.id} (${spec.capabilityClass}, ${budget})${purpose.length > 0 ? `: ${purpose}` : ""}`;
|
|
77
79
|
}
|
|
@@ -160,9 +162,8 @@ export function renderAgentCatalogSectionsFromSpecs(input: ReadonlyArray<AgentSp
|
|
|
160
162
|
function formatSpecLine(spec: AgentSpec, suffix: string): string {
|
|
161
163
|
const tags = spec.tags.length > 0 ? `, tags=${spec.tags.join("/")}` : "";
|
|
162
164
|
const skills = spec.skills.length > 0 ? `, skills=${spec.skills.join("/")}` : "";
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
: ", budget=operator-default";
|
|
165
|
+
const maximum = spec.budget.maximum ? `..${spec.budget.maximum.toolCalls}/${spec.budget.maximum.readReserve}` : "";
|
|
166
|
+
const budget = `, budget=${spec.budget.toolCalls}/${spec.budget.readReserve}${maximum}/${spec.budget.synthesis ? "synthesize" : "stop"}`;
|
|
166
167
|
return `- ${spec.name} [${spec.id}] (${spec.audience}, ${spec.category}, ${spec.capabilityClass}, ${spec.latencyClass}, ${spec.source}${tags}${skills}${budget})${suffix}`;
|
|
167
168
|
}
|
|
168
169
|
|
|
@@ -9,33 +9,33 @@ import type {
|
|
|
9
9
|
AgentProjectContextTier,
|
|
10
10
|
} from "./spec.js";
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
export interface
|
|
12
|
+
/** One bounded worker-loop phase policy. */
|
|
13
|
+
export interface AgentBudgetPhase {
|
|
14
14
|
/** Admitted tool-call boundary before the final-response phase. */
|
|
15
15
|
toolCalls: number;
|
|
16
16
|
/** Tail of the admitted boundary reserved for canonical `read` calls. */
|
|
17
17
|
readReserve: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Authored worker-loop phase policy carried by an agent recipe. */
|
|
21
|
+
export interface AgentBudget extends AgentBudgetPhase {
|
|
18
22
|
/** Whether reaching the boundary transitions to text-only synthesis. */
|
|
19
23
|
synthesis: boolean;
|
|
24
|
+
/** Optional upper bound for invocation-level requests. Absence pins the default exactly. */
|
|
25
|
+
maximum?: AgentBudgetPhase;
|
|
20
26
|
}
|
|
21
27
|
|
|
22
|
-
const AGENT_BUDGET_KEYS = ["toolCalls", "readReserve", "synthesis"] as const;
|
|
28
|
+
const AGENT_BUDGET_KEYS = ["toolCalls", "readReserve", "synthesis", "maximum"] as const;
|
|
23
29
|
|
|
24
|
-
|
|
25
|
-
export function parseAgentBudget(value: unknown, sourcePath: string): AgentBudget | undefined {
|
|
26
|
-
if (value === undefined) return undefined;
|
|
27
|
-
const prefix = `agent budget: ${sourcePath}: budget`;
|
|
30
|
+
function parseAgentBudgetPhase(value: unknown, prefix: string, relationTarget: string): AgentBudgetPhase {
|
|
28
31
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
29
32
|
throw new Error(`${prefix} must be a non-null YAML object`);
|
|
30
33
|
}
|
|
31
|
-
|
|
32
34
|
const record = value as Record<string, unknown>;
|
|
33
35
|
for (const key of Object.keys(record)) {
|
|
34
|
-
if (
|
|
35
|
-
throw new Error(`${prefix}.${key} is unknown`);
|
|
36
|
-
}
|
|
36
|
+
if (key !== "toolCalls" && key !== "readReserve") throw new Error(`${prefix}.${key} is unknown`);
|
|
37
37
|
}
|
|
38
|
-
for (const key of
|
|
38
|
+
for (const key of ["toolCalls", "readReserve"] as const) {
|
|
39
39
|
if (!Object.hasOwn(record, key)) throw new Error(`${prefix}.${key} is required`);
|
|
40
40
|
}
|
|
41
41
|
|
|
@@ -50,12 +50,52 @@ export function parseAgentBudget(value: unknown, sourcePath: string): AgentBudge
|
|
|
50
50
|
throw new Error(`${prefix}.readReserve must be a finite safe integer`);
|
|
51
51
|
}
|
|
52
52
|
if (readReserve < 0) throw new Error(`${prefix}.readReserve must be greater than or equal to 0`);
|
|
53
|
-
if (readReserve >= toolCalls) throw new Error(`${prefix}.readReserve must be less than
|
|
53
|
+
if (readReserve >= toolCalls) throw new Error(`${prefix}.readReserve must be less than ${relationTarget}`);
|
|
54
|
+
|
|
55
|
+
return { toolCalls, readReserve };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Strict parser shared by the one recipe schema and direct contract fixtures. */
|
|
59
|
+
export function parseAgentBudget(value: unknown, sourcePath: string): AgentBudget | undefined {
|
|
60
|
+
if (value === undefined) return undefined;
|
|
61
|
+
const prefix = `agent budget: ${sourcePath}: budget`;
|
|
62
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
63
|
+
throw new Error(`${prefix} must be a non-null YAML object`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const record = value as Record<string, unknown>;
|
|
67
|
+
for (const key of Object.keys(record)) {
|
|
68
|
+
if (!(AGENT_BUDGET_KEYS as ReadonlyArray<string>).includes(key)) {
|
|
69
|
+
throw new Error(`${prefix}.${key} is unknown`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
for (const key of ["toolCalls", "readReserve", "synthesis"] as const) {
|
|
73
|
+
if (!Object.hasOwn(record, key)) throw new Error(`${prefix}.${key} is required`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const phase = parseAgentBudgetPhase(
|
|
77
|
+
{ toolCalls: record.toolCalls, readReserve: record.readReserve },
|
|
78
|
+
prefix,
|
|
79
|
+
"budget.toolCalls",
|
|
80
|
+
);
|
|
54
81
|
|
|
55
82
|
const synthesis = record.synthesis;
|
|
56
83
|
if (typeof synthesis !== "boolean") throw new Error(`${prefix}.synthesis must be a boolean`);
|
|
57
84
|
|
|
58
|
-
|
|
85
|
+
const maximum =
|
|
86
|
+
record.maximum === undefined
|
|
87
|
+
? undefined
|
|
88
|
+
: parseAgentBudgetPhase(record.maximum, `${prefix}.maximum`, "budget.maximum.toolCalls");
|
|
89
|
+
if (maximum !== undefined) {
|
|
90
|
+
if (maximum.toolCalls < phase.toolCalls) {
|
|
91
|
+
throw new Error(`${prefix}.maximum.toolCalls must be greater than or equal to budget.toolCalls`);
|
|
92
|
+
}
|
|
93
|
+
if (maximum.readReserve < phase.readReserve) {
|
|
94
|
+
throw new Error(`${prefix}.maximum.readReserve must be greater than or equal to budget.readReserve`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return { ...phase, synthesis, ...(maximum === undefined ? {} : { maximum }) };
|
|
59
99
|
}
|
|
60
100
|
|
|
61
101
|
export interface AgentToolAnyOfRequirement {
|
|
@@ -1147,12 +1147,13 @@ export interface ResultContractRepairInput {
|
|
|
1147
1147
|
attempt: number;
|
|
1148
1148
|
/** `path:line` anchors from reads that succeeded in this run. */
|
|
1149
1149
|
anchors: ReadonlyArray<string>;
|
|
1150
|
+
/** True only when admission preauthorized a larger tool-call revision phase. */
|
|
1151
|
+
toolsAvailable?: boolean;
|
|
1150
1152
|
}
|
|
1151
1153
|
|
|
1152
1154
|
/**
|
|
1153
|
-
* One repair directive. It states the validator's reason
|
|
1154
|
-
*
|
|
1155
|
-
* terminal document from evidence it already has.
|
|
1155
|
+
* One repair directive. It states the validator's reason and exact shape. Tool
|
|
1156
|
+
* use remains closed unless dispatch preauthorized a larger revision phase.
|
|
1156
1157
|
*/
|
|
1157
1158
|
export function resultContractRepairMessage(input: ResultContractRepairInput): string {
|
|
1158
1159
|
const last = input.attempt >= RESULT_CONTRACT_REPAIR_LIMIT;
|
|
@@ -1161,7 +1162,9 @@ export function resultContractRepairMessage(input: ResultContractRepairInput): s
|
|
|
1161
1162
|
? "FINAL RESULT REQUIRED IN THIS RESPONSE. Your previous response still did not satisfy this run's result contract."
|
|
1162
1163
|
: "Your previous response did not satisfy this run's result contract.",
|
|
1163
1164
|
`Validator reason: ${input.reason}`,
|
|
1164
|
-
|
|
1165
|
+
input.toolsAvailable === true
|
|
1166
|
+
? "You may use the admitted tools to repair this validator failure, then emit the required terminal result."
|
|
1167
|
+
: "Tool use is over. Answer from the evidence you already gathered.",
|
|
1165
1168
|
`Emit exactly this shape and nothing else: ${resultContractShape(input.contract)}`,
|
|
1166
1169
|
"Do not add prose, code fences, or commentary around it. Do not describe work you intend to do next.",
|
|
1167
1170
|
];
|
|
@@ -2,6 +2,7 @@ import { execFileSync } from "node:child_process";
|
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { dirname, join, parse } from "node:path";
|
|
4
4
|
import type { ContextActivityPayload } from "../../core/bus-events.js";
|
|
5
|
+
import { createTomlFileReader, type TomlFileReader, tomlTableAt } from "../../core/toml.js";
|
|
5
6
|
import { classifyProjectPreload, type ProjectPreloadClass } from "../prompts/preload.js";
|
|
6
7
|
import { detectProjectType, type ProjectType } from "../session/workspace/project-type.js";
|
|
7
8
|
import {
|
|
@@ -15,7 +16,7 @@ import { type ClioMdSection, type ParsedClioMd, parseClioMd, serializeClioMd, tr
|
|
|
15
16
|
import { buildCodewikiCandidate, coordinateCodewikiWrite } from "./codewiki/coordinator.js";
|
|
16
17
|
import type { Codewiki } from "./codewiki/schema.js";
|
|
17
18
|
import type { Fingerprint } from "./fingerprint.js";
|
|
18
|
-
import {
|
|
19
|
+
import { type ProjectMetadata, readProjectMetadata } from "./project-metadata.js";
|
|
19
20
|
import { renderPromptContext } from "./prompt-context.js";
|
|
20
21
|
import type { SiblingContextFile } from "./sibling-files.js";
|
|
21
22
|
import {
|
|
@@ -49,6 +50,8 @@ export interface BootstrapIo {
|
|
|
49
50
|
export interface BootstrapGenerateInput {
|
|
50
51
|
cwd: string;
|
|
51
52
|
expectedProjectName?: string;
|
|
53
|
+
/** Operation-scoped parsed TOML documents shared by bootstrap consumers. */
|
|
54
|
+
tomlFiles?: TomlFileReader;
|
|
52
55
|
projectType: ProjectType;
|
|
53
56
|
siblingFiles: ReadonlyArray<SiblingContextFile>;
|
|
54
57
|
adoption: AdoptionScanResult;
|
|
@@ -211,8 +214,8 @@ function projectNameFrom(metadata: ProjectMetadata, cwd: string): string {
|
|
|
211
214
|
return titleFromPackageName(parse(cwd).base || "Project");
|
|
212
215
|
}
|
|
213
216
|
|
|
214
|
-
function projectName(cwd: string): string {
|
|
215
|
-
return projectNameFrom(readProjectMetadata(cwd), cwd);
|
|
217
|
+
function projectName(cwd: string, tomlFiles: TomlFileReader): string {
|
|
218
|
+
return projectNameFrom(readProjectMetadata(cwd, tomlFiles), cwd);
|
|
216
219
|
}
|
|
217
220
|
|
|
218
221
|
function projectTypeLabel(projectType: ProjectType): string {
|
|
@@ -270,8 +273,9 @@ function resolveDefaultIdentity(
|
|
|
270
273
|
cwd: string,
|
|
271
274
|
projectType: ProjectType,
|
|
272
275
|
files: ReadonlyArray<SiblingContextFile>,
|
|
276
|
+
tomlFiles: TomlFileReader,
|
|
273
277
|
): DeterministicIdentity {
|
|
274
|
-
const metadata = readProjectMetadata(cwd);
|
|
278
|
+
const metadata = readProjectMetadata(cwd, tomlFiles);
|
|
275
279
|
const name = projectNameFrom(metadata, cwd);
|
|
276
280
|
const context = allContextText(files);
|
|
277
281
|
if (/Clio owns the agent loop/i.test(context) && /pi-(?:ai|SDK)/i.test(context)) {
|
|
@@ -303,8 +307,8 @@ function resolveDefaultIdentity(
|
|
|
303
307
|
* which tells a reader nothing the directory name did not. A model sentence is
|
|
304
308
|
* strictly better than that, and only than that.
|
|
305
309
|
*/
|
|
306
|
-
function stabilizedIdentity(input: BootstrapGenerateInput, modelIdentity: unknown): string {
|
|
307
|
-
const deterministic = resolveDefaultIdentity(input.cwd, input.projectType, input.siblingFiles);
|
|
310
|
+
function stabilizedIdentity(input: BootstrapGenerateInput, modelIdentity: unknown, tomlFiles: TomlFileReader): string {
|
|
311
|
+
const deterministic = resolveDefaultIdentity(input.cwd, input.projectType, input.siblingFiles, tomlFiles);
|
|
308
312
|
const model = typeof modelIdentity === "string" ? modelIdentity.trim() : "";
|
|
309
313
|
if (deterministic.bare && model.length > 0) return model;
|
|
310
314
|
return deterministic.text;
|
|
@@ -504,23 +508,21 @@ function cmakeVerificationLines(cwd: string): string[] {
|
|
|
504
508
|
* other way. Tox wins when both are declared because it typically wraps the
|
|
505
509
|
* pytest run.
|
|
506
510
|
*/
|
|
507
|
-
function pythonVerificationLines(cwd: string): string[] {
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
pyproject = readFileSync(join(cwd, "pyproject.toml"), "utf8");
|
|
511
|
-
} catch {
|
|
512
|
-
pyproject = "";
|
|
513
|
-
}
|
|
514
|
-
if (existsSync(join(cwd, "tox.ini")) || hasTomlTable(pyproject, "tool.tox")) {
|
|
511
|
+
function pythonVerificationLines(cwd: string, tomlFiles: TomlFileReader): string[] {
|
|
512
|
+
const pyproject = tomlFiles.read("pyproject.toml");
|
|
513
|
+
if (existsSync(join(cwd, "tox.ini")) || (pyproject !== null && tomlTableAt(pyproject, ["tool", "tox"]))) {
|
|
515
514
|
return ["Run `tox` before handoff."];
|
|
516
515
|
}
|
|
517
|
-
if (
|
|
516
|
+
if (
|
|
517
|
+
existsSync(join(cwd, "pytest.ini")) ||
|
|
518
|
+
(pyproject !== null && tomlTableAt(pyproject, ["tool", "pytest", "ini_options"]))
|
|
519
|
+
) {
|
|
518
520
|
return ["Run `pytest` before handoff."];
|
|
519
521
|
}
|
|
520
522
|
return [];
|
|
521
523
|
}
|
|
522
524
|
|
|
523
|
-
function verificationSection(cwd: string): ClioMdSection | null {
|
|
525
|
+
function verificationSection(cwd: string, tomlFiles: TomlFileReader): ClioMdSection | null {
|
|
524
526
|
const scripts = packageScripts(cwd);
|
|
525
527
|
const pm = packageManager(cwd);
|
|
526
528
|
const hasScript = (name: string) => typeof scripts[name] === "string";
|
|
@@ -557,7 +559,8 @@ function verificationSection(cwd: string): ClioMdSection | null {
|
|
|
557
559
|
// Cargo's commands are defined by the toolchain, not by each project, so
|
|
558
560
|
// naming them for any Cargo workspace carries the same confidence as a
|
|
559
561
|
// declared package script.
|
|
560
|
-
|
|
562
|
+
const cargo = tomlFiles.read("Cargo.toml");
|
|
563
|
+
if (cargo !== null && (tomlTableAt(cargo, ["package"]) || tomlTableAt(cargo, ["workspace"]))) {
|
|
561
564
|
lines.push("Run `cargo build` and `cargo test` before handoff.");
|
|
562
565
|
}
|
|
563
566
|
// Go's commands are defined by the toolchain, not by each project, so
|
|
@@ -566,7 +569,7 @@ function verificationSection(cwd: string): ClioMdSection | null {
|
|
|
566
569
|
if (existsSync(join(cwd, "go.mod"))) {
|
|
567
570
|
lines.push("Run `go build ./...` and `go test ./...` before handoff.");
|
|
568
571
|
}
|
|
569
|
-
lines.push(...pythonVerificationLines(cwd));
|
|
572
|
+
lines.push(...pythonVerificationLines(cwd, tomlFiles));
|
|
570
573
|
if (lines.length === 0) return null;
|
|
571
574
|
return { title: "Verification expectations", body: lines.join(" ") };
|
|
572
575
|
}
|
|
@@ -717,6 +720,7 @@ function stabilizeGeneratedOutput(
|
|
|
717
720
|
onModelSectionRetained?: () => void,
|
|
718
721
|
groundModelOutput = false,
|
|
719
722
|
): BootstrapStructuredOutput {
|
|
723
|
+
const tomlFiles = input.tomlFiles ?? createTomlFileReader(input.cwd);
|
|
720
724
|
const existing = input.existingClioMd;
|
|
721
725
|
const conventions: string[] = [];
|
|
722
726
|
for (const convention of existing?.conventions ?? []) pushUnique(conventions, convention);
|
|
@@ -727,7 +731,7 @@ function stabilizeGeneratedOutput(
|
|
|
727
731
|
for (const invariant of existing?.invariants ?? []) pushUnique(invariants, invariant);
|
|
728
732
|
for (const invariant of inferInvariants(input.siblingFiles)) pushUnique(invariants, invariant);
|
|
729
733
|
|
|
730
|
-
const verification = verificationSection(input.cwd);
|
|
734
|
+
const verification = verificationSection(input.cwd, tomlFiles);
|
|
731
735
|
const inferredSections = inferHeuristicSections(input);
|
|
732
736
|
const existingSections = existing?.sections ?? [];
|
|
733
737
|
const ordinarySections: ClioMdSection[] = [];
|
|
@@ -754,8 +758,8 @@ function stabilizeGeneratedOutput(
|
|
|
754
758
|
}
|
|
755
759
|
return {
|
|
756
760
|
...base,
|
|
757
|
-
projectName: existing?.projectName ?? projectName(input.cwd),
|
|
758
|
-
identity: existing?.identity ?? stabilizedIdentity(input, base.identity),
|
|
761
|
+
projectName: existing?.projectName ?? projectName(input.cwd, tomlFiles),
|
|
762
|
+
identity: existing?.identity ?? stabilizedIdentity(input, base.identity, tomlFiles),
|
|
759
763
|
conventions: conventions.slice(0, 6),
|
|
760
764
|
invariants: invariants.slice(0, 3),
|
|
761
765
|
sections: [...retainedOrdinarySections, ...(verification ? [verification] : [])],
|
|
@@ -819,9 +823,11 @@ function inferHeuristicSections(input: BootstrapGenerateInput): ClioMdSection[]
|
|
|
819
823
|
* unavailable or fails.
|
|
820
824
|
*/
|
|
821
825
|
function heuristicBootstrapOutputSync(input: BootstrapGenerateInput): BootstrapStructuredOutput {
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
826
|
+
const tomlFiles = input.tomlFiles ?? createTomlFileReader(input.cwd);
|
|
827
|
+
const sharedInput = input.tomlFiles ? input : { ...input, tomlFiles };
|
|
828
|
+
return stabilizeGeneratedOutput(sharedInput, {
|
|
829
|
+
projectName: projectName(input.cwd, tomlFiles),
|
|
830
|
+
identity: resolveDefaultIdentity(input.cwd, input.projectType, input.siblingFiles, tomlFiles).text,
|
|
825
831
|
conventions: inferConventions(input.cwd, input.siblingFiles, input.codewiki),
|
|
826
832
|
invariants: inferInvariants(input.siblingFiles),
|
|
827
833
|
sections: inferHeuristicSections(input),
|
|
@@ -1229,6 +1235,7 @@ function codewikiEntryPoints(codewiki: Codewiki, limit = 6): string[] {
|
|
|
1229
1235
|
|
|
1230
1236
|
export async function runBootstrap(input: RunBootstrapInput = {}): Promise<RunBootstrapResult> {
|
|
1231
1237
|
const cwd = input.cwd ?? process.cwd();
|
|
1238
|
+
const tomlFiles = createTomlFileReader(cwd);
|
|
1232
1239
|
const projectType = detectProjectType(cwd);
|
|
1233
1240
|
progress(input, {
|
|
1234
1241
|
phase: "scan",
|
|
@@ -1327,7 +1334,8 @@ export async function runBootstrap(input: RunBootstrapInput = {}): Promise<RunBo
|
|
|
1327
1334
|
});
|
|
1328
1335
|
output = await (input.generate ?? heuristicBootstrapOutput)({
|
|
1329
1336
|
cwd,
|
|
1330
|
-
expectedProjectName: projectName(cwd),
|
|
1337
|
+
expectedProjectName: projectName(cwd, tomlFiles),
|
|
1338
|
+
tomlFiles,
|
|
1331
1339
|
projectType,
|
|
1332
1340
|
siblingFiles,
|
|
1333
1341
|
adoption,
|
|
@@ -1342,7 +1350,8 @@ export async function runBootstrap(input: RunBootstrapInput = {}): Promise<RunBo
|
|
|
1342
1350
|
output = stabilizeGeneratedOutput(
|
|
1343
1351
|
{
|
|
1344
1352
|
cwd,
|
|
1345
|
-
expectedProjectName: projectName(cwd),
|
|
1353
|
+
expectedProjectName: projectName(cwd, tomlFiles),
|
|
1354
|
+
tomlFiles,
|
|
1346
1355
|
projectType,
|
|
1347
1356
|
siblingFiles,
|
|
1348
1357
|
adoption,
|
|
@@ -1372,7 +1381,7 @@ export async function runBootstrap(input: RunBootstrapInput = {}): Promise<RunBo
|
|
|
1372
1381
|
} else {
|
|
1373
1382
|
output = existingParsed
|
|
1374
1383
|
? bootstrapOutputFromParsed(existingParsed)
|
|
1375
|
-
: await heuristicBootstrapOutput({ cwd, projectType, siblingFiles, adoption, codewiki });
|
|
1384
|
+
: await heuristicBootstrapOutput({ cwd, tomlFiles, projectType, siblingFiles, adoption, codewiki });
|
|
1376
1385
|
progress(input, {
|
|
1377
1386
|
phase: "generate",
|
|
1378
1387
|
status: "completed",
|