lockstep-cli 0.0.5 → 0.1.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 (80) hide show
  1. package/README.md +29 -0
  2. package/dist/adapters/claude.js +26 -7
  3. package/dist/adapters/claude.js.map +1 -1
  4. package/dist/adapters/install.test.js +53 -2
  5. package/dist/adapters/install.test.js.map +1 -1
  6. package/dist/adapters/merge.d.ts +11 -0
  7. package/dist/adapters/merge.js +41 -0
  8. package/dist/adapters/merge.js.map +1 -1
  9. package/dist/adapters/templates.d.ts +3 -2
  10. package/dist/adapters/templates.js +92 -3
  11. package/dist/adapters/templates.js.map +1 -1
  12. package/dist/capture/classify-edge.test.js +9 -7
  13. package/dist/capture/classify-edge.test.js.map +1 -1
  14. package/dist/capture/classify.d.ts +6 -4
  15. package/dist/capture/classify.js +9 -8
  16. package/dist/capture/classify.js.map +1 -1
  17. package/dist/capture/classify.test.js +7 -2
  18. package/dist/capture/classify.test.js.map +1 -1
  19. package/dist/capture/diff.d.ts +2 -0
  20. package/dist/capture/diff.js +15 -0
  21. package/dist/capture/diff.js.map +1 -1
  22. package/dist/capture/extract.d.ts +5 -0
  23. package/dist/capture/extract.js +17 -0
  24. package/dist/capture/extract.js.map +1 -0
  25. package/dist/capture/feature-context.d.ts +3 -0
  26. package/dist/capture/feature-context.js +43 -0
  27. package/dist/capture/feature-context.js.map +1 -0
  28. package/dist/capture/feature-context.test.d.ts +1 -0
  29. package/dist/capture/feature-context.test.js +45 -0
  30. package/dist/capture/feature-context.test.js.map +1 -0
  31. package/dist/capture/index.d.ts +59 -0
  32. package/dist/capture/index.js +101 -21
  33. package/dist/capture/index.js.map +1 -1
  34. package/dist/capture/manifest.d.ts +26 -0
  35. package/dist/capture/manifest.js +98 -0
  36. package/dist/capture/manifest.js.map +1 -0
  37. package/dist/capture/manifest.test.d.ts +1 -0
  38. package/dist/capture/manifest.test.js +40 -0
  39. package/dist/capture/manifest.test.js.map +1 -0
  40. package/dist/capture/outbound.d.ts +10 -0
  41. package/dist/capture/outbound.js +139 -0
  42. package/dist/capture/outbound.js.map +1 -0
  43. package/dist/capture/outbound.test.d.ts +1 -0
  44. package/dist/capture/outbound.test.js +89 -0
  45. package/dist/capture/outbound.test.js.map +1 -0
  46. package/dist/capture/python.d.ts +5 -0
  47. package/dist/capture/python.js +127 -0
  48. package/dist/capture/python.js.map +1 -0
  49. package/dist/capture/python.test.d.ts +1 -0
  50. package/dist/capture/python.test.js +99 -0
  51. package/dist/capture/python.test.js.map +1 -0
  52. package/dist/capture/replay.test.d.ts +1 -0
  53. package/dist/capture/replay.test.js +101 -0
  54. package/dist/capture/replay.test.js.map +1 -0
  55. package/dist/capture/surface.d.ts +23 -0
  56. package/dist/capture/surface.js +83 -0
  57. package/dist/capture/surface.js.map +1 -0
  58. package/dist/capture/surface.test.d.ts +1 -0
  59. package/dist/capture/surface.test.js +37 -0
  60. package/dist/capture/surface.test.js.map +1 -0
  61. package/dist/connect.d.ts +1 -1
  62. package/dist/connect.js +23 -12
  63. package/dist/connect.js.map +1 -1
  64. package/dist/index.js +25 -0
  65. package/dist/index.js.map +1 -1
  66. package/dist/init.js +3 -1
  67. package/dist/init.js.map +1 -1
  68. package/dist/mcp/server.d.ts +1 -1
  69. package/dist/mcp/server.js +26 -3
  70. package/dist/mcp/server.js.map +1 -1
  71. package/dist/scan.d.ts +64 -0
  72. package/dist/scan.js +176 -0
  73. package/dist/scan.js.map +1 -0
  74. package/dist/scan.test.d.ts +1 -0
  75. package/dist/scan.test.js +258 -0
  76. package/dist/scan.test.js.map +1 -0
  77. package/dist/statusline.d.ts +6 -0
  78. package/dist/statusline.js +108 -0
  79. package/dist/statusline.js.map +1 -0
  80. package/package.json +8 -4
@@ -16,4 +16,19 @@ export function changedFiles(cwd) {
16
16
  return [];
17
17
  }
18
18
  }
19
+ /** Every tracked file in the repo (+ untracked, minus gitignored), read-only. The full-repo walk `lockstep scan` runs over. */
20
+ export function trackedFiles(cwd) {
21
+ try {
22
+ const tracked = execFileSync("git", ["-C", cwd, "ls-files"], { encoding: "utf8" }).split("\n").filter(Boolean);
23
+ const untracked = execFileSync("git", ["-C", cwd, "ls-files", "--others", "--exclude-standard"], {
24
+ encoding: "utf8",
25
+ })
26
+ .split("\n")
27
+ .filter(Boolean);
28
+ return [...new Set([...tracked, ...untracked])];
29
+ }
30
+ catch {
31
+ return [];
32
+ }
33
+ }
19
34
  //# sourceMappingURL=diff.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/capture/diff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,+FAA+F;AAC/F,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;aAClG,KAAK,CAAC,IAAI,CAAC;aACX,MAAM,CAAC,OAAO,CAAC,CAAC;QACnB,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,UAAU,EAAE,UAAU,EAAE,oBAAoB,CAAC,EAAE;YAC/F,QAAQ,EAAE,MAAM;SACjB,CAAC;aACC,KAAK,CAAC,IAAI,CAAC;aACX,MAAM,CAAC,OAAO,CAAC,CAAC;QACnB,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/capture/diff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,+FAA+F;AAC/F,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;aAClG,KAAK,CAAC,IAAI,CAAC;aACX,MAAM,CAAC,OAAO,CAAC,CAAC;QACnB,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,UAAU,EAAE,UAAU,EAAE,oBAAoB,CAAC,EAAE;YAC/F,QAAQ,EAAE,MAAM;SACjB,CAAC;aACC,KAAK,CAAC,IAAI,CAAC;aACX,MAAM,CAAC,OAAO,CAAC,CAAC;QACnB,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,+HAA+H;AAC/H,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC/G,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,UAAU,EAAE,UAAU,EAAE,oBAAoB,CAAC,EAAE;YAC/F,QAAQ,EAAE,MAAM;SACjB,CAAC;aACC,KAAK,CAAC,IAAI,CAAC;aACX,MAAM,CAAC,OAAO,CAAC,CAAC;QACnB,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { type OutboundRef } from "./outbound.js";
2
+ /** Every canonical surface ID a file defines (produces), across all supported languages. */
3
+ export declare function extractAllSurfaces(path: string, content?: string): string[];
4
+ /** Every outbound-call candidate a file makes (consumes), across all supported languages. */
5
+ export declare function extractAllOutbound(path: string, content?: string): OutboundRef[];
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Language-composed extraction — the single entry point scan/capture use. Each language module
3
+ * stays pure and self-gated by extension; this file just unions their results. `surface.ts` is
4
+ * deliberately untouched (it is vendored to the GitHub Action's `surface.mjs`).
5
+ */
6
+ import { extractSurfaces } from "./surface.js";
7
+ import { extractOutbound } from "./outbound.js";
8
+ import { extractPythonOutbound, extractPythonSurfaces } from "./python.js";
9
+ /** Every canonical surface ID a file defines (produces), across all supported languages. */
10
+ export function extractAllSurfaces(path, content) {
11
+ return [...new Set([...extractSurfaces(path, content), ...extractPythonSurfaces(path, content)])];
12
+ }
13
+ /** Every outbound-call candidate a file makes (consumes), across all supported languages. */
14
+ export function extractAllOutbound(path, content) {
15
+ return [...extractOutbound(path, content), ...extractPythonOutbound(path, content)];
16
+ }
17
+ //# sourceMappingURL=extract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/capture/extract.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAoB,MAAM,eAAe,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAE3E,4FAA4F;AAC5F,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,OAAgB;IAC/D,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,GAAG,qBAAqB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AACpG,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,OAAgB;IAC/D,OAAO,CAAC,GAAG,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,GAAG,qBAAqB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;AACtF,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function writeFeatureContext(remote: string, ref: string): void;
2
+ export declare function readFeatureContext(remote: string): string | null;
3
+ export declare function clearFeatureContext(remote: string): void;
@@ -0,0 +1,43 @@
1
+ import { readFileSync, writeFileSync, unlinkSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { tmpdir } from "node:os";
4
+ import { createHash } from "node:crypto";
5
+ /**
6
+ * Session feature-context cache — mirrors statusline.ts's tmpdir cache, but keyed by git remote.
7
+ * `set_feature_context` writes here so the (separate-process) capture hook can attach the
8
+ * capabilityRef to change events. Accepted limitation (B-DB2): concurrent sessions on one
9
+ * checkout share one context, same as the statusline cache.
10
+ */
11
+ const TTL_MS = 8 * 3600_000; // 8 hours
12
+ function pathFor(remote) {
13
+ const key = createHash("sha1").update(remote).digest("hex").slice(0, 12);
14
+ return join(tmpdir(), `lockstep-feature-${key}.json`);
15
+ }
16
+ export function writeFeatureContext(remote, ref) {
17
+ try {
18
+ writeFileSync(pathFor(remote), JSON.stringify({ ref, ts: Date.now() }));
19
+ }
20
+ catch {
21
+ /* ignore */
22
+ }
23
+ }
24
+ export function readFeatureContext(remote) {
25
+ try {
26
+ const c = JSON.parse(readFileSync(pathFor(remote), "utf8"));
27
+ if (Date.now() - c.ts < TTL_MS)
28
+ return c.ref;
29
+ }
30
+ catch {
31
+ /* no context */
32
+ }
33
+ return null;
34
+ }
35
+ export function clearFeatureContext(remote) {
36
+ try {
37
+ unlinkSync(pathFor(remote));
38
+ }
39
+ catch {
40
+ /* ignore */
41
+ }
42
+ }
43
+ //# sourceMappingURL=feature-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-context.js","sourceRoot":"","sources":["../../src/capture/feature-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;GAKG;AACH,MAAM,MAAM,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,UAAU;AAOvC,SAAS,OAAO,CAAC,MAAc;IAC7B,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACzE,OAAO,IAAI,CAAC,MAAM,EAAE,EAAE,oBAAoB,GAAG,OAAO,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAc,EAAE,GAAW;IAC7D,IAAI,CAAC;QACH,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAgB,CAAC,CAAC,CAAC;IACxF,CAAC;IAAC,MAAM,CAAC;QACP,YAAY;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAQ,CAAC;QACnE,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,MAAM;YAAE,OAAO,CAAC,CAAC,GAAG,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,gBAAgB;IAClB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,IAAI,CAAC;QACH,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,YAAY;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,45 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { readFileSync, writeFileSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { tmpdir } from "node:os";
6
+ import { createHash } from "node:crypto";
7
+ import { writeFeatureContext, readFeatureContext, clearFeatureContext } from "./feature-context.js";
8
+ // Unique remote per run so parallel/repeat runs don't collide on the tmpdir file.
9
+ const remote = `github.com/lockstep-test/feature-ctx-${process.pid}-${Date.now()}`;
10
+ const pathFor = (r) => join(tmpdir(), `lockstep-feature-${createHash("sha1").update(r).digest("hex").slice(0, 12)}.json`);
11
+ test("write → read round-trips the capabilityRef", () => {
12
+ clearFeatureContext(remote);
13
+ writeFeatureContext(remote, "feature:guest-checkout");
14
+ assert.equal(readFeatureContext(remote), "feature:guest-checkout");
15
+ clearFeatureContext(remote);
16
+ });
17
+ test("missing context → null", () => {
18
+ clearFeatureContext(remote);
19
+ assert.equal(readFeatureContext(remote), null);
20
+ });
21
+ test("stale ts (older than TTL) → null", () => {
22
+ // Hand-write a context with a timestamp well beyond the 8h TTL.
23
+ const stale = { ref: "feature:old", ts: Date.now() - 9 * 3600_000 };
24
+ writeFileSync(pathFor(remote), JSON.stringify(stale));
25
+ assert.equal(readFeatureContext(remote), null);
26
+ clearFeatureContext(remote);
27
+ });
28
+ test("distinct remotes get distinct files", () => {
29
+ const a = `${remote}-a`;
30
+ const b = `${remote}-b`;
31
+ writeFeatureContext(a, "feature:a");
32
+ writeFeatureContext(b, "feature:b");
33
+ assert.equal(readFeatureContext(a), "feature:a");
34
+ assert.equal(readFeatureContext(b), "feature:b");
35
+ clearFeatureContext(a);
36
+ clearFeatureContext(b);
37
+ });
38
+ test("clear removes the file (read → null after)", () => {
39
+ writeFeatureContext(remote, "feature:x");
40
+ const p = pathFor(remote);
41
+ assert.equal(JSON.parse(readFileSync(p, "utf8")).ref, "feature:x");
42
+ clearFeatureContext(remote);
43
+ assert.equal(readFeatureContext(remote), null);
44
+ });
45
+ //# sourceMappingURL=feature-context.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-context.test.js","sourceRoot":"","sources":["../../src/capture/feature-context.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEpG,kFAAkF;AAClF,MAAM,MAAM,GAAG,wCAAwC,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;AACnF,MAAM,OAAO,GAAG,CAAC,CAAS,EAAE,EAAE,CAC5B,IAAI,CAAC,MAAM,EAAE,EAAE,oBAAoB,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;AAErG,IAAI,CAAC,4CAA4C,EAAE,GAAG,EAAE;IACtD,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC5B,mBAAmB,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC;IACtD,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,wBAAwB,CAAC,CAAC;IACnE,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAC9B,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,wBAAwB,EAAE,GAAG,EAAE;IAClC,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC5B,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,kCAAkC,EAAE,GAAG,EAAE;IAC5C,gEAAgE;IAChE,MAAM,KAAK,GAAG,EAAE,GAAG,EAAE,aAAa,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,QAAQ,EAAE,CAAC;IACpE,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IACtD,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;IAC/C,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAC9B,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,qCAAqC,EAAE,GAAG,EAAE;IAC/C,MAAM,CAAC,GAAG,GAAG,MAAM,IAAI,CAAC;IACxB,MAAM,CAAC,GAAG,GAAG,MAAM,IAAI,CAAC;IACxB,mBAAmB,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IACpC,mBAAmB,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IACpC,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IACjD,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IACjD,mBAAmB,CAAC,CAAC,CAAC,CAAC;IACvB,mBAAmB,CAAC,CAAC,CAAC,CAAC;AACzB,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,4CAA4C,EAAE,GAAG,EAAE;IACtD,mBAAmB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACzC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1B,MAAM,CAAC,KAAK,CAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAqB,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACxF,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC5B,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC"}
@@ -1,6 +1,65 @@
1
+ interface InboxResp {
2
+ unread?: number;
3
+ changes?: Array<{
4
+ summary: string;
5
+ surface: string | null;
6
+ impact?: number;
7
+ }>;
8
+ questions?: Array<{
9
+ id: string;
10
+ body: string;
11
+ scopeRef: string | null;
12
+ urgent: boolean;
13
+ status: string;
14
+ }>;
15
+ tasks?: Array<{
16
+ id: string;
17
+ title: string;
18
+ runState: string;
19
+ status: string;
20
+ }>;
21
+ decisions?: Array<{
22
+ id: string;
23
+ scopeRef: string;
24
+ ruleText: string;
25
+ status: string;
26
+ impact?: number;
27
+ }>;
28
+ conflicts?: Array<{
29
+ id: string;
30
+ surface: string;
31
+ constraintRuleText: string;
32
+ engRuleText: string;
33
+ }>;
34
+ }
35
+ interface DecisionsResp {
36
+ decisions?: Array<{
37
+ scopeRef: string;
38
+ status: string;
39
+ ruleText: string;
40
+ impact?: number;
41
+ }>;
42
+ }
43
+ /** Product-layer briefing: ranked, budget-capped constraints (origin=document, binding) in scope. */
44
+ export interface BriefingResp {
45
+ constraints: Array<{
46
+ line: string;
47
+ impact: number;
48
+ conflictOpen: boolean;
49
+ }>;
50
+ overflow: number;
51
+ /** Phase P: binding decisionType=principle decisions — the team's standing decision criteria. */
52
+ principles?: Array<{
53
+ line: string;
54
+ impact: number;
55
+ }>;
56
+ principlesOverflow?: number;
57
+ }
58
+ export declare function formatReplay(inbox: InboxResp | null, decisions: DecisionsResp | null, briefing?: BriefingResp | null): string;
1
59
  /**
2
60
  * Hook entrypoint. Resilient by design — never break the agent: on any error it exits 0.
3
61
  * SessionStart → replay inbox + binding decisions as additionalContext.
4
62
  * PostToolUse/Stop → diff → classify surface → risk-tiered publish via notify.
5
63
  */
6
64
  export declare function runCapture(event: string): Promise<void>;
65
+ export {};
@@ -3,15 +3,29 @@ import { join } from "node:path";
3
3
  import { createHash } from "node:crypto";
4
4
  import { registerSession } from "../mcp/session.js";
5
5
  import { call } from "../mcp/api.js";
6
+ import { gitRemote } from "../mcp/git.js";
7
+ import { readFeatureContext } from "./feature-context.js";
6
8
  import { changedFiles } from "./diff.js";
7
9
  import { isContractSurface, riskTierFor } from "./classify.js";
8
- function formatReplay(inbox, decisions) {
10
+ import { extractAllSurfaces } from "./extract.js";
11
+ import { readManifest } from "./manifest.js";
12
+ /** Sync this repo's declared dependencies (lockstep.yaml `consumes:`) into the usage graph. Idempotent. */
13
+ async function syncManifestDeps(cwd, sessionId) {
14
+ const { consumes } = readManifest(cwd);
15
+ for (const producedSurface of consumes) {
16
+ await call("POST", "/dependencies", sessionId, { producedSurface, source: "manifest" }).catch(() => { });
17
+ }
18
+ }
19
+ /** Highest-blast-radius first, so the session-start briefing leads with what matters most. */
20
+ const byImpact = (a, b) => (b.impact ?? 0) - (a.impact ?? 0);
21
+ const tag = (impact) => ((impact ?? 0) > 0 ? `[impact ${impact}] ` : "");
22
+ export function formatReplay(inbox, decisions, briefing) {
9
23
  const lines = [];
10
- const changes = inbox?.changes ?? [];
24
+ const changes = [...(inbox?.changes ?? [])].sort(byImpact);
11
25
  if (changes.length) {
12
26
  lines.push(`📥 ${changes.length} change(s) since you were last here:`);
13
27
  for (const c of changes.slice(0, 8))
14
- lines.push(` • ${c.summary}${c.surface ? ` (${c.surface})` : ""}`);
28
+ lines.push(` • ${tag(c.impact)}${c.summary}${c.surface ? ` (${c.surface})` : ""}`);
15
29
  }
16
30
  const qs = (inbox?.questions ?? []).filter((q) => q.status === "open");
17
31
  if (qs.length) {
@@ -25,12 +39,44 @@ function formatReplay(inbox, decisions) {
25
39
  for (const t of ts.slice(0, 8))
26
40
  lines.push(` • ${t.title}`);
27
41
  }
28
- const binding = (decisions?.decisions ?? []).filter((d) => d.status === "binding");
29
- if (binding.length) {
30
- lines.push(`📌 ${binding.length} binding decision(s) in effect:`);
31
- for (const d of binding.slice(0, 8))
42
+ const pendingDecisions = (inbox?.decisions ?? []).filter((d) => d.status === "open");
43
+ if (pendingDecisions.length) {
44
+ lines.push(`⚖️ ${pendingDecisions.length} decision(s) pending your acknowledgment:`);
45
+ for (const d of pendingDecisions.slice(0, 8))
32
46
  lines.push(` • [${d.scopeRef}] ${d.ruleText}`);
33
47
  }
48
+ const conflicts = inbox?.conflicts ?? [];
49
+ if (conflicts.length) {
50
+ lines.push(`⚔️ ${conflicts.length} drift conflict(s) — your work may conflict with a ratified product constraint:`);
51
+ for (const c of conflicts.slice(0, 8))
52
+ lines.push(` • [${c.surface}] your "${c.engRuleText}" vs constraint "${c.constraintRuleText}" — review both`);
53
+ }
54
+ // Principles lead — they're the criteria the agent should judge everything else by (TOMASP "M").
55
+ const principles = briefing?.principles ?? [];
56
+ if (principles.length) {
57
+ lines.push(`◆ ${principles.length} project principle(s) — the team's standing decision criteria:`);
58
+ for (const p of principles)
59
+ lines.push(` • ${p.line}`);
60
+ if ((briefing?.principlesOverflow ?? 0) > 0)
61
+ lines.push(` • (+${briefing?.principlesOverflow} more — query the ledger)`);
62
+ }
63
+ const binding = (decisions?.decisions ?? []).filter((d) => d.status === "binding").sort(byImpact);
64
+ const constraints = briefing?.constraints ?? [];
65
+ if (binding.length || constraints.length) {
66
+ const rows = [
67
+ ...binding.map((d) => ({
68
+ impact: d.impact ?? 0,
69
+ isConstraint: false,
70
+ line: ` • ${tag(d.impact)}[${d.scopeRef}] ${d.ruleText}`,
71
+ })),
72
+ ...constraints.map((c) => ({ impact: c.impact, isConstraint: true, line: ` • ${c.line}` })),
73
+ ].sort((a, b) => b.impact - a.impact || Number(b.isConstraint) - Number(a.isConstraint));
74
+ lines.push(`📌 ${rows.length} binding decision(s) in effect:`);
75
+ for (const r of rows.slice(0, 8))
76
+ lines.push(r.line);
77
+ if ((briefing?.overflow ?? 0) > 0)
78
+ lines.push(` • (+${briefing?.overflow} product constraints in scope — get_product_context)`);
79
+ }
34
80
  return lines.length ? `Lockstep:\n${lines.join("\n")}` : "Lockstep: nothing new.";
35
81
  }
36
82
  /** Format a short badge from inbox peek counts. Returns null if nothing new. */
@@ -42,6 +88,8 @@ function formatPeek(peek) {
42
88
  parts.push(`${peek.questions} question${peek.questions > 1 ? "s" : ""}`);
43
89
  if (peek.tasks)
44
90
  parts.push(`${peek.tasks} task${peek.tasks > 1 ? "s" : ""}`);
91
+ if (peek.decisions)
92
+ parts.push(`${peek.decisions} decision${peek.decisions > 1 ? "s" : ""} to review`);
45
93
  if (peek.changes)
46
94
  parts.push(`${peek.changes} change${peek.changes > 1 ? "s" : ""}`);
47
95
  if (parts.length === 0)
@@ -63,11 +111,15 @@ export async function runCapture(event) {
63
111
  catch {
64
112
  process.exit(0); // not a connected repo / not logged in → silent no-op
65
113
  }
114
+ const remote = gitRemote(cwd);
115
+ const capabilityRef = remote ? readFeatureContext(remote) : null;
66
116
  try {
67
117
  if (event === "SessionStart") {
118
+ await syncManifestDeps(cwd, session.sessionId); // keep the usage graph current from lockstep.yaml
68
119
  const inbox = await call("GET", "/inbox", session.sessionId).catch(() => null);
69
120
  const decisions = await call("GET", "/decisions", session.sessionId).catch(() => null);
70
- const replay = formatReplay(inbox, decisions);
121
+ const briefing = await call("GET", "/briefing", session.sessionId).catch(() => null);
122
+ const replay = formatReplay(inbox, decisions, briefing);
71
123
  process.stdout.write(JSON.stringify({
72
124
  hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: replay },
73
125
  }));
@@ -81,7 +133,9 @@ export async function runCapture(event) {
81
133
  const files = changedFiles(cwd);
82
134
  if (files.length === 0)
83
135
  return;
84
- const surfaces = [];
136
+ // Extract CANONICAL surface IDs (e.g. "http:POST /auth/session") — the shared vocabulary that
137
+ // lets a consumer's declared dependency match a producer's change. File paths never matched.
138
+ const surfaceIds = new Set();
85
139
  let anyContractSurface = false;
86
140
  for (const f of files) {
87
141
  let content = "";
@@ -91,24 +145,50 @@ export async function runCapture(event) {
91
145
  catch {
92
146
  /* deleted/binary — skip content */
93
147
  }
94
- if (isContractSurface(f, content)) {
148
+ const ids = extractAllSurfaces(f, content);
149
+ if (ids.length > 0) {
95
150
  anyContractSurface = true;
96
- surfaces.push(f);
151
+ ids.forEach((s) => surfaceIds.add(s));
152
+ }
153
+ else if (isContractSurface(f, content)) {
154
+ anyContractSurface = true; // contract-ish file we couldn't parse into an exact surface
97
155
  }
98
156
  }
99
157
  // v1: contract surface ⇒ shared (the safety-critical bias). Ownership-based refinement later.
100
158
  const riskTier = riskTierFor({ anyContractSurface, allOwnedByMe: true });
101
159
  const summary = `${event}: changed ${files.length} file(s): ${files.slice(0, 5).join(", ")}${files.length > 5 ? "…" : ""}`;
102
- const diffHash = createHash("sha256").update(files.sort().join("|")).digest("hex").slice(0, 16);
103
- await call("POST", "/changes", session.sessionId, {
104
- summary,
105
- surface: surfaces[0],
106
- riskTier,
107
- verified: true, // mechanical delta is derived from real local code
108
- verifiedAgainst: "git-diff",
109
- diffHash,
110
- }).catch(() => { });
111
- process.stderr.write(`[lockstep] published change (${riskTier})\n`);
160
+ const baseHash = createHash("sha256").update(files.sort().join("|")).digest("hex").slice(0, 16);
161
+ const ids = [...surfaceIds].slice(0, 10);
162
+ if (ids.length === 0) {
163
+ // No contract surface touched — record a single owned activity entry (routes to no one).
164
+ await call("POST", "/changes", session.sessionId, {
165
+ summary,
166
+ riskTier,
167
+ verified: true,
168
+ verifiedAgainst: "git-diff",
169
+ diffHash: baseHash,
170
+ capabilityRef: capabilityRef ?? undefined,
171
+ }).catch(() => { });
172
+ }
173
+ else {
174
+ // One change per changed surface, so each routes to that surface's consumers.
175
+ for (const surface of ids) {
176
+ await call("POST", "/changes", session.sessionId, {
177
+ summary,
178
+ surface,
179
+ riskTier,
180
+ verified: true, // mechanical delta is derived from real local code (displayed as "extracted", not "verified")
181
+ verifiedAgainst: "git-diff",
182
+ diffHash: `${baseHash}:${surface}`,
183
+ capabilityRef: capabilityRef ?? undefined,
184
+ }).catch(() => { });
185
+ }
186
+ }
187
+ process.stderr.write(`[lockstep] published change (${riskTier}, ${ids.length} surface(s))\n`);
188
+ // NOTE: capture publishes a CHANGE event only. A change is NOT a decision — decisions are
189
+ // durable rules/architectural choices, logged deliberately by the agent via propose_decision
190
+ // (see the lockstep skill). Auto-minting a decision per save was a category error that flooded
191
+ // the ledger; routing/impact for changes is handled by recordChange on the server.
112
192
  // Peek at inbox (without marking as read) — notify the agent if there are unread items
113
193
  const peek = await call("GET", "/inbox/peek", session.sessionId).catch(() => null);
114
194
  const badge = formatPeek(peek);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/capture/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/capture/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ export interface Manifest {
2
+ produces: string[];
3
+ consumes: string[];
4
+ }
5
+ /**
6
+ * Read `lockstep.yaml` from the repo root. This is the deterministic source of truth for the usage
7
+ * graph: `consumes:` declares the canonical surface IDs this repo depends on (so it gets warned when
8
+ * they change), `produces:` optionally declares/overrides what it exposes. We parse a minimal YAML
9
+ * subset (two top-level keys, each a `- item` list) to stay dependency-free and predictable.
10
+ *
11
+ * Example:
12
+ * produces:
13
+ * - http:POST /auth/session
14
+ * consumes:
15
+ * - http:GET /orders/:id
16
+ */
17
+ export declare function readManifest(cwd: string): Manifest;
18
+ /**
19
+ * Write `lockstep.yaml`, MERGE-preserving what's already there — existing human entries are unioned
20
+ * with the proposed ones (never dropped), and the file's leading comment block is kept. Atomic write
21
+ * with a one-time `.lockstep.bak` and idempotent no-op, via the shared `applyFile`. This is the single
22
+ * sanctioned writer of the manifest — the capture hook never touches it (see IMPROVEMENTS #11).
23
+ */
24
+ export declare function writeManifest(cwd: string, manifest: Manifest, opts?: {
25
+ dryRun?: boolean;
26
+ }): Promise<string>;
@@ -0,0 +1,98 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { applyFile } from "../adapters/fsutil.js";
4
+ /**
5
+ * Read `lockstep.yaml` from the repo root. This is the deterministic source of truth for the usage
6
+ * graph: `consumes:` declares the canonical surface IDs this repo depends on (so it gets warned when
7
+ * they change), `produces:` optionally declares/overrides what it exposes. We parse a minimal YAML
8
+ * subset (two top-level keys, each a `- item` list) to stay dependency-free and predictable.
9
+ *
10
+ * Example:
11
+ * produces:
12
+ * - http:POST /auth/session
13
+ * consumes:
14
+ * - http:GET /orders/:id
15
+ */
16
+ export function readManifest(cwd) {
17
+ let raw;
18
+ try {
19
+ raw = readFileSync(join(cwd, "lockstep.yaml"), "utf8");
20
+ }
21
+ catch {
22
+ return { produces: [], consumes: [] };
23
+ }
24
+ const out = { produces: [], consumes: [] };
25
+ let key = null;
26
+ for (const line of raw.split(/\r?\n/)) {
27
+ if (/^\s*#/.test(line) || line.trim() === "")
28
+ continue;
29
+ const top = line.match(/^(produces|consumes)\s*:\s*$/);
30
+ if (top) {
31
+ key = top[1];
32
+ continue;
33
+ }
34
+ const item = line.match(/^\s*-\s*(.+?)\s*$/);
35
+ if (item && key) {
36
+ out[key].push(item[1].replace(/^["']|["']$/g, ""));
37
+ }
38
+ else if (/^\S/.test(line)) {
39
+ key = null; // a new unindented non-list key ends the current list
40
+ }
41
+ }
42
+ return out;
43
+ }
44
+ const DEFAULT_HEADER = `# Lockstep manifest — the deterministic source of truth for the usage graph.
45
+ # Managed by the \`/lockstep-setup\` skill (the only sanctioned writer; the capture hook is read-only).
46
+ # Surface IDs are canonical: http:METHOD /path · proto:pkg.Service/Rpc · gql:Root.field
47
+ `;
48
+ /** Preserve the file's existing top-of-file comment block (so human notes survive a rewrite). */
49
+ function leadingComment(raw) {
50
+ if (!raw)
51
+ return null;
52
+ const head = [];
53
+ for (const line of raw.split(/\r?\n/)) {
54
+ if (/^\s*#/.test(line) || line.trim() === "")
55
+ head.push(line);
56
+ else
57
+ break;
58
+ }
59
+ const block = head.join("\n").trimEnd();
60
+ return block ? block + "\n" : null;
61
+ }
62
+ const union = (a, b) => {
63
+ const out = [];
64
+ const seen = new Set();
65
+ for (const x of [...a, ...b])
66
+ if (x && !seen.has(x))
67
+ (seen.add(x), out.push(x));
68
+ return out;
69
+ };
70
+ function serialize(m, header) {
71
+ const list = (items) => items.map((i) => ` - ${i}`).join("\n");
72
+ const block = (key, items) => (items.length ? `${key}:\n${list(items)}\n` : `${key}:\n`);
73
+ return `${header}\n${block("produces", m.produces)}\n${block("consumes", m.consumes)}`;
74
+ }
75
+ /**
76
+ * Write `lockstep.yaml`, MERGE-preserving what's already there — existing human entries are unioned
77
+ * with the proposed ones (never dropped), and the file's leading comment block is kept. Atomic write
78
+ * with a one-time `.lockstep.bak` and idempotent no-op, via the shared `applyFile`. This is the single
79
+ * sanctioned writer of the manifest — the capture hook never touches it (see IMPROVEMENTS #11).
80
+ */
81
+ export async function writeManifest(cwd, manifest, opts = {}) {
82
+ const path = join(cwd, "lockstep.yaml");
83
+ let raw;
84
+ try {
85
+ raw = readFileSync(path, "utf8");
86
+ }
87
+ catch {
88
+ raw = null;
89
+ }
90
+ const existing = readManifest(cwd);
91
+ const merged = {
92
+ produces: union(existing.produces, manifest.produces),
93
+ consumes: union(existing.consumes, manifest.consumes),
94
+ };
95
+ const header = leadingComment(raw) ?? DEFAULT_HEADER;
96
+ return applyFile(path, () => serialize(merged, header), opts.dryRun ?? false);
97
+ }
98
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/capture/manifest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,40 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { mkdtemp, readFile, writeFile, access } from "node:fs/promises";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+ import { readManifest, writeManifest } from "./manifest.js";
7
+ const tmp = () => mkdtemp(join(tmpdir(), "lockstep-manifest-"));
8
+ test("writeManifest round-trips through readManifest", async () => {
9
+ const dir = await tmp();
10
+ await writeManifest(dir, { produces: ["http:POST /a"], consumes: ["http:GET /b"] });
11
+ assert.deepEqual(readManifest(dir), { produces: ["http:POST /a"], consumes: ["http:GET /b"] });
12
+ });
13
+ test("merges with (never drops) existing human entries", async () => {
14
+ const dir = await tmp();
15
+ await writeFile(join(dir, "lockstep.yaml"), "# my notes\nproduces:\n - http:POST /a\nconsumes:\n - http:GET /manual\n");
16
+ await writeManifest(dir, { produces: ["http:POST /a", "http:GET /new"], consumes: ["http:GET /b"] });
17
+ const m = readManifest(dir);
18
+ assert.deepEqual(m.produces, ["http:POST /a", "http:GET /new"]);
19
+ assert.deepEqual(m.consumes, ["http:GET /manual", "http:GET /b"], "human entry kept, new one appended");
20
+ const raw = await readFile(join(dir, "lockstep.yaml"), "utf8");
21
+ assert.ok(raw.startsWith("# my notes"), "existing comment header preserved");
22
+ });
23
+ test("writes a one-time .lockstep.bak and is idempotent on no-op re-write", async () => {
24
+ const dir = await tmp();
25
+ await writeFile(join(dir, "lockstep.yaml"), "produces:\nconsumes:\n");
26
+ await writeManifest(dir, { produces: ["http:POST /a"], consumes: [] });
27
+ await access(join(dir, "lockstep.yaml.lockstep.bak")); // throws if missing
28
+ const first = await readFile(join(dir, "lockstep.yaml"), "utf8");
29
+ const status = await writeManifest(dir, { produces: ["http:POST /a"], consumes: [] });
30
+ const second = await readFile(join(dir, "lockstep.yaml"), "utf8");
31
+ assert.equal(first, second, "re-write with same content is a no-op");
32
+ assert.match(status, /^unchanged/);
33
+ });
34
+ test("dry-run does not write the file", async () => {
35
+ const dir = await tmp();
36
+ const status = await writeManifest(dir, { produces: ["http:POST /a"], consumes: [] }, { dryRun: true });
37
+ assert.match(status, /^would write/);
38
+ await assert.rejects(access(join(dir, "lockstep.yaml")));
39
+ });
40
+ //# sourceMappingURL=manifest.test.js.map