@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,101 +0,0 @@
1
- /**
2
- * WARP Observer Factory — canonical observer lenses for graft queries.
3
- *
4
- * Observer Law: this module READS through observers. It never
5
- * walks the graph directly, maintains shadow state, or implements
6
- * traversal algorithms.
7
- *
8
- * Each function returns a lens or an observer with a focused lens.
9
- * The lens determines the aperture — what the observer can see.
10
- */
11
-
12
- import type { Lens, Observer } from "@git-stunts/git-warp";
13
- import type { WarpContext } from "./context.js";
14
- import { observeGraph } from "./context.js";
15
-
16
- export type { Lens };
17
-
18
- /**
19
- * Observe all symbols in a specific file.
20
- * Aperture: sym:<path>:*
21
- */
22
- export function fileSymbolsLens(filePath: string): Lens {
23
- return {
24
- match: `sym:${filePath}:*`,
25
- expose: ["name", "kind", "signature", "exported", "startLine", "endLine", "symbolPath", "identityId"],
26
- };
27
- }
28
-
29
- /**
30
- * Observe all symbols in the project.
31
- * Aperture: sym:*
32
- */
33
- export function allSymbolsLens(): Lens {
34
- return {
35
- match: "sym:*",
36
- expose: ["name", "kind", "signature", "exported", "startLine", "endLine", "symbolPath", "identityId"],
37
- };
38
- }
39
-
40
- /**
41
- * Observe all files in the project.
42
- * Aperture: file:*
43
- */
44
- export function allFilesLens(): Lens {
45
- return {
46
- match: "file:*",
47
- expose: ["path", "lang"],
48
- };
49
- }
50
-
51
- /**
52
- * Observe a single symbol by name across all files.
53
- * Aperture: sym:*:<name>
54
- */
55
- export function symbolByNameLens(symbolName: string): Lens {
56
- return {
57
- match: `sym:*:${symbolName}`,
58
- expose: ["name", "kind", "signature", "exported", "startLine", "endLine", "symbolPath", "identityId"],
59
- };
60
- }
61
-
62
- /**
63
- * Observe a directory subtree.
64
- * Aperture: dir:<path>*
65
- */
66
- export function directoryLens(dirPath: string): Lens {
67
- return {
68
- match: `dir:${dirPath}*`,
69
- expose: ["path"],
70
- };
71
- }
72
-
73
- /**
74
- * Observe all files under a directory.
75
- * Aperture: file:<path>/*
76
- */
77
- export function directoryFilesLens(dirPath: string): Lens {
78
- return {
79
- match: `file:${dirPath}/*`,
80
- expose: ["path", "lang"],
81
- };
82
- }
83
-
84
- /**
85
- * Observe commit metadata.
86
- * Aperture: commit:*
87
- */
88
- export function commitsLens(): Lens {
89
- return {
90
- match: "commit:*",
91
- expose: ["sha", "message", "timestamp", "author", "email", "tick"],
92
- };
93
- }
94
-
95
- /**
96
- * Create an observer on the current frontier with a given lens.
97
- * Observers are static snapshots — create a new one after writes.
98
- */
99
- export function observe(ctx: WarpContext, lens: Lens): Promise<Observer> {
100
- return observeGraph(ctx, lens);
101
- }
package/src/warp/open.ts DELETED
@@ -1,67 +0,0 @@
1
- /**
2
- * WARP graph initialization — opens the graft-ast graph backed by
3
- * the repo's own .git directory.
4
- *
5
- * Sole construction adapter. After this, git-warp types flow directly.
6
- */
7
-
8
- import WarpApp, { GitGraphAdapter } from "@git-stunts/git-warp";
9
- import GitPlumbing from "@git-stunts/plumbing";
10
- import { DEFAULT_WARP_WRITER_ID } from "./writer-id.js";
11
-
12
- export const GRAPH_NAME = "graft-ast";
13
- export const DEFAULT_WARP_CHECKPOINT_EVERY = 128;
14
- const WARP_GIT_MAX_BUFFER_BYTES = 128 * 1024 * 1024;
15
-
16
- interface GitExecuteOptions {
17
- readonly args: string[];
18
- readonly input?: string | Uint8Array;
19
- readonly env?: Record<string, string>;
20
- readonly maxBytes?: number;
21
- }
22
-
23
- interface GitStreamLike {
24
- readonly finished: Promise<{ code: number; stderr: string; error?: Error | undefined }>;
25
- collect(opts?: { maxBytes?: number; asString?: boolean; encoding?: string }): Promise<Uint8Array | string>;
26
- [Symbol.asyncIterator](): AsyncIterator<Uint8Array>;
27
- }
28
-
29
- function raiseWarpGitBufferLimit(plumbing: GitPlumbing): GitPlumbing {
30
- const execute = plumbing.execute.bind(plumbing);
31
- plumbing.execute = ((options: GitExecuteOptions) => execute({
32
- ...options,
33
- maxBytes: options.maxBytes ?? WARP_GIT_MAX_BUFFER_BYTES,
34
- })) as GitPlumbing["execute"];
35
-
36
- const executeStream = plumbing.executeStream.bind(plumbing);
37
- plumbing.executeStream = (async (options: { args: string[]; input?: string | Uint8Array; env?: Record<string, string> }) => {
38
- const stream = await executeStream(options);
39
- const collect = stream.collect.bind(stream);
40
- stream.collect = (opts = {}) => collect({
41
- ...opts,
42
- maxBytes: opts.maxBytes ?? WARP_GIT_MAX_BUFFER_BYTES,
43
- });
44
- return stream as GitStreamLike;
45
- }) as GitPlumbing["executeStream"];
46
-
47
- return plumbing;
48
- }
49
-
50
- export interface OpenWarpOptions {
51
- readonly cwd: string;
52
- readonly writerId?: string;
53
- readonly checkpointEvery?: number;
54
- }
55
-
56
- export async function openWarp(options: OpenWarpOptions): Promise<WarpApp> {
57
- const plumbing = raiseWarpGitBufferLimit(GitPlumbing.createDefault({ cwd: options.cwd }));
58
- const persistence = new GitGraphAdapter({ plumbing });
59
-
60
- return WarpApp.open({
61
- persistence,
62
- graphName: GRAPH_NAME,
63
- writerId: options.writerId ?? DEFAULT_WARP_WRITER_ID,
64
- checkpointPolicy: { every: options.checkpointEvery ?? DEFAULT_WARP_CHECKPOINT_EVERY },
65
- onDeleteWithData: "cascade",
66
- });
67
- }
@@ -1,100 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Outline Diff Commit Trailer — structural summary in git commit messages
3
- // ---------------------------------------------------------------------------
4
-
5
- /** A single symbol change to include in the trailer. */
6
- export interface SymbolDiffEntry {
7
- readonly name: string;
8
- readonly kind: string;
9
- readonly changeKind: "added" | "removed" | "changed";
10
- }
11
-
12
- /** Options for trailer formatting. */
13
- export interface TrailerOptions {
14
- /** Maximum entries before truncation. Default: 20. */
15
- readonly maxEntries?: number;
16
- }
17
-
18
- /** Short kind abbreviations for the trailer format. */
19
- const KIND_ABBREV: Readonly<Record<string, string>> = {
20
- function: "fn",
21
- class: "class",
22
- interface: "iface",
23
- type: "type",
24
- variable: "var",
25
- method: "method",
26
- property: "prop",
27
- };
28
-
29
- function abbrevKind(kind: string): string {
30
- return KIND_ABBREV[kind] ?? kind;
31
- }
32
-
33
- /**
34
- * Format a list of symbol changes as a Git commit trailer.
35
- *
36
- * Format: `Structural-Diff: added fn:X; removed class:Y; changed fn:Z`
37
- *
38
- * Returns empty string if there are no changes.
39
- */
40
- export function formatStructuralDiffTrailer(
41
- entries: readonly SymbolDiffEntry[],
42
- options?: TrailerOptions,
43
- ): string {
44
- if (entries.length === 0) return "";
45
-
46
- const max = options?.maxEntries ?? 20;
47
- const display = entries.slice(0, max);
48
- const parts = display.map(
49
- (e) => `${e.changeKind} ${abbrevKind(e.kind)}:${e.name}`,
50
- );
51
-
52
- let trailer = `Structural-Diff: ${parts.join("; ")}`;
53
-
54
- if (entries.length > max) {
55
- trailer += `; ... (${String(entries.length)} total)`;
56
- }
57
-
58
- return trailer;
59
- }
60
-
61
- // ---------------------------------------------------------------------------
62
- // Parser
63
- // ---------------------------------------------------------------------------
64
-
65
- const TRAILER_PREFIX = "Structural-Diff:";
66
-
67
- const ENTRY_RE = /^(added|removed|changed)\s+(\w+):(\w+)$/;
68
-
69
- /**
70
- * Parse a Structural-Diff trailer back into structured entries.
71
- *
72
- * Skips malformed entries gracefully.
73
- */
74
- export function parseStructuralDiffTrailer(text: string): SymbolDiffEntry[] {
75
- const idx = text.indexOf(TRAILER_PREFIX);
76
- if (idx === -1) return [];
77
-
78
- const body = text.slice(idx + TRAILER_PREFIX.length).trim();
79
- const parts = body.split(";").map((p) => p.trim());
80
- const results: SymbolDiffEntry[] = [];
81
-
82
- for (const part of parts) {
83
- if (part.startsWith("...")) continue;
84
- const match = ENTRY_RE.exec(part);
85
- if (match === null) continue;
86
-
87
- const changeKind = match[1] as "added" | "removed" | "changed";
88
- const abbrev = match[2] ?? "unknown";
89
- const name = match[3] ?? "unknown";
90
-
91
- // Reverse the abbreviation
92
- const kind = Object.entries(KIND_ABBREV).find(
93
- ([, v]) => v === abbrev,
94
- )?.[0] ?? abbrev;
95
-
96
- results.push({ name, kind, changeKind });
97
- }
98
-
99
- return results;
100
- }
@@ -1,24 +0,0 @@
1
- declare module "@git-stunts/plumbing" {
2
- import type { GitPlumbing as GitPlumbingInterface } from "@git-stunts/git-warp";
3
-
4
- export default class GitPlumbing implements GitPlumbingInterface {
5
- readonly emptyTree: string;
6
- constructor(options: { runner: unknown; cwd?: string });
7
- static createDefault(options?: { cwd?: string; env?: string }): GitPlumbing;
8
- execute(options: {
9
- args: string[];
10
- input?: string | Uint8Array;
11
- env?: Record<string, string>;
12
- maxBytes?: number;
13
- }): Promise<string>;
14
- executeStream(options: {
15
- args: string[];
16
- input?: string | Uint8Array;
17
- env?: Record<string, string>;
18
- }): Promise<{
19
- finished: Promise<{ code: number; stderr: string; error?: Error }>;
20
- collect(opts?: { maxBytes?: number; asString?: boolean; encoding?: string }): Promise<Uint8Array | string>;
21
- [Symbol.asyncIterator](): AsyncIterator<Uint8Array>;
22
- }>;
23
- }
24
- }
@@ -1,257 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Refactor Difficulty — curvature x friction over WARP facts
3
- // ---------------------------------------------------------------------------
4
-
5
- import type { AggregateResult, QueryResultV1 } from "@git-stunts/git-warp";
6
- import type { WarpContext } from "./context.js";
7
- import { observeGraph } from "./context.js";
8
- import { symbolTimeline, type SymbolVersion } from "./symbol-timeline.js";
9
- import { countSymbolReferencesFromGraph } from "./warp-reference-count.js";
10
-
11
- const CHANGE_EDGE_LABELS = ["adds", "changes", "removes"] as const;
12
-
13
- export type RefactorDifficultyRisk = "low" | "medium" | "high";
14
-
15
- export type RefactorDifficultyRecommendation =
16
- | "refactor_freely"
17
- | "refactor_with_tests"
18
- | "plan_before_refactor";
19
-
20
- export interface RefactorDifficultyOptions {
21
- readonly symbol: string;
22
- readonly path?: string | undefined;
23
- readonly limit?: number | undefined;
24
- }
25
-
26
- export interface RefactorDifficultyAxis {
27
- readonly score: number;
28
- }
29
-
30
- export interface RefactorDifficultyCurvature extends RefactorDifficultyAxis {
31
- readonly changeCount: number;
32
- readonly signatureChangeCount: number;
33
- }
34
-
35
- export interface RefactorDifficultyFriction extends RefactorDifficultyAxis {
36
- readonly referenceCount: number;
37
- readonly referencingFiles: readonly string[];
38
- }
39
-
40
- export interface RefactorDifficultyEntry {
41
- readonly symbol: string;
42
- readonly filePath: string;
43
- readonly kind: string;
44
- readonly score: number;
45
- readonly risk: RefactorDifficultyRisk;
46
- readonly recommendation: RefactorDifficultyRecommendation;
47
- readonly curvature: RefactorDifficultyCurvature;
48
- readonly friction: RefactorDifficultyFriction;
49
- }
50
-
51
- export interface RefactorDifficultyResult {
52
- readonly symbol: string;
53
- readonly path?: string | undefined;
54
- readonly entries: readonly RefactorDifficultyEntry[];
55
- readonly total: number;
56
- readonly summary: string;
57
- }
58
-
59
- interface SymbolCandidate {
60
- readonly id: string;
61
- readonly symbol: string;
62
- readonly filePath: string;
63
- readonly kind: string;
64
- }
65
-
66
- export async function refactorDifficultyFromGraph(
67
- ctx: WarpContext,
68
- options: RefactorDifficultyOptions,
69
- ): Promise<RefactorDifficultyResult> {
70
- const symbol = options.symbol.trim();
71
- if (symbol.length === 0) {
72
- throw new Error("refactorDifficultyFromGraph: symbol must be non-empty");
73
- }
74
-
75
- const pathFilter = normalizeOptionalPath(options.path);
76
- const limit = options.limit ?? 20;
77
- const candidates = await findSymbolCandidates(ctx, symbol, pathFilter);
78
- const entries = await Promise.all(
79
- candidates.map((candidate) => scoreCandidate(ctx, candidate)),
80
- );
81
-
82
- const sorted = entries.sort(compareDifficultyEntries).slice(0, limit);
83
- const top = sorted[0];
84
- const summary = top === undefined
85
- ? `No indexed symbols matched ${symbol}.`
86
- : `${String(entries.length)} symbol matches. Highest difficulty: ${top.symbol} in ${top.filePath} (${String(top.score)}).`;
87
-
88
- return {
89
- symbol,
90
- ...(pathFilter !== undefined ? { path: pathFilter } : {}),
91
- entries: sorted,
92
- total: entries.length,
93
- summary,
94
- };
95
- }
96
-
97
- async function findSymbolCandidates(
98
- ctx: WarpContext,
99
- symbol: string,
100
- pathFilter: string | undefined,
101
- ): Promise<SymbolCandidate[]> {
102
- const obs = await observeGraph(ctx, {
103
- match: "sym:*",
104
- expose: ["name", "kind", "filePath"],
105
- });
106
-
107
- const result = await obs.query()
108
- .match("sym:*")
109
- .where((node) => {
110
- const parsed = parseSymId(node.id);
111
- if (parsed === null) return false;
112
- if (!matchesPathFilter(parsed.filePath, pathFilter)) return false;
113
-
114
- const propName = typeof node.props["name"] === "string" ? node.props["name"] : "";
115
- return parsed.symbol === symbol || propName === symbol;
116
- })
117
- .select(["id", "props"])
118
- .run() as QueryResultV1;
119
-
120
- const candidates: SymbolCandidate[] = [];
121
- for (const node of result.nodes) {
122
- if (node.id === undefined) continue;
123
- const parsed = parseSymId(node.id);
124
- if (parsed === null) continue;
125
-
126
- candidates.push({
127
- id: node.id,
128
- symbol: parsed.symbol,
129
- filePath: parsed.filePath,
130
- kind: typeof node.props?.["kind"] === "string" ? node.props["kind"] : "unknown",
131
- });
132
- }
133
- return candidates;
134
- }
135
-
136
- async function scoreCandidate(
137
- ctx: WarpContext,
138
- candidate: SymbolCandidate,
139
- ): Promise<RefactorDifficultyEntry> {
140
- const [changeCount, timeline, references] = await Promise.all([
141
- countSymbolTouches(ctx, candidate.id),
142
- symbolTimeline(ctx, candidate.symbol, candidate.filePath),
143
- countSymbolReferencesFromGraph(ctx, candidate.symbol, candidate.filePath),
144
- ]);
145
-
146
- const signatureChangeCount = countSignatureChanges(timeline.versions);
147
- const curvatureScore = changeCount + signatureChangeCount;
148
- const frictionScore = references.referenceCount;
149
- const score = curvatureScore * frictionScore;
150
-
151
- return {
152
- symbol: candidate.symbol,
153
- filePath: candidate.filePath,
154
- kind: candidate.kind,
155
- score,
156
- risk: riskForScore(score),
157
- recommendation: recommendationForScore(score),
158
- curvature: {
159
- changeCount,
160
- signatureChangeCount,
161
- score: curvatureScore,
162
- },
163
- friction: {
164
- referenceCount: references.referenceCount,
165
- referencingFiles: references.referencingFiles,
166
- score: frictionScore,
167
- },
168
- };
169
- }
170
-
171
- async function countSymbolTouches(
172
- ctx: WarpContext,
173
- symId: string,
174
- ): Promise<number> {
175
- const obs = await observeGraph(ctx, {
176
- match: ["commit:*", "sym:*"],
177
- expose: ["tick"],
178
- });
179
-
180
- const counts = await Promise.all(CHANGE_EDGE_LABELS.map(async (label): Promise<number> => {
181
- const result = await obs.query()
182
- .match("commit:*")
183
- .where((node) => node.edgesOut.some((edge) => edge.label === label && edge.to === symId))
184
- .aggregate({ count: true })
185
- .run() as AggregateResult;
186
- return result.count ?? 0;
187
- }));
188
-
189
- return counts.reduce((sum, count) => sum + count, 0);
190
- }
191
-
192
- function countSignatureChanges(versions: readonly SymbolVersion[]): number {
193
- let lastSignature: string | undefined;
194
- let changes = 0;
195
-
196
- for (const version of versions) {
197
- if (version.signature === undefined) continue;
198
- if (lastSignature === undefined) {
199
- lastSignature = version.signature;
200
- continue;
201
- }
202
- if (version.signature !== lastSignature) {
203
- changes++;
204
- lastSignature = version.signature;
205
- }
206
- }
207
-
208
- return changes;
209
- }
210
-
211
- function riskForScore(score: number): RefactorDifficultyRisk {
212
- if (score >= 12) return "high";
213
- if (score >= 4) return "medium";
214
- return "low";
215
- }
216
-
217
- function recommendationForScore(score: number): RefactorDifficultyRecommendation {
218
- if (score >= 12) return "plan_before_refactor";
219
- if (score >= 4) return "refactor_with_tests";
220
- return "refactor_freely";
221
- }
222
-
223
- function compareDifficultyEntries(
224
- left: RefactorDifficultyEntry,
225
- right: RefactorDifficultyEntry,
226
- ): number {
227
- return right.score - left.score ||
228
- right.curvature.score - left.curvature.score ||
229
- right.friction.score - left.friction.score ||
230
- left.filePath.localeCompare(right.filePath) ||
231
- left.symbol.localeCompare(right.symbol);
232
- }
233
-
234
- function parseSymId(symId: string): { filePath: string; symbol: string } | null {
235
- if (!symId.startsWith("sym:")) return null;
236
-
237
- const withoutPrefix = symId.slice("sym:".length);
238
- const lastColon = withoutPrefix.lastIndexOf(":");
239
- if (lastColon === -1) return null;
240
-
241
- return {
242
- filePath: withoutPrefix.slice(0, lastColon),
243
- symbol: withoutPrefix.slice(lastColon + 1),
244
- };
245
- }
246
-
247
- function normalizeOptionalPath(path: string | undefined): string | undefined {
248
- if (path === undefined) return undefined;
249
- const trimmed = path.trim();
250
- return trimmed.length > 0 ? trimmed : undefined;
251
- }
252
-
253
- function matchesPathFilter(filePath: string, pathFilter: string | undefined): boolean {
254
- return pathFilter === undefined ||
255
- filePath === pathFilter ||
256
- filePath.startsWith(`${pathFilter}/`);
257
- }
@@ -1,77 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Symbol reference queries — find what depends on a symbol via the WARP graph
3
- // ---------------------------------------------------------------------------
4
-
5
- import type { QueryResultV1 } from "@git-stunts/git-warp";
6
- import type { WarpContext } from "./context.js";
7
- import { observeGraph } from "./context.js";
8
-
9
- export interface SymbolReference {
10
- readonly filePath: string;
11
- readonly importedName: string;
12
- readonly localName: string;
13
- }
14
-
15
- /**
16
- * Find all files that reference a symbol, by querying the WARP graph's
17
- * cross-file import resolution edges.
18
- *
19
- * Uses traverse.bfs for edge discovery (substrate-side) and QueryBuilder
20
- * for batch prop reads. No getEdges() — never assumes all edges fit in
21
- * memory.
22
- *
23
- * For named symbols: finds import_specifier/export_specifier nodes that
24
- * have a `references` edge pointing at `sym:<filePath>:<symbolName>`.
25
- *
26
- * For namespace imports ("*"): finds namespace_import nodes that have a
27
- * `references` edge pointing at `file:<filePath>`.
28
- */
29
- export async function referencesForSymbol(
30
- ctx: WarpContext,
31
- symbolName: string,
32
- filePath: string,
33
- ): Promise<SymbolReference[]> {
34
- const obs = await observeGraph(ctx, { match: ["ast:*", "file:*", "sym:*"] });
35
-
36
- // Determine the target node ID
37
- const targetId = symbolName === "*"
38
- ? `file:${filePath}`
39
- : `sym:${filePath}:${symbolName}`;
40
-
41
- // Guard: target must exist for traverse to work.
42
- const targetExists = await obs.hasNode(targetId);
43
- if (!targetExists) return [];
44
-
45
- // Traverse: find AST nodes with incoming `references` edges to the target.
46
- const referrerIds = await obs.traverse.bfs(targetId, {
47
- dir: "in",
48
- labelFilter: "references",
49
- maxDepth: 1,
50
- });
51
-
52
- const astReferrerIds = referrerIds.filter((id) => id.startsWith("ast:"));
53
- if (astReferrerIds.length === 0) return [];
54
-
55
- // Batch prop read for all referencing nodes.
56
- const propsResult = await obs.query()
57
- .match(astReferrerIds)
58
- .select(["id", "props"])
59
- .run() as QueryResultV1;
60
-
61
- const results: SymbolReference[] = [];
62
-
63
- for (const node of propsResult.nodes) {
64
- if (node.id === undefined) continue;
65
- const props = node.props ?? {};
66
-
67
- const importedName = typeof props["importedName"] === "string" ? props["importedName"] : symbolName;
68
- const localName = typeof props["localName"] === "string" ? props["localName"] : importedName;
69
- const nodeFilePath = typeof props["filePath"] === "string" ? props["filePath"] : null;
70
-
71
- if (nodeFilePath !== null) {
72
- results.push({ filePath: nodeFilePath, importedName, localName });
73
- }
74
- }
75
-
76
- return results;
77
- }