@iowarp/clio-coder 0.3.3 → 0.3.4
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 +39 -0
- package/CONTRIBUTING.md +1 -1
- package/README.md +3 -3
- package/dist/{acp-P2AQILE2.js → acp-S5R4RR5B.js} +7 -6
- package/dist/{agents-72W3BI7I.js → agents-P6DMMVZY.js} +24 -21
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-5TWEIYDN.js → auth-2XCZLPKS.js} +12 -8
- package/dist/{chunk-GGXXDWE4.js → chunk-22NAGB7X.js} +2 -2
- package/dist/{chunk-2DJ2KNFG.js → chunk-2LZI5CAG.js} +133 -13
- package/dist/{chunk-OAO4GE4M.js → chunk-2TZWSW76.js} +2 -2
- package/dist/{chunk-OOJYHWRB.js → chunk-34475P3I.js} +2 -2
- package/dist/{chunk-4XUGQOHA.js → chunk-35MKKU5R.js} +4 -4
- package/dist/{chunk-LM5TQCJZ.js → chunk-3HZ5RWN2.js} +5 -5
- package/dist/{chunk-AGYYIBLL.js → chunk-3JLKSKD7.js} +2 -2
- package/dist/{chunk-KZWTDYJF.js → chunk-4JUF2NNX.js} +7 -7
- package/dist/{chunk-ZDOOVTXZ.js → chunk-4OC57DA6.js} +27 -4
- package/dist/chunk-5M54SPOL.js +926 -0
- package/dist/{chunk-STBPMHSX.js → chunk-7RXG6QRZ.js} +51 -11
- package/dist/{chunk-X6IAEBZR.js → chunk-A2GZF7DC.js} +5 -5
- package/dist/{chunk-A3CYT5EX.js → chunk-AD2SYQYC.js} +55 -2
- package/dist/chunk-AOCYTWAV.js +449 -0
- package/dist/chunk-BEY543CS.js +258 -0
- package/dist/{chunk-6N5PTWMY.js → chunk-BP4OYD6A.js} +32 -13
- package/dist/chunk-BPGS2WCQ.js +612 -0
- package/dist/{chunk-V6RTAOC2.js → chunk-BRXQQJFP.js} +8 -8
- package/dist/chunk-CFGTUFWB.js +67 -0
- package/dist/{chunk-CBCAPZAA.js → chunk-E25LMLRW.js} +2 -2
- package/dist/{chunk-DUYJ5IO6.js → chunk-EDRHSCIE.js} +4 -4
- package/dist/{chunk-XBXAASKX.js → chunk-EFADSJET.js} +2 -2
- package/dist/{chunk-M6SHUN7Q.js → chunk-FO5ZOVUY.js} +2 -2
- package/dist/chunk-FYYLNIL5.js +313 -0
- package/dist/{chunk-FNTMWMX5.js → chunk-HV5X7OR2.js} +14 -12
- package/dist/{chunk-TZTZS7QK.js → chunk-HXG4IURW.js} +5 -3
- package/dist/{chunk-5UFT4SUX.js → chunk-K6WL7QZT.js} +3 -3
- package/dist/chunk-K7VKOLQQ.js +15 -0
- package/dist/{chunk-BMEMKKIT.js → chunk-KOHPCX4K.js} +2 -2
- package/dist/{chunk-OC7FIQPC.js → chunk-KRPY7NTG.js} +10 -7
- package/dist/chunk-LL4KHSZI.js +22 -0
- package/dist/{chunk-DSELYM6W.js → chunk-MEQ45TQ4.js} +15 -9
- package/dist/{chunk-5UUP6MWO.js → chunk-MV3K5QF2.js} +5 -436
- package/dist/{chunk-6SGHMWE3.js → chunk-N4CZJQRK.js} +5 -5
- package/dist/{chunk-TZK7PACC.js → chunk-NILBFAPG.js} +14 -8
- package/dist/chunk-OZNBF4L3.js +23 -0
- package/dist/{verify-375KUB3Y.js → chunk-PCZJO5TI.js} +127 -42
- package/dist/chunk-QQK64KLB.js +1360 -0
- package/dist/{chunk-SRDMMSEP.js → chunk-QQL5RT5M.js} +979 -1619
- package/dist/{chunk-LZSJBIVT.js → chunk-QWU7ZBO7.js} +70 -720
- package/dist/{chunk-2TLUCQVG.js → chunk-RD5U66HV.js} +3 -3
- package/dist/{chunk-OKGUZO2U.js → chunk-SPULKLCF.js} +4 -3
- package/dist/{chunk-OQ33BKR3.js → chunk-TTNYS3EA.js} +3 -60
- package/dist/chunk-TW3WDMVS.js +677 -0
- package/dist/chunk-TZSKNMZG.js +434 -0
- package/dist/{chunk-7MNJORFF.js → chunk-UL3WSD3F.js} +6 -1
- package/dist/{chunk-PIWWS5BL.js → chunk-UZHIZC5S.js} +7 -7
- package/dist/{chunk-UFIIWP2H.js → chunk-VAWWTKDP.js} +8 -8
- package/dist/{chunk-COU2UHX6.js → chunk-VEZEGCGW.js} +170 -2
- package/dist/{chunk-LW6DSM3M.js → chunk-VMNQ6OZA.js} +98 -202
- package/dist/chunk-VSNATDE6.js +122 -0
- package/dist/chunk-W6GROXXM.js +69 -0
- package/dist/chunk-WPQLXFOZ.js +375 -0
- package/dist/{chunk-ORBHGJC5.js → chunk-WR67VIZY.js} +3 -3
- package/dist/{chunk-PAJK6MAQ.js → chunk-X6COSD2O.js} +5 -5
- package/dist/chunk-ZGVHUX3M.js +66 -0
- package/dist/{chunk-LWLEKMDQ.js → chunk-ZYKPLLNQ.js} +510 -547
- package/dist/cli/index.js +27 -23
- package/dist/{clio-JOU4FXVA.js → clio-J5JIOIDS.js} +7 -6
- package/dist/{code-nav-7AX6FYE6.js → code-nav-AXCXSBHX.js} +5 -3
- package/dist/{config-XCDVKR23.js → config-OEBMIN2U.js} +37 -27
- package/dist/{configure-4GAP54ZW.js → configure-PUQOSIXQ.js} +16 -13
- package/dist/{context-5VKGUVJJ.js → context-EKDCKUUZ.js} +82 -7
- package/dist/{context-4UOGGLQ5.js → context-MGSE4Z2T.js} +33 -23
- package/dist/{context-77FM5DV5.js → context-URSXPBCK.js} +17 -9
- package/dist/{context-clear-XXJRLCJJ.js → context-clear-KDAJRNUK.js} +33 -23
- package/dist/context-working-set-SBKMPPI2.js +1552 -0
- package/dist/{dispatch-runner-QPRDDBDX.js → dispatch-runner-MSWN72NK.js} +43 -29
- package/dist/{doctor-HR46URBJ.js → doctor-7BSE27PJ.js} +10 -10
- package/dist/{eval-XSSNATB4.js → eval-IZGDOO4H.js} +9 -8
- package/dist/{evidence-6HG2PY2B.js → evidence-SR7WXB5B.js} +51 -23
- package/dist/{evolve-K7YU3NCY.js → evolve-K7VE2CBX.js} +30 -20
- package/dist/{fleet-VY3HHKN6.js → fleet-7XMJNQNF.js} +48 -38
- package/dist/{fleet-preflight-DDN536IT.js → fleet-preflight-AQNAH644.js} +3 -3
- package/dist/{init-JYGXI3FK.js → init-JGNPAYXT.js} +41 -31
- package/dist/{memory-WFZMGYHX.js → memory-4ALKDJ4Q.js} +32 -22
- package/dist/{models-I5QWSEOM.js → models-ZMMLFJNN.js} +22 -19
- package/dist/{monitor-GE4ID3IA.js → monitor-2F3T5KHP.js} +55 -43
- package/dist/{orchestrator-EM5MC3HM.js → orchestrator-ORHT43JB.js} +572 -388
- package/dist/{reset-L2FQEE3E.js → reset-NXGTYNUO.js} +4 -3
- package/dist/{run-ZU3QMZPZ.js → run-RF4WJGMT.js} +51 -41
- package/dist/{share-S5BZQC5I.js → share-UT3W6E4M.js} +5 -4
- package/dist/{skills-X5VXCRNQ.js → skills-PSACKC5Q.js} +2 -2
- package/dist/{skills-eval-WKIHWTHR.js → skills-eval-WJSI55RZ.js} +34 -24
- package/dist/{targets-SNCPI2NR.js → targets-PIIRAOYS.js} +23 -20
- package/dist/{terminal-lease-BNAHVHBS.js → terminal-lease-ULWXWNVY.js} +4 -3
- package/dist/{upgrade-JQHHPQ4K.js → upgrade-346TZ6AV.js} +18 -17
- package/dist/{usage-OR4O5SMZ.js → usage-6KKXR32N.js} +34 -24
- package/dist/verifiers-4UUM6TEE.js +1214 -0
- package/dist/verify-X5HDROLA.js +25 -0
- package/dist/{wiki-generate-UEXP2ARI.js → wiki-generate-7STOCIFZ.js} +42 -31
- package/dist/worker/entry.js +33 -24
- package/docs/README.md +7 -6
- package/docs/acp.md +1 -1
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +2 -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 +53 -21
- package/docs/config-knobs-audit.md +1 -2
- package/docs/configuration-and-targets.md +15 -1
- package/docs/context-engine.md +64 -12
- package/docs/context-working-set.md +194 -0
- package/docs/development-pipeline.md +1 -1
- package/docs/documentation-coverage.md +5 -5
- package/docs/documentation-guide.md +6 -5
- package/docs/environment-variables.md +2 -1
- package/docs/eval-runner.md +1 -1
- package/docs/evals-internal.md +14 -1
- package/docs/evidence-and-memory.md +74 -2
- 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 +22 -7
- package/docs/glossary.md +21 -1
- package/docs/installation-and-lifecycle.md +2 -2
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +7 -9
- package/docs/observability.md +4 -4
- package/docs/proactive-memory.md +1 -1
- package/docs/prompt-envelope-and-tools.md +4 -4
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/release-cut-checklist.md +31 -31
- package/docs/safety-model.md +23 -4
- package/docs/scientific-validation.md +21 -3
- package/docs/session-lifecycle.md +3 -3
- package/docs/skills-marketplace.md +1 -1
- package/docs/tool-usage.md +79 -12
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +1 -1
- package/docs/tui-design.md +1 -1
- package/docs/worker-dispatch-mechanics.md +11 -1
- package/package.json +8 -11
- package/skills/meta/clio-test/SKILL.md +20 -17
- package/skills/meta/clio-test/evals.md +3 -3
- package/skills/meta/clio-test/references/harness.md +35 -6
- package/skills/meta/clio-test/references/test-map.md +20 -10
- package/skills/registry.yaml +2 -2
- package/skills/skill-marketplace.json +1 -1
- package/src/cli/context-working-set.ts +513 -0
- package/src/cli/context.ts +8 -0
- package/src/cli/evidence.ts +20 -2
- package/src/cli/index.ts +4 -0
- package/src/cli/verifiers.ts +325 -0
- package/src/core/bash-exec.ts +39 -14
- package/src/core/bus-events.ts +19 -4
- package/src/core/config.ts +54 -0
- package/src/core/defaults.ts +50 -3
- package/src/core/verification-scripts.ts +6 -0
- package/src/domains/agents/builtins/verifier.md +3 -0
- package/src/domains/config/classify.ts +1 -0
- package/src/domains/context/working-set/contract.ts +161 -0
- package/src/domains/context/working-set/defaults.ts +28 -0
- package/src/domains/context/working-set/engine.ts +203 -0
- package/src/domains/context/working-set/fold.ts +62 -0
- package/src/domains/context/working-set/horizon.ts +38 -0
- package/src/domains/context/working-set/marker.ts +103 -0
- package/src/domains/context/working-set/path-index.ts +436 -0
- package/src/domains/context/working-set/payload.ts +152 -0
- package/src/domains/context/working-set/policies/age-horizon.ts +55 -0
- package/src/domains/context/working-set/policies/index.ts +21 -0
- package/src/domains/context/working-set/policies/structural.ts +160 -0
- package/src/domains/context/working-set/project.ts +132 -0
- package/src/domains/context/working-set/protect.ts +109 -0
- package/src/domains/context/working-set/recall.ts +177 -0
- package/src/domains/context/working-set/replay/controls.ts +112 -0
- package/src/domains/context/working-set/replay/load-clio.ts +199 -0
- package/src/domains/context/working-set/replay/metrics.ts +185 -0
- package/src/domains/context/working-set/replay/reference-graph.ts +79 -0
- package/src/domains/context/working-set/replay/report.ts +139 -0
- package/src/domains/context/working-set/replay/runner.ts +325 -0
- package/src/domains/context/working-set/replay/synthetic.ts +422 -0
- package/src/domains/context/working-set/replay/trace.ts +21 -0
- package/src/domains/context/working-set/visible.ts +54 -0
- package/src/domains/evidence/build.ts +112 -45
- package/src/domains/evidence/eval.ts +24 -7
- package/src/domains/evidence/index.ts +53 -0
- package/src/domains/evidence/ordering.ts +12 -0
- package/src/domains/evidence/run-trust.ts +221 -0
- package/src/domains/evidence/store.ts +46 -6
- package/src/domains/evidence/trust-status.ts +854 -0
- package/src/domains/evidence/types.ts +26 -0
- package/src/domains/middleware/memory-intervention.ts +3 -0
- package/src/domains/middleware/stalled-turn.ts +165 -4
- package/src/domains/safety/autonomy.ts +1 -1
- package/src/domains/safety/default-path-policy.ts +8 -0
- package/src/domains/safety/finish-contract.ts +4 -3
- package/src/domains/safety/policy-engine.ts +48 -6
- package/src/domains/session/compaction/compact.ts +23 -1
- package/src/domains/session/compaction/cut-point.ts +2 -0
- package/src/domains/session/compaction/tokens.ts +16 -1
- package/src/domains/session/context-ledger.ts +2 -0
- package/src/domains/session/entries.ts +107 -1
- package/src/domains/session/manager.ts +9 -2
- package/src/domains/session/migrations/index.ts +22 -3
- package/src/engine/acp/server.ts +3 -0
- package/src/engine/agent.ts +18 -1
- package/src/engine/session.ts +9 -3
- package/src/entry/orchestrator.ts +16 -4
- package/src/interactive/chat-loop-messages.ts +18 -6
- package/src/interactive/chat-panel.ts +17 -1
- package/src/interactive/chat-renderer.ts +30 -21
- package/src/interactive/context-meter.ts +10 -0
- package/src/interactive/context-overlay.ts +81 -6
- package/src/interactive/context-recall-command.ts +110 -0
- package/src/interactive/interactive-slash-runtime.ts +37 -1
- package/src/interactive/model-session-replay.ts +21 -0
- package/src/interactive/overlay-general-openers.ts +6 -0
- package/src/interactive/overlay-session-lifecycle.ts +8 -4
- package/src/interactive/renderers/tool-execution.ts +18 -2
- package/src/interactive/session-transcript.ts +2 -2
- package/src/interactive/slash-commands.ts +29 -2
- package/src/interactive/turn-context.ts +238 -88
- package/src/interactive/turn-middleware.ts +6 -6
- package/src/tools/agent-tools.ts +11 -4
- package/src/tools/bash.ts +144 -82
- package/src/tools/builtin-tool-catalog.ts +11 -5
- package/src/tools/context/index.ts +105 -3
- package/src/tools/context/surface.ts +3 -2
- package/src/tools/core-bootstrap.ts +21 -0
- package/src/tools/dispatch-runner.ts +9 -7
- package/src/tools/monitor.ts +28 -20
- package/src/tools/registry.ts +59 -7
- package/src/tools/result-disposition.ts +550 -0
- package/src/tools/result-shaping.ts +262 -19
- package/src/tools/safe-exec.ts +2 -0
- package/src/tools/verify/authoring.ts +1119 -0
- package/src/tools/verify/catalog.ts +346 -0
- package/src/tools/verify/index.ts +13 -3
- package/src/tools/verify/scripts.ts +135 -37
- package/src/tools/verify/surface.ts +9 -5
- package/src/tools/worker-evidence.ts +35 -12
- package/dist/chunk-J7CWMCQD.js +0 -255
- package/dist/chunk-T6YILFSB.js +0 -80
- package/dist/chunk-VAKQQHWR.js +0 -434
- package/dist/chunk-VPAYEGVX.js +0 -184
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
4
|
+
import { assertSafeId } from "../core/safe-id.js";
|
|
5
|
+
import { clioStatePath } from "../core/xdg.js";
|
|
6
|
+
import { DEFAULT_WORKING_SET_SETTINGS } from "../domains/context/working-set/defaults.js";
|
|
7
|
+
import { foldWorkingSet } from "../domains/context/working-set/fold.js";
|
|
8
|
+
import { buildPathIndex } from "../domains/context/working-set/path-index.js";
|
|
9
|
+
import { resolveWorkingSetPolicy } from "../domains/context/working-set/policies/index.js";
|
|
10
|
+
import { makeOraclePolicy, makeRandomPolicy, nonePolicy } from "../domains/context/working-set/replay/controls.js";
|
|
11
|
+
import { loadClioTraces, type ReplayLoadCascade } from "../domains/context/working-set/replay/load-clio.js";
|
|
12
|
+
import { aggregateReplayMetrics, type ReplayMeasurement } from "../domains/context/working-set/replay/metrics.js";
|
|
13
|
+
import { buildReferenceGraph, type ReferenceGraph } from "../domains/context/working-set/replay/reference-graph.js";
|
|
14
|
+
import {
|
|
15
|
+
type ReplayPolicyResult,
|
|
16
|
+
type ReplayReportInput,
|
|
17
|
+
renderReplayJson,
|
|
18
|
+
renderReplayMarkdown,
|
|
19
|
+
} from "../domains/context/working-set/replay/report.js";
|
|
20
|
+
import { replayTrace } from "../domains/context/working-set/replay/runner.js";
|
|
21
|
+
import { generateSyntheticCorpora, SYNTHETIC_CORPORA } from "../domains/context/working-set/replay/synthetic.js";
|
|
22
|
+
import type { Trace } from "../domains/context/working-set/replay/trace.js";
|
|
23
|
+
import { parseSessionEntries } from "../domains/session/archive-readers.js";
|
|
24
|
+
import { DEFAULT_KEEP_RECENT_TOKENS } from "../domains/session/compaction/defaults.js";
|
|
25
|
+
import { filterEntriesToActivePath } from "../domains/session/tree/active-path.js";
|
|
26
|
+
|
|
27
|
+
const REPLAY_HELP = `Usage:
|
|
28
|
+
clio-coder context replay (--sessions <path>... | --synthetic <corpus>...) [options]
|
|
29
|
+
|
|
30
|
+
Options:
|
|
31
|
+
--sessions <path>... Clio session directories, sessions roots, or ledger JSONL files
|
|
32
|
+
--synthetic <ids> comma-separated procedural corpora: ${SYNTHETIC_CORPORA.map((spec) => spec.id).join(",")}
|
|
33
|
+
--policies <ids> comma-separated none,random,age-horizon,structural-v1,oracle
|
|
34
|
+
--budgets <tokens> comma-separated budgets (default: 16000,32000,64000)
|
|
35
|
+
--threshold <ratio> pressure threshold (default: 0.8)
|
|
36
|
+
--target <ratio> post-eviction pressure target (default: 0.6)
|
|
37
|
+
--protect-last-turns <n>
|
|
38
|
+
protected recent turns (default: ${DEFAULT_WORKING_SET_SETTINGS.protectLastTurns})
|
|
39
|
+
--min-evictable-tokens <n>
|
|
40
|
+
minimum tool-result body tokens (default: ${DEFAULT_WORKING_SET_SETTINGS.minEvictableTokens})
|
|
41
|
+
--seed <integer> deterministic random-policy seed (default: 0)
|
|
42
|
+
--no-filter include every readable transcript
|
|
43
|
+
--json <path> write the stable JSON report
|
|
44
|
+
--md <path> write Markdown instead of printing it
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
const WORKING_SET_HELP = `Usage:
|
|
48
|
+
clio-coder context working-set --session <id|path>
|
|
49
|
+
|
|
50
|
+
Print the durable working-set fold and path-index summary for one Clio session.
|
|
51
|
+
`;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Conservative stand-in for replay's summary paraphrase. Five recorded local
|
|
55
|
+
* compactions price at 405, 405, 968, 981, and 1,124 tokens; 1,500 sits above
|
|
56
|
+
* that observed range. The replay README records the sample and sensitivity.
|
|
57
|
+
*/
|
|
58
|
+
const REPLAY_SUMMARY_TOKENS = 1_500;
|
|
59
|
+
|
|
60
|
+
const POLICY_IDS = ["none", "random", "age-horizon", "structural-v1", "oracle"] as const;
|
|
61
|
+
type ReplayPolicyId = (typeof POLICY_IDS)[number];
|
|
62
|
+
|
|
63
|
+
class CliUsageError extends Error {}
|
|
64
|
+
|
|
65
|
+
interface ReplayArgs {
|
|
66
|
+
sessions: string[];
|
|
67
|
+
policies: ReplayPolicyId[];
|
|
68
|
+
budgets: number[];
|
|
69
|
+
threshold: number;
|
|
70
|
+
target: number;
|
|
71
|
+
protectLastTurns: number;
|
|
72
|
+
minEvictableTokens: number;
|
|
73
|
+
seed: number;
|
|
74
|
+
synthetic: string[];
|
|
75
|
+
noFilter: boolean;
|
|
76
|
+
jsonPath?: string;
|
|
77
|
+
markdownPath?: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function commaValues(value: string, flag: string): string[] {
|
|
81
|
+
const values = value
|
|
82
|
+
.split(",")
|
|
83
|
+
.map((entry) => entry.trim())
|
|
84
|
+
.filter((entry) => entry.length > 0);
|
|
85
|
+
if (values.length === 0) throw new CliUsageError(`${flag} requires at least one value`);
|
|
86
|
+
return [...new Set(values)];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function numberValue(value: string, flag: string): number {
|
|
90
|
+
const parsed = Number(value);
|
|
91
|
+
if (!Number.isFinite(parsed)) throw new CliUsageError(`${flag} requires a finite number`);
|
|
92
|
+
return parsed;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function requiredValue(args: ReadonlyArray<string>, index: number, flag: string): string {
|
|
96
|
+
const value = args[index + 1];
|
|
97
|
+
if (value === undefined || value.startsWith("--")) throw new CliUsageError(`${flag} requires a value`);
|
|
98
|
+
return value;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function policyResolves(id: ReplayPolicyId): boolean {
|
|
102
|
+
if (id === "none" || id === "random" || id === "oracle") return true;
|
|
103
|
+
try {
|
|
104
|
+
resolveWorkingSetPolicy(id);
|
|
105
|
+
return true;
|
|
106
|
+
} catch {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function defaultPolicies(): ReplayPolicyId[] {
|
|
112
|
+
return POLICY_IDS.filter(policyResolves);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function parseReplayArgs(args: ReadonlyArray<string>): ReplayArgs {
|
|
116
|
+
const parsed: ReplayArgs = {
|
|
117
|
+
sessions: [],
|
|
118
|
+
policies: defaultPolicies(),
|
|
119
|
+
budgets: [16_000, 32_000, 64_000],
|
|
120
|
+
threshold: 0.8,
|
|
121
|
+
target: 0.6,
|
|
122
|
+
protectLastTurns: DEFAULT_WORKING_SET_SETTINGS.protectLastTurns,
|
|
123
|
+
minEvictableTokens: DEFAULT_WORKING_SET_SETTINGS.minEvictableTokens,
|
|
124
|
+
seed: 0,
|
|
125
|
+
synthetic: [],
|
|
126
|
+
noFilter: false,
|
|
127
|
+
};
|
|
128
|
+
let policiesExplicit = false;
|
|
129
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
130
|
+
const arg = args[index];
|
|
131
|
+
if (arg === "--no-filter") {
|
|
132
|
+
parsed.noFilter = true;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (arg === "--sessions") {
|
|
136
|
+
let consumed = 0;
|
|
137
|
+
while (index + 1 < args.length && !args[index + 1]?.startsWith("--")) {
|
|
138
|
+
parsed.sessions.push(args[index + 1] as string);
|
|
139
|
+
index += 1;
|
|
140
|
+
consumed += 1;
|
|
141
|
+
}
|
|
142
|
+
if (consumed === 0) throw new CliUsageError("--sessions requires at least one path");
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (
|
|
146
|
+
arg === "--policies" ||
|
|
147
|
+
arg === "--budgets" ||
|
|
148
|
+
arg === "--synthetic" ||
|
|
149
|
+
arg === "--threshold" ||
|
|
150
|
+
arg === "--target" ||
|
|
151
|
+
arg === "--protect-last-turns" ||
|
|
152
|
+
arg === "--min-evictable-tokens" ||
|
|
153
|
+
arg === "--seed"
|
|
154
|
+
) {
|
|
155
|
+
const value = requiredValue(args, index, arg);
|
|
156
|
+
index += 1;
|
|
157
|
+
if (arg === "--policies") {
|
|
158
|
+
const values = commaValues(value, arg);
|
|
159
|
+
const unknown = values.filter((entry) => !(POLICY_IDS as ReadonlyArray<string>).includes(entry));
|
|
160
|
+
if (unknown.length > 0) throw new CliUsageError(`unknown replay policy: ${unknown.join(", ")}`);
|
|
161
|
+
parsed.policies = values as ReplayPolicyId[];
|
|
162
|
+
policiesExplicit = true;
|
|
163
|
+
} else if (arg === "--budgets") {
|
|
164
|
+
parsed.budgets = commaValues(value, arg).map((entry) => {
|
|
165
|
+
const budget = numberValue(entry, arg);
|
|
166
|
+
if (!Number.isInteger(budget) || budget <= 0) {
|
|
167
|
+
throw new CliUsageError("--budgets values must be positive integers");
|
|
168
|
+
}
|
|
169
|
+
return budget;
|
|
170
|
+
});
|
|
171
|
+
} else if (arg === "--synthetic") {
|
|
172
|
+
const values = commaValues(value, arg);
|
|
173
|
+
const known = SYNTHETIC_CORPORA.map((spec) => spec.id);
|
|
174
|
+
const unknown = values.filter((entry) => !known.includes(entry));
|
|
175
|
+
if (unknown.length > 0) throw new CliUsageError(`unknown synthetic corpus: ${unknown.join(", ")}`);
|
|
176
|
+
parsed.synthetic = values;
|
|
177
|
+
} else if (arg === "--threshold") {
|
|
178
|
+
parsed.threshold = numberValue(value, arg);
|
|
179
|
+
if (parsed.threshold <= 0 || parsed.threshold > 1) {
|
|
180
|
+
throw new CliUsageError("--threshold must be greater than 0 and at most 1");
|
|
181
|
+
}
|
|
182
|
+
} else if (arg === "--target") {
|
|
183
|
+
parsed.target = numberValue(value, arg);
|
|
184
|
+
if (parsed.target <= 0 || parsed.target >= 1) {
|
|
185
|
+
throw new CliUsageError("--target must be greater than 0 and less than 1");
|
|
186
|
+
}
|
|
187
|
+
} else if (arg === "--protect-last-turns") {
|
|
188
|
+
parsed.protectLastTurns = numberValue(value, arg);
|
|
189
|
+
if (!Number.isInteger(parsed.protectLastTurns) || parsed.protectLastTurns < 1) {
|
|
190
|
+
throw new CliUsageError("--protect-last-turns must be an integer at least 1");
|
|
191
|
+
}
|
|
192
|
+
} else if (arg === "--min-evictable-tokens") {
|
|
193
|
+
parsed.minEvictableTokens = numberValue(value, arg);
|
|
194
|
+
if (!Number.isInteger(parsed.minEvictableTokens) || parsed.minEvictableTokens < 0) {
|
|
195
|
+
throw new CliUsageError("--min-evictable-tokens must be a non-negative integer");
|
|
196
|
+
}
|
|
197
|
+
} else {
|
|
198
|
+
parsed.seed = numberValue(value, arg);
|
|
199
|
+
if (!Number.isInteger(parsed.seed)) throw new CliUsageError("--seed must be an integer");
|
|
200
|
+
}
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (arg === "--json" || arg === "--md") {
|
|
204
|
+
const value = requiredValue(args, index, arg);
|
|
205
|
+
index += 1;
|
|
206
|
+
if (arg === "--json") parsed.jsonPath = value;
|
|
207
|
+
else parsed.markdownPath = value;
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
throw new CliUsageError(`unknown flag ${arg}`);
|
|
211
|
+
}
|
|
212
|
+
if (parsed.sessions.length === 0 && parsed.synthetic.length === 0) {
|
|
213
|
+
throw new CliUsageError("--sessions or --synthetic is required");
|
|
214
|
+
}
|
|
215
|
+
if (parsed.target >= parsed.threshold) throw new CliUsageError("--target must be less than --threshold");
|
|
216
|
+
if (policiesExplicit) {
|
|
217
|
+
const unavailable = parsed.policies.filter((id) => !policyResolves(id));
|
|
218
|
+
if (unavailable.length > 0) {
|
|
219
|
+
throw new CliUsageError(`replay policy is not available in this build: ${unavailable.join(", ")}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return parsed;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function policyForTrace(id: ReplayPolicyId, graph: ReferenceGraph, seed: number) {
|
|
226
|
+
if (id === "none") return nonePolicy;
|
|
227
|
+
if (id === "random") return makeRandomPolicy(seed);
|
|
228
|
+
if (id === "oracle") return makeOraclePolicy(graph);
|
|
229
|
+
return resolveWorkingSetPolicy(id);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function gitSha(): string | null {
|
|
233
|
+
try {
|
|
234
|
+
return execFileSync("git", ["rev-parse", "HEAD"], {
|
|
235
|
+
cwd: process.cwd(),
|
|
236
|
+
encoding: "utf8",
|
|
237
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
238
|
+
}).trim();
|
|
239
|
+
} catch {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function exactCommandLine(): string[] {
|
|
245
|
+
return [process.execPath, ...process.execArgv, ...process.argv.slice(1)];
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async function writeOutput(path: string, contents: string): Promise<string> {
|
|
249
|
+
const output = resolve(path);
|
|
250
|
+
await mkdir(dirname(output), { recursive: true });
|
|
251
|
+
await writeFile(output, contents, "utf8");
|
|
252
|
+
return output;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function cascadeLine(cascade: ReplayLoadCascade): string {
|
|
256
|
+
const filtered = Object.entries(cascade.filtered)
|
|
257
|
+
.map(([stage, count]) => `${stage}=${count}`)
|
|
258
|
+
.join(" ");
|
|
259
|
+
return `cascade found=${cascade.found} unreadable=${cascade.unreadable} ${filtered} kept=${cascade.kept}`;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export async function runContextReplayCommand(args: string[]): Promise<number> {
|
|
263
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
264
|
+
process.stdout.write(REPLAY_HELP);
|
|
265
|
+
return 0;
|
|
266
|
+
}
|
|
267
|
+
let parsed: ReplayArgs;
|
|
268
|
+
try {
|
|
269
|
+
parsed = parseReplayArgs(args);
|
|
270
|
+
} catch (error) {
|
|
271
|
+
process.stderr.write(
|
|
272
|
+
`clio-coder context replay: ${error instanceof Error ? error.message : String(error)}\n${REPLAY_HELP}`,
|
|
273
|
+
);
|
|
274
|
+
return 2;
|
|
275
|
+
}
|
|
276
|
+
try {
|
|
277
|
+
const ledgers = await loadClioTraces(parsed.sessions, { filter: parsed.noFilter ? false : {} });
|
|
278
|
+
const synthetic = generateSyntheticCorpora(parsed.synthetic);
|
|
279
|
+
const loaded = {
|
|
280
|
+
traces: [...ledgers.traces, ...synthetic.traces],
|
|
281
|
+
cascade: {
|
|
282
|
+
found: ledgers.cascade.found + synthetic.cascade.found,
|
|
283
|
+
unreadable: ledgers.cascade.unreadable,
|
|
284
|
+
filtered: ledgers.cascade.filtered,
|
|
285
|
+
kept: ledgers.cascade.kept + synthetic.cascade.kept,
|
|
286
|
+
},
|
|
287
|
+
};
|
|
288
|
+
if (loaded.traces.length === 0) {
|
|
289
|
+
process.stderr.write(`clio-coder context replay: no traces to replay (${cascadeLine(loaded.cascade)})\n`);
|
|
290
|
+
return 1;
|
|
291
|
+
}
|
|
292
|
+
const indexed = loaded.traces.map((trace) => {
|
|
293
|
+
const index = buildPathIndex(trace.entries, { cwd: trace.cwd });
|
|
294
|
+
return { trace, index, graph: buildReferenceGraph(trace, index) };
|
|
295
|
+
});
|
|
296
|
+
const settings = {
|
|
297
|
+
...DEFAULT_WORKING_SET_SETTINGS,
|
|
298
|
+
target: parsed.target,
|
|
299
|
+
protectLastTurns: parsed.protectLastTurns,
|
|
300
|
+
minEvictableTokens: parsed.minEvictableTokens,
|
|
301
|
+
};
|
|
302
|
+
const results: ReplayPolicyResult[] = [];
|
|
303
|
+
for (const budgetTokens of parsed.budgets) {
|
|
304
|
+
for (const policyId of parsed.policies) {
|
|
305
|
+
const measurements: ReplayMeasurement[] = indexed.map(({ trace, index, graph }) => ({
|
|
306
|
+
trace,
|
|
307
|
+
index,
|
|
308
|
+
graph,
|
|
309
|
+
replay: replayTrace(trace, policyForTrace(policyId, graph, parsed.seed), {
|
|
310
|
+
policyId,
|
|
311
|
+
budgetTokens,
|
|
312
|
+
threshold: parsed.threshold,
|
|
313
|
+
target: parsed.target,
|
|
314
|
+
settings,
|
|
315
|
+
seed: parsed.seed,
|
|
316
|
+
summaries: { keepRecentTokens: DEFAULT_KEEP_RECENT_TOKENS, summaryTokens: REPLAY_SUMMARY_TOKENS },
|
|
317
|
+
}),
|
|
318
|
+
}));
|
|
319
|
+
results.push({ budgetTokens, policyId, metrics: aggregateReplayMetrics(measurements) });
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
const report: ReplayReportInput = {
|
|
323
|
+
config: {
|
|
324
|
+
policies: parsed.policies,
|
|
325
|
+
budgets: parsed.budgets,
|
|
326
|
+
threshold: parsed.threshold,
|
|
327
|
+
target: parsed.target,
|
|
328
|
+
seed: parsed.seed,
|
|
329
|
+
corpus: [...(parsed.sessions.length > 0 ? ["ledgers"] : []), ...parsed.synthetic],
|
|
330
|
+
filter: parsed.noFilter ? "none" : "default",
|
|
331
|
+
settings,
|
|
332
|
+
},
|
|
333
|
+
cascade: loaded.cascade,
|
|
334
|
+
results,
|
|
335
|
+
gitSha: gitSha(),
|
|
336
|
+
commandLine: exactCommandLine(),
|
|
337
|
+
};
|
|
338
|
+
const markdown = renderReplayMarkdown(report);
|
|
339
|
+
if (parsed.markdownPath === undefined) process.stdout.write(markdown);
|
|
340
|
+
else {
|
|
341
|
+
const path = await writeOutput(parsed.markdownPath, markdown);
|
|
342
|
+
process.stdout.write(`${cascadeLine(loaded.cascade)}\nmarkdown ${path}\n`);
|
|
343
|
+
}
|
|
344
|
+
if (parsed.jsonPath !== undefined) {
|
|
345
|
+
const path = await writeOutput(parsed.jsonPath, renderReplayJson(report));
|
|
346
|
+
process.stdout.write(`json ${path}\n`);
|
|
347
|
+
}
|
|
348
|
+
return 0;
|
|
349
|
+
} catch (error) {
|
|
350
|
+
process.stderr.write(`clio-coder context replay failed: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
351
|
+
return 1;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
async function sessionPath(value: string): Promise<string> {
|
|
356
|
+
const candidate = resolve(value);
|
|
357
|
+
try {
|
|
358
|
+
const facts = await stat(candidate);
|
|
359
|
+
if (facts.isDirectory()) return join(candidate, "current.jsonl");
|
|
360
|
+
if (facts.isFile()) return candidate;
|
|
361
|
+
} catch {
|
|
362
|
+
// A non-path value is resolved as a validated session id below.
|
|
363
|
+
}
|
|
364
|
+
try {
|
|
365
|
+
assertSafeId(value, "session");
|
|
366
|
+
} catch (error) {
|
|
367
|
+
throw new CliUsageError(error instanceof Error ? error.message : String(error));
|
|
368
|
+
}
|
|
369
|
+
const sessionsRoot = join(clioStatePath(), "sessions");
|
|
370
|
+
let cwdHashes: string[];
|
|
371
|
+
try {
|
|
372
|
+
cwdHashes = await readdir(sessionsRoot);
|
|
373
|
+
} catch {
|
|
374
|
+
throw new Error(`session not found: ${value}`);
|
|
375
|
+
}
|
|
376
|
+
for (const cwdHash of cwdHashes.sort()) {
|
|
377
|
+
const current = join(sessionsRoot, cwdHash, value, "current.jsonl");
|
|
378
|
+
try {
|
|
379
|
+
if ((await stat(current)).isFile()) return current;
|
|
380
|
+
} catch {
|
|
381
|
+
// Continue across repositories until the id is found.
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
throw new Error(`session not found: ${value}`);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
async function pinnedLeafForSession(source: string): Promise<string | undefined> {
|
|
388
|
+
try {
|
|
389
|
+
const raw = await readFile(join(dirname(source), "meta.json"), "utf8");
|
|
390
|
+
const value = JSON.parse(raw) as unknown;
|
|
391
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined;
|
|
392
|
+
const pinned = (value as Record<string, unknown>).pinnedLeafTurnId;
|
|
393
|
+
return typeof pinned === "string" && pinned.length > 0 ? pinned : undefined;
|
|
394
|
+
} catch {
|
|
395
|
+
return undefined;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
async function sessionCwdForSession(source: string): Promise<string | null> {
|
|
400
|
+
try {
|
|
401
|
+
const raw = await readFile(join(dirname(source), "meta.json"), "utf8");
|
|
402
|
+
const value = JSON.parse(raw) as unknown;
|
|
403
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
|
|
404
|
+
const cwd = (value as Record<string, unknown>).cwd;
|
|
405
|
+
return typeof cwd === "string" && cwd.length > 0 ? cwd : null;
|
|
406
|
+
} catch {
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function formatWorkingSet(trace: Trace): string {
|
|
412
|
+
const view = foldWorkingSet(trace.entries);
|
|
413
|
+
const index = buildPathIndex(trace.entries, { cwd: trace.cwd });
|
|
414
|
+
const graph = buildReferenceGraph(trace, index);
|
|
415
|
+
const evictedTokens = [...view.evicted.values()].reduce((sum, state) => sum + state.tokensFreed, 0);
|
|
416
|
+
const churn = view.itemsEvicted === 0 ? "n/a" : (view.recalls / view.itemsEvicted).toFixed(3);
|
|
417
|
+
const opCounts = new Map<string, number>();
|
|
418
|
+
for (const observation of index.observations) {
|
|
419
|
+
opCounts.set(observation.op, (opCounts.get(observation.op) ?? 0) + 1);
|
|
420
|
+
}
|
|
421
|
+
const rewrittenPaths = new Set<string>();
|
|
422
|
+
for (const edge of graph.edges) {
|
|
423
|
+
if (edge.kind !== "file_rewrite") continue;
|
|
424
|
+
const path = index.byRef.get(edge.from)?.path;
|
|
425
|
+
if (path) rewrittenPaths.add(path);
|
|
426
|
+
}
|
|
427
|
+
const lines = [
|
|
428
|
+
`session: ${trace.id}`,
|
|
429
|
+
`source: ${trace.source}`,
|
|
430
|
+
"working set:",
|
|
431
|
+
` policy: ${view.lastPolicyId ?? "none"}`,
|
|
432
|
+
` eviction events: ${view.evictionEvents}`,
|
|
433
|
+
` evicted refs: ${view.evicted.size}`,
|
|
434
|
+
` items evicted: ${view.itemsEvicted}`,
|
|
435
|
+
` evicted tokens: ${evictedTokens}`,
|
|
436
|
+
` recalls: ${view.recalls}`,
|
|
437
|
+
` churn: ${churn}`,
|
|
438
|
+
" refs:",
|
|
439
|
+
...([...view.evicted.entries()].length === 0
|
|
440
|
+
? [" none"]
|
|
441
|
+
: [...view.evicted.entries()]
|
|
442
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
443
|
+
.map(([ref, state]) => ` ${ref} reason=${state.reason} by=${state.by ?? "-"} tokens=${state.tokensFreed}`)),
|
|
444
|
+
"path index:",
|
|
445
|
+
` observations: ${index.observations.length}`,
|
|
446
|
+
` ops: ${
|
|
447
|
+
[...opCounts.entries()]
|
|
448
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
449
|
+
.map(([op, count]) => `${op}=${count}`)
|
|
450
|
+
.join(", ") || "none"
|
|
451
|
+
}`,
|
|
452
|
+
` paths with rewrites: ${rewrittenPaths.size}`,
|
|
453
|
+
...[...rewrittenPaths].sort().map((path) => ` ${path}`),
|
|
454
|
+
"",
|
|
455
|
+
];
|
|
456
|
+
return lines.join("\n");
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
export async function runContextWorkingSetCommand(args: string[]): Promise<number> {
|
|
460
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
461
|
+
process.stdout.write(WORKING_SET_HELP);
|
|
462
|
+
return 0;
|
|
463
|
+
}
|
|
464
|
+
let session: string | undefined;
|
|
465
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
466
|
+
const arg = args[index];
|
|
467
|
+
if (arg === "--session") {
|
|
468
|
+
try {
|
|
469
|
+
session = requiredValue(args, index, arg);
|
|
470
|
+
} catch (error) {
|
|
471
|
+
process.stderr.write(
|
|
472
|
+
`clio-coder context working-set: ${error instanceof Error ? error.message : String(error)}\n${WORKING_SET_HELP}`,
|
|
473
|
+
);
|
|
474
|
+
return 2;
|
|
475
|
+
}
|
|
476
|
+
index += 1;
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
process.stderr.write(`clio-coder context working-set: unknown flag ${arg}\n${WORKING_SET_HELP}`);
|
|
480
|
+
return 2;
|
|
481
|
+
}
|
|
482
|
+
if (session === undefined) {
|
|
483
|
+
process.stderr.write(`clio-coder context working-set: --session is required\n${WORKING_SET_HELP}`);
|
|
484
|
+
return 2;
|
|
485
|
+
}
|
|
486
|
+
try {
|
|
487
|
+
const source = await sessionPath(session);
|
|
488
|
+
const raw = await readFile(source, "utf8");
|
|
489
|
+
const parsed = parseSessionEntries(raw, source);
|
|
490
|
+
if (parsed.errors.length > 0) throw new Error(parsed.errors.join("; "));
|
|
491
|
+
const entries = filterEntriesToActivePath(parsed.entries, await pinnedLeafForSession(source));
|
|
492
|
+
const cwd = await sessionCwdForSession(source);
|
|
493
|
+
process.stdout.write(
|
|
494
|
+
formatWorkingSet({
|
|
495
|
+
id: basename(dirname(source)),
|
|
496
|
+
source,
|
|
497
|
+
cwd,
|
|
498
|
+
entries,
|
|
499
|
+
turnCount: buildPathIndex(entries, { cwd }).turnCount,
|
|
500
|
+
}),
|
|
501
|
+
);
|
|
502
|
+
return 0;
|
|
503
|
+
} catch (error) {
|
|
504
|
+
if (error instanceof CliUsageError) {
|
|
505
|
+
process.stderr.write(`clio-coder context working-set: ${error.message}\n${WORKING_SET_HELP}`);
|
|
506
|
+
return 2;
|
|
507
|
+
}
|
|
508
|
+
process.stderr.write(
|
|
509
|
+
`clio-coder context working-set failed: ${error instanceof Error ? error.message : String(error)}\n`,
|
|
510
|
+
);
|
|
511
|
+
return 1;
|
|
512
|
+
}
|
|
513
|
+
}
|
package/src/cli/context.ts
CHANGED
|
@@ -10,6 +10,8 @@ const HELP = `Usage:
|
|
|
10
10
|
[--target <id>] [--model <id>] [--thinking off|low|medium|high]
|
|
11
11
|
clio-coder context reset [--all] [--yes]
|
|
12
12
|
clio-coder context index [--json]
|
|
13
|
+
clio-coder context replay --sessions <path>... [options]
|
|
14
|
+
clio-coder context working-set --session <id|path>
|
|
13
15
|
|
|
14
16
|
Project context commands:
|
|
15
17
|
clio-coder context show project context status (CLIO-CODER.md, preload, codewiki)
|
|
@@ -18,6 +20,8 @@ Project context commands:
|
|
|
18
20
|
clio-coder context wiki generate or inspect the agent-authored Markdown wiki
|
|
19
21
|
clio-coder context reset clear accumulated project context artifacts
|
|
20
22
|
clio-coder context index build the codewiki index without model calls
|
|
23
|
+
clio-coder context replay compare working-set policies over Clio ledgers
|
|
24
|
+
clio-coder context working-set inspect one session's working-set fold and path index
|
|
21
25
|
`;
|
|
22
26
|
|
|
23
27
|
function printWikiProgress(event: BootstrapProgressEvent): void {
|
|
@@ -313,6 +317,10 @@ export async function runContextCommand(args: string[]): Promise<number> {
|
|
|
313
317
|
return (await import("./context-clear.js")).runContextClearCommand(rest);
|
|
314
318
|
case "index":
|
|
315
319
|
return (await import("./context-index.js")).runContextIndexCommand(rest);
|
|
320
|
+
case "replay":
|
|
321
|
+
return (await import("./context-working-set.js")).runContextReplayCommand(rest);
|
|
322
|
+
case "working-set":
|
|
323
|
+
return (await import("./context-working-set.js")).runContextWorkingSetCommand(rest);
|
|
316
324
|
default:
|
|
317
325
|
process.stderr.write(`clio-coder context: unknown subcommand ${verb}\n`);
|
|
318
326
|
process.stdout.write(HELP);
|
package/src/cli/evidence.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { InvalidIdError } from "../core/safe-id.js";
|
|
2
2
|
import { clioDataDir, clioStateDir } from "../core/xdg.js";
|
|
3
|
-
import type { EvidenceOverview, EvidenceRunProvenance } from "../domains/evidence/index.js";
|
|
3
|
+
import type { CanonicalTrustStatus, EvidenceOverview, EvidenceRunProvenance } from "../domains/evidence/index.js";
|
|
4
4
|
import {
|
|
5
5
|
buildEvalEvidence,
|
|
6
6
|
buildEvidence,
|
|
@@ -178,7 +178,7 @@ function renderEvidence(
|
|
|
178
178
|
input: Awaited<ReturnType<typeof inspectEvidence>>,
|
|
179
179
|
provenance: ReadonlyArray<EvidenceRunProvenance> = [],
|
|
180
180
|
): void {
|
|
181
|
-
const { overview, findings } = input;
|
|
181
|
+
const { overview, findings, trustStatus } = input;
|
|
182
182
|
process.stdout.write(`evidence: ${overview.evidenceId}\n`);
|
|
183
183
|
process.stdout.write(`source: ${formatSource(overview)}\n`);
|
|
184
184
|
process.stdout.write(`generated: ${overview.generatedAt}\n`);
|
|
@@ -188,6 +188,13 @@ function renderEvidence(
|
|
|
188
188
|
process.stdout.write(`blocked tools: ${overview.totals.blockedToolCalls}\n`);
|
|
189
189
|
process.stdout.write(`tags: ${formatList(overview.tags)}\n`);
|
|
190
190
|
process.stdout.write(`findings: ${findings.length}\n`);
|
|
191
|
+
if (trustStatus.projection === "historical_format") {
|
|
192
|
+
process.stdout.write("trust status: unavailable (historical bundle without canonical projection)\n");
|
|
193
|
+
} else {
|
|
194
|
+
for (const run of trustStatus.runs) {
|
|
195
|
+
process.stdout.write(`trust ${run.runId}: ${formatTrustStatus(run.status)}\n`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
191
198
|
// Provenance is printed only for runs whose receipts carry it, so a legacy
|
|
192
199
|
// bundle prints nothing new here.
|
|
193
200
|
for (const { runId, view } of provenance) {
|
|
@@ -197,6 +204,17 @@ function renderEvidence(
|
|
|
197
204
|
process.stdout.write(`files: ${formatList(overview.files)}\n`);
|
|
198
205
|
}
|
|
199
206
|
|
|
207
|
+
function formatTrustStatus(status: CanonicalTrustStatus): string {
|
|
208
|
+
return [
|
|
209
|
+
`artifactIntegrity=${status.artifactIntegrity.state}`,
|
|
210
|
+
`validationGrounding=${status.validationGrounding.state}`,
|
|
211
|
+
`independentReview=${status.independentReview.state}`,
|
|
212
|
+
`contextProvenance=${status.contextProvenance.state}`,
|
|
213
|
+
`autonomyEnforcement=${status.autonomyEnforcement.state}`,
|
|
214
|
+
`completionEvidence=${status.completionEvidence.state}`,
|
|
215
|
+
].join(" ");
|
|
216
|
+
}
|
|
217
|
+
|
|
200
218
|
function renderEvidenceList(overviews: ReadonlyArray<EvidenceOverview>): void {
|
|
201
219
|
process.stdout.write(`${overviews.length} evidence artifacts\n`);
|
|
202
220
|
if (overviews.length === 0) return;
|
package/src/cli/index.ts
CHANGED
|
@@ -52,6 +52,8 @@ Usage:
|
|
|
52
52
|
clio-coder context wiki [--update] [--status] [--depth auto|simple|medium|detailed] [--target <id>] [--model <id>]
|
|
53
53
|
clio-coder context reset [--all] [--yes] clear accumulated project context artifacts
|
|
54
54
|
clio-coder context index [--json] build the codewiki index without model calls
|
|
55
|
+
clio-coder context replay --sessions <path>... compare working-set policies over Clio ledgers
|
|
56
|
+
clio-coder context working-set --session <id|path> inspect one session's working-set state
|
|
55
57
|
clio-coder uninstall remove all Clio Coder state; --remove-binary also unlinks the launcher
|
|
56
58
|
clio-coder upgrade upgrade Clio Coder and run pending migrations
|
|
57
59
|
clio-coder agents list discovered agent recipes
|
|
@@ -63,6 +65,7 @@ Usage:
|
|
|
63
65
|
clio-coder trace query or view the durable dispatch trace mirror
|
|
64
66
|
clio-coder extensions install, list, enable, disable, or remove extension packages
|
|
65
67
|
clio-coder skills list, inspect, validate, or install skills
|
|
68
|
+
clio-coder verifiers discover, author, validate, edit, or dry-run project checks
|
|
66
69
|
clio-coder docs [topic] serve the HTML docs of a source checkout on 127.0.0.1 (--no-open to skip browser)
|
|
67
70
|
clio-coder dev <command> harness instruments; run 'clio-coder dev' for the list
|
|
68
71
|
clio-coder --help, -h this message
|
|
@@ -243,6 +246,7 @@ const COMMAND_HANDLERS = new Map<string, CommandHandler>([
|
|
|
243
246
|
["ext", extensionsCommand],
|
|
244
247
|
["fleet", async (subArgs) => (await import("./fleet.js")).runFleetCommand(subArgs)],
|
|
245
248
|
["skills", async (subArgs) => (await import("./skills.js")).runSkillsCommand(subArgs)],
|
|
249
|
+
["verifiers", async (subArgs) => (await import("./verifiers.js")).runVerifiersCommand(subArgs)],
|
|
246
250
|
["docs", async (subArgs) => (await import("./docs.js")).runDocsCommand(subArgs)],
|
|
247
251
|
["share", async (subArgs) => (await import("./share.js")).runShareCommand(subArgs)],
|
|
248
252
|
["export", async (subArgs) => (await import("./share.js")).runExportCommand(subArgs)],
|