@iowarp/clio-coder 0.3.6 → 0.3.7
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 +28 -0
- package/README.md +16 -5
- package/dist/{acp-2BEHC4DL.js → acp-SK4MD6MM.js} +10 -10
- package/dist/{agents-LNNFTM53.js → agents-2FN2K6ME.js} +30 -25
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-KXXFI2VS.js → auth-QIYZWM5I.js} +13 -13
- package/dist/{chunk-KHSFENX2.js → chunk-3HAPLH5M.js} +10 -10
- package/dist/{chunk-24I7BN55.js → chunk-465YSENW.js} +2 -2
- package/dist/{chunk-4OC57DA6.js → chunk-4DGYLA73.js} +53 -2
- package/dist/{chunk-CYQKWTG3.js → chunk-4DWFMQDR.js} +4 -4
- package/dist/{chunk-E2ER4LJF.js → chunk-5C3AQNDW.js} +25 -1
- package/dist/{chunk-22NAGB7X.js → chunk-5C77SEEY.js} +5 -94
- package/dist/{chunk-43AOLP7E.js → chunk-5FR74PWO.js} +2 -1
- package/dist/{chunk-K7T3E2SR.js → chunk-5UJ6ECTS.js} +10 -9
- package/dist/{chunk-6US73PDB.js → chunk-6M7VS3J3.js} +5 -5
- package/dist/{chunk-CJUB2JJ2.js → chunk-6TUKSZVF.js} +5 -5
- package/dist/{chunk-5JGRAMKL.js → chunk-AB4XIIVB.js} +8 -6
- package/dist/{chunk-R46L2BIR.js → chunk-BMWK7ZIZ.js} +14 -20
- package/dist/{chunk-4BPJXDWC.js → chunk-C4JBQ5SR.js} +30 -14
- package/dist/{chunk-XXQNGV4M.js → chunk-CEYBNUGC.js} +243 -63
- package/dist/{chunk-VEZEGCGW.js → chunk-D4MDIG46.js} +20 -18
- package/dist/chunk-DJNLUABN.js +843 -0
- package/dist/{chunk-RY3LY4J5.js → chunk-DMD2AGVS.js} +5 -4
- package/dist/{chunk-KOHPCX4K.js → chunk-DOOEX22V.js} +2 -2
- package/dist/chunk-DQA7QLMD.js +123 -0
- package/dist/chunk-DR52UMZW.js +21 -0
- package/dist/{chunk-XF5N4U5A.js → chunk-EBEFWSGL.js} +6 -5
- package/dist/{chunk-EYPA3EGJ.js → chunk-EELBMBT6.js} +120 -13
- package/dist/{chunk-CKXWIANG.js → chunk-EOOQZZDE.js} +16 -14
- package/dist/{chunk-WR67VIZY.js → chunk-FOT2FX5J.js} +63 -5
- package/dist/{chunk-FYYLNIL5.js → chunk-GH5622CP.js} +2 -2
- package/dist/chunk-GWS3VEIW.js +195 -0
- package/dist/{chunk-LYF7OHWH.js → chunk-J7PIKKWC.js} +8 -463
- package/dist/{chunk-NILBFAPG.js → chunk-JNXPYBB4.js} +2 -2
- package/dist/{chunk-4VP4KH3K.js → chunk-JRIO5UD2.js} +4 -4
- package/dist/{chunk-6XXKFVSN.js → chunk-JTSEDYVQ.js} +7 -7
- package/dist/{chunk-QKMUKYO7.js → chunk-KCMKRQX4.js} +236 -84
- package/dist/chunk-KZ2H5X4G.js +1026 -0
- package/dist/{chunk-QNQHSOLF.js → chunk-LADCF22A.js} +12 -12
- package/dist/chunk-M4AKACEO.js +382 -0
- package/dist/{chunk-XYDYPRZI.js → chunk-MXI6J5JF.js} +7 -7
- package/dist/{chunk-G7MUEIGA.js → chunk-OB5HIGJY.js} +1 -1
- package/dist/{chunk-EKY57CSP.js → chunk-OBMAI2DP.js} +61 -767
- package/dist/chunk-PD3MESLB.js +242 -0
- package/dist/{chunk-ZRGEBJ4T.js → chunk-QCTRSGHQ.js} +21 -21
- package/dist/chunk-RVG5JXAL.js +41 -0
- package/dist/{chunk-RD5U66HV.js → chunk-SROCI7ZU.js} +7 -7
- package/dist/{chunk-MFFY33HR.js → chunk-THKY7CD7.js} +466 -205
- package/dist/{chunk-PCZJO5TI.js → chunk-UFQ3F4FW.js} +13 -178
- package/dist/{chunk-AD2SYQYC.js → chunk-UHXRNZ2J.js} +121 -3
- package/dist/chunk-UND3GU2L.js +103 -0
- package/dist/{chunk-QM3F2GKX.js → chunk-UUANF5CR.js} +2247 -2096
- package/dist/chunk-UVDSQ6LW.js +472 -0
- package/dist/{chunk-DJVECN66.js → chunk-VQNODYQ4.js} +14 -14
- package/dist/{chunk-3BPUFZDL.js → chunk-VREKEFLL.js} +3 -3
- package/dist/{chunk-PBTHKCPN.js → chunk-WJHBC77E.js} +6 -6
- package/dist/{chunk-XE2VEJHX.js → chunk-X2KV5FXT.js} +2 -2
- package/dist/{chunk-ZXF4XRKW.js → chunk-XEGB6BCN.js} +157 -7
- package/dist/{chunk-E25LMLRW.js → chunk-YD734TPH.js} +2 -2
- package/dist/{verifiers-NCBTHHN2.js → chunk-YTYFXUI3.js} +65 -322
- package/dist/{chunk-OH3TOQTB.js → chunk-ZGH7FGS5.js} +13 -7
- package/dist/cli/index.js +32 -30
- package/dist/{clio-M2KGYUFZ.js → clio-WBVQEBKO.js} +7 -7
- package/dist/{code-nav-GQNL7XA6.js → code-nav-FGGFIE7L.js} +3 -3
- package/dist/{components-5TTYYX6G.js → components-F7OEATSO.js} +4 -4
- package/dist/{config-XUUYQIWO.js → config-TRBL3RCF.js} +34 -29
- package/dist/{configure-IHJ7YOMV.js → configure-OLCVPHNM.js} +15 -15
- package/dist/{context-74JLXAWD.js → context-MJIJ6GOX.js} +11 -11
- package/dist/{context-ZQ7SIFJV.js → context-WFPKQSM6.js} +19 -3
- package/dist/{context-75MIWW3U.js → context-XEWE3MOJ.js} +31 -26
- package/dist/{context-clear-GYKWNUML.js → context-clear-KNOS2JPB.js} +31 -26
- package/dist/{context-working-set-UX5KEP4J.js → context-working-set-EUXAZI6N.js} +8 -8
- package/dist/{dispatch-runner-GIJBHNFL.js → dispatch-runner-B7MTOVKL.js} +313 -53
- package/dist/{docs-6FZSCG5B.js → docs-FLJTIDSE.js} +4 -4
- package/dist/{doctor-SVJ5BZCW.js → doctor-RN4YKO2X.js} +14 -14
- package/dist/{eval-CG6LLBLD.js → eval-RUBJVSNQ.js} +8 -7
- package/dist/{evidence-ZYFIEN42.js → evidence-JZNBUOQZ.js} +30 -25
- package/dist/{evolve-QGEXEMDW.js → evolve-FJVC4KKI.js} +30 -25
- package/dist/{extensions-ADGNCJJD.js → extensions-IQL36S7K.js} +4 -4
- package/dist/{fleet-S5R4ZOQY.js → fleet-BDKYJFCP.js} +214 -360
- package/dist/fleet-commands-ZFIWZSB3.js +70 -0
- package/dist/fleet-graph-Y6HPXIVF.js +125 -0
- package/dist/fleet-new-RDVJLHHH.js +48 -0
- package/dist/fleet-validate-BIYREGIK.js +79 -0
- package/dist/{init-5DRU55YR.js → init-LQUB5COQ.js} +44 -37
- package/dist/library-NJAHIGG4.js +217 -0
- package/dist/{memory-7YKKR6UC.js → memory-OG6HOYKM.js} +31 -26
- package/dist/{models-ZPOLRU2C.js → models-5ZG5XY7J.js} +21 -20
- package/dist/{monitor-US5F5YGZ.js → monitor-TJ7AMTGB.js} +49 -30
- package/dist/{orchestrator-E2AL4T5N.js → orchestrator-WZYB54DM.js} +3827 -581
- package/dist/{paths-E7KYAQWE.js → paths-XUC7GS6E.js} +4 -4
- package/dist/{reset-KZ652EK6.js → reset-PXQT45IY.js} +7 -7
- package/dist/{run-SRNBKDWD.js → run-FQ74YF62.js} +53 -45
- package/dist/{share-CGZE33UP.js → share-FW7SVCL3.js} +33 -9
- package/dist/{skills-S2X4DLY5.js → skills-7E7IRB3R.js} +24 -8
- package/dist/{skills-eval-W2GGIC4R.js → skills-eval-LI75W6OK.js} +34 -27
- package/dist/{targets-54SWINWB.js → targets-4CIFKCTW.js} +23 -22
- package/dist/{terminal-lease-SAIF2OGY.js → terminal-lease-WUZY7ZV5.js} +4 -4
- package/dist/{uninstall-BVLWXKBT.js → uninstall-7FV7IP4E.js} +4 -4
- package/dist/{upgrade-JKAR27XC.js → upgrade-K2HVIVMQ.js} +20 -19
- package/dist/{usage-MSAWCLX4.js → usage-GTZELZQX.js} +116 -49
- package/dist/verifiers-RLAHT27O.js +336 -0
- package/dist/{verify-X5HDROLA.js → verify-BX3BRKH5.js} +7 -6
- package/dist/{wiki-generate-GUSOQ6ZP.js → wiki-generate-ASIFASCN.js} +45 -37
- package/dist/worker/entry.js +38 -35
- package/docs/README.md +3 -2
- package/docs/acp.md +1 -1
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +2 -2
- package/docs/artifact-versions.md +10 -6
- package/docs/built-in-agents.md +26 -2
- package/docs/capacity-and-scheduling.md +1 -1
- package/docs/commands-and-modes.md +82 -2
- package/docs/configuration-and-targets.md +79 -2
- package/docs/context-engine.md +1 -1
- package/docs/development-pipeline.md +1 -1
- package/docs/dispatch-architecture-rationale.md +1 -1
- package/docs/documentation-coverage.md +3 -3
- package/docs/documentation-guide.md +3 -3
- package/docs/eval-runner.md +1 -1
- package/docs/evals-internal.md +1 -1
- package/docs/evidence-and-memory.md +5 -5
- package/docs/evolution.md +1 -1
- package/docs/exit-codes-and-output.md +4 -1
- package/docs/extensions-and-sharing.md +6 -2
- package/docs/fleet-demo-runbook.md +2 -2
- package/docs/fleet-dispatch.md +197 -10
- package/docs/git-commit-provenance.md +2 -2
- package/docs/glossary.md +1 -1
- package/docs/installation-and-lifecycle.md +2 -2
- package/docs/middleware-and-components.md +2 -1
- package/docs/model-catalog.md +1 -1
- package/docs/observability.md +55 -8
- package/docs/proactive-memory.md +1 -1
- package/docs/prompt-envelope-and-tools.md +1 -1
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/release-cut-checklist.md +79 -64
- package/docs/resource-library.md +59 -0
- package/docs/safety-model.md +2 -2
- package/docs/scientific-validation.md +3 -3
- package/docs/session-lifecycle.md +37 -1
- package/docs/skills-marketplace.md +16 -3
- package/docs/tool-usage.md +14 -7
- 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 +3 -3
- package/package.json +1 -1
- package/src/cli/fleet-commands.ts +37 -0
- package/src/cli/fleet-graph.ts +102 -0
- package/src/cli/fleet-new.ts +36 -0
- package/src/cli/fleet-preflight.ts +121 -0
- package/src/cli/fleet-validate.ts +30 -0
- package/src/cli/fleet.ts +173 -335
- package/src/cli/index.ts +3 -1
- package/src/cli/library.ts +190 -0
- package/src/cli/share.ts +13 -1
- package/src/cli/usage.ts +111 -19
- package/src/core/bus-events.ts +4 -0
- package/src/core/commit-attribution.ts +4 -4
- package/src/core/config.ts +130 -0
- package/src/core/defaults.ts +81 -0
- package/src/domains/agents/builtins/architect.md +1 -0
- package/src/domains/agents/builtins/oracle.md +33 -0
- package/src/domains/agents/catalog.ts +13 -1
- package/src/domains/agents/fleet-contract.ts +278 -16
- package/src/domains/agents/index.ts +14 -0
- package/src/domains/agents/result-contract.ts +235 -1
- package/src/domains/config/classify.ts +4 -0
- package/src/domains/dispatch/active-route-planner.ts +14 -0
- package/src/domains/dispatch/backoff.ts +2 -1
- package/src/domains/dispatch/capability-match.ts +1 -0
- package/src/domains/dispatch/checkout-writer-lease.ts +175 -0
- package/src/domains/dispatch/contract.ts +34 -0
- package/src/domains/dispatch/delegation-plan.ts +167 -0
- package/src/domains/dispatch/execution-plan.ts +76 -5
- package/src/domains/dispatch/execution-role.ts +3 -1
- package/src/domains/dispatch/execution-scheduler.ts +183 -67
- package/src/domains/dispatch/extension.ts +258 -9
- package/src/domains/dispatch/fleet-gate.ts +14 -0
- package/src/domains/dispatch/fleet-plan.ts +63 -3
- package/src/domains/dispatch/fleet-run.ts +737 -0
- package/src/domains/dispatch/gate-role-prompts.ts +9 -0
- package/src/domains/dispatch/host-verification.ts +178 -0
- package/src/domains/dispatch/index.ts +38 -0
- package/src/domains/dispatch/intent.ts +159 -0
- package/src/domains/dispatch/receipt-integrity.ts +8 -4
- package/src/domains/dispatch/state.ts +36 -3
- package/src/domains/dispatch/types.ts +51 -6
- package/src/domains/dispatch/validation.ts +66 -6
- package/src/domains/evidence/trust-status.ts +10 -1
- package/src/domains/middleware/index.ts +15 -0
- package/src/domains/middleware/watchdog.ts +281 -0
- package/src/domains/observability/contract.ts +3 -1
- package/src/domains/observability/cost.ts +12 -1
- package/src/domains/observability/extension.ts +2 -2
- package/src/domains/observability/index.ts +10 -0
- package/src/domains/observability/out-of-turn-usage.ts +223 -0
- package/src/domains/resources/index.ts +20 -0
- package/src/domains/resources/library.ts +326 -0
- package/src/domains/resources/skills/marketplace.ts +37 -12
- package/src/domains/session/handoff.ts +629 -0
- package/src/domains/share/archive.ts +67 -2
- package/src/entry/orchestrator.ts +37 -0
- package/src/interactive/bus-notices.ts +26 -0
- package/src/interactive/chat-loop.ts +235 -1
- package/src/interactive/chat-renderer.ts +22 -0
- package/src/interactive/cost-overlay.ts +31 -3
- package/src/interactive/council-dispatch.ts +30 -0
- package/src/interactive/council-grid.ts +213 -0
- package/src/interactive/council.ts +99 -0
- package/src/interactive/dispatch-board.ts +260 -16
- package/src/interactive/fleet-run-preview.ts +307 -0
- package/src/interactive/footer/notifications.ts +219 -0
- package/src/interactive/handoff-round.ts +56 -0
- package/src/interactive/interactive-application.ts +43 -1
- package/src/interactive/interactive-event-projection.ts +9 -1
- package/src/interactive/interactive-slash-runtime.ts +52 -2
- package/src/interactive/interactive-subscriptions.ts +14 -2
- package/src/interactive/oracle.ts +179 -0
- package/src/interactive/overlay-ask-user-lifecycle.ts +6 -0
- package/src/interactive/overlay-general-openers.ts +190 -1
- package/src/interactive/overlay-key-routing.ts +17 -1
- package/src/interactive/overlay-lifecycle.ts +41 -1
- package/src/interactive/overlay-permission-lifecycle.ts +10 -0
- package/src/interactive/overlay-resource-openers.ts +11 -3
- package/src/interactive/overlay-session-lifecycle.ts +234 -2
- package/src/interactive/overlays/fleet-run-approval.ts +208 -0
- package/src/interactive/overlays/handoff-review.ts +185 -0
- package/src/interactive/overlays/library-install-confirm.ts +151 -0
- package/src/interactive/overlays/list-overlay.ts +168 -2
- package/src/interactive/overlays/settings.ts +101 -4
- package/src/interactive/overlays/side-question.ts +139 -0
- package/src/interactive/overlays/skills-hub.ts +401 -15
- package/src/interactive/side-question.ts +171 -0
- package/src/interactive/slash-commands.ts +432 -5
- package/src/interactive/slash-spec.ts +19 -6
- package/src/interactive/theme/tokens.ts +30 -0
- package/src/interactive/turn-middleware.ts +15 -1
- package/src/interactive/watchdog-run.ts +75 -0
- package/src/interactive/worker-share.ts +56 -1
- package/src/interactive/worker-stream.ts +7 -0
- package/src/tools/bootstrap.ts +3 -0
- package/src/tools/compete-worktrees.ts +13 -79
- package/src/tools/dispatch-admission.ts +242 -8
- package/src/tools/dispatch-arguments.ts +57 -1
- package/src/tools/dispatch-plan.ts +136 -6
- package/src/tools/dispatch-runner.ts +319 -13
- package/src/tools/dispatch-types.ts +20 -1
- package/src/tools/dispatch.ts +72 -2
- package/src/tools/monitor.ts +16 -0
- package/src/tools/profiles.ts +18 -4
- package/src/tools/task-worktree.ts +238 -0
- package/src/tools/verify/authoring.ts +61 -1
- package/src/tools/verify/scripts.ts +62 -0
- package/src/tools/worker-evidence.ts +2 -1
- package/src/worker/spec-contract.ts +1 -0
- package/dist/chunk-HC4CLZ2Y.js +0 -68
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
3
|
+
import { existsSync, mkdirSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
5
|
+
|
|
6
|
+
export type TaskWorktreeApply = "merge" | "preserve";
|
|
7
|
+
|
|
8
|
+
export interface TaskWorktree {
|
|
9
|
+
root: string;
|
|
10
|
+
runId: string;
|
|
11
|
+
path: string;
|
|
12
|
+
branch: string;
|
|
13
|
+
base: string;
|
|
14
|
+
ownerToken: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface TaskWorktreeReceipt {
|
|
18
|
+
path: string;
|
|
19
|
+
branch: string;
|
|
20
|
+
diffHash: string;
|
|
21
|
+
apply: TaskWorktreeApply;
|
|
22
|
+
applied: boolean;
|
|
23
|
+
reason?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const SAFE_RUN_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u;
|
|
27
|
+
const OWNER_FILE_SUFFIX = ".task-owner.json";
|
|
28
|
+
const COMMIT_IDENTITY = "clio-task";
|
|
29
|
+
|
|
30
|
+
function gitBytes(root: string, args: string[]): Buffer {
|
|
31
|
+
return execFileSync("git", ["-C", root, ...args], {
|
|
32
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
33
|
+
timeout: 30_000,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function git(root: string, args: string[]): string {
|
|
38
|
+
return gitBytes(root, args).toString("utf8").trim();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function isCanonicalWorktreePathInside(parent: string, candidate: string): boolean {
|
|
42
|
+
let canonicalParent: string;
|
|
43
|
+
let canonicalCandidate: string;
|
|
44
|
+
try {
|
|
45
|
+
canonicalParent = realpathSync(parent);
|
|
46
|
+
} catch {
|
|
47
|
+
canonicalParent = resolve(parent);
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
canonicalCandidate = realpathSync(candidate);
|
|
51
|
+
} catch {
|
|
52
|
+
canonicalCandidate = resolve(candidate);
|
|
53
|
+
}
|
|
54
|
+
const rel = relative(canonicalParent, canonicalCandidate);
|
|
55
|
+
return rel.length > 0 && rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function commitWorktreePath(path: string, identity: string, message: string): boolean {
|
|
59
|
+
git(path, ["add", "-A"]);
|
|
60
|
+
if (git(path, ["status", "--porcelain"]).length === 0) return false;
|
|
61
|
+
git(path, [
|
|
62
|
+
"-c",
|
|
63
|
+
`user.name=${identity}`,
|
|
64
|
+
"-c",
|
|
65
|
+
`user.email=${identity}@local`,
|
|
66
|
+
"commit",
|
|
67
|
+
"-m",
|
|
68
|
+
message,
|
|
69
|
+
"--no-verify",
|
|
70
|
+
]);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function worktreeBranchDiffStat(root: string, branch: string): string {
|
|
75
|
+
try {
|
|
76
|
+
return git(root, ["diff", "--shortstat", `HEAD...${branch}`]) || "no changes";
|
|
77
|
+
} catch {
|
|
78
|
+
return "diff unavailable";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function protectedPathsChangedByWorktreeBranch(
|
|
83
|
+
root: string,
|
|
84
|
+
branch: string,
|
|
85
|
+
protectedPaths: ReadonlyArray<string>,
|
|
86
|
+
): string[] {
|
|
87
|
+
const canonical = realpathSync(root);
|
|
88
|
+
const protectedInside = protectedPaths
|
|
89
|
+
.map((path) => resolve(path))
|
|
90
|
+
.filter((path) => {
|
|
91
|
+
const rel = relative(canonical, path);
|
|
92
|
+
return rel.length > 0 && rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel);
|
|
93
|
+
});
|
|
94
|
+
if (protectedInside.length === 0) return [];
|
|
95
|
+
const changed = git(canonical, ["diff", "--name-only", "-z", "--no-renames", `HEAD...${branch}`])
|
|
96
|
+
.split("\0")
|
|
97
|
+
.filter((path) => path.length > 0)
|
|
98
|
+
.map((path) => resolve(canonical, path));
|
|
99
|
+
const blocked = new Set<string>();
|
|
100
|
+
for (const candidate of changed) {
|
|
101
|
+
for (const protectedPath of protectedInside) {
|
|
102
|
+
const rel = relative(protectedPath, candidate);
|
|
103
|
+
if (
|
|
104
|
+
candidate === protectedPath ||
|
|
105
|
+
(rel.length > 0 && rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel))
|
|
106
|
+
) {
|
|
107
|
+
blocked.add(protectedPath);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return [...blocked].sort();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function mergeWorktreeBranch(
|
|
115
|
+
root: string,
|
|
116
|
+
branch: string,
|
|
117
|
+
identity: string,
|
|
118
|
+
): { ok: true } | { ok: false; reason: string } {
|
|
119
|
+
try {
|
|
120
|
+
git(root, [
|
|
121
|
+
"-c",
|
|
122
|
+
`user.name=${identity}`,
|
|
123
|
+
"-c",
|
|
124
|
+
`user.email=${identity}@local`,
|
|
125
|
+
"merge",
|
|
126
|
+
"--no-edit",
|
|
127
|
+
"--no-verify",
|
|
128
|
+
branch,
|
|
129
|
+
]);
|
|
130
|
+
return { ok: true };
|
|
131
|
+
} catch (error) {
|
|
132
|
+
try {
|
|
133
|
+
git(root, ["merge", "--abort"]);
|
|
134
|
+
} catch {
|
|
135
|
+
// No merge remains to abort.
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
ok: false,
|
|
139
|
+
reason: error instanceof Error ? (error.message.split("\n")[0] ?? "merge failed") : String(error),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function validateRunId(runId: string): void {
|
|
145
|
+
if (!SAFE_RUN_ID.test(runId) || runId === "." || runId === "..")
|
|
146
|
+
throw new Error(`invalid task worktree run id '${runId}'`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function gitCheckoutRoot(cwd: string): string | null {
|
|
150
|
+
try {
|
|
151
|
+
return realpathSync(git(cwd, ["rev-parse", "--show-toplevel"]));
|
|
152
|
+
} catch {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function createTaskWorktree(root: string, runId: string, base?: string): TaskWorktree {
|
|
158
|
+
validateRunId(runId);
|
|
159
|
+
const canonical = realpathSync(root);
|
|
160
|
+
const resolvedBase = base ?? git(canonical, ["rev-parse", "HEAD"]);
|
|
161
|
+
const parent = join(canonical, ".clio-coder", "worktrees");
|
|
162
|
+
const path = join(parent, runId);
|
|
163
|
+
const branch = `clio/task/${runId}`;
|
|
164
|
+
mkdirSync(parent, { recursive: true });
|
|
165
|
+
if (!isCanonicalWorktreePathInside(parent, path))
|
|
166
|
+
throw new Error(`task worktree path escapes its parent for run ${runId}`);
|
|
167
|
+
git(canonical, ["worktree", "add", "-b", branch, path, resolvedBase]);
|
|
168
|
+
const ownerToken = randomBytes(16).toString("hex");
|
|
169
|
+
writeFileSync(
|
|
170
|
+
`${path}${OWNER_FILE_SUFFIX}`,
|
|
171
|
+
`${JSON.stringify({ version: 1, kind: "clio-task-worktree", root: canonical, runId, branch, base: resolvedBase, ownerToken }, null, 2)}\n`,
|
|
172
|
+
{ encoding: "utf8", flag: "wx" },
|
|
173
|
+
);
|
|
174
|
+
return { root: canonical, runId, path, branch, base: resolvedBase, ownerToken };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function assertOwnership(worktree: TaskWorktree): void {
|
|
178
|
+
const expected = join(worktree.root, ".clio-coder", "worktrees", worktree.runId);
|
|
179
|
+
if (
|
|
180
|
+
resolve(worktree.path) !== resolve(expected) ||
|
|
181
|
+
!isCanonicalWorktreePathInside(join(worktree.root, ".clio-coder", "worktrees"), worktree.path)
|
|
182
|
+
) {
|
|
183
|
+
throw new Error(`task worktree ${worktree.runId} has an invalid ownership path`);
|
|
184
|
+
}
|
|
185
|
+
if (!existsSync(`${worktree.path}${OWNER_FILE_SUFFIX}`))
|
|
186
|
+
throw new Error(`task worktree ${worktree.runId} has no ownership file`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function commitTaskWorktree(worktree: TaskWorktree, message = `Clio task ${worktree.runId}`): boolean {
|
|
190
|
+
assertOwnership(worktree);
|
|
191
|
+
return commitWorktreePath(worktree.path, COMMIT_IDENTITY, message);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function taskWorktreeDiffHash(worktree: Pick<TaskWorktree, "root" | "base" | "branch">): string {
|
|
195
|
+
const bytes = gitBytes(worktree.root, ["diff", `${worktree.base}..${worktree.branch}`]);
|
|
196
|
+
return createHash("sha256").update(bytes).digest("hex");
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function protectedPathsChangedByTaskBranch(
|
|
200
|
+
worktree: Pick<TaskWorktree, "root" | "branch">,
|
|
201
|
+
protectedPaths: ReadonlyArray<string>,
|
|
202
|
+
): string[] {
|
|
203
|
+
return protectedPathsChangedByWorktreeBranch(worktree.root, worktree.branch, protectedPaths);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export function applyTaskWorktree(input: {
|
|
207
|
+
worktree: TaskWorktree;
|
|
208
|
+
apply: TaskWorktreeApply;
|
|
209
|
+
protectedPaths?: ReadonlyArray<string>;
|
|
210
|
+
}): TaskWorktreeReceipt {
|
|
211
|
+
assertOwnership(input.worktree);
|
|
212
|
+
commitTaskWorktree(input.worktree);
|
|
213
|
+
const receipt: TaskWorktreeReceipt = {
|
|
214
|
+
path: input.worktree.path,
|
|
215
|
+
branch: input.worktree.branch,
|
|
216
|
+
diffHash: taskWorktreeDiffHash(input.worktree),
|
|
217
|
+
apply: input.apply,
|
|
218
|
+
applied: false,
|
|
219
|
+
};
|
|
220
|
+
if (input.apply === "preserve") return receipt;
|
|
221
|
+
const protectedChanges = protectedPathsChangedByTaskBranch(input.worktree, input.protectedPaths ?? []);
|
|
222
|
+
if (protectedChanges.length > 0) return { ...receipt, reason: "protected_artifact_changed" };
|
|
223
|
+
const merged = mergeWorktreeBranch(input.worktree.root, input.worktree.branch, COMMIT_IDENTITY);
|
|
224
|
+
if (!merged.ok) return { ...receipt, reason: "worktree_merge_conflict" };
|
|
225
|
+
return { ...receipt, applied: true };
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export function cleanupTaskWorktree(worktree: TaskWorktree, deleteBranch: boolean): void {
|
|
229
|
+
assertOwnership(worktree);
|
|
230
|
+
try {
|
|
231
|
+
git(worktree.root, ["worktree", "remove", "--force", worktree.path]);
|
|
232
|
+
} catch {
|
|
233
|
+
if (existsSync(worktree.path)) rmSync(worktree.path, { recursive: true, force: true });
|
|
234
|
+
git(worktree.root, ["worktree", "prune"]);
|
|
235
|
+
}
|
|
236
|
+
if (deleteBranch) git(worktree.root, ["branch", "-D", worktree.branch]);
|
|
237
|
+
rmSync(`${worktree.path}${OWNER_FILE_SUFFIX}`, { force: true });
|
|
238
|
+
}
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
parseProjectVerifierCatalogText,
|
|
25
25
|
} from "./catalog.js";
|
|
26
26
|
import { verifyTool } from "./index.js";
|
|
27
|
-
import { discoverDeclaredChecksAtRoot } from "./scripts.js";
|
|
27
|
+
import { discoverDeclaredChecksAtRoot, discoverDeclaredProjectEntriesAtRoot } from "./scripts.js";
|
|
28
28
|
|
|
29
29
|
export type VerifierProposalAuthority = "project-declared" | "toolchain-defined";
|
|
30
30
|
|
|
@@ -34,6 +34,8 @@ export type VerifierSignalKind =
|
|
|
34
34
|
| "cargo"
|
|
35
35
|
| "cmake-preset"
|
|
36
36
|
| "python-runner"
|
|
37
|
+
| "just-recipe"
|
|
38
|
+
| "make-target"
|
|
37
39
|
| "go-module"
|
|
38
40
|
| "validation-contract"
|
|
39
41
|
| "manual-entry";
|
|
@@ -149,6 +151,12 @@ export interface VerifierAuthoringWorkflowOptions {
|
|
|
149
151
|
runCheck?: (id: string) => Promise<ToolResult>;
|
|
150
152
|
}
|
|
151
153
|
|
|
154
|
+
export interface DeclaredProjectCommand {
|
|
155
|
+
id: string;
|
|
156
|
+
command: string[];
|
|
157
|
+
provenance: VerifierProvenance;
|
|
158
|
+
}
|
|
159
|
+
|
|
152
160
|
interface RawProposal {
|
|
153
161
|
preferredId: string;
|
|
154
162
|
description: string;
|
|
@@ -466,6 +474,58 @@ function pythonProposals(workspaceRoot: string, diagnostics: string[]): RawPropo
|
|
|
466
474
|
return proposals;
|
|
467
475
|
}
|
|
468
476
|
|
|
477
|
+
/**
|
|
478
|
+
* Discover exact invocation vectors from project declarations for fleet command
|
|
479
|
+
* authoring. This shares the verifier authoring readers and provenance model,
|
|
480
|
+
* while retaining entries that are not verification-family names.
|
|
481
|
+
*/
|
|
482
|
+
export function discoverDeclaredProjectCommands(workspaceRoot = process.cwd()): DeclaredProjectCommand[] {
|
|
483
|
+
const commands: DeclaredProjectCommand[] = [];
|
|
484
|
+
const add = (id: string, command: string[], pathValue: string, detail: string, kind: VerifierSignalKind): void => {
|
|
485
|
+
commands.push({
|
|
486
|
+
id,
|
|
487
|
+
command,
|
|
488
|
+
provenance: { kind, path: pathValue, detail, authority: "project-declared" },
|
|
489
|
+
});
|
|
490
|
+
};
|
|
491
|
+
for (const entry of discoverDeclaredProjectEntriesAtRoot(workspaceRoot)) {
|
|
492
|
+
add(entry.id, entry.command, entry.path, entry.detail, entry.kind);
|
|
493
|
+
}
|
|
494
|
+
const pyprojectText = regularFileText(path.join(workspaceRoot, "pyproject.toml"), workspaceRoot);
|
|
495
|
+
if (typeof pyprojectText === "string") {
|
|
496
|
+
const document = parseTomlDocument(pyprojectText);
|
|
497
|
+
if (document !== null) {
|
|
498
|
+
for (const [tablePath, label] of [
|
|
499
|
+
[["project", "scripts"], "project.scripts"],
|
|
500
|
+
[["tool", "poetry", "scripts"], "tool.poetry.scripts"],
|
|
501
|
+
] as const) {
|
|
502
|
+
const scripts = tomlTableAt(document, tablePath);
|
|
503
|
+
if (scripts === null) continue;
|
|
504
|
+
for (const [name, target] of Object.entries(scripts).sort(([left], [right]) => compareCodepoints(left, right))) {
|
|
505
|
+
if (typeof target === "string") add(name, [name], "pyproject.toml", `[${label}] entry '${name}'`, "python-runner");
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
for (const [tablePath, module, id, label] of [
|
|
509
|
+
[["tool", "pytest", "ini_options"], "pytest", "pytest", "tool.pytest.ini_options"],
|
|
510
|
+
[["tool", "tox"], "tox", "tox", "tool.tox"],
|
|
511
|
+
[["tool", "nox"], "nox", "nox", "tool.nox"],
|
|
512
|
+
] as const) {
|
|
513
|
+
if (tomlTableAt(document, tablePath) !== null)
|
|
514
|
+
add(id, ["python", "-m", module], "pyproject.toml", `[${label}]`, "python-runner");
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
const seen = new Set<string>();
|
|
519
|
+
return commands.filter((entry) => {
|
|
520
|
+
let id = slug(entry.id, "command");
|
|
521
|
+
let suffix = 2;
|
|
522
|
+
while (seen.has(id)) id = `${slug(entry.id, "command")}-${suffix++}`;
|
|
523
|
+
seen.add(id);
|
|
524
|
+
entry.id = id;
|
|
525
|
+
return true;
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
|
|
469
529
|
function goProposals(workspaceRoot: string, diagnostics: string[]): RawProposal[] {
|
|
470
530
|
const relative = "go.mod";
|
|
471
531
|
const text = regularFileText(path.join(workspaceRoot, relative), workspaceRoot);
|
|
@@ -21,6 +21,14 @@ import {
|
|
|
21
21
|
|
|
22
22
|
export type DeclaredCheckDiscoveryResult = { ok: true; sources: DeclaredCheckSource[] } | { ok: false; reason: string };
|
|
23
23
|
|
|
24
|
+
export interface DeclaredProjectEntry {
|
|
25
|
+
id: string;
|
|
26
|
+
command: string[];
|
|
27
|
+
path: string;
|
|
28
|
+
detail: string;
|
|
29
|
+
kind: "package-script" | "just-recipe" | "make-target";
|
|
30
|
+
}
|
|
31
|
+
|
|
24
32
|
function repositoryRelativeCwd(workspaceRoot: string, resolved: string): string {
|
|
25
33
|
const relative = path.relative(workspaceRoot, resolved);
|
|
26
34
|
return relative.length === 0 ? "." : relative.split(path.sep).join("/");
|
|
@@ -43,6 +51,60 @@ function packageCheckSource(packageRoot: string, workspaceRoot: string): Declare
|
|
|
43
51
|
return { kind: "package.json", path: packagePath, checks };
|
|
44
52
|
}
|
|
45
53
|
|
|
54
|
+
/** Discover every exact project-declared entry without promoting it to a verifier check. */
|
|
55
|
+
export function discoverDeclaredProjectEntriesAtRoot(workspaceRoot: string): DeclaredProjectEntry[] {
|
|
56
|
+
const entries: DeclaredProjectEntry[] = [];
|
|
57
|
+
const packagePath = path.join(workspaceRoot, "package.json");
|
|
58
|
+
if (existsSync(packagePath)) {
|
|
59
|
+
const pkg = parsePackageJson(packagePath);
|
|
60
|
+
if (pkg.ok) {
|
|
61
|
+
for (const name of Object.keys(pkg.scripts).sort()) {
|
|
62
|
+
if (typeof pkg.scripts[name] !== "string") continue;
|
|
63
|
+
entries.push({
|
|
64
|
+
id: name,
|
|
65
|
+
command: ["npm", "run", name],
|
|
66
|
+
path: "package.json",
|
|
67
|
+
detail: `package.json script '${name}'`,
|
|
68
|
+
kind: "package-script",
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
for (const relative of ["justfile", "Justfile"] as const) {
|
|
74
|
+
const filePath = path.join(workspaceRoot, relative);
|
|
75
|
+
if (!existsSync(filePath)) continue;
|
|
76
|
+
const text = readFileSync(filePath, "utf8");
|
|
77
|
+
for (const match of text.matchAll(/^([A-Za-z0-9][A-Za-z0-9_-]*)\s*(?:[^:=\n]*)?:\s*(?:#.*)?$/gmu)) {
|
|
78
|
+
const name = match[1];
|
|
79
|
+
if (name === undefined || name.startsWith("_")) continue;
|
|
80
|
+
entries.push({
|
|
81
|
+
id: name,
|
|
82
|
+
command: ["just", name],
|
|
83
|
+
path: relative,
|
|
84
|
+
detail: `just recipe '${name}'`,
|
|
85
|
+
kind: "just-recipe",
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
const makePath = path.join(workspaceRoot, "Makefile");
|
|
91
|
+
if (existsSync(makePath)) {
|
|
92
|
+
const text = readFileSync(makePath, "utf8");
|
|
93
|
+
for (const match of text.matchAll(/^([A-Za-z0-9][A-Za-z0-9_.-]*)\s*:(?![=])[^\n]*$/gmu)) {
|
|
94
|
+
const name = match[1];
|
|
95
|
+
if (name === undefined || name.startsWith(".")) continue;
|
|
96
|
+
entries.push({
|
|
97
|
+
id: name,
|
|
98
|
+
command: ["make", name],
|
|
99
|
+
path: "Makefile",
|
|
100
|
+
detail: `Makefile target '${name}'`,
|
|
101
|
+
kind: "make-target",
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return entries;
|
|
106
|
+
}
|
|
107
|
+
|
|
46
108
|
function providerCollision(sources: ReadonlyArray<DeclaredCheckSource>): string | null {
|
|
47
109
|
const seen = new Map<string, DeclaredCheck>();
|
|
48
110
|
for (const source of sources) {
|
|
@@ -127,7 +127,7 @@ export function receiptEvidenceLabels(
|
|
|
127
127
|
verification: RunReceiptVerification,
|
|
128
128
|
integrity: ReceiptIntegrityResult,
|
|
129
129
|
): string[] {
|
|
130
|
-
const status = adaptRunReceiptTrustStatus({ ...receipt, verification }, { integrity });
|
|
130
|
+
const status = adaptRunReceiptTrustStatus({ ...receipt, verification: verification }, { integrity });
|
|
131
131
|
const canonical = canonicalTrustLabel(status);
|
|
132
132
|
if (!integrity.ok) {
|
|
133
133
|
return [canonical, `receipt_integrity=FAILED reason=${JSON.stringify(integrity.reason)}`];
|
|
@@ -157,6 +157,7 @@ export function receiptEvidenceLabels(
|
|
|
157
157
|
canonical,
|
|
158
158
|
`receipt_integrity=verified/v${receipt.integrity.version}/${receipt.integrity.algorithm}`,
|
|
159
159
|
`evidence_verification=${verification.state}/${verification.basis}`,
|
|
160
|
+
`host_verification=${receipt.hostVerification?.status ?? "not_requested"}`,
|
|
160
161
|
...(responseModelIdObservation ? [responseModelIdObservation] : []),
|
|
161
162
|
...budget,
|
|
162
163
|
...receiptAdmissionLabels(receipt),
|
|
@@ -225,6 +225,7 @@ const TOOL_PROFILE_NAMES = [
|
|
|
225
225
|
"minimal-local",
|
|
226
226
|
"science-local",
|
|
227
227
|
"full-agent",
|
|
228
|
+
"council-read-only",
|
|
228
229
|
] as const satisfies ReadonlyArray<ToolProfileName>;
|
|
229
230
|
const WORKER_PRODUCTS = ["orientation"] as const satisfies ReadonlyArray<AgentProduct>;
|
|
230
231
|
const TARGET_LIFECYCLES = ["user-managed", "clio-managed"] as const;
|
package/dist/chunk-HC4CLZ2Y.js
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { createRequire as __clioCreateRequire } from "node:module"; const require = __clioCreateRequire(import.meta.url);
|
|
2
|
-
import {
|
|
3
|
-
withStateFileLock
|
|
4
|
-
} from "./chunk-IKCO5N3L.js";
|
|
5
|
-
import {
|
|
6
|
-
safeResourceWrite
|
|
7
|
-
} from "./chunk-WEPFGWHJ.js";
|
|
8
|
-
import {
|
|
9
|
-
init_esm_shims
|
|
10
|
-
} from "./chunk-3R73A4XB.js";
|
|
11
|
-
|
|
12
|
-
// src/domains/observability/evidence-index.ts
|
|
13
|
-
init_esm_shims();
|
|
14
|
-
import { readFileSync } from "node:fs";
|
|
15
|
-
import { join } from "node:path";
|
|
16
|
-
var MAX_EVIDENCE_INDEX_ROWS = 1e3;
|
|
17
|
-
var EVIDENCE_INDEX_FILE = "evidence-index.json";
|
|
18
|
-
var evidenceIndexWriteQueue = Promise.resolve();
|
|
19
|
-
function indexPath(stateDir) {
|
|
20
|
-
return join(stateDir, EVIDENCE_INDEX_FILE);
|
|
21
|
-
}
|
|
22
|
-
function isEvidenceIndexRow(value) {
|
|
23
|
-
if (typeof value !== "object" || value === null) return false;
|
|
24
|
-
const row = value;
|
|
25
|
-
return typeof row.runId === "string" && typeof row.evidenceId === "string" && Array.isArray(row.tags) && row.tags.every((tag) => typeof tag === "string") && typeof row.firstPassSuccess === "boolean" && typeof row.findingCount === "number" && typeof row.generatedAt === "string";
|
|
26
|
-
}
|
|
27
|
-
function readEvidenceIndex(stateDir) {
|
|
28
|
-
let raw;
|
|
29
|
-
try {
|
|
30
|
-
raw = readFileSync(indexPath(stateDir), "utf8");
|
|
31
|
-
} catch {
|
|
32
|
-
return [];
|
|
33
|
-
}
|
|
34
|
-
let parsed;
|
|
35
|
-
try {
|
|
36
|
-
parsed = JSON.parse(raw);
|
|
37
|
-
} catch {
|
|
38
|
-
return [];
|
|
39
|
-
}
|
|
40
|
-
if (!Array.isArray(parsed)) return [];
|
|
41
|
-
return parsed.filter(isEvidenceIndexRow);
|
|
42
|
-
}
|
|
43
|
-
async function writeEvidenceIndexRow(stateDir, row) {
|
|
44
|
-
let bounded = [];
|
|
45
|
-
await withStateFileLock(indexPath(stateDir), () => {
|
|
46
|
-
const existing = readEvidenceIndex(stateDir).filter((entry) => entry.runId !== row.runId);
|
|
47
|
-
existing.push(row);
|
|
48
|
-
bounded = existing.length > MAX_EVIDENCE_INDEX_ROWS ? existing.slice(-MAX_EVIDENCE_INDEX_ROWS) : existing;
|
|
49
|
-
safeResourceWrite(indexPath(stateDir), `${JSON.stringify(bounded, null, 2)}
|
|
50
|
-
`, { encoding: "utf8" });
|
|
51
|
-
});
|
|
52
|
-
return bounded;
|
|
53
|
-
}
|
|
54
|
-
async function writeEvidenceIndexRowQueued(stateDir, row) {
|
|
55
|
-
let written = [];
|
|
56
|
-
const write = evidenceIndexWriteQueue.then(async () => {
|
|
57
|
-
written = await writeEvidenceIndexRow(stateDir, row);
|
|
58
|
-
});
|
|
59
|
-
evidenceIndexWriteQueue = write.catch(() => void 0);
|
|
60
|
-
await write;
|
|
61
|
-
return written;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export {
|
|
65
|
-
readEvidenceIndex,
|
|
66
|
-
writeEvidenceIndexRowQueued
|
|
67
|
-
};
|
|
68
|
-
//# sourceMappingURL=chunk-HC4CLZ2Y.js.map
|