@cleocode/core 2026.9.22 → 2026.9.23
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/dist/build-provenance.json +6 -0
- package/dist/decide/audit.d.ts +7 -1
- package/dist/decide/audit.d.ts.map +1 -1
- package/dist/decide/audit.js.map +1 -1
- package/dist/decide/client.d.ts +46 -4
- package/dist/decide/client.d.ts.map +1 -1
- package/dist/decide/client.js +328 -33
- package/dist/decide/client.js.map +1 -1
- package/dist/decide/credentials.d.ts +28 -4
- package/dist/decide/credentials.d.ts.map +1 -1
- package/dist/decide/credentials.js +50 -12
- package/dist/decide/credentials.js.map +1 -1
- package/dist/decide/index.d.ts +10 -4
- package/dist/decide/index.d.ts.map +1 -1
- package/dist/decide/index.js +10 -4
- package/dist/decide/index.js.map +1 -1
- package/dist/decide/jev-wire.d.ts +100 -8
- package/dist/decide/jev-wire.d.ts.map +1 -1
- package/dist/decide/jev-wire.js +402 -55
- package/dist/decide/jev-wire.js.map +1 -1
- package/dist/decide/operations.d.ts +97 -20
- package/dist/decide/operations.d.ts.map +1 -1
- package/dist/decide/operations.js +180 -28
- package/dist/decide/operations.js.map +1 -1
- package/dist/decide/provider-state.d.ts +89 -0
- package/dist/decide/provider-state.d.ts.map +1 -0
- package/dist/decide/provider-state.js +134 -0
- package/dist/decide/provider-state.js.map +1 -0
- package/dist/decide/provider.d.ts +26 -5
- package/dist/decide/provider.d.ts.map +1 -1
- package/dist/decide/provider.js.map +1 -1
- package/dist/decide/providers.d.ts +58 -0
- package/dist/decide/providers.d.ts.map +1 -0
- package/dist/decide/providers.js +69 -0
- package/dist/decide/providers.js.map +1 -0
- package/dist/decide/site.d.ts +2 -2
- package/dist/decide/site.d.ts.map +1 -1
- package/dist/decide/site.js +2 -0
- package/dist/decide/site.js.map +1 -1
- package/dist/decide/sites/list.d.ts +46 -0
- package/dist/decide/sites/list.d.ts.map +1 -0
- package/dist/decide/sites/list.js +206 -0
- package/dist/decide/sites/list.js.map +1 -0
- package/dist/decide/sites/registry.d.ts +130 -0
- package/dist/decide/sites/registry.d.ts.map +1 -0
- package/dist/decide/sites/registry.js +375 -0
- package/dist/decide/sites/registry.js.map +1 -0
- package/dist/decide/spend.d.ts +196 -0
- package/dist/decide/spend.d.ts.map +1 -0
- package/dist/decide/spend.js +387 -0
- package/dist/decide/spend.js.map +1 -0
- package/dist/decide/wizard.d.ts +53 -0
- package/dist/decide/wizard.d.ts.map +1 -0
- package/dist/decide/wizard.js +144 -0
- package/dist/decide/wizard.js.map +1 -0
- package/dist/docs/docs-audit.d.ts.map +1 -1
- package/dist/docs/docs-audit.js +1 -2
- package/dist/docs/docs-audit.js.map +1 -1
- package/dist/docs/export-document.js +775 -415
- package/dist/docs/export-document.js.map +3 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/init/scaffold-workflows.d.ts.map +1 -1
- package/dist/init/scaffold-workflows.js +6 -3
- package/dist/init/scaffold-workflows.js.map +1 -1
- package/dist/init/upgrade-workflows.d.ts.map +1 -1
- package/dist/init/upgrade-workflows.js +6 -3
- package/dist/init/upgrade-workflows.js.map +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +1 -1
- package/dist/internal.js.map +1 -1
- package/dist/llm/plugin-facade.js +886 -526
- package/dist/llm/plugin-facade.js.map +3 -3
- package/dist/memory/decision-contradiction.d.ts +3 -3
- package/dist/memory/decision-contradiction.d.ts.map +1 -1
- package/dist/memory/decision-contradiction.js +4 -3
- package/dist/memory/decision-contradiction.js.map +1 -1
- package/dist/memory/graph-memory-bridge.d.ts.map +1 -1
- package/dist/memory/graph-memory-bridge.js +2 -0
- package/dist/memory/graph-memory-bridge.js.map +1 -1
- package/dist/memory/observation-type-decision.d.ts +2 -2
- package/dist/memory/observation-type-decision.d.ts.map +1 -1
- package/dist/memory/observation-type-decision.js +3 -2
- package/dist/memory/observation-type-decision.js.map +1 -1
- package/dist/memory/pipeline-manifest-sqlite.d.ts +111 -0
- package/dist/memory/pipeline-manifest-sqlite.d.ts.map +1 -1
- package/dist/memory/pipeline-manifest-sqlite.js +230 -2
- package/dist/memory/pipeline-manifest-sqlite.js.map +1 -1
- package/dist/nexus/migrations/M-split-graph.d.ts.map +1 -1
- package/dist/nexus/migrations/M-split-graph.js +4 -0
- package/dist/nexus/migrations/M-split-graph.js.map +1 -1
- package/dist/nexus/store.d.ts.map +1 -1
- package/dist/nexus/store.js +2 -0
- package/dist/nexus/store.js.map +1 -1
- package/dist/orchestrate/pivot.d.ts.map +1 -1
- package/dist/orchestrate/pivot.js +13 -8
- package/dist/orchestrate/pivot.js.map +1 -1
- package/dist/orchestrate/plan.d.ts.map +1 -1
- package/dist/orchestrate/plan.js +3 -0
- package/dist/orchestrate/plan.js.map +1 -1
- package/dist/orchestration/lead-rollup.js +14 -2
- package/dist/orchestration/lead-rollup.js.map +1 -1
- package/dist/orchestration/owner-decision-readiness.d.ts +2 -2
- package/dist/orchestration/owner-decision-readiness.d.ts.map +1 -1
- package/dist/orchestration/owner-decision-readiness.js +3 -2
- package/dist/orchestration/owner-decision-readiness.js.map +1 -1
- package/dist/orchestration/validate-spawn.d.ts.map +1 -1
- package/dist/orchestration/validate-spawn.js +2 -0
- package/dist/orchestration/validate-spawn.js.map +1 -1
- package/dist/project-scope.d.ts +16 -0
- package/dist/project-scope.d.ts.map +1 -1
- package/dist/project-scope.js +38 -2
- package/dist/project-scope.js.map +1 -1
- package/dist/release/github-pr.d.ts.map +1 -1
- package/dist/release/github-pr.js +2 -1
- package/dist/release/github-pr.js.map +1 -1
- package/dist/routing/capability-matrix.d.ts.map +1 -1
- package/dist/routing/capability-matrix.js +7 -0
- package/dist/routing/capability-matrix.js.map +1 -1
- package/dist/selfimprove/fix-gen.js +895 -535
- package/dist/selfimprove/fix-gen.js.map +3 -3
- package/dist/sessions/briefing.d.ts.map +1 -1
- package/dist/sessions/briefing.js +23 -62
- package/dist/sessions/briefing.js.map +1 -1
- package/dist/sessions/focus-state-store.d.ts +6 -1
- package/dist/sessions/focus-state-store.d.ts.map +1 -1
- package/dist/sessions/focus-state-store.js +5 -2
- package/dist/sessions/focus-state-store.js.map +1 -1
- package/dist/setup/config-json-merge.d.ts +28 -0
- package/dist/setup/config-json-merge.d.ts.map +1 -1
- package/dist/setup/config-json-merge.js +51 -0
- package/dist/setup/config-json-merge.js.map +1 -1
- package/dist/setup/index.d.ts +13 -10
- package/dist/setup/index.d.ts.map +1 -1
- package/dist/setup/index.js +15 -10
- package/dist/setup/index.js.map +1 -1
- package/dist/setup/sections/llm.js +1 -1
- package/dist/setup/sections/llm.js.map +1 -1
- package/dist/setup/sections/system-one.d.ts +28 -0
- package/dist/setup/sections/system-one.d.ts.map +1 -0
- package/dist/setup/sections/system-one.js +53 -0
- package/dist/setup/sections/system-one.js.map +1 -0
- package/dist/setup/wizard.d.ts +15 -1
- package/dist/setup/wizard.d.ts.map +1 -1
- package/dist/setup/wizard.js +15 -0
- package/dist/setup/wizard.js.map +1 -1
- package/dist/skills/prune-bundled.d.ts +40 -1
- package/dist/skills/prune-bundled.d.ts.map +1 -1
- package/dist/skills/prune-bundled.js +117 -1
- package/dist/skills/prune-bundled.js.map +1 -1
- package/dist/store/agent-registry-accessor.d.ts.map +1 -1
- package/dist/store/agent-registry-accessor.js +2 -0
- package/dist/store/agent-registry-accessor.js.map +1 -1
- package/dist/store/backup-pack.js +1 -1
- package/dist/store/backup-pack.js.map +1 -1
- package/dist/store/backup.d.ts +15 -1
- package/dist/store/backup.d.ts.map +1 -1
- package/dist/store/backup.js +18 -2
- package/dist/store/backup.js.map +1 -1
- package/dist/store/conduit-sqlite.d.ts.map +1 -1
- package/dist/store/conduit-sqlite.js +3 -0
- package/dist/store/conduit-sqlite.js.map +1 -1
- package/dist/store/credential-transfer.d.ts.map +1 -1
- package/dist/store/credential-transfer.js +2 -0
- package/dist/store/credential-transfer.js.map +1 -1
- package/dist/store/cross-db-cleanup.d.ts.map +1 -1
- package/dist/store/cross-db-cleanup.js +2 -0
- package/dist/store/cross-db-cleanup.js.map +1 -1
- package/dist/store/dual-scope-db.d.ts.map +1 -1
- package/dist/store/dual-scope-db.js +13 -2
- package/dist/store/dual-scope-db.js.map +1 -1
- package/dist/store/migrate-signaldock-to-conduit.d.ts.map +1 -1
- package/dist/store/migrate-signaldock-to-conduit.js +3 -0
- package/dist/store/migrate-signaldock-to-conduit.js.map +1 -1
- package/dist/store/migration-manager.d.ts.map +1 -1
- package/dist/store/migration-manager.js +37 -3
- package/dist/store/migration-manager.js.map +1 -1
- package/dist/store/migration-sqlite.d.ts.map +1 -1
- package/dist/store/migration-sqlite.js +2 -0
- package/dist/store/migration-sqlite.js.map +1 -1
- package/dist/store/nexus-sqlite.d.ts.map +1 -1
- package/dist/store/nexus-sqlite.js +3 -0
- package/dist/store/nexus-sqlite.js.map +1 -1
- package/dist/store/open-cleo-db.d.ts.map +1 -1
- package/dist/store/open-cleo-db.js +3 -0
- package/dist/store/open-cleo-db.js.map +1 -1
- package/dist/store/portable-bundle-import.d.ts.map +1 -1
- package/dist/store/portable-bundle-import.js +2 -0
- package/dist/store/portable-bundle-import.js.map +1 -1
- package/dist/store/portable-bundle-relocate.d.ts.map +1 -1
- package/dist/store/portable-bundle-relocate.js +2 -0
- package/dist/store/portable-bundle-relocate.js.map +1 -1
- package/dist/store/portable-bundle-scan.js +1 -1
- package/dist/store/portable-bundle-scan.js.map +1 -1
- package/dist/store/ports/domain-binding.d.ts.map +1 -1
- package/dist/store/ports/domain-binding.js +5 -0
- package/dist/store/ports/domain-binding.js.map +1 -1
- package/dist/store/split-brain-import.d.ts.map +1 -1
- package/dist/store/split-brain-import.js +2 -0
- package/dist/store/split-brain-import.js.map +1 -1
- package/dist/store/sqlite-data-accessor.js +7 -0
- package/dist/store/sqlite-data-accessor.js.map +1 -1
- package/dist/store/sqlite-native.d.ts.map +1 -1
- package/dist/store/sqlite-native.js +1 -0
- package/dist/store/sqlite-native.js.map +1 -1
- package/dist/store/sqlite.d.ts.map +1 -1
- package/dist/store/sqlite.js +5 -0
- package/dist/store/sqlite.js.map +1 -1
- package/dist/store/worktree-build-guard.d.ts +191 -0
- package/dist/store/worktree-build-guard.d.ts.map +1 -0
- package/dist/store/worktree-build-guard.js +486 -0
- package/dist/store/worktree-build-guard.js.map +1 -0
- package/dist/store/worktree-isolation-guard.d.ts +27 -0
- package/dist/store/worktree-isolation-guard.d.ts.map +1 -1
- package/dist/store/worktree-isolation-guard.js +67 -1
- package/dist/store/worktree-isolation-guard.js.map +1 -1
- package/dist/store/writer-lease.d.ts.map +1 -1
- package/dist/store/writer-lease.js +2 -0
- package/dist/store/writer-lease.js.map +1 -1
- package/dist/system/backup.d.ts +6 -2
- package/dist/system/backup.d.ts.map +1 -1
- package/dist/system/backup.js +6 -3
- package/dist/system/backup.js.map +1 -1
- package/dist/task-tools/index.d.ts +4 -2
- package/dist/task-tools/index.d.ts.map +1 -1
- package/dist/task-tools/index.js +3 -2
- package/dist/task-tools/index.js.map +1 -1
- package/dist/task-tools/score-task-priority.d.ts +93 -18
- package/dist/task-tools/score-task-priority.d.ts.map +1 -1
- package/dist/task-tools/score-task-priority.js +193 -81
- package/dist/task-tools/score-task-priority.js.map +1 -1
- package/dist/tasks/affected-packages.d.ts +5 -1
- package/dist/tasks/affected-packages.d.ts.map +1 -1
- package/dist/tasks/affected-packages.js +21 -3
- package/dist/tasks/affected-packages.js.map +1 -1
- package/dist/tasks/analyze.d.ts +29 -1
- package/dist/tasks/analyze.d.ts.map +1 -1
- package/dist/tasks/analyze.js +45 -34
- package/dist/tasks/analyze.js.map +1 -1
- package/dist/tasks/backfill-child-projections.d.ts.map +1 -1
- package/dist/tasks/backfill-child-projections.js +4 -1
- package/dist/tasks/backfill-child-projections.js.map +1 -1
- package/dist/tasks/change-set.d.ts.map +1 -1
- package/dist/tasks/change-set.js +16 -3
- package/dist/tasks/change-set.js.map +1 -1
- package/dist/tasks/command-line.d.ts +54 -0
- package/dist/tasks/command-line.d.ts.map +1 -0
- package/dist/tasks/command-line.js +151 -0
- package/dist/tasks/command-line.js.map +1 -0
- package/dist/tasks/component-pr.d.ts.map +1 -1
- package/dist/tasks/component-pr.js +97 -12
- package/dist/tasks/component-pr.js.map +1 -1
- package/dist/tasks/delete.d.ts.map +1 -1
- package/dist/tasks/delete.js +20 -0
- package/dist/tasks/delete.js.map +1 -1
- package/dist/tasks/duplicate-detector.d.ts +3 -3
- package/dist/tasks/duplicate-detector.d.ts.map +1 -1
- package/dist/tasks/duplicate-detector.js +4 -3
- package/dist/tasks/duplicate-detector.js.map +1 -1
- package/dist/tasks/engine-wrap-ops.d.ts +29 -0
- package/dist/tasks/engine-wrap-ops.d.ts.map +1 -1
- package/dist/tasks/engine-wrap-ops.js +40 -0
- package/dist/tasks/engine-wrap-ops.js.map +1 -1
- package/dist/tasks/engine-wrap.d.ts +1 -1
- package/dist/tasks/engine-wrap.d.ts.map +1 -1
- package/dist/tasks/engine-wrap.js +1 -1
- package/dist/tasks/engine-wrap.js.map +1 -1
- package/dist/tasks/evidence.d.ts +2 -0
- package/dist/tasks/evidence.d.ts.map +1 -1
- package/dist/tasks/evidence.js +30 -4
- package/dist/tasks/evidence.js.map +1 -1
- package/dist/tasks/gate-runner.d.ts.map +1 -1
- package/dist/tasks/gate-runner.js +48 -12
- package/dist/tasks/gate-runner.js.map +1 -1
- package/dist/tasks/index.d.ts +1 -1
- package/dist/tasks/index.d.ts.map +1 -1
- package/dist/tasks/index.js +1 -1
- package/dist/tasks/index.js.map +1 -1
- package/dist/tasks/ops.d.ts +1 -0
- package/dist/tasks/ops.d.ts.map +1 -1
- package/dist/tasks/ranking-audit.d.ts +122 -0
- package/dist/tasks/ranking-audit.d.ts.map +1 -0
- package/dist/tasks/ranking-audit.js +193 -0
- package/dist/tasks/ranking-audit.js.map +1 -0
- package/dist/tasks/task-analyze.d.ts.map +1 -1
- package/dist/tasks/task-analyze.js +19 -32
- package/dist/tasks/task-analyze.js.map +1 -1
- package/dist/tasks/task-next.d.ts +44 -2
- package/dist/tasks/task-next.d.ts.map +1 -1
- package/dist/tasks/task-next.js +80 -102
- package/dist/tasks/task-next.js.map +1 -1
- package/dist/tasks/task-ops.d.ts +1 -1
- package/dist/tasks/task-ops.d.ts.map +1 -1
- package/dist/tasks/task-ops.js +1 -1
- package/dist/tasks/task-ops.js.map +1 -1
- package/dist/tasks/tool-resolver.d.ts +7 -1
- package/dist/tasks/tool-resolver.d.ts.map +1 -1
- package/dist/tasks/tool-resolver.js +24 -10
- package/dist/tasks/tool-resolver.js.map +1 -1
- package/dist/tasks/update.d.ts +8 -2
- package/dist/tasks/update.d.ts.map +1 -1
- package/dist/tasks/update.js +28 -1
- package/dist/tasks/update.js.map +1 -1
- package/dist/telemetry/sqlite.d.ts.map +1 -1
- package/dist/telemetry/sqlite.js +2 -0
- package/dist/telemetry/sqlite.js.map +1 -1
- package/dist/validation/doctor/checks.d.ts.map +1 -1
- package/dist/validation/doctor/checks.js +2 -2
- package/dist/validation/doctor/checks.js.map +1 -1
- package/package.json +14 -14
- package/schemas/config.schema.json +13 -0
- package/templates/CLEO-INJECTION.md +1 -1
- package/templates/CLEO-REFERENCE.md +5 -1
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Monthly spend cap for System One decisions — the CLEO-enforced COST budget
|
|
3
|
+
* of owner decision D11159 (spec `system-one-integration` §7).
|
|
4
|
+
*
|
|
5
|
+
* Every CLEO process on the machine records provider-reported cost (integer
|
|
6
|
+
* micro-dollars) into ONE ledger, `<cleoHome>/decide/spend.json`, guarded by a
|
|
7
|
+
* `proper-lockfile` lock. Once the month-to-date spend reaches the cap
|
|
8
|
+
* (`decide.budget.monthlyMicros`, default
|
|
9
|
+
* {@link DEFAULT_MONTHLY_SPEND_CAP_MICROS} = $1), every site degrades to its
|
|
10
|
+
* heuristic with fallback reason `budget` until the UTC month rolls over. It
|
|
11
|
+
* never fails a command.
|
|
12
|
+
*
|
|
13
|
+
* ## Reserve, then commit
|
|
14
|
+
*
|
|
15
|
+
* A caller reserves its estimated cost BEFORE the provider call, under the
|
|
16
|
+
* same lock as the cap check, and commits the reported cost (or releases the
|
|
17
|
+
* reservation) after it. Concurrent callers therefore see each other's
|
|
18
|
+
* in-flight spend and cannot overshoot the cap together. A reservation still
|
|
19
|
+
* pending after {@link RESERVATION_TTL_MS} (its process died, or exited
|
|
20
|
+
* before its commit landed) is CHARGED at its estimate, not dropped: the
|
|
21
|
+
* request may have been billed, and the cap must not undercount it.
|
|
22
|
+
*
|
|
23
|
+
* The lock retries for about a second with backoff: a decision may wait for
|
|
24
|
+
* the ledger, but a cost is never dropped because 40 processes recorded at
|
|
25
|
+
* once (review of #1685: the first version lost 33 of 40 concurrent records).
|
|
26
|
+
*
|
|
27
|
+
* The ledger also carries the key-limit stop: a 403 `key_limit_exceeded`
|
|
28
|
+
* (an unverified provider extension) means the key's monthly decision limit
|
|
29
|
+
* is reached, so decisions stop until the end of the UTC month.
|
|
30
|
+
*
|
|
31
|
+
* A corrupt ledger fails closed (every site uses its heuristic) and
|
|
32
|
+
* `cleo decide status` says so; `cleo decide budget reset` repairs it, moving
|
|
33
|
+
* the bad file aside as a receipt. It refuses a readable ledger unless
|
|
34
|
+
* `--force` is given, and then keeps the month-to-date spend, so a reset can
|
|
35
|
+
* never lift a reached cap.
|
|
36
|
+
*
|
|
37
|
+
* @task T12664
|
|
38
|
+
* @epic T12486
|
|
39
|
+
*/
|
|
40
|
+
import { randomBytes } from 'node:crypto';
|
|
41
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from 'node:fs';
|
|
42
|
+
import { dirname, join } from 'node:path';
|
|
43
|
+
import { getCleoHome } from '@cleocode/paths';
|
|
44
|
+
import lockfile from 'proper-lockfile';
|
|
45
|
+
import { z } from 'zod';
|
|
46
|
+
/** Default monthly cap: 1,000,000 micro-dollars = $1 (D11159). */
|
|
47
|
+
export const DEFAULT_MONTHLY_SPEND_CAP_MICROS = 1_000_000;
|
|
48
|
+
/** Config key holding the monthly cap in micro-dollars. */
|
|
49
|
+
export const MONTHLY_SPEND_CAP_KEY = 'decide.budget.monthlyMicros';
|
|
50
|
+
/**
|
|
51
|
+
* How long a reservation stays pending, ms. After that it is charged at its
|
|
52
|
+
* estimate (it may have been billed). Decision deadlines are hundreds of ms,
|
|
53
|
+
* so a live call always commits or releases long before this.
|
|
54
|
+
*/
|
|
55
|
+
export const RESERVATION_TTL_MS = 60_000;
|
|
56
|
+
/**
|
|
57
|
+
* The UTC month of `epochMs`, `YYYY-MM`.
|
|
58
|
+
*
|
|
59
|
+
* @param epochMs - Epoch milliseconds.
|
|
60
|
+
* @returns The month string.
|
|
61
|
+
*/
|
|
62
|
+
export function utcMonth(epochMs) {
|
|
63
|
+
const d = new Date(epochMs);
|
|
64
|
+
return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}`;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Epoch ms of the first instant of the next UTC month.
|
|
68
|
+
*
|
|
69
|
+
* @param epochMs - Epoch milliseconds.
|
|
70
|
+
* @returns Start of the next UTC month.
|
|
71
|
+
*/
|
|
72
|
+
export function startOfNextUtcMonth(epochMs) {
|
|
73
|
+
const d = new Date(epochMs);
|
|
74
|
+
return Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + 1, 1);
|
|
75
|
+
}
|
|
76
|
+
function freshState(now) {
|
|
77
|
+
return { month: utcMonth(now), spentMicros: 0, keyLimitedUntil: 0, reservations: {} };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Roll a state over to the current month and charge expired reservations at
|
|
81
|
+
* their estimate (mutates). An expired reservation's call may have been
|
|
82
|
+
* billed, so it is counted rather than forgotten.
|
|
83
|
+
*/
|
|
84
|
+
function roll(state, now) {
|
|
85
|
+
const month = utcMonth(now);
|
|
86
|
+
if (state.month !== month) {
|
|
87
|
+
state.month = month;
|
|
88
|
+
state.spentMicros = 0;
|
|
89
|
+
}
|
|
90
|
+
if (state.keyLimitedUntil <= now)
|
|
91
|
+
state.keyLimitedUntil = 0;
|
|
92
|
+
for (const [id, r] of Object.entries(state.reservations)) {
|
|
93
|
+
if (now - r.at >= RESERVATION_TTL_MS) {
|
|
94
|
+
state.spentMicros += positive(r.micros);
|
|
95
|
+
delete state.reservations[id];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function reservedOf(state) {
|
|
100
|
+
return Object.values(state.reservations).reduce((n, r) => n + r.micros, 0);
|
|
101
|
+
}
|
|
102
|
+
function positive(micros) {
|
|
103
|
+
return Number.isFinite(micros) && micros > 0 ? Math.round(micros) : 0;
|
|
104
|
+
}
|
|
105
|
+
function doReserve(state, capMicros, estimateMicros, now) {
|
|
106
|
+
roll(state, now);
|
|
107
|
+
if (state.keyLimitedUntil > now)
|
|
108
|
+
return { verdict: 'key_limited' };
|
|
109
|
+
const estimate = positive(estimateMicros);
|
|
110
|
+
if (state.spentMicros + reservedOf(state) + estimate > capMicros ||
|
|
111
|
+
state.spentMicros >= capMicros) {
|
|
112
|
+
return { verdict: 'over_budget' };
|
|
113
|
+
}
|
|
114
|
+
const id = randomBytes(8).toString('hex');
|
|
115
|
+
state.reservations[id] = { micros: estimate, at: now };
|
|
116
|
+
return { verdict: 'ok', id };
|
|
117
|
+
}
|
|
118
|
+
function toStatus(state) {
|
|
119
|
+
return {
|
|
120
|
+
month: state.month,
|
|
121
|
+
spentMicros: state.spentMicros,
|
|
122
|
+
reservedMicros: reservedOf(state),
|
|
123
|
+
...(state.keyLimitedUntil > 0 ? { keyLimitedUntil: state.keyLimitedUntil } : {}),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/** The operations every ledger implements, over a state accessor. */
|
|
127
|
+
function ledgerOver(withState, now) {
|
|
128
|
+
return {
|
|
129
|
+
async reserve(capMicros, estimateMicros) {
|
|
130
|
+
try {
|
|
131
|
+
return await withState((s) => doReserve(s, capMicros, estimateMicros, now()), true);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return { verdict: 'unavailable' };
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
async commit(id, costMicros) {
|
|
138
|
+
try {
|
|
139
|
+
await withState((s) => {
|
|
140
|
+
roll(s, now());
|
|
141
|
+
delete s.reservations[id];
|
|
142
|
+
s.spentMicros += positive(costMicros);
|
|
143
|
+
}, true);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
/* the reservation expires; an unrecorded cost only makes the cap later */
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
async release(id) {
|
|
150
|
+
try {
|
|
151
|
+
await withState((s) => {
|
|
152
|
+
delete s.reservations[id];
|
|
153
|
+
}, true);
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
/* the reservation expires on its own */
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
async record(costMicros) {
|
|
160
|
+
const micros = positive(costMicros);
|
|
161
|
+
if (micros === 0)
|
|
162
|
+
return;
|
|
163
|
+
try {
|
|
164
|
+
await withState((s) => {
|
|
165
|
+
roll(s, now());
|
|
166
|
+
s.spentMicros += micros;
|
|
167
|
+
}, true);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
/* best effort */
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
async markKeyLimited() {
|
|
174
|
+
try {
|
|
175
|
+
await withState((s) => {
|
|
176
|
+
roll(s, now());
|
|
177
|
+
s.keyLimitedUntil = startOfNextUtcMonth(now());
|
|
178
|
+
}, true);
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
/* the next call meets the 403 again */
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
async status() {
|
|
185
|
+
try {
|
|
186
|
+
return await withState((s) => {
|
|
187
|
+
roll(s, now());
|
|
188
|
+
return toStatus(s);
|
|
189
|
+
}, false);
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* A process-local ledger (tests, callers that must not touch disk).
|
|
199
|
+
*
|
|
200
|
+
* @param opts - Clock.
|
|
201
|
+
* @returns A {@link SpendLedger} that does NOT coordinate across processes.
|
|
202
|
+
*/
|
|
203
|
+
export function createMemorySpendLedger(opts = {}) {
|
|
204
|
+
const now = opts.now ?? Date.now;
|
|
205
|
+
const state = freshState(now());
|
|
206
|
+
return ledgerOver(async (mutate) => mutate(state), now);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Default ledger location: `<cleoHome>/decide/spend.json`.
|
|
210
|
+
*
|
|
211
|
+
* @returns Absolute path.
|
|
212
|
+
*/
|
|
213
|
+
export function defaultSpendStatePath() {
|
|
214
|
+
return join(getCleoHome(), 'decide', 'spend.json');
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Lock retries: about a second with backoff (5 ms growing to 50 ms). Long
|
|
218
|
+
* enough that dozens of concurrent processes all get their turn; a caller on
|
|
219
|
+
* a decision deadline is bounded by that deadline, not by this.
|
|
220
|
+
*/
|
|
221
|
+
const LOCK_OPTIONS = {
|
|
222
|
+
realpath: false,
|
|
223
|
+
stale: 5_000,
|
|
224
|
+
retries: { retries: 40, factor: 1.2, minTimeout: 5, maxTimeout: 50, randomize: true },
|
|
225
|
+
};
|
|
226
|
+
const ledgerSchema = z.object({
|
|
227
|
+
month: z.string(),
|
|
228
|
+
spentMicros: z.number().nonnegative(),
|
|
229
|
+
keyLimitedUntil: z.number().nonnegative(),
|
|
230
|
+
reservations: z
|
|
231
|
+
.record(z.string(), z.object({ micros: z.number().nonnegative(), at: z.number() }))
|
|
232
|
+
.default({}),
|
|
233
|
+
});
|
|
234
|
+
/** Thrown when the ledger file exists but cannot be parsed. */
|
|
235
|
+
class CorruptLedgerError extends Error {
|
|
236
|
+
}
|
|
237
|
+
function readLedger(path, now) {
|
|
238
|
+
let raw;
|
|
239
|
+
try {
|
|
240
|
+
raw = readFileSync(path, 'utf-8');
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
return freshState(now);
|
|
244
|
+
}
|
|
245
|
+
let json;
|
|
246
|
+
try {
|
|
247
|
+
json = JSON.parse(raw);
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
throw new CorruptLedgerError('spend ledger is not JSON');
|
|
251
|
+
}
|
|
252
|
+
const parsed = ledgerSchema.safeParse(json);
|
|
253
|
+
if (!parsed.success)
|
|
254
|
+
throw new CorruptLedgerError('spend ledger has an unexpected shape');
|
|
255
|
+
return parsed.data;
|
|
256
|
+
}
|
|
257
|
+
function writeLedger(path, state) {
|
|
258
|
+
const tmp = join(dirname(path), `.spend.${randomBytes(6).toString('hex')}.tmp`);
|
|
259
|
+
writeFileSync(tmp, JSON.stringify(state), 'utf-8');
|
|
260
|
+
try {
|
|
261
|
+
renameSync(tmp, path);
|
|
262
|
+
}
|
|
263
|
+
catch (err) {
|
|
264
|
+
try {
|
|
265
|
+
unlinkSync(tmp);
|
|
266
|
+
}
|
|
267
|
+
catch {
|
|
268
|
+
/* ignore cleanup failure */
|
|
269
|
+
}
|
|
270
|
+
throw err;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* A ledger shared by every process on the machine through a locked JSON file.
|
|
275
|
+
* A lock or read failure (including a corrupt file) makes `reserve` answer
|
|
276
|
+
* `unavailable`, which the client treats as a fallback: the cap fails closed,
|
|
277
|
+
* like the request bucket.
|
|
278
|
+
*
|
|
279
|
+
* @param opts - Clock and state path.
|
|
280
|
+
* @returns A {@link SpendLedger}.
|
|
281
|
+
*/
|
|
282
|
+
export function createFileSpendLedger(opts = {}) {
|
|
283
|
+
const now = opts.now ?? Date.now;
|
|
284
|
+
const statePath = opts.statePath ?? defaultSpendStatePath();
|
|
285
|
+
return ledgerOver(async (mutate, write) => {
|
|
286
|
+
mkdirSync(dirname(statePath), { recursive: true });
|
|
287
|
+
const release = await lockfile.lock(statePath, LOCK_OPTIONS);
|
|
288
|
+
try {
|
|
289
|
+
const state = readLedger(statePath, now());
|
|
290
|
+
const result = mutate(state);
|
|
291
|
+
if (write)
|
|
292
|
+
writeLedger(statePath, state);
|
|
293
|
+
return result;
|
|
294
|
+
}
|
|
295
|
+
finally {
|
|
296
|
+
await release().catch(() => undefined);
|
|
297
|
+
}
|
|
298
|
+
}, now);
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Whether the ledger file is readable.
|
|
302
|
+
*
|
|
303
|
+
* @param statePath - Ledger path. Default {@link defaultSpendStatePath}.
|
|
304
|
+
* @returns `ok`, `absent`, `corrupt` or `unavailable` (unreadable for another reason).
|
|
305
|
+
*/
|
|
306
|
+
export function inspectSpendLedger(statePath = defaultSpendStatePath()) {
|
|
307
|
+
if (!existsSync(statePath))
|
|
308
|
+
return 'absent';
|
|
309
|
+
try {
|
|
310
|
+
readLedger(statePath, Date.now());
|
|
311
|
+
return 'ok';
|
|
312
|
+
}
|
|
313
|
+
catch (err) {
|
|
314
|
+
return err instanceof CorruptLedgerError ? 'corrupt' : 'unavailable';
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Thrown by {@link resetSpendLedger} when the ledger is not corrupt and
|
|
319
|
+
* `force` was not given. A reached cap is not a fault to repair.
|
|
320
|
+
*/
|
|
321
|
+
export class SpendResetRefusedError extends Error {
|
|
322
|
+
/** Health of the ledger that was not reset. */
|
|
323
|
+
health;
|
|
324
|
+
/** @param health - The ledger's health (anything but `corrupt`). */
|
|
325
|
+
constructor(health) {
|
|
326
|
+
super(`The System One spend ledger is ${health === 'ok' ? 'healthy' : health}, so it was not reset: ` +
|
|
327
|
+
'`cleo decide budget reset` only repairs a corrupt ledger. A reached monthly cap lifts when ' +
|
|
328
|
+
'the UTC month rolls over or when `decide.budget.monthlyMicros` is raised; resetting does not ' +
|
|
329
|
+
'lift it. Pass --force to reset anyway (month-to-date spend is kept; in-flight reservations ' +
|
|
330
|
+
'and the key-limit stop are cleared).');
|
|
331
|
+
this.name = 'SpendResetRefusedError';
|
|
332
|
+
this.health = health;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Reset the ledger (`cleo decide budget reset`): move the current file aside
|
|
337
|
+
* to `spend.json.reset-<iso>` and start a new ledger for this month. The
|
|
338
|
+
* repair for a corrupt ledger, which otherwise fails closed forever.
|
|
339
|
+
*
|
|
340
|
+
* Refuses (throws {@link SpendResetRefusedError}) unless the ledger is
|
|
341
|
+
* corrupt or `opts.force` is set, so an agent cannot reset its way past a
|
|
342
|
+
* reached cap. When the old file is readable its month-to-date spend
|
|
343
|
+
* (expired reservations included) is carried over; only a corrupt file's
|
|
344
|
+
* spend is lost, and the moved file is kept as the receipt of it.
|
|
345
|
+
*
|
|
346
|
+
* @param statePath - Ledger path. Default {@link defaultSpendStatePath}.
|
|
347
|
+
* @param now - Wall clock, epoch ms.
|
|
348
|
+
* @param opts - `force` resets a ledger that is not corrupt.
|
|
349
|
+
* @returns What was reset, the spend carried over and where the old file went.
|
|
350
|
+
* @throws {SpendResetRefusedError} When the ledger is not corrupt and `force` is not set.
|
|
351
|
+
*/
|
|
352
|
+
export async function resetSpendLedger(statePath = defaultSpendStatePath(), now = Date.now(), opts = {}) {
|
|
353
|
+
const resetAt = new Date(now).toISOString();
|
|
354
|
+
mkdirSync(dirname(statePath), { recursive: true });
|
|
355
|
+
const release = await lockfile.lock(statePath, LOCK_OPTIONS);
|
|
356
|
+
try {
|
|
357
|
+
// Inspect under the lock, so the verdict is about the file we move.
|
|
358
|
+
const before = inspectSpendLedger(statePath);
|
|
359
|
+
const forced = opts.force === true;
|
|
360
|
+
if (before !== 'corrupt' && !forced)
|
|
361
|
+
throw new SpendResetRefusedError(before);
|
|
362
|
+
const next = freshState(now);
|
|
363
|
+
if (before === 'ok') {
|
|
364
|
+
const old = readLedger(statePath, now);
|
|
365
|
+
roll(old, now);
|
|
366
|
+
next.spentMicros = old.spentMicros;
|
|
367
|
+
}
|
|
368
|
+
let backupPath;
|
|
369
|
+
if (existsSync(statePath)) {
|
|
370
|
+
backupPath = `${statePath}.reset-${resetAt.replace(/[:.]/g, '-')}`;
|
|
371
|
+
renameSync(statePath, backupPath);
|
|
372
|
+
}
|
|
373
|
+
writeLedger(statePath, next);
|
|
374
|
+
return {
|
|
375
|
+
statePath,
|
|
376
|
+
before,
|
|
377
|
+
...(backupPath ? { backupPath } : {}),
|
|
378
|
+
resetAt,
|
|
379
|
+
spentMicros: next.spentMicros,
|
|
380
|
+
forced,
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
finally {
|
|
384
|
+
await release().catch(() => undefined);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
//# sourceMappingURL=spend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spend.js","sourceRoot":"","sources":["../../src/decide/spend.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive System One setup: `cleo decide config` on a TTY, and the
|
|
3
|
+
* `system-one` section of `cleo setup`.
|
|
4
|
+
*
|
|
5
|
+
* Steps: pick the provider (layahost first, recommended) → `jev` only: the
|
|
6
|
+
* URL → the API key through {@link WizardIO.secret} (never echoed) → probe
|
|
7
|
+
* `GET /v1/models` → pick the model (layahost defaults to its routing model)
|
|
8
|
+
* → optionally confirm a one-question smoke test → save (which probes again
|
|
9
|
+
* and re-detects capabilities) → run the smoke test when confirmed.
|
|
10
|
+
*
|
|
11
|
+
* All logic lives here; the IO is injected, so tests drive it with a stub and
|
|
12
|
+
* the CLI with readline. Nothing this module returns or prints carries the
|
|
13
|
+
* key: only the masked last-4 preview from the saved summary.
|
|
14
|
+
*
|
|
15
|
+
* @task T12713
|
|
16
|
+
* @epic T12486
|
|
17
|
+
*/
|
|
18
|
+
import type { WizardIO } from '../setup/wizard.js';
|
|
19
|
+
import { type DecideAskResult, type DecideConfigureResult } from './operations.js';
|
|
20
|
+
/** How many times the wizard re-asks for a URL or model name before giving up. */
|
|
21
|
+
export declare const DECIDE_WIZARD_MAX_ATTEMPTS = 3;
|
|
22
|
+
/** Options for {@link runDecideWizard}. */
|
|
23
|
+
export interface DecideWizardOptions {
|
|
24
|
+
/** `fetch` for the model probe and the save-time probe; tests inject a stub. */
|
|
25
|
+
readonly fetch?: typeof fetch;
|
|
26
|
+
/** Deadline for each probe, ms. Default {@link DEFAULT_DECIDE_PROBE_TIMEOUT_MS}. */
|
|
27
|
+
readonly timeoutMs?: number;
|
|
28
|
+
/** Smoke-test runner. Default: one `decide ask` through the saved settings. */
|
|
29
|
+
readonly smoke?: () => Promise<DecideAskResult>;
|
|
30
|
+
/** Project root for the smoke test's audit line. Default: the resolved project root. */
|
|
31
|
+
readonly projectRoot?: string;
|
|
32
|
+
}
|
|
33
|
+
/** Result of {@link runDecideWizard}. Secret-free. */
|
|
34
|
+
export interface DecideWizardResult {
|
|
35
|
+
/** Whether settings were saved. */
|
|
36
|
+
readonly configured: boolean;
|
|
37
|
+
/** One-line human summary. */
|
|
38
|
+
readonly summary: string;
|
|
39
|
+
/** The saved settings, when saved. */
|
|
40
|
+
readonly config?: DecideConfigureResult;
|
|
41
|
+
/** The smoke-test answer, when one ran. */
|
|
42
|
+
readonly smoke?: DecideAskResult;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Run the interactive System One setup.
|
|
46
|
+
*
|
|
47
|
+
* @param io - Prompt surface. The key is read with {@link WizardIO.secret}.
|
|
48
|
+
* @param opts - Injectable `fetch`, deadline and smoke runner.
|
|
49
|
+
* @returns Whether settings were saved, a summary and the secret-free results.
|
|
50
|
+
* @throws {DecideCredentialsError} Only when the save itself rejects the settings.
|
|
51
|
+
*/
|
|
52
|
+
export declare function runDecideWizard(io: WizardIO, opts?: DecideWizardOptions): Promise<DecideWizardResult>;
|
|
53
|
+
//# sourceMappingURL=wizard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wizard.d.ts","sourceRoot":"","sources":["../../src/decide/wizard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAIL,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC3B,MAAM,iBAAiB,CAAC;AAGzB,kFAAkF;AAClF,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAM5C,2CAA2C;AAC3C,MAAM,WAAW,mBAAmB;IAClC,gFAAgF;IAChF,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IAC9B,oFAAoF;IACpF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,CAAC;IAChD,wFAAwF;IACxF,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IACjC,mCAAmC;IACnC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,8BAA8B;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,qBAAqB,CAAC;IACxC,2CAA2C;IAC3C,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,CAAC;CAClC;AAkDD;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,QAAQ,EACZ,IAAI,GAAE,mBAAwB,GAC7B,OAAO,CAAC,kBAAkB,CAAC,CAsF7B"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive System One setup: `cleo decide config` on a TTY, and the
|
|
3
|
+
* `system-one` section of `cleo setup`.
|
|
4
|
+
*
|
|
5
|
+
* Steps: pick the provider (layahost first, recommended) → `jev` only: the
|
|
6
|
+
* URL → the API key through {@link WizardIO.secret} (never echoed) → probe
|
|
7
|
+
* `GET /v1/models` → pick the model (layahost defaults to its routing model)
|
|
8
|
+
* → optionally confirm a one-question smoke test → save (which probes again
|
|
9
|
+
* and re-detects capabilities) → run the smoke test when confirmed.
|
|
10
|
+
*
|
|
11
|
+
* All logic lives here; the IO is injected, so tests drive it with a stub and
|
|
12
|
+
* the CLI with readline. Nothing this module returns or prints carries the
|
|
13
|
+
* key: only the masked last-4 preview from the saved summary.
|
|
14
|
+
*
|
|
15
|
+
* @task T12713
|
|
16
|
+
* @epic T12486
|
|
17
|
+
*/
|
|
18
|
+
import { isAllowedDecideBaseUrl } from './credentials.js';
|
|
19
|
+
import { isValidDecisionModelName, listJevModels } from './jev-wire.js';
|
|
20
|
+
import { askDecideDebug, configureDecide, DEFAULT_DECIDE_PROBE_TIMEOUT_MS, } from './operations.js';
|
|
21
|
+
import { listDecisionProviderPresets } from './providers.js';
|
|
22
|
+
/** How many times the wizard re-asks for a URL or model name before giving up. */
|
|
23
|
+
export const DECIDE_WIZARD_MAX_ATTEMPTS = 3;
|
|
24
|
+
/** State the smoke test judges; the question should come back "yes". */
|
|
25
|
+
const SMOKE_STATE = 'CLEO setup check: the System One provider was just configured.';
|
|
26
|
+
const SMOKE_QUESTION = 'The text says a provider was configured.';
|
|
27
|
+
/** Ask for a base URL until it is acceptable, or give up. */
|
|
28
|
+
async function askBaseUrl(io) {
|
|
29
|
+
for (let attempt = 0; attempt < DECIDE_WIZARD_MAX_ATTEMPTS; attempt++) {
|
|
30
|
+
const url = (await io.prompt('Jev-compatible base URL (e.g. https://provider.example):')).trim();
|
|
31
|
+
if (!url)
|
|
32
|
+
return undefined;
|
|
33
|
+
if (isAllowedDecideBaseUrl(url))
|
|
34
|
+
return url;
|
|
35
|
+
io.warn('That URL is not accepted: use an absolute https:// URL (plain http:// only for localhost, 127.0.0.1 or ::1), without user:pass@.');
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
/** Ask for a model name until it is valid, or give up. */
|
|
40
|
+
async function askModelName(io) {
|
|
41
|
+
for (let attempt = 0; attempt < DECIDE_WIZARD_MAX_ATTEMPTS; attempt++) {
|
|
42
|
+
const model = (await io.prompt('Model name (the provider listed none):')).trim();
|
|
43
|
+
if (!model)
|
|
44
|
+
return undefined;
|
|
45
|
+
if (isValidDecisionModelName(model))
|
|
46
|
+
return model;
|
|
47
|
+
io.warn('Model names may contain only letters, digits and . _ : / @ - (1-128 characters).');
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Choose the model: the preset default first (layahost), then the listed
|
|
53
|
+
* models in the provider's order. With one candidate there is nothing to ask.
|
|
54
|
+
*/
|
|
55
|
+
async function chooseModel(io, preset, listed) {
|
|
56
|
+
const fallback = preset.defaultModel;
|
|
57
|
+
const candidates = fallback ? [fallback, ...listed.filter((m) => m !== fallback)] : [...listed];
|
|
58
|
+
if (candidates.length === 0)
|
|
59
|
+
return askModelName(io);
|
|
60
|
+
if (candidates.length === 1) {
|
|
61
|
+
io.info(`Model: ${candidates[0]}`);
|
|
62
|
+
return candidates[0];
|
|
63
|
+
}
|
|
64
|
+
const question = fallback
|
|
65
|
+
? `Which model? (${fallback} is the recommended default)`
|
|
66
|
+
: 'Which model?';
|
|
67
|
+
return io.select(question, candidates);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Run the interactive System One setup.
|
|
71
|
+
*
|
|
72
|
+
* @param io - Prompt surface. The key is read with {@link WizardIO.secret}.
|
|
73
|
+
* @param opts - Injectable `fetch`, deadline and smoke runner.
|
|
74
|
+
* @returns Whether settings were saved, a summary and the secret-free results.
|
|
75
|
+
* @throws {DecideCredentialsError} Only when the save itself rejects the settings.
|
|
76
|
+
*/
|
|
77
|
+
export async function runDecideWizard(io, opts = {}) {
|
|
78
|
+
const presets = listDecisionProviderPresets();
|
|
79
|
+
const picked = await io.select('Which System One provider?', presets.map((p) => p.label));
|
|
80
|
+
const preset = presets.find((p) => p.label === picked) ?? presets[0];
|
|
81
|
+
if (!preset)
|
|
82
|
+
return { configured: false, summary: 'skipped (no provider presets)' };
|
|
83
|
+
let baseUrl = preset.defaultBaseUrl;
|
|
84
|
+
if (preset.requiresUrl || !baseUrl) {
|
|
85
|
+
baseUrl = await askBaseUrl(io);
|
|
86
|
+
if (!baseUrl) {
|
|
87
|
+
io.warn('No valid URL entered; System One left unchanged.');
|
|
88
|
+
return { configured: false, summary: 'skipped (no valid URL)' };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const apiKey = (await io.secret(`${preset.kind} API key (input hidden):`)).trim();
|
|
92
|
+
if (!apiKey) {
|
|
93
|
+
io.warn('No API key entered; System One left unchanged.');
|
|
94
|
+
return { configured: false, summary: 'skipped (empty api key)' };
|
|
95
|
+
}
|
|
96
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_DECIDE_PROBE_TIMEOUT_MS;
|
|
97
|
+
let listed = [];
|
|
98
|
+
try {
|
|
99
|
+
listed = await listJevModels({ baseUrl, apiKey }, AbortSignal.timeout(timeoutMs), {
|
|
100
|
+
fetch: opts.fetch,
|
|
101
|
+
});
|
|
102
|
+
io.info(`Reached ${baseUrl}: ${listed.length} model(s) listed.`);
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
io.warn(`Could not list models at ${baseUrl}: ${err instanceof Error ? err.message : 'probe failed'}`);
|
|
106
|
+
if (!(await io.confirm('Save these settings anyway?', false))) {
|
|
107
|
+
return { configured: false, summary: 'cancelled (provider probe failed)' };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const model = await chooseModel(io, preset, listed);
|
|
111
|
+
if (!model) {
|
|
112
|
+
io.warn('No model chosen; System One left unchanged (the provider rejects requests without one).');
|
|
113
|
+
return { configured: false, summary: 'skipped (no model)' };
|
|
114
|
+
}
|
|
115
|
+
const wantsSmoke = await io.confirm('After saving, ask one test question to confirm it works? (one billed decision)', true);
|
|
116
|
+
const config = await configureDecide({
|
|
117
|
+
provider: preset.kind,
|
|
118
|
+
baseUrl,
|
|
119
|
+
apiKey,
|
|
120
|
+
model,
|
|
121
|
+
fetch: opts.fetch,
|
|
122
|
+
timeoutMs,
|
|
123
|
+
});
|
|
124
|
+
io.info(`Saved ${preset.kind} at ${config.baseUrl ?? baseUrl}: model ${config.model ?? 'none'}, key ${config.keyPreview ?? '…'} (${config.providerState}).`);
|
|
125
|
+
if (config.warning)
|
|
126
|
+
io.warn(config.warning);
|
|
127
|
+
const summary = `${preset.kind} configured (model ${config.model ?? 'none'}, ${config.providerState})`;
|
|
128
|
+
if (!wantsSmoke)
|
|
129
|
+
return { configured: true, summary, config };
|
|
130
|
+
const smoke = await (opts.smoke ??
|
|
131
|
+
(() => askDecideDebug({
|
|
132
|
+
state: SMOKE_STATE,
|
|
133
|
+
question: SMOKE_QUESTION,
|
|
134
|
+
...(opts.projectRoot ? { projectRoot: opts.projectRoot } : {}),
|
|
135
|
+
})))();
|
|
136
|
+
if (smoke.source === 'provider') {
|
|
137
|
+
io.info(`Smoke test answered by the provider in ${smoke.latencyMs} ms.`);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
io.warn(`Smoke test fell back to the heuristic (${smoke.fallbackReason ?? smoke.source}). Check \`cleo decide status\`.`);
|
|
141
|
+
}
|
|
142
|
+
return { configured: true, summary, config, smoke };
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=wizard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wizard.js","sourceRoot":"","sources":["../../src/decide/wizard.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docs-audit.d.ts","sourceRoot":"","sources":["../../src/docs/docs-audit.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;GAiBG;
|
|
1
|
+
{"version":3,"file":"docs-audit.d.ts","sourceRoot":"","sources":["../../src/docs/docs-audit.ts"],"names":[],"mappings":"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"}
|
package/dist/docs/docs-audit.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* @task T11182 (Saga T10516 — docs audit trail)
|
|
19
19
|
*/
|
|
20
20
|
import { createHmac, randomBytes } from 'node:crypto';
|
|
21
|
-
import { appendFileSync, existsSync, mkdirSync, readFileSync, renameSync } from 'node:fs';
|
|
21
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync, } from 'node:fs';
|
|
22
22
|
import { join } from 'node:path';
|
|
23
23
|
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
24
24
|
/** Project-root-relative path to the unified docs audit log. */
|
|
@@ -46,7 +46,6 @@ function getCheckpointSecret(projectRoot) {
|
|
|
46
46
|
const secret = randomBytes(CHECKPOINT_SECRET_BYTES);
|
|
47
47
|
// Atomically write: tmp → rename
|
|
48
48
|
const tmpPath = join(auditDir, '.audit-secret.tmp');
|
|
49
|
-
const { writeFileSync } = require('node:fs');
|
|
50
49
|
writeFileSync(tmpPath, secret.toString('hex'), { encoding: 'utf-8', mode: 0o600 });
|
|
51
50
|
renameSync(tmpPath, secretPath);
|
|
52
51
|
return secret;
|