@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.
Files changed (258) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +16 -5
  3. package/dist/{acp-2BEHC4DL.js → acp-SK4MD6MM.js} +10 -10
  4. package/dist/{agents-LNNFTM53.js → agents-2FN2K6ME.js} +30 -25
  5. package/dist/assets/codewiki.json +1 -1
  6. package/dist/{auth-KXXFI2VS.js → auth-QIYZWM5I.js} +13 -13
  7. package/dist/{chunk-KHSFENX2.js → chunk-3HAPLH5M.js} +10 -10
  8. package/dist/{chunk-24I7BN55.js → chunk-465YSENW.js} +2 -2
  9. package/dist/{chunk-4OC57DA6.js → chunk-4DGYLA73.js} +53 -2
  10. package/dist/{chunk-CYQKWTG3.js → chunk-4DWFMQDR.js} +4 -4
  11. package/dist/{chunk-E2ER4LJF.js → chunk-5C3AQNDW.js} +25 -1
  12. package/dist/{chunk-22NAGB7X.js → chunk-5C77SEEY.js} +5 -94
  13. package/dist/{chunk-43AOLP7E.js → chunk-5FR74PWO.js} +2 -1
  14. package/dist/{chunk-K7T3E2SR.js → chunk-5UJ6ECTS.js} +10 -9
  15. package/dist/{chunk-6US73PDB.js → chunk-6M7VS3J3.js} +5 -5
  16. package/dist/{chunk-CJUB2JJ2.js → chunk-6TUKSZVF.js} +5 -5
  17. package/dist/{chunk-5JGRAMKL.js → chunk-AB4XIIVB.js} +8 -6
  18. package/dist/{chunk-R46L2BIR.js → chunk-BMWK7ZIZ.js} +14 -20
  19. package/dist/{chunk-4BPJXDWC.js → chunk-C4JBQ5SR.js} +30 -14
  20. package/dist/{chunk-XXQNGV4M.js → chunk-CEYBNUGC.js} +243 -63
  21. package/dist/{chunk-VEZEGCGW.js → chunk-D4MDIG46.js} +20 -18
  22. package/dist/chunk-DJNLUABN.js +843 -0
  23. package/dist/{chunk-RY3LY4J5.js → chunk-DMD2AGVS.js} +5 -4
  24. package/dist/{chunk-KOHPCX4K.js → chunk-DOOEX22V.js} +2 -2
  25. package/dist/chunk-DQA7QLMD.js +123 -0
  26. package/dist/chunk-DR52UMZW.js +21 -0
  27. package/dist/{chunk-XF5N4U5A.js → chunk-EBEFWSGL.js} +6 -5
  28. package/dist/{chunk-EYPA3EGJ.js → chunk-EELBMBT6.js} +120 -13
  29. package/dist/{chunk-CKXWIANG.js → chunk-EOOQZZDE.js} +16 -14
  30. package/dist/{chunk-WR67VIZY.js → chunk-FOT2FX5J.js} +63 -5
  31. package/dist/{chunk-FYYLNIL5.js → chunk-GH5622CP.js} +2 -2
  32. package/dist/chunk-GWS3VEIW.js +195 -0
  33. package/dist/{chunk-LYF7OHWH.js → chunk-J7PIKKWC.js} +8 -463
  34. package/dist/{chunk-NILBFAPG.js → chunk-JNXPYBB4.js} +2 -2
  35. package/dist/{chunk-4VP4KH3K.js → chunk-JRIO5UD2.js} +4 -4
  36. package/dist/{chunk-6XXKFVSN.js → chunk-JTSEDYVQ.js} +7 -7
  37. package/dist/{chunk-QKMUKYO7.js → chunk-KCMKRQX4.js} +236 -84
  38. package/dist/chunk-KZ2H5X4G.js +1026 -0
  39. package/dist/{chunk-QNQHSOLF.js → chunk-LADCF22A.js} +12 -12
  40. package/dist/chunk-M4AKACEO.js +382 -0
  41. package/dist/{chunk-XYDYPRZI.js → chunk-MXI6J5JF.js} +7 -7
  42. package/dist/{chunk-G7MUEIGA.js → chunk-OB5HIGJY.js} +1 -1
  43. package/dist/{chunk-EKY57CSP.js → chunk-OBMAI2DP.js} +61 -767
  44. package/dist/chunk-PD3MESLB.js +242 -0
  45. package/dist/{chunk-ZRGEBJ4T.js → chunk-QCTRSGHQ.js} +21 -21
  46. package/dist/chunk-RVG5JXAL.js +41 -0
  47. package/dist/{chunk-RD5U66HV.js → chunk-SROCI7ZU.js} +7 -7
  48. package/dist/{chunk-MFFY33HR.js → chunk-THKY7CD7.js} +466 -205
  49. package/dist/{chunk-PCZJO5TI.js → chunk-UFQ3F4FW.js} +13 -178
  50. package/dist/{chunk-AD2SYQYC.js → chunk-UHXRNZ2J.js} +121 -3
  51. package/dist/chunk-UND3GU2L.js +103 -0
  52. package/dist/{chunk-QM3F2GKX.js → chunk-UUANF5CR.js} +2247 -2096
  53. package/dist/chunk-UVDSQ6LW.js +472 -0
  54. package/dist/{chunk-DJVECN66.js → chunk-VQNODYQ4.js} +14 -14
  55. package/dist/{chunk-3BPUFZDL.js → chunk-VREKEFLL.js} +3 -3
  56. package/dist/{chunk-PBTHKCPN.js → chunk-WJHBC77E.js} +6 -6
  57. package/dist/{chunk-XE2VEJHX.js → chunk-X2KV5FXT.js} +2 -2
  58. package/dist/{chunk-ZXF4XRKW.js → chunk-XEGB6BCN.js} +157 -7
  59. package/dist/{chunk-E25LMLRW.js → chunk-YD734TPH.js} +2 -2
  60. package/dist/{verifiers-NCBTHHN2.js → chunk-YTYFXUI3.js} +65 -322
  61. package/dist/{chunk-OH3TOQTB.js → chunk-ZGH7FGS5.js} +13 -7
  62. package/dist/cli/index.js +32 -30
  63. package/dist/{clio-M2KGYUFZ.js → clio-WBVQEBKO.js} +7 -7
  64. package/dist/{code-nav-GQNL7XA6.js → code-nav-FGGFIE7L.js} +3 -3
  65. package/dist/{components-5TTYYX6G.js → components-F7OEATSO.js} +4 -4
  66. package/dist/{config-XUUYQIWO.js → config-TRBL3RCF.js} +34 -29
  67. package/dist/{configure-IHJ7YOMV.js → configure-OLCVPHNM.js} +15 -15
  68. package/dist/{context-74JLXAWD.js → context-MJIJ6GOX.js} +11 -11
  69. package/dist/{context-ZQ7SIFJV.js → context-WFPKQSM6.js} +19 -3
  70. package/dist/{context-75MIWW3U.js → context-XEWE3MOJ.js} +31 -26
  71. package/dist/{context-clear-GYKWNUML.js → context-clear-KNOS2JPB.js} +31 -26
  72. package/dist/{context-working-set-UX5KEP4J.js → context-working-set-EUXAZI6N.js} +8 -8
  73. package/dist/{dispatch-runner-GIJBHNFL.js → dispatch-runner-B7MTOVKL.js} +313 -53
  74. package/dist/{docs-6FZSCG5B.js → docs-FLJTIDSE.js} +4 -4
  75. package/dist/{doctor-SVJ5BZCW.js → doctor-RN4YKO2X.js} +14 -14
  76. package/dist/{eval-CG6LLBLD.js → eval-RUBJVSNQ.js} +8 -7
  77. package/dist/{evidence-ZYFIEN42.js → evidence-JZNBUOQZ.js} +30 -25
  78. package/dist/{evolve-QGEXEMDW.js → evolve-FJVC4KKI.js} +30 -25
  79. package/dist/{extensions-ADGNCJJD.js → extensions-IQL36S7K.js} +4 -4
  80. package/dist/{fleet-S5R4ZOQY.js → fleet-BDKYJFCP.js} +214 -360
  81. package/dist/fleet-commands-ZFIWZSB3.js +70 -0
  82. package/dist/fleet-graph-Y6HPXIVF.js +125 -0
  83. package/dist/fleet-new-RDVJLHHH.js +48 -0
  84. package/dist/fleet-validate-BIYREGIK.js +79 -0
  85. package/dist/{init-5DRU55YR.js → init-LQUB5COQ.js} +44 -37
  86. package/dist/library-NJAHIGG4.js +217 -0
  87. package/dist/{memory-7YKKR6UC.js → memory-OG6HOYKM.js} +31 -26
  88. package/dist/{models-ZPOLRU2C.js → models-5ZG5XY7J.js} +21 -20
  89. package/dist/{monitor-US5F5YGZ.js → monitor-TJ7AMTGB.js} +49 -30
  90. package/dist/{orchestrator-E2AL4T5N.js → orchestrator-WZYB54DM.js} +3827 -581
  91. package/dist/{paths-E7KYAQWE.js → paths-XUC7GS6E.js} +4 -4
  92. package/dist/{reset-KZ652EK6.js → reset-PXQT45IY.js} +7 -7
  93. package/dist/{run-SRNBKDWD.js → run-FQ74YF62.js} +53 -45
  94. package/dist/{share-CGZE33UP.js → share-FW7SVCL3.js} +33 -9
  95. package/dist/{skills-S2X4DLY5.js → skills-7E7IRB3R.js} +24 -8
  96. package/dist/{skills-eval-W2GGIC4R.js → skills-eval-LI75W6OK.js} +34 -27
  97. package/dist/{targets-54SWINWB.js → targets-4CIFKCTW.js} +23 -22
  98. package/dist/{terminal-lease-SAIF2OGY.js → terminal-lease-WUZY7ZV5.js} +4 -4
  99. package/dist/{uninstall-BVLWXKBT.js → uninstall-7FV7IP4E.js} +4 -4
  100. package/dist/{upgrade-JKAR27XC.js → upgrade-K2HVIVMQ.js} +20 -19
  101. package/dist/{usage-MSAWCLX4.js → usage-GTZELZQX.js} +116 -49
  102. package/dist/verifiers-RLAHT27O.js +336 -0
  103. package/dist/{verify-X5HDROLA.js → verify-BX3BRKH5.js} +7 -6
  104. package/dist/{wiki-generate-GUSOQ6ZP.js → wiki-generate-ASIFASCN.js} +45 -37
  105. package/dist/worker/entry.js +38 -35
  106. package/docs/README.md +3 -2
  107. package/docs/acp.md +1 -1
  108. package/docs/alcf-provider.md +1 -1
  109. package/docs/architecture.md +2 -2
  110. package/docs/artifact-versions.md +10 -6
  111. package/docs/built-in-agents.md +26 -2
  112. package/docs/capacity-and-scheduling.md +1 -1
  113. package/docs/commands-and-modes.md +82 -2
  114. package/docs/configuration-and-targets.md +79 -2
  115. package/docs/context-engine.md +1 -1
  116. package/docs/development-pipeline.md +1 -1
  117. package/docs/dispatch-architecture-rationale.md +1 -1
  118. package/docs/documentation-coverage.md +3 -3
  119. package/docs/documentation-guide.md +3 -3
  120. package/docs/eval-runner.md +1 -1
  121. package/docs/evals-internal.md +1 -1
  122. package/docs/evidence-and-memory.md +5 -5
  123. package/docs/evolution.md +1 -1
  124. package/docs/exit-codes-and-output.md +4 -1
  125. package/docs/extensions-and-sharing.md +6 -2
  126. package/docs/fleet-demo-runbook.md +2 -2
  127. package/docs/fleet-dispatch.md +197 -10
  128. package/docs/git-commit-provenance.md +2 -2
  129. package/docs/glossary.md +1 -1
  130. package/docs/installation-and-lifecycle.md +2 -2
  131. package/docs/middleware-and-components.md +2 -1
  132. package/docs/model-catalog.md +1 -1
  133. package/docs/observability.md +55 -8
  134. package/docs/proactive-memory.md +1 -1
  135. package/docs/prompt-envelope-and-tools.md +1 -1
  136. package/docs/provider-adapter-cookbook.md +1 -1
  137. package/docs/release-cut-checklist.md +79 -64
  138. package/docs/resource-library.md +59 -0
  139. package/docs/safety-model.md +2 -2
  140. package/docs/scientific-validation.md +3 -3
  141. package/docs/session-lifecycle.md +37 -1
  142. package/docs/skills-marketplace.md +16 -3
  143. package/docs/tool-usage.md +14 -7
  144. package/docs/trace-store.md +1 -1
  145. package/docs/troubleshooting.md +1 -1
  146. package/docs/tui-design.md +1 -1
  147. package/docs/worker-dispatch-mechanics.md +3 -3
  148. package/package.json +1 -1
  149. package/src/cli/fleet-commands.ts +37 -0
  150. package/src/cli/fleet-graph.ts +102 -0
  151. package/src/cli/fleet-new.ts +36 -0
  152. package/src/cli/fleet-preflight.ts +121 -0
  153. package/src/cli/fleet-validate.ts +30 -0
  154. package/src/cli/fleet.ts +173 -335
  155. package/src/cli/index.ts +3 -1
  156. package/src/cli/library.ts +190 -0
  157. package/src/cli/share.ts +13 -1
  158. package/src/cli/usage.ts +111 -19
  159. package/src/core/bus-events.ts +4 -0
  160. package/src/core/commit-attribution.ts +4 -4
  161. package/src/core/config.ts +130 -0
  162. package/src/core/defaults.ts +81 -0
  163. package/src/domains/agents/builtins/architect.md +1 -0
  164. package/src/domains/agents/builtins/oracle.md +33 -0
  165. package/src/domains/agents/catalog.ts +13 -1
  166. package/src/domains/agents/fleet-contract.ts +278 -16
  167. package/src/domains/agents/index.ts +14 -0
  168. package/src/domains/agents/result-contract.ts +235 -1
  169. package/src/domains/config/classify.ts +4 -0
  170. package/src/domains/dispatch/active-route-planner.ts +14 -0
  171. package/src/domains/dispatch/backoff.ts +2 -1
  172. package/src/domains/dispatch/capability-match.ts +1 -0
  173. package/src/domains/dispatch/checkout-writer-lease.ts +175 -0
  174. package/src/domains/dispatch/contract.ts +34 -0
  175. package/src/domains/dispatch/delegation-plan.ts +167 -0
  176. package/src/domains/dispatch/execution-plan.ts +76 -5
  177. package/src/domains/dispatch/execution-role.ts +3 -1
  178. package/src/domains/dispatch/execution-scheduler.ts +183 -67
  179. package/src/domains/dispatch/extension.ts +258 -9
  180. package/src/domains/dispatch/fleet-gate.ts +14 -0
  181. package/src/domains/dispatch/fleet-plan.ts +63 -3
  182. package/src/domains/dispatch/fleet-run.ts +737 -0
  183. package/src/domains/dispatch/gate-role-prompts.ts +9 -0
  184. package/src/domains/dispatch/host-verification.ts +178 -0
  185. package/src/domains/dispatch/index.ts +38 -0
  186. package/src/domains/dispatch/intent.ts +159 -0
  187. package/src/domains/dispatch/receipt-integrity.ts +8 -4
  188. package/src/domains/dispatch/state.ts +36 -3
  189. package/src/domains/dispatch/types.ts +51 -6
  190. package/src/domains/dispatch/validation.ts +66 -6
  191. package/src/domains/evidence/trust-status.ts +10 -1
  192. package/src/domains/middleware/index.ts +15 -0
  193. package/src/domains/middleware/watchdog.ts +281 -0
  194. package/src/domains/observability/contract.ts +3 -1
  195. package/src/domains/observability/cost.ts +12 -1
  196. package/src/domains/observability/extension.ts +2 -2
  197. package/src/domains/observability/index.ts +10 -0
  198. package/src/domains/observability/out-of-turn-usage.ts +223 -0
  199. package/src/domains/resources/index.ts +20 -0
  200. package/src/domains/resources/library.ts +326 -0
  201. package/src/domains/resources/skills/marketplace.ts +37 -12
  202. package/src/domains/session/handoff.ts +629 -0
  203. package/src/domains/share/archive.ts +67 -2
  204. package/src/entry/orchestrator.ts +37 -0
  205. package/src/interactive/bus-notices.ts +26 -0
  206. package/src/interactive/chat-loop.ts +235 -1
  207. package/src/interactive/chat-renderer.ts +22 -0
  208. package/src/interactive/cost-overlay.ts +31 -3
  209. package/src/interactive/council-dispatch.ts +30 -0
  210. package/src/interactive/council-grid.ts +213 -0
  211. package/src/interactive/council.ts +99 -0
  212. package/src/interactive/dispatch-board.ts +260 -16
  213. package/src/interactive/fleet-run-preview.ts +307 -0
  214. package/src/interactive/footer/notifications.ts +219 -0
  215. package/src/interactive/handoff-round.ts +56 -0
  216. package/src/interactive/interactive-application.ts +43 -1
  217. package/src/interactive/interactive-event-projection.ts +9 -1
  218. package/src/interactive/interactive-slash-runtime.ts +52 -2
  219. package/src/interactive/interactive-subscriptions.ts +14 -2
  220. package/src/interactive/oracle.ts +179 -0
  221. package/src/interactive/overlay-ask-user-lifecycle.ts +6 -0
  222. package/src/interactive/overlay-general-openers.ts +190 -1
  223. package/src/interactive/overlay-key-routing.ts +17 -1
  224. package/src/interactive/overlay-lifecycle.ts +41 -1
  225. package/src/interactive/overlay-permission-lifecycle.ts +10 -0
  226. package/src/interactive/overlay-resource-openers.ts +11 -3
  227. package/src/interactive/overlay-session-lifecycle.ts +234 -2
  228. package/src/interactive/overlays/fleet-run-approval.ts +208 -0
  229. package/src/interactive/overlays/handoff-review.ts +185 -0
  230. package/src/interactive/overlays/library-install-confirm.ts +151 -0
  231. package/src/interactive/overlays/list-overlay.ts +168 -2
  232. package/src/interactive/overlays/settings.ts +101 -4
  233. package/src/interactive/overlays/side-question.ts +139 -0
  234. package/src/interactive/overlays/skills-hub.ts +401 -15
  235. package/src/interactive/side-question.ts +171 -0
  236. package/src/interactive/slash-commands.ts +432 -5
  237. package/src/interactive/slash-spec.ts +19 -6
  238. package/src/interactive/theme/tokens.ts +30 -0
  239. package/src/interactive/turn-middleware.ts +15 -1
  240. package/src/interactive/watchdog-run.ts +75 -0
  241. package/src/interactive/worker-share.ts +56 -1
  242. package/src/interactive/worker-stream.ts +7 -0
  243. package/src/tools/bootstrap.ts +3 -0
  244. package/src/tools/compete-worktrees.ts +13 -79
  245. package/src/tools/dispatch-admission.ts +242 -8
  246. package/src/tools/dispatch-arguments.ts +57 -1
  247. package/src/tools/dispatch-plan.ts +136 -6
  248. package/src/tools/dispatch-runner.ts +319 -13
  249. package/src/tools/dispatch-types.ts +20 -1
  250. package/src/tools/dispatch.ts +72 -2
  251. package/src/tools/monitor.ts +16 -0
  252. package/src/tools/profiles.ts +18 -4
  253. package/src/tools/task-worktree.ts +238 -0
  254. package/src/tools/verify/authoring.ts +61 -1
  255. package/src/tools/verify/scripts.ts +62 -0
  256. package/src/tools/worker-evidence.ts +2 -1
  257. package/src/worker/spec-contract.ts +1 -0
  258. 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;
@@ -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