@flyingrobots/graft 0.7.0 → 0.7.1

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 (283) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +0 -1
  3. package/bin/graft.js +26 -26
  4. package/dist/cli/init-client-config.d.ts.map +1 -1
  5. package/dist/cli/init-client-config.js +40 -4
  6. package/dist/cli/init-client-config.js.map +1 -1
  7. package/dist/cli/init-model.js +2 -2
  8. package/dist/cli/init-model.js.map +1 -1
  9. package/dist/cli/json-document.d.ts +1 -0
  10. package/dist/cli/json-document.d.ts.map +1 -1
  11. package/dist/cli/json-document.js +3 -0
  12. package/dist/cli/json-document.js.map +1 -1
  13. package/dist/hooks/posttooluse-read.js +1 -1
  14. package/dist/hooks/posttooluse-read.js.map +1 -1
  15. package/dist/hooks/pretooluse-read.js +1 -1
  16. package/dist/hooks/pretooluse-read.js.map +1 -1
  17. package/dist/mcp/daemon-worker-child-pool.d.ts +2 -0
  18. package/dist/mcp/daemon-worker-child-pool.d.ts.map +1 -1
  19. package/dist/mcp/daemon-worker-child-pool.js +10 -3
  20. package/dist/mcp/daemon-worker-child-pool.js.map +1 -1
  21. package/dist/mcp/daemon-worker-pool.d.ts +1 -1
  22. package/dist/mcp/daemon-worker-pool.d.ts.map +1 -1
  23. package/dist/mcp/daemon-worker-pool.js +1 -1
  24. package/dist/mcp/daemon-worker-pool.js.map +1 -1
  25. package/dist/version.d.ts.map +1 -1
  26. package/dist/version.js +3 -1
  27. package/dist/version.js.map +1 -1
  28. package/docs/SETUP.md +11 -7
  29. package/package.json +9 -4
  30. package/src/adapters/canonical-json.ts +0 -56
  31. package/src/adapters/json-text-decoder.ts +0 -11
  32. package/src/adapters/node-fs.ts +0 -43
  33. package/src/adapters/node-git.ts +0 -47
  34. package/src/adapters/node-paths.ts +0 -35
  35. package/src/adapters/node-process-runner.ts +0 -27
  36. package/src/adapters/repo-paths.ts +0 -63
  37. package/src/adapters/rotating-ndjson-log.ts +0 -66
  38. package/src/api/index.ts +0 -107
  39. package/src/api/repo-local-graft.ts +0 -21
  40. package/src/api/repo-workspace.ts +0 -34
  41. package/src/api/tool-bridge.ts +0 -22
  42. package/src/cli/activity-render.ts +0 -112
  43. package/src/cli/cli-error.ts +0 -192
  44. package/src/cli/command-parser.ts +0 -484
  45. package/src/cli/daemon-status-model.ts +0 -238
  46. package/src/cli/daemon-status-render.ts +0 -102
  47. package/src/cli/daemon-status.ts +0 -100
  48. package/src/cli/entrypoint.ts +0 -18
  49. package/src/cli/git-graft-enhance-model.ts +0 -131
  50. package/src/cli/git-graft-enhance-render.ts +0 -33
  51. package/src/cli/git-graft-enhance.ts +0 -54
  52. package/src/cli/index-cmd.ts +0 -90
  53. package/src/cli/index-model.ts +0 -75
  54. package/src/cli/init-bootstrap.ts +0 -47
  55. package/src/cli/init-client-config.ts +0 -428
  56. package/src/cli/init-model.ts +0 -284
  57. package/src/cli/init-render.ts +0 -54
  58. package/src/cli/init-target-hooks.ts +0 -93
  59. package/src/cli/init.ts +0 -124
  60. package/src/cli/json-document.ts +0 -155
  61. package/src/cli/local-history-dag-model.ts +0 -437
  62. package/src/cli/local-history-dag-render.ts +0 -133
  63. package/src/cli/local-history-dag.ts +0 -103
  64. package/src/cli/main.ts +0 -197
  65. package/src/cli/migrate-local-history.ts +0 -119
  66. package/src/cli/peer-command.ts +0 -60
  67. package/src/contracts/capabilities.ts +0 -540
  68. package/src/contracts/causal-ontology.ts +0 -627
  69. package/src/contracts/causal-surface-next-action.ts +0 -18
  70. package/src/contracts/json-object.ts +0 -18
  71. package/src/contracts/mcp-runtime.ts +0 -16
  72. package/src/contracts/output-schema-cli.ts +0 -103
  73. package/src/contracts/output-schema-fragments.ts +0 -881
  74. package/src/contracts/output-schema-mcp.ts +0 -501
  75. package/src/contracts/output-schema-meta.ts +0 -119
  76. package/src/contracts/output-schemas.ts +0 -1524
  77. package/src/git/diff.ts +0 -161
  78. package/src/git/target-git-hook-bootstrap.ts +0 -56
  79. package/src/guards/stream-boundary.ts +0 -110
  80. package/src/hooks/posttooluse-read.ts +0 -54
  81. package/src/hooks/pretooluse-read.ts +0 -52
  82. package/src/hooks/read-governor.ts +0 -95
  83. package/src/hooks/read-messages.ts +0 -53
  84. package/src/hooks/shared.ts +0 -168
  85. package/src/index.ts +0 -1
  86. package/src/mcp/burden.ts +0 -132
  87. package/src/mcp/cache.ts +0 -7
  88. package/src/mcp/cached-file.ts +0 -1
  89. package/src/mcp/context.ts +0 -150
  90. package/src/mcp/control-plane/authz-storage.ts +0 -129
  91. package/src/mcp/control-plane/session-registry.ts +0 -115
  92. package/src/mcp/control-plane/status-projection.ts +0 -76
  93. package/src/mcp/control-plane/types.ts +0 -144
  94. package/src/mcp/daemon-bootstrap.ts +0 -100
  95. package/src/mcp/daemon-control-plane.ts +0 -310
  96. package/src/mcp/daemon-job-scheduler.ts +0 -279
  97. package/src/mcp/daemon-repos.ts +0 -99
  98. package/src/mcp/daemon-server.ts +0 -172
  99. package/src/mcp/daemon-session-host.ts +0 -234
  100. package/src/mcp/daemon-stdio-bridge.ts +0 -262
  101. package/src/mcp/daemon-worker-child-pool.ts +0 -213
  102. package/src/mcp/daemon-worker-inline-pool.ts +0 -46
  103. package/src/mcp/daemon-worker-pool.ts +0 -7
  104. package/src/mcp/daemon-worker-process.ts +0 -52
  105. package/src/mcp/daemon-worker-types.ts +0 -66
  106. package/src/mcp/metrics.ts +0 -176
  107. package/src/mcp/monitor-health.ts +0 -83
  108. package/src/mcp/monitor-persistence.ts +0 -54
  109. package/src/mcp/monitor-tick-job.ts +0 -153
  110. package/src/mcp/monitor-types.ts +0 -103
  111. package/src/mcp/persisted-local-history-graph.ts +0 -592
  112. package/src/mcp/persisted-local-history-policy.ts +0 -501
  113. package/src/mcp/persisted-local-history-views.ts +0 -250
  114. package/src/mcp/persisted-local-history.ts +0 -1621
  115. package/src/mcp/persistent-monitor-runtime.ts +0 -482
  116. package/src/mcp/policy.ts +0 -75
  117. package/src/mcp/receipt.ts +0 -201
  118. package/src/mcp/repo-concurrency.ts +0 -392
  119. package/src/mcp/repo-overview/filter.ts +0 -44
  120. package/src/mcp/repo-overview/types.ts +0 -63
  121. package/src/mcp/repo-overview/view-projection.ts +0 -90
  122. package/src/mcp/repo-state-git.ts +0 -247
  123. package/src/mcp/repo-state-observation.ts +0 -203
  124. package/src/mcp/repo-state-transition.ts +0 -151
  125. package/src/mcp/repo-state-types.ts +0 -107
  126. package/src/mcp/repo-state.ts +0 -146
  127. package/src/mcp/repo-tool-job.ts +0 -102
  128. package/src/mcp/repo-tool-worker-context.ts +0 -215
  129. package/src/mcp/repo-workspace.ts +0 -21
  130. package/src/mcp/run-capture-config.ts +0 -33
  131. package/src/mcp/runtime-causal-context.ts +0 -72
  132. package/src/mcp/runtime-observability.ts +0 -217
  133. package/src/mcp/runtime-staged-target.ts +0 -161
  134. package/src/mcp/runtime-workspace-overlay.ts +0 -255
  135. package/src/mcp/secret-scrub.ts +0 -89
  136. package/src/mcp/semantic-transition-guidance.ts +0 -60
  137. package/src/mcp/semantic-transition-summary.ts +0 -130
  138. package/src/mcp/server-context.ts +0 -236
  139. package/src/mcp/server-invocation.ts +0 -388
  140. package/src/mcp/server-tool-access.ts +0 -148
  141. package/src/mcp/server.ts +0 -270
  142. package/src/mcp/stdio-server.ts +0 -26
  143. package/src/mcp/stdio.ts +0 -3
  144. package/src/mcp/tool-registry.ts +0 -98
  145. package/src/mcp/tools/activity-view.ts +0 -325
  146. package/src/mcp/tools/budget.ts +0 -23
  147. package/src/mcp/tools/causal-attach.ts +0 -67
  148. package/src/mcp/tools/causal-status.ts +0 -58
  149. package/src/mcp/tools/changed-since.ts +0 -71
  150. package/src/mcp/tools/code-find.ts +0 -192
  151. package/src/mcp/tools/code-refs.ts +0 -470
  152. package/src/mcp/tools/code-show.ts +0 -289
  153. package/src/mcp/tools/daemon-monitors.ts +0 -14
  154. package/src/mcp/tools/daemon-repos.ts +0 -22
  155. package/src/mcp/tools/daemon-sessions.ts +0 -14
  156. package/src/mcp/tools/daemon-status.ts +0 -12
  157. package/src/mcp/tools/diagnostic-models.ts +0 -97
  158. package/src/mcp/tools/doctor.ts +0 -83
  159. package/src/mcp/tools/explain.ts +0 -84
  160. package/src/mcp/tools/export-surface-diff.ts +0 -26
  161. package/src/mcp/tools/file-outline.ts +0 -67
  162. package/src/mcp/tools/git-files.ts +0 -73
  163. package/src/mcp/tools/graft-diff.ts +0 -35
  164. package/src/mcp/tools/graft-edit.ts +0 -276
  165. package/src/mcp/tools/knowledge-map.ts +0 -34
  166. package/src/mcp/tools/map-collector.ts +0 -338
  167. package/src/mcp/tools/map.ts +0 -185
  168. package/src/mcp/tools/monitor-nudge.ts +0 -19
  169. package/src/mcp/tools/monitor-pause.ts +0 -18
  170. package/src/mcp/tools/monitor-resume.ts +0 -18
  171. package/src/mcp/tools/monitor-start.ts +0 -20
  172. package/src/mcp/tools/monitor-stop.ts +0 -18
  173. package/src/mcp/tools/precision-live.ts +0 -158
  174. package/src/mcp/tools/precision-match.ts +0 -54
  175. package/src/mcp/tools/precision-paths.ts +0 -59
  176. package/src/mcp/tools/precision-query.ts +0 -127
  177. package/src/mcp/tools/precision-show.ts +0 -86
  178. package/src/mcp/tools/precision-visibility.ts +0 -44
  179. package/src/mcp/tools/precision-warp.ts +0 -101
  180. package/src/mcp/tools/precision.ts +0 -21
  181. package/src/mcp/tools/read-range.ts +0 -28
  182. package/src/mcp/tools/refactor-difficulty.ts +0 -42
  183. package/src/mcp/tools/run-capture.ts +0 -149
  184. package/src/mcp/tools/safe-read.ts +0 -148
  185. package/src/mcp/tools/since.ts +0 -53
  186. package/src/mcp/tools/state.ts +0 -39
  187. package/src/mcp/tools/stats.ts +0 -24
  188. package/src/mcp/tools/structural-blame.ts +0 -55
  189. package/src/mcp/tools/structural-churn.ts +0 -28
  190. package/src/mcp/tools/structural-log.ts +0 -41
  191. package/src/mcp/tools/structural-review.ts +0 -63
  192. package/src/mcp/tools/workspace-authorizations.ts +0 -14
  193. package/src/mcp/tools/workspace-authorize.ts +0 -20
  194. package/src/mcp/tools/workspace-bind.ts +0 -25
  195. package/src/mcp/tools/workspace-rebind.ts +0 -25
  196. package/src/mcp/tools/workspace-revoke.ts +0 -18
  197. package/src/mcp/tools/workspace-status.ts +0 -12
  198. package/src/mcp/warp-pool.ts +0 -36
  199. package/src/mcp/workspace-read-observation-model.ts +0 -48
  200. package/src/mcp/workspace-read-observation.ts +0 -103
  201. package/src/mcp/workspace-router-capability.ts +0 -32
  202. package/src/mcp/workspace-router-history.ts +0 -233
  203. package/src/mcp/workspace-router-model.ts +0 -131
  204. package/src/mcp/workspace-router-resolution.ts +0 -71
  205. package/src/mcp/workspace-router-runtime.ts +0 -246
  206. package/src/mcp/workspace-router.ts +0 -688
  207. package/src/metrics/logger.ts +0 -40
  208. package/src/metrics/types.ts +0 -40
  209. package/src/operations/adaptive-projection.ts +0 -54
  210. package/src/operations/agent-handoff.ts +0 -59
  211. package/src/operations/cached-file.ts +0 -40
  212. package/src/operations/capture-range.ts +0 -64
  213. package/src/operations/conversation-primer.ts +0 -82
  214. package/src/operations/cross-session-resume.ts +0 -104
  215. package/src/operations/deterministic-replay.ts +0 -143
  216. package/src/operations/diff-identity.ts +0 -127
  217. package/src/operations/export-surface-diff.ts +0 -355
  218. package/src/operations/file-outline.ts +0 -48
  219. package/src/operations/footprint-parallelism.ts +0 -98
  220. package/src/operations/graft-diff.ts +0 -169
  221. package/src/operations/horizon-of-readability.ts +0 -60
  222. package/src/operations/import-reference-impact.ts +0 -143
  223. package/src/operations/knowledge-map.ts +0 -96
  224. package/src/operations/observation-cache.ts +0 -165
  225. package/src/operations/projection-safety.ts +0 -111
  226. package/src/operations/read-range.ts +0 -64
  227. package/src/operations/repo-workspace.ts +0 -339
  228. package/src/operations/result-dto.ts +0 -23
  229. package/src/operations/safe-read.ts +0 -118
  230. package/src/operations/semantic-drift.ts +0 -70
  231. package/src/operations/session-filtration.ts +0 -76
  232. package/src/operations/session-replay.ts +0 -73
  233. package/src/operations/sludge-detector.ts +0 -356
  234. package/src/operations/state.ts +0 -66
  235. package/src/operations/structural-blame.ts +0 -197
  236. package/src/operations/structural-review.ts +0 -317
  237. package/src/operations/structured-buffer-compare.ts +0 -429
  238. package/src/operations/structured-buffer-model.ts +0 -456
  239. package/src/operations/structured-buffer-query.ts +0 -794
  240. package/src/operations/structured-buffer.ts +0 -181
  241. package/src/operations/teaching-hints.ts +0 -52
  242. package/src/parser/diff.ts +0 -320
  243. package/src/parser/lang.ts +0 -71
  244. package/src/parser/markdown.ts +0 -197
  245. package/src/parser/outline.ts +0 -316
  246. package/src/parser/runtime.ts +0 -71
  247. package/src/parser/types.ts +0 -75
  248. package/src/policy/evaluate.ts +0 -178
  249. package/src/policy/graftignore.ts +0 -6
  250. package/src/policy/types.ts +0 -87
  251. package/src/ports/codec.ts +0 -13
  252. package/src/ports/filesystem.ts +0 -18
  253. package/src/ports/git.ts +0 -16
  254. package/src/ports/guards.ts +0 -68
  255. package/src/ports/paths.ts +0 -22
  256. package/src/ports/process-runner.ts +0 -22
  257. package/src/release/security-gate.ts +0 -102
  258. package/src/session/tracker.ts +0 -145
  259. package/src/session/types.ts +0 -23
  260. package/src/version.ts +0 -3
  261. package/src/warp/ast-emitter.ts +0 -133
  262. package/src/warp/ast-import-resolver.ts +0 -333
  263. package/src/warp/commit-meta.ts +0 -19
  264. package/src/warp/context.ts +0 -48
  265. package/src/warp/dead-symbols.ts +0 -174
  266. package/src/warp/drift-sentinel.ts +0 -101
  267. package/src/warp/index-head.ts +0 -348
  268. package/src/warp/observers.ts +0 -101
  269. package/src/warp/open.ts +0 -67
  270. package/src/warp/outline-diff-trailer.ts +0 -100
  271. package/src/warp/plumbing.d.ts +0 -24
  272. package/src/warp/refactor-difficulty.ts +0 -257
  273. package/src/warp/references.ts +0 -77
  274. package/src/warp/stale-docs.ts +0 -210
  275. package/src/warp/structural-drift-detection.ts +0 -97
  276. package/src/warp/structural-queries.ts +0 -258
  277. package/src/warp/symbol-timeline.ts +0 -209
  278. package/src/warp/traverse-hydrate.ts +0 -61
  279. package/src/warp/warp-reference-count.ts +0 -47
  280. package/src/warp/warp-structural-blame.ts +0 -65
  281. package/src/warp/warp-structural-churn.ts +0 -309
  282. package/src/warp/warp-structural-log.ts +0 -149
  283. package/src/warp/writer-id.ts +0 -30
@@ -1,40 +0,0 @@
1
- import { RotatingNdjsonLog } from "../adapters/rotating-ndjson-log.js";
2
- import type { FileSystem } from "../ports/filesystem.js";
3
- import type { JsonCodec } from "../ports/codec.js";
4
- import { DecisionEntry } from "./types.js";
5
-
6
- export interface MetricsLoggerOptions {
7
- readonly fs: FileSystem;
8
- readonly codec: JsonCodec;
9
- readonly maxBytes?: number;
10
- }
11
-
12
- export class MetricsLogger {
13
- private readonly writer: RotatingNdjsonLog;
14
-
15
- constructor(logPath: string, options: MetricsLoggerOptions) {
16
- const writerOptions = {
17
- logPath,
18
- fs: options.fs,
19
- codec: options.codec,
20
- ...(options.maxBytes === undefined ? {} : { maxBytes: options.maxBytes }),
21
- };
22
- this.writer = new RotatingNdjsonLog(writerOptions);
23
- }
24
-
25
- async log(entry: Omit<DecisionEntry, "ts">): Promise<void> {
26
- const full = new DecisionEntry({
27
- ts: new Date().toISOString(),
28
- command: entry.command,
29
- path: entry.path,
30
- projection: entry.projection,
31
- reason: entry.reason,
32
- lines: entry.lines,
33
- bytes: entry.bytes,
34
- estimatedBytesAvoided: entry.estimatedBytesAvoided,
35
- sessionDepth: entry.sessionDepth,
36
- tripwire: entry.tripwire,
37
- });
38
- await this.writer.append(full);
39
- }
40
- }
@@ -1,40 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // DecisionEntry — runtime-backed metric event for policy decisions
3
- // ---------------------------------------------------------------------------
4
-
5
- export class DecisionEntry {
6
- readonly ts: string;
7
- readonly command: string;
8
- readonly path: string;
9
- readonly projection: string;
10
- readonly reason: string;
11
- readonly lines: number;
12
- readonly bytes: number;
13
- readonly estimatedBytesAvoided?: number | undefined;
14
- readonly sessionDepth?: string | undefined;
15
- readonly tripwire?: string | null | undefined;
16
-
17
- constructor(fields: {
18
- readonly ts: string;
19
- readonly command: string;
20
- readonly path: string;
21
- readonly projection: string;
22
- readonly reason: string;
23
- readonly lines: number;
24
- readonly bytes: number;
25
- readonly estimatedBytesAvoided?: number | undefined;
26
- readonly sessionDepth?: string | undefined;
27
- readonly tripwire?: string | null | undefined;
28
- }) {
29
- this.ts = fields.ts;
30
- this.command = fields.command;
31
- this.path = fields.path;
32
- this.projection = fields.projection;
33
- this.reason = fields.reason;
34
- this.lines = fields.lines;
35
- this.bytes = fields.bytes;
36
- this.estimatedBytesAvoided = fields.estimatedBytesAvoided;
37
- this.sessionDepth = fields.sessionDepth;
38
- this.tripwire = fields.tripwire;
39
- }
40
- }
@@ -1,54 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Adaptive Projection Selection — structural auto-selection
3
- // ---------------------------------------------------------------------------
4
-
5
- /** Structural metrics for projection selection. */
6
- export interface ProjectionCandidate {
7
- readonly fileLines: number;
8
- readonly fileBytes: number;
9
- readonly symbolCount: number;
10
- readonly outlineCompressionRatio: number;
11
- readonly targetSymbol?: string;
12
- }
13
-
14
- /** Selected projection with reasoning. */
15
- export interface ProjectionSelection {
16
- readonly projection: "outline" | "content" | "range";
17
- readonly reason: string;
18
- }
19
-
20
- const SMALL_FILE_THRESHOLD = 50;
21
- const HORIZON_RATIO = 0.7;
22
-
23
- /**
24
- * Select the optimal projection based on structural metrics.
25
- *
26
- * - Dense large files → outline (saves the most context)
27
- * - Small or irreducibly complex files → content (outline doesn't help)
28
- * - Targeted symbol investigation → range (surgical read)
29
- */
30
- export function selectProjection(candidate: ProjectionCandidate): ProjectionSelection {
31
- // If a specific symbol is targeted, use range
32
- if (candidate.targetSymbol !== undefined) {
33
- return {
34
- projection: "range",
35
- reason: `Targeted read for symbol "${candidate.targetSymbol}" — range is most efficient.`,
36
- };
37
- }
38
-
39
- // Small files or high compression ratio → content
40
- if (candidate.fileLines <= SMALL_FILE_THRESHOLD || candidate.outlineCompressionRatio >= HORIZON_RATIO) {
41
- return {
42
- projection: "content",
43
- reason: candidate.fileLines <= SMALL_FILE_THRESHOLD
44
- ? `Small file (${String(candidate.fileLines)} lines) — content fits easily.`
45
- : `Outline is ${String(Math.round(candidate.outlineCompressionRatio * 100))}% of content — outline provides negligible savings.`,
46
- };
47
- }
48
-
49
- // Default: outline for larger files with good compression
50
- return {
51
- projection: "outline",
52
- reason: `${String(candidate.fileLines)} lines, ${String(candidate.symbolCount)} symbols, ${String(Math.round(candidate.outlineCompressionRatio * 100))}% compression — outline is efficient.`,
53
- };
54
- }
@@ -1,59 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Agent Handoff Protocol — structured session transfer
3
- // ---------------------------------------------------------------------------
4
-
5
- import type { ObservationCache } from "./observation-cache.js";
6
-
7
- /** The structured handoff payload. */
8
- export interface HandoffPayload {
9
- readonly sessionId: string;
10
- readonly filesRead: readonly string[];
11
- readonly symbolsInspected: readonly string[];
12
- readonly observations: number;
13
- readonly budgetConsumed: string;
14
- }
15
-
16
- /** Options for building a handoff. */
17
- export interface HandoffOptions {
18
- readonly cache: ObservationCache;
19
- readonly sessionId: string;
20
- readonly budgetTotal?: number;
21
- readonly budgetConsumed?: number;
22
- }
23
-
24
- /**
25
- * Build a structured handoff payload from the current session state.
26
- *
27
- * Projects the observation cache into a portable JSON payload that
28
- * a receiving agent can use to understand what the departing agent
29
- * knew and where it left off.
30
- */
31
- export function buildHandoff(options: HandoffOptions): HandoffPayload {
32
- const { cache, sessionId } = options;
33
-
34
- const filesRead: string[] = [];
35
- const symbolsInspected: string[] = [];
36
- let observationCount = 0;
37
-
38
- for (const [filePath, observation] of cache.allEntries()) {
39
- filesRead.push(filePath);
40
- for (const entry of observation.outline) {
41
- symbolsInspected.push(entry.name);
42
- }
43
- observationCount++;
44
- }
45
-
46
- let budgetStr = "unknown";
47
- if (options.budgetTotal !== undefined && options.budgetConsumed !== undefined && options.budgetTotal > 0) {
48
- const pct = Math.round((options.budgetConsumed / options.budgetTotal) * 100);
49
- budgetStr = `${String(pct)}%`;
50
- }
51
-
52
- return {
53
- sessionId,
54
- filesRead,
55
- symbolsInspected,
56
- observations: observationCount,
57
- budgetConsumed: budgetStr,
58
- };
59
- }
@@ -1,40 +0,0 @@
1
- import { extractOutlineForFile } from "../parser/outline.js";
2
- import { detectStructuredFormat } from "../parser/lang.js";
3
- import type { SupportedStructuredFormat } from "../parser/lang.js";
4
- import type { OutlineEntry, JumpEntry } from "../parser/types.js";
5
- import { hashContent } from "./observation-cache.js";
6
-
7
- /**
8
- * Immutable snapshot of a file read. Built once from a single read,
9
- * shared by all consumers (cache, policy, outline extraction) to eliminate
10
- * TOCTOU races where the file changes between reads.
11
- */
12
- export class CachedFile {
13
- /** @internal */
14
- private readonly _brand = "CachedFile" as const;
15
- readonly path: string;
16
- readonly rawContent: string;
17
- readonly hash: string;
18
- readonly lang: SupportedStructuredFormat | null;
19
- readonly supportsOutline: boolean;
20
- readonly outline: readonly OutlineEntry[];
21
- readonly jumpTable: readonly JumpEntry[];
22
- readonly actual: { readonly lines: number; readonly bytes: number };
23
-
24
- constructor(filePath: string, rawContent: string) {
25
- this.path = filePath;
26
- this.rawContent = rawContent;
27
- this.hash = hashContent(rawContent);
28
- this.actual = {
29
- lines: rawContent.split("\n").length,
30
- bytes: Buffer.byteLength(rawContent),
31
- };
32
- this.lang = detectStructuredFormat(filePath);
33
- this.supportsOutline = this.lang !== null;
34
- const result = extractOutlineForFile(filePath, rawContent);
35
- this.outline = result?.entries ?? [];
36
- this.jumpTable = result?.jumpTable ?? [];
37
- Object.freeze(this.actual);
38
- Object.freeze(this);
39
- }
40
- }
@@ -1,64 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Capture Range — opaque handles for run_capture output
3
- // ---------------------------------------------------------------------------
4
-
5
-
6
-
7
- interface CaptureEntry {
8
- readonly sessionId: string;
9
- readonly content: string;
10
- readonly lines: readonly string[];
11
- }
12
-
13
- /** Result of a range retrieval. */
14
- export type CaptureRangeResult =
15
- | { readonly ok: true; readonly lines: readonly string[]; readonly totalLines: number }
16
- | { readonly ok: false; readonly error: string };
17
-
18
- /**
19
- * Registry of opaque capture handles.
20
- *
21
- * Maps UUIDs to capture content. Handles are session-scoped — a
22
- * handle from one session is rejected in another.
23
- */
24
- export class CaptureHandleRegistry {
25
- private nextId = 0;
26
- private readonly entries = new Map<string, CaptureEntry>();
27
-
28
- /**
29
- * Register capture content and return an opaque handle.
30
- */
31
- register(sessionId: string, content: string): string {
32
- const handle = `capture-${String(++this.nextId)}`;
33
- const lines = content.split("\n").filter(
34
- (line, index, arr) => index < arr.length - 1 || line.length > 0,
35
- );
36
- this.entries.set(handle, { sessionId, content, lines });
37
- return handle;
38
- }
39
-
40
- /**
41
- * Retrieve a line range from a capture handle.
42
- *
43
- * @param handle - The opaque handle from register()
44
- * @param sessionId - The requesting session (must match the registering session)
45
- * @param start - 1-based start line (inclusive)
46
- * @param end - 1-based end line (inclusive)
47
- */
48
- getRange(handle: string, sessionId: string, start: number, end: number): CaptureRangeResult {
49
- const entry = this.entries.get(handle);
50
- if (entry === undefined) {
51
- return { ok: false, error: "Capture handle not found" };
52
- }
53
- if (entry.sessionId !== sessionId) {
54
- return { ok: false, error: "Capture handle belongs to a different session" };
55
- }
56
-
57
- const totalLines = entry.lines.length;
58
- const clampedStart = Math.max(1, start);
59
- const clampedEnd = Math.min(totalLines, end);
60
- const lines = entry.lines.slice(clampedStart - 1, clampedEnd);
61
-
62
- return { ok: true, lines, totalLines };
63
- }
64
- }
@@ -1,82 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Conversation Primer — auto-orient agent at session start via graft_map
3
- // ---------------------------------------------------------------------------
4
-
5
- import type { GitClient } from "../ports/git.js";
6
- import type { FileSystem } from "../ports/filesystem.js";
7
- import type { PathOps } from "../ports/paths.js";
8
-
9
- /** Result of building a conversation primer. */
10
- export interface ConversationPrimerResult {
11
- readonly scope: string;
12
- readonly files: readonly string[];
13
- readonly truncated: boolean;
14
- readonly totalFiles: number;
15
- }
16
-
17
- /** Options for building a primer. */
18
- export interface ConversationPrimerOptions {
19
- readonly cwd: string;
20
- readonly git: GitClient;
21
- readonly fs: FileSystem;
22
- readonly pathOps: PathOps;
23
- readonly scope?: string;
24
- readonly maxFiles?: number;
25
- }
26
-
27
- /** Common source directory names, in priority order. */
28
- const COMMON_SCOPES = ["src", "lib", "app", "packages"];
29
-
30
- async function isDirectory(fileSystem: FileSystem, dirPath: string): Promise<boolean> {
31
- try {
32
- await fileSystem.readdir(dirPath);
33
- return true;
34
- } catch {
35
- return false;
36
- }
37
- }
38
-
39
- /**
40
- * Build a conversation primer for the given project.
41
- *
42
- * Auto-detects the best scope (src/, lib/, etc.) or uses an explicit
43
- * scope. Returns a list of tracked files, truncated if beyond maxFiles.
44
- */
45
- export async function buildConversationPrimer(
46
- options: ConversationPrimerOptions,
47
- ): Promise<ConversationPrimerResult> {
48
- const { cwd, git, fs: fileSystem, pathOps, maxFiles = 50 } = options;
49
-
50
- // Detect scope
51
- let scope = options.scope ?? ".";
52
- if (options.scope === undefined) {
53
- for (const candidate of COMMON_SCOPES) {
54
- const candidatePath = pathOps.join(cwd, candidate);
55
- if (await isDirectory(fileSystem, candidatePath)) {
56
- scope = candidate;
57
- break;
58
- }
59
- }
60
- }
61
-
62
- // List tracked files via git ls-files (allowed by plumbing)
63
- const lsResult = await git.run({
64
- cwd,
65
- args: ["ls-files", "--", scope],
66
- });
67
-
68
- const allFiles = lsResult.stdout
69
- .split("\n")
70
- .map((f) => f.trim())
71
- .filter((f) => f.length > 0);
72
-
73
- const truncated = allFiles.length > maxFiles;
74
- const files = truncated ? allFiles.slice(0, maxFiles) : allFiles;
75
-
76
- return {
77
- scope,
78
- files,
79
- truncated,
80
- totalFiles: allFiles.length,
81
- };
82
- }
@@ -1,104 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Cross-session resume — structural diff from saved HEAD to current HEAD
3
- // ---------------------------------------------------------------------------
4
-
5
- import type { GitClient } from "../ports/git.js";
6
-
7
- /** A file that changed between saved HEAD and current HEAD. */
8
- export interface ResumeChangedFile {
9
- readonly path: string;
10
- readonly status: "added" | "modified" | "deleted" | "renamed";
11
- }
12
-
13
- /** Result of attempting to resume from a saved session state. */
14
- export interface SessionResumeResult {
15
- readonly resumable: boolean;
16
- readonly currentHead: string;
17
- readonly savedHead: string;
18
- readonly changedFiles: readonly ResumeChangedFile[];
19
- readonly commitsBehind: number;
20
- readonly error?: string;
21
- }
22
-
23
- export interface SessionResumeOptions {
24
- readonly cwd: string;
25
- readonly savedHeadSha: string;
26
- readonly git: GitClient;
27
- }
28
-
29
- /**
30
- * Build a structural resume from a saved HEAD to current HEAD.
31
- *
32
- * Uses plumbing-safe git commands (diff-tree, rev-list, log) to
33
- * find changed files and count commits between two points.
34
- */
35
- export async function buildSessionResume(
36
- options: SessionResumeOptions,
37
- ): Promise<SessionResumeResult> {
38
- const { cwd, savedHeadSha, git } = options;
39
-
40
- const headResult = await git.run({ cwd, args: ["rev-parse", "HEAD"] });
41
- const currentHead = headResult.stdout.trim();
42
- if (headResult.status !== 0 || currentHead.length === 0) {
43
- return {
44
- resumable: false, currentHead: "", savedHead: savedHeadSha,
45
- changedFiles: [], commitsBehind: 0,
46
- error: "Cannot resolve current HEAD",
47
- };
48
- }
49
-
50
- // Check if saved HEAD exists in the repo
51
- const verifyResult = await git.run({ cwd, args: ["cat-file", "-t", savedHeadSha] });
52
- if (verifyResult.stdout.trim() !== "commit") {
53
- return {
54
- resumable: false, currentHead, savedHead: savedHeadSha,
55
- changedFiles: [], commitsBehind: 0,
56
- error: "Saved HEAD SHA not found in repository",
57
- };
58
- }
59
-
60
- if (currentHead === savedHeadSha) {
61
- return {
62
- resumable: true, currentHead, savedHead: savedHeadSha,
63
- changedFiles: [], commitsBehind: 0,
64
- };
65
- }
66
-
67
- // Use diff-tree (plumbing-safe) with -r for recursive
68
- const diffResult = await git.run({
69
- cwd,
70
- args: ["diff-tree", "-r", "--name-status", "--no-commit-id", savedHeadSha, currentHead],
71
- });
72
- const changedFiles: ResumeChangedFile[] = [];
73
- const diffOutput = diffResult.stdout.trim();
74
-
75
- if (diffOutput.length > 0) {
76
- for (const line of diffOutput.split("\n")) {
77
- const parts = line.split("\t");
78
- if (parts.length < 2) continue;
79
- const statusChar = (parts[0] ?? "").charAt(0);
80
- const filePath = parts[parts.length - 1] ?? "";
81
-
82
- let status: ResumeChangedFile["status"];
83
- switch (statusChar) {
84
- case "A": status = "added"; break;
85
- case "D": status = "deleted"; break;
86
- case "R": status = "renamed"; break;
87
- default: status = "modified"; break;
88
- }
89
- changedFiles.push({ path: filePath, status });
90
- }
91
- }
92
-
93
- // Count commits
94
- const countResult = await git.run({
95
- cwd,
96
- args: ["rev-list", "--count", `${savedHeadSha}..${currentHead}`],
97
- });
98
- const commitsBehind = parseInt(countResult.stdout.trim(), 10) || 0;
99
-
100
- return {
101
- resumable: true, currentHead, savedHead: savedHeadSha,
102
- changedFiles, commitsBehind,
103
- };
104
- }
@@ -1,143 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Deterministic Scenario Replay — re-drive sessions for CI regression
3
- // ---------------------------------------------------------------------------
4
-
5
- import type { FileSystem } from "../ports/filesystem.js";
6
-
7
- /** A recorded tool call with its expected result. */
8
- export interface RecordedToolCall {
9
- readonly tool: string;
10
- readonly args: Readonly<Record<string, unknown>>;
11
- readonly expectedResult: Readonly<Record<string, unknown>>;
12
- }
13
-
14
- /** A replay scenario: filesystem snapshot + recorded calls. */
15
- interface _ReplayScenario {
16
- readonly files: Readonly<Record<string, string>>;
17
- readonly calls: readonly RecordedToolCall[];
18
- }
19
-
20
- /** A single mismatch between expected and actual. */
21
- export interface ReplayFailure {
22
- readonly index: number;
23
- readonly tool: string;
24
- readonly expected: Readonly<Record<string, unknown>>;
25
- readonly actual: Readonly<Record<string, unknown>>;
26
- }
27
-
28
- /** Result of replaying a scenario. */
29
- export interface ReplayResult {
30
- readonly passed: boolean;
31
- readonly total: number;
32
- readonly matched: number;
33
- readonly mismatched: number;
34
- readonly failures: readonly ReplayFailure[];
35
- }
36
-
37
- /** Handler that executes a tool call and returns the result. */
38
- export type ToolCallHandler = (
39
- tool: string,
40
- args: Readonly<Record<string, unknown>>,
41
- ) => Promise<Readonly<Record<string, unknown>>>;
42
-
43
- /**
44
- * Create a mock FileSystem from a snapshot map.
45
- *
46
- * Keys are file paths, values are file contents. Provides readFile,
47
- * readdir, stat, and other FileSystem methods backed by the map.
48
- */
49
- export function createSnapshotFs(
50
- files: Readonly<Record<string, string>>,
51
- ): FileSystem {
52
- const fileMap = new Map(Object.entries(files));
53
-
54
- return {
55
- readFile(path: string, _encoding?: string): Promise<string> {
56
- const content = fileMap.get(path);
57
- if (content === undefined) {
58
- return Promise.reject(new Error(`File not found in snapshot: ${path}`));
59
- }
60
- return Promise.resolve(content);
61
- },
62
-
63
- readFileSync(path: string): string {
64
- const content = fileMap.get(path);
65
- if (content === undefined) {
66
- throw new Error(`File not found in snapshot: ${path}`);
67
- }
68
- return content;
69
- },
70
-
71
- readdir(dirPath: string): Promise<string[]> {
72
- const prefix = dirPath.endsWith("/") ? dirPath : `${dirPath}/`;
73
- const entries = new Set<string>();
74
- for (const key of fileMap.keys()) {
75
- if (key.startsWith(prefix)) {
76
- const rest = key.slice(prefix.length);
77
- const firstSegment = rest.split("/")[0];
78
- if (firstSegment !== undefined && firstSegment.length > 0) {
79
- entries.add(firstSegment);
80
- }
81
- }
82
- }
83
- return Promise.resolve([...entries].sort());
84
- },
85
-
86
- writeFile(): Promise<void> {
87
- return Promise.resolve();
88
- },
89
-
90
- appendFile(): Promise<void> {
91
- return Promise.resolve();
92
- },
93
-
94
- mkdir(): Promise<void> {
95
- return Promise.resolve();
96
- },
97
-
98
- stat(path: string): Promise<{ size: number }> {
99
- const content = fileMap.get(path);
100
- return Promise.resolve({ size: content?.length ?? 0 });
101
- },
102
- } as unknown as FileSystem;
103
- }
104
-
105
- /**
106
- * Replay a sequence of recorded tool calls against a handler.
107
- *
108
- * Compares each actual result to the expected result from the
109
- * recording. Returns pass/fail with details on mismatches.
110
- */
111
- export async function replayToolCalls(
112
- calls: readonly RecordedToolCall[],
113
- handler: ToolCallHandler,
114
- ): Promise<ReplayResult> {
115
- const failures: ReplayFailure[] = [];
116
- let matched = 0;
117
-
118
- for (let i = 0; i < calls.length; i++) {
119
- const call = calls[i] ?? { tool: "", args: {}, expectedResult: {} };
120
- const actual = await handler(call.tool, call.args);
121
- const expectedJson = JSON.stringify(call.expectedResult);
122
- const actualJson = JSON.stringify(actual);
123
-
124
- if (expectedJson === actualJson) {
125
- matched++;
126
- } else {
127
- failures.push({
128
- index: i,
129
- tool: call.tool,
130
- expected: call.expectedResult,
131
- actual,
132
- });
133
- }
134
- }
135
-
136
- return {
137
- passed: failures.length === 0,
138
- total: calls.length,
139
- matched,
140
- mismatched: failures.length,
141
- failures,
142
- };
143
- }