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.
- package/README.md +29 -0
- package/dist/adapters/claude.js +26 -7
- package/dist/adapters/claude.js.map +1 -1
- package/dist/adapters/install.test.js +53 -2
- package/dist/adapters/install.test.js.map +1 -1
- package/dist/adapters/merge.d.ts +11 -0
- package/dist/adapters/merge.js +41 -0
- package/dist/adapters/merge.js.map +1 -1
- package/dist/adapters/templates.d.ts +3 -2
- package/dist/adapters/templates.js +92 -3
- package/dist/adapters/templates.js.map +1 -1
- package/dist/capture/classify-edge.test.js +9 -7
- package/dist/capture/classify-edge.test.js.map +1 -1
- package/dist/capture/classify.d.ts +6 -4
- package/dist/capture/classify.js +9 -8
- package/dist/capture/classify.js.map +1 -1
- package/dist/capture/classify.test.js +7 -2
- package/dist/capture/classify.test.js.map +1 -1
- package/dist/capture/diff.d.ts +2 -0
- package/dist/capture/diff.js +15 -0
- package/dist/capture/diff.js.map +1 -1
- package/dist/capture/extract.d.ts +5 -0
- package/dist/capture/extract.js +17 -0
- package/dist/capture/extract.js.map +1 -0
- package/dist/capture/feature-context.d.ts +3 -0
- package/dist/capture/feature-context.js +43 -0
- package/dist/capture/feature-context.js.map +1 -0
- package/dist/capture/feature-context.test.d.ts +1 -0
- package/dist/capture/feature-context.test.js +45 -0
- package/dist/capture/feature-context.test.js.map +1 -0
- package/dist/capture/index.d.ts +59 -0
- package/dist/capture/index.js +101 -21
- package/dist/capture/index.js.map +1 -1
- package/dist/capture/manifest.d.ts +26 -0
- package/dist/capture/manifest.js +98 -0
- package/dist/capture/manifest.js.map +1 -0
- package/dist/capture/manifest.test.d.ts +1 -0
- package/dist/capture/manifest.test.js +40 -0
- package/dist/capture/manifest.test.js.map +1 -0
- package/dist/capture/outbound.d.ts +10 -0
- package/dist/capture/outbound.js +139 -0
- package/dist/capture/outbound.js.map +1 -0
- package/dist/capture/outbound.test.d.ts +1 -0
- package/dist/capture/outbound.test.js +89 -0
- package/dist/capture/outbound.test.js.map +1 -0
- package/dist/capture/python.d.ts +5 -0
- package/dist/capture/python.js +127 -0
- package/dist/capture/python.js.map +1 -0
- package/dist/capture/python.test.d.ts +1 -0
- package/dist/capture/python.test.js +99 -0
- package/dist/capture/python.test.js.map +1 -0
- package/dist/capture/replay.test.d.ts +1 -0
- package/dist/capture/replay.test.js +101 -0
- package/dist/capture/replay.test.js.map +1 -0
- package/dist/capture/surface.d.ts +23 -0
- package/dist/capture/surface.js +83 -0
- package/dist/capture/surface.js.map +1 -0
- package/dist/capture/surface.test.d.ts +1 -0
- package/dist/capture/surface.test.js +37 -0
- package/dist/capture/surface.test.js.map +1 -0
- package/dist/connect.d.ts +1 -1
- package/dist/connect.js +23 -12
- package/dist/connect.js.map +1 -1
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -1
- package/dist/init.js +3 -1
- package/dist/init.js.map +1 -1
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +26 -3
- package/dist/mcp/server.js.map +1 -1
- package/dist/scan.d.ts +64 -0
- package/dist/scan.js +176 -0
- package/dist/scan.js.map +1 -0
- package/dist/scan.test.d.ts +1 -0
- package/dist/scan.test.js +258 -0
- package/dist/scan.test.js.map +1 -0
- package/dist/statusline.d.ts +6 -0
- package/dist/statusline.js +108 -0
- package/dist/statusline.js.map +1 -0
- package/package.json +8 -4
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { formatReplay } from "./index.js";
|
|
4
|
+
const decisions = {
|
|
5
|
+
decisions: [
|
|
6
|
+
{ scopeRef: "http:POST /auth/session", status: "binding", ruleText: "Sessions expire in 24h", impact: 3 },
|
|
7
|
+
{ scopeRef: "svc:orders", status: "binding", ruleText: "Orders are append-only", impact: 1 },
|
|
8
|
+
{ scopeRef: "svc:draft", status: "proposed", ruleText: "not binding — ignored", impact: 9 },
|
|
9
|
+
],
|
|
10
|
+
};
|
|
11
|
+
// The server pre-renders `line`; formatReplay only prefixes " • " and interleaves by impact.
|
|
12
|
+
const briefing = {
|
|
13
|
+
constraints: [
|
|
14
|
+
{ line: "⚠ [ratified · PRD-142] Guest flow must not present OTP before payment (impact 5)", impact: 5, conflictOpen: false },
|
|
15
|
+
{ line: "⚠ [ratified · PRD-142] Checkout must accept guest orders (impact 3) · conflict open", impact: 3, conflictOpen: true },
|
|
16
|
+
],
|
|
17
|
+
overflow: 0,
|
|
18
|
+
};
|
|
19
|
+
test("null briefing → output is byte-identical to the pre-Phase-B format", () => {
|
|
20
|
+
const out = formatReplay(null, decisions, null);
|
|
21
|
+
const expected = [
|
|
22
|
+
"Lockstep:",
|
|
23
|
+
"📌 2 binding decision(s) in effect:",
|
|
24
|
+
" • [impact 3] [http:POST /auth/session] Sessions expire in 24h",
|
|
25
|
+
" • [impact 1] [svc:orders] Orders are append-only",
|
|
26
|
+
].join("\n");
|
|
27
|
+
assert.equal(out, expected);
|
|
28
|
+
// absent briefing arg behaves the same as explicit null
|
|
29
|
+
assert.equal(formatReplay(null, decisions), expected);
|
|
30
|
+
});
|
|
31
|
+
test("constraints interleave into the binding section, impact-desc", () => {
|
|
32
|
+
const out = formatReplay(null, decisions, briefing);
|
|
33
|
+
const lines = out.split("\n");
|
|
34
|
+
assert.equal(lines[0], "Lockstep:");
|
|
35
|
+
assert.equal(lines[1], "📌 4 binding decision(s) in effect:"); // 2 decisions + 2 constraints
|
|
36
|
+
assert.deepEqual(lines.slice(2), [
|
|
37
|
+
" • ⚠ [ratified · PRD-142] Guest flow must not present OTP before payment (impact 5)", // impact 5
|
|
38
|
+
" • ⚠ [ratified · PRD-142] Checkout must accept guest orders (impact 3) · conflict open", // impact 3, tie → constraint first
|
|
39
|
+
" • [impact 3] [http:POST /auth/session] Sessions expire in 24h", // impact 3 decision, after the constraint
|
|
40
|
+
" • [impact 1] [svc:orders] Orders are append-only",
|
|
41
|
+
]);
|
|
42
|
+
});
|
|
43
|
+
test("on an impact tie, the constraint leads the plain decision", () => {
|
|
44
|
+
const tied = {
|
|
45
|
+
decisions: [{ scopeRef: "svc:x", status: "binding", ruleText: "plain", impact: 3 }],
|
|
46
|
+
};
|
|
47
|
+
const b = {
|
|
48
|
+
constraints: [{ line: "⚠ [ratified · PRD-9] constraint", impact: 3, conflictOpen: false }],
|
|
49
|
+
overflow: 0,
|
|
50
|
+
};
|
|
51
|
+
const lines = formatReplay(null, tied, b).split("\n");
|
|
52
|
+
assert.equal(lines[2], " • ⚠ [ratified · PRD-9] constraint");
|
|
53
|
+
assert.equal(lines[3], " • [impact 3] [svc:x] plain");
|
|
54
|
+
});
|
|
55
|
+
test("overflow line appears only when overflow > 0", () => {
|
|
56
|
+
const withOverflow = { constraints: briefing.constraints, overflow: 7 };
|
|
57
|
+
const out = formatReplay(null, decisions, withOverflow);
|
|
58
|
+
assert.match(out, /\n {2}• \(\+7 product constraints in scope — get_product_context\)$/);
|
|
59
|
+
// no overflow → no line
|
|
60
|
+
assert.doesNotMatch(formatReplay(null, decisions, briefing), /product constraints in scope/);
|
|
61
|
+
});
|
|
62
|
+
test("constraints render even when there are no binding decisions", () => {
|
|
63
|
+
const out = formatReplay(null, { decisions: [] }, briefing);
|
|
64
|
+
const lines = out.split("\n");
|
|
65
|
+
assert.equal(lines[1], "📌 2 binding decision(s) in effect:");
|
|
66
|
+
assert.ok(lines[2]?.startsWith(" • ⚠ [ratified · PRD-142]"));
|
|
67
|
+
});
|
|
68
|
+
test("empty briefing (no constraints, overflow 0) leaves prior behavior intact", () => {
|
|
69
|
+
const empty = { constraints: [], overflow: 0 };
|
|
70
|
+
assert.equal(formatReplay(null, decisions, empty), formatReplay(null, decisions, null));
|
|
71
|
+
});
|
|
72
|
+
test("drift conflicts from the inbox render their own briefing section", () => {
|
|
73
|
+
const inbox = {
|
|
74
|
+
conflicts: [{ id: "k7", surface: "http:POST /payments/init", constraintRuleText: "no OTP before payment", engRuleText: "OTP on all inits" }],
|
|
75
|
+
};
|
|
76
|
+
const out = formatReplay(inbox, null, null);
|
|
77
|
+
assert.match(out, /⚔️ 1 drift conflict\(s\)/);
|
|
78
|
+
assert.match(out, /\[http:POST \/payments\/init\] your "OTP on all inits" vs constraint "no OTP before payment" — review both/);
|
|
79
|
+
});
|
|
80
|
+
test("project principles lead the briefing, above the binding-decisions section (Phase P)", () => {
|
|
81
|
+
const withPrinciples = {
|
|
82
|
+
constraints: [],
|
|
83
|
+
overflow: 0,
|
|
84
|
+
principles: [
|
|
85
|
+
{ line: "◆ [principle] Server-side business logic is Ruby.", impact: 3 },
|
|
86
|
+
{ line: "◆ [principle] Prefer boring technology.", impact: 0 },
|
|
87
|
+
],
|
|
88
|
+
principlesOverflow: 0,
|
|
89
|
+
};
|
|
90
|
+
const out = formatReplay(null, decisions, withPrinciples);
|
|
91
|
+
const lines = out.split("\n");
|
|
92
|
+
assert.equal(lines[1], "◆ 2 project principle(s) — the team's standing decision criteria:");
|
|
93
|
+
assert.ok(lines[2].includes("Server-side business logic is Ruby."));
|
|
94
|
+
assert.ok(out.indexOf("project principle(s)") < out.indexOf("binding decision(s)"), "principles render before binding decisions");
|
|
95
|
+
assert.doesNotMatch(out, /more — query the ledger/);
|
|
96
|
+
const overflowing = { ...withPrinciples, principlesOverflow: 2 };
|
|
97
|
+
assert.match(formatReplay(null, decisions, overflowing), /\(\+2 more — query the ledger\)/);
|
|
98
|
+
// Absent principles (old core) → byte-identical to before.
|
|
99
|
+
assert.equal(formatReplay(null, decisions, { constraints: [], overflow: 0 }), formatReplay(null, decisions, null));
|
|
100
|
+
});
|
|
101
|
+
//# sourceMappingURL=replay.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay.test.js","sourceRoot":"","sources":["../../src/capture/replay.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,YAAY,EAAqB,MAAM,YAAY,CAAC;AAE7D,MAAM,SAAS,GAAG;IAChB,SAAS,EAAE;QACT,EAAE,QAAQ,EAAE,yBAAyB,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,wBAAwB,EAAE,MAAM,EAAE,CAAC,EAAE;QACzG,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,wBAAwB,EAAE,MAAM,EAAE,CAAC,EAAE;QAC5F,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,uBAAuB,EAAE,MAAM,EAAE,CAAC,EAAE;KAC5F;CACF,CAAC;AAEF,8FAA8F;AAC9F,MAAM,QAAQ,GAAiB;IAC7B,WAAW,EAAE;QACX,EAAE,IAAI,EAAE,kFAAkF,EAAE,MAAM,EAAE,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE;QAC5H,EAAE,IAAI,EAAE,qFAAqF,EAAE,MAAM,EAAE,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE;KAC/H;IACD,QAAQ,EAAE,CAAC;CACZ,CAAC;AAEF,IAAI,CAAC,oEAAoE,EAAE,GAAG,EAAE;IAC9E,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG;QACf,WAAW;QACX,qCAAqC;QACrC,iEAAiE;QACjE,oDAAoD;KACrD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC5B,wDAAwD;IACxD,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,QAAQ,CAAC,CAAC;AACxD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,8DAA8D,EAAE,GAAG,EAAE;IACxE,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IACpD,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IACpC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,qCAAqC,CAAC,CAAC,CAAC,8BAA8B;IAC7F,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;QAC/B,sFAAsF,EAAE,WAAW;QACnG,yFAAyF,EAAE,mCAAmC;QAC9H,iEAAiE,EAAE,0CAA0C;QAC7G,oDAAoD;KACrD,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,2DAA2D,EAAE,GAAG,EAAE;IACrE,MAAM,IAAI,GAAG;QACX,SAAS,EAAE,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;KACpF,CAAC;IACF,MAAM,CAAC,GAAiB;QACtB,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,iCAAiC,EAAE,MAAM,EAAE,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;QAC1F,QAAQ,EAAE,CAAC;KACZ,CAAC;IACF,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,qCAAqC,CAAC,CAAC;IAC9D,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,8BAA8B,CAAC,CAAC;AACzD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,8CAA8C,EAAE,GAAG,EAAE;IACxD,MAAM,YAAY,GAAiB,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACtF,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;IACxD,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,qEAAqE,CAAC,CAAC;IACzF,wBAAwB;IACxB,MAAM,CAAC,YAAY,CAAC,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,8BAA8B,CAAC,CAAC;AAC/F,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,6DAA6D,EAAE,GAAG,EAAE;IACvE,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC5D,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,qCAAqC,CAAC,CAAC;IAC9D,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,4BAA4B,CAAC,CAAC,CAAC;AAChE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,0EAA0E,EAAE,GAAG,EAAE;IACpF,MAAM,KAAK,GAAiB,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IAC7D,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;AAC1F,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,kEAAkE,EAAE,GAAG,EAAE;IAC5E,MAAM,KAAK,GAAG;QACZ,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,0BAA0B,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,WAAW,EAAE,kBAAkB,EAAE,CAAC;KAC7I,CAAC;IACF,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5C,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,0BAA0B,CAAC,CAAC;IAC9C,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,4GAA4G,CAAC,CAAC;AAClI,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,qFAAqF,EAAE,GAAG,EAAE;IAC/F,MAAM,cAAc,GAAiB;QACnC,WAAW,EAAE,EAAE;QACf,QAAQ,EAAE,CAAC;QACX,UAAU,EAAE;YACV,EAAE,IAAI,EAAE,mDAAmD,EAAE,MAAM,EAAE,CAAC,EAAE;YACxE,EAAE,IAAI,EAAE,yCAAyC,EAAE,MAAM,EAAE,CAAC,EAAE;SAC/D;QACD,kBAAkB,EAAE,CAAC;KACtB,CAAC;IACF,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,mEAAmE,CAAC,CAAC;IAC5F,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC,CAAC,CAAC;IACrE,MAAM,CAAC,EAAE,CACP,GAAG,CAAC,OAAO,CAAC,sBAAsB,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,qBAAqB,CAAC,EACxE,4CAA4C,CAC7C,CAAC;IACF,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,yBAAyB,CAAC,CAAC;IAEpD,MAAM,WAAW,GAAiB,EAAE,GAAG,cAAc,EAAE,kBAAkB,EAAE,CAAC,EAAE,CAAC;IAC/E,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,WAAW,CAAC,EAAE,iCAAiC,CAAC,CAAC;IAE5F,2DAA2D;IAC3D,MAAM,CAAC,KAAK,CACV,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,EAC/D,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,CACpC,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical surface identity — the shared vocabulary that lets a producer and a consumer name the
|
|
3
|
+
* same logical interface as the SAME string, without sharing source. This is the keystone of
|
|
4
|
+
* routing/impact: a change to `http:POST /auth/session` matches a dependency on `http:POST /auth/session`.
|
|
5
|
+
*
|
|
6
|
+
* Format: `<kind>:<normalized-id>`
|
|
7
|
+
* http → http:POST /auth/session (method + normalized path)
|
|
8
|
+
* proto → proto:auth.v1.AuthService/Login (package.Service/Method)
|
|
9
|
+
* gql → gql:Mutation.login
|
|
10
|
+
* pkg → pkg:@scope/name#exportName (published-package export)
|
|
11
|
+
*
|
|
12
|
+
* Pure + testable. HTTP is first-class; proto is parsed; gql/openapi/pkg are light stubs we can
|
|
13
|
+
* deepen later behind this same interface.
|
|
14
|
+
*/
|
|
15
|
+
export type SurfaceId = string;
|
|
16
|
+
/** Normalize a route path: ensure a leading slash, `{id}`→`:id`, strip querystring/trailing slash. */
|
|
17
|
+
export declare function normalizePath(p: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Extract every canonical surface ID a changed file *defines* (i.e. produces). Returns [] for files
|
|
20
|
+
* that expose no public interface — which is most files. This narrowness is intentional: it's what
|
|
21
|
+
* keeps the ledger quiet (a bare `export` is NOT a contract surface).
|
|
22
|
+
*/
|
|
23
|
+
export declare function extractSurfaces(path: string, content?: string): SurfaceId[];
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
const HTTP_VERBS = "get|post|put|patch|delete|options|head|all";
|
|
2
|
+
/** Normalize a route path: ensure a leading slash, `{id}`→`:id`, strip querystring/trailing slash. */
|
|
3
|
+
export function normalizePath(p) {
|
|
4
|
+
let s = p.split("?")[0].trim();
|
|
5
|
+
if (!s.startsWith("/"))
|
|
6
|
+
s = "/" + s;
|
|
7
|
+
s = s.replace(/\{([^}]+)\}/g, ":$1"); // OpenAPI/Express-style {id} → :id
|
|
8
|
+
if (s.length > 1)
|
|
9
|
+
s = s.replace(/\/+$/, ""); // drop trailing slash (keep root "/")
|
|
10
|
+
return s;
|
|
11
|
+
}
|
|
12
|
+
const httpId = (method, path) => `http:${method.toUpperCase() === "ALL" ? "ANY" : method.toUpperCase()} ${normalizePath(path)}`;
|
|
13
|
+
/** Express/Fastify-style: `app.get("/x")`, `router.post('/y', ...)`, `fastify.delete(\`/z\`)`. */
|
|
14
|
+
function extractExpressRoutes(content) {
|
|
15
|
+
const re = new RegExp(`\\.(${HTTP_VERBS})\\s*\\(\\s*['"\`]([^'"\`]+)['"\`]`, "gi");
|
|
16
|
+
const out = [];
|
|
17
|
+
for (const m of content.matchAll(re))
|
|
18
|
+
out.push(httpId(m[1], m[2]));
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
/** Next.js app-router: `app/auth/session/route.ts` + `export async function POST` → http:POST /auth/session. */
|
|
22
|
+
function extractNextRoutes(path, content) {
|
|
23
|
+
const m = path.match(/(?:^|\/)app\/(.*)\/route\.(?:ts|tsx|js|mjs)$/i);
|
|
24
|
+
if (!m)
|
|
25
|
+
return [];
|
|
26
|
+
const segments = m[1]
|
|
27
|
+
.split("/")
|
|
28
|
+
.filter((seg) => !(seg.startsWith("(") && seg.endsWith(")"))) // route groups don't affect the URL
|
|
29
|
+
.map((seg) => seg.replace(/^\[(?:\.\.\.)?([^\]]+)\]$/, ":$1")); // [id] / [...slug] → :id
|
|
30
|
+
const routePath = "/" + segments.join("/");
|
|
31
|
+
const out = [];
|
|
32
|
+
for (const v of content.matchAll(/export\s+(?:async\s+)?function\s+(GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD)\b/g)) {
|
|
33
|
+
out.push(httpId(v[1], routePath));
|
|
34
|
+
}
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
/** Protobuf: `package auth.v1;` + `service AuthService { rpc Login (...) ... }` → proto:auth.v1.AuthService/Login. */
|
|
38
|
+
function extractProto(content) {
|
|
39
|
+
const pkg = content.match(/^\s*package\s+([\w.]+)\s*;/m)?.[1] ?? "";
|
|
40
|
+
const out = [];
|
|
41
|
+
const svcRe = /service\s+(\w+)\s*\{([\s\S]*?)\}/g;
|
|
42
|
+
for (const svc of content.matchAll(svcRe)) {
|
|
43
|
+
const service = svc[1];
|
|
44
|
+
for (const rpc of svc[2].matchAll(/rpc\s+(\w+)\s*\(/g)) {
|
|
45
|
+
out.push(`proto:${pkg ? pkg + "." : ""}${service}/${rpc[1]}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
/** GraphQL (light stub): top-level Query/Mutation/Subscription fields → gql:Mutation.login. */
|
|
51
|
+
function extractGraphql(content) {
|
|
52
|
+
const out = [];
|
|
53
|
+
const blockRe = /\b(type|extend\s+type)\s+(Query|Mutation|Subscription)\s*\{([\s\S]*?)\}/g;
|
|
54
|
+
for (const block of content.matchAll(blockRe)) {
|
|
55
|
+
const root = block[2];
|
|
56
|
+
for (const field of block[3].matchAll(/^\s*(\w+)\s*[(:]/gm))
|
|
57
|
+
out.push(`gql:${root}.${field[1]}`);
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
const isHttpRoutey = (path) => /(^|\/)(routes?|controllers?|api|handlers?|endpoints?)(\/|\.)/i.test(path);
|
|
62
|
+
/**
|
|
63
|
+
* Extract every canonical surface ID a changed file *defines* (i.e. produces). Returns [] for files
|
|
64
|
+
* that expose no public interface — which is most files. This narrowness is intentional: it's what
|
|
65
|
+
* keeps the ledger quiet (a bare `export` is NOT a contract surface).
|
|
66
|
+
*/
|
|
67
|
+
export function extractSurfaces(path, content) {
|
|
68
|
+
const out = new Set();
|
|
69
|
+
if (/\.proto$/i.test(path) && content)
|
|
70
|
+
extractProto(content).forEach((s) => out.add(s));
|
|
71
|
+
if (/\.(graphql|gql)$/i.test(path) && content)
|
|
72
|
+
extractGraphql(content).forEach((s) => out.add(s));
|
|
73
|
+
if (/\.(ts|tsx|js|mjs|cjs)$/i.test(path) && content) {
|
|
74
|
+
extractNextRoutes(path, content).forEach((s) => out.add(s));
|
|
75
|
+
// Express/Fastify route literals — only trust them in files that look like route/handler code,
|
|
76
|
+
// so an incidental `.get("...")` on some object elsewhere doesn't mint a phantom endpoint.
|
|
77
|
+
if (isHttpRoutey(path) || /\b(express|fastify|router|app)\b/.test(content)) {
|
|
78
|
+
extractExpressRoutes(content).forEach((s) => out.add(s));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return [...out];
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=surface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surface.js","sourceRoot":"","sources":["../../src/capture/surface.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { extractSurfaces } from "./surface.js";
|
|
4
|
+
test("extracts Express/Fastify routes as canonical http IDs", () => {
|
|
5
|
+
const ids = extractSurfaces("src/routes/auth.ts", `router.post('/auth/session', login)\napp.get("/auth/me", me)`);
|
|
6
|
+
assert.deepEqual(ids.sort(), ["http:GET /auth/me", "http:POST /auth/session"]);
|
|
7
|
+
});
|
|
8
|
+
test("normalizes path params and casing", () => {
|
|
9
|
+
const ids = extractSurfaces("src/routes/users.ts", "router.GET('/users/{id}/', show)");
|
|
10
|
+
assert.deepEqual(ids, ["http:GET /users/:id"]);
|
|
11
|
+
});
|
|
12
|
+
test("producer and consumer derive the SAME id for the same endpoint", () => {
|
|
13
|
+
const producer = extractSurfaces("services/auth/src/routes/session.ts", "app.post('/auth/session', h)");
|
|
14
|
+
// A consumer would declare this exact string in lockstep.yaml — they must match.
|
|
15
|
+
assert.equal(producer[0], "http:POST /auth/session");
|
|
16
|
+
});
|
|
17
|
+
test("Next.js app-router route file", () => {
|
|
18
|
+
const ids = extractSurfaces("app/auth/session/route.ts", "export async function POST(req) {}\nexport function GET() {}");
|
|
19
|
+
assert.deepEqual(ids.sort(), ["http:GET /auth/session", "http:POST /auth/session"]);
|
|
20
|
+
});
|
|
21
|
+
test("Next.js dynamic + route-group segments", () => {
|
|
22
|
+
const ids = extractSurfaces("app/(marketing)/users/[id]/route.ts", "export async function GET() {}");
|
|
23
|
+
assert.deepEqual(ids, ["http:GET /users/:id"]);
|
|
24
|
+
});
|
|
25
|
+
test("protobuf service/rpc with package", () => {
|
|
26
|
+
const ids = extractSurfaces("proto/auth.proto", "package auth.v1;\nservice AuthService {\n rpc Login (Req) returns (Res);\n rpc Logout (Req) returns (Res);\n}");
|
|
27
|
+
assert.deepEqual(ids.sort(), ["proto:auth.v1.AuthService/Login", "proto:auth.v1.AuthService/Logout"]);
|
|
28
|
+
});
|
|
29
|
+
test("graphql root fields", () => {
|
|
30
|
+
const ids = extractSurfaces("schema.graphql", "type Mutation {\n login(x: String): Token\n}");
|
|
31
|
+
assert.deepEqual(ids, ["gql:Mutation.login"]);
|
|
32
|
+
});
|
|
33
|
+
test("a non-interface file yields no surfaces", () => {
|
|
34
|
+
assert.deepEqual(extractSurfaces("src/util.ts", "export function add(a,b){return a+b}"), []);
|
|
35
|
+
assert.deepEqual(extractSurfaces("README.md", "# hi"), []);
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=surface.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surface.test.js","sourceRoot":"","sources":["../../src/capture/surface.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,IAAI,CAAC,uDAAuD,EAAE,GAAG,EAAE;IACjE,MAAM,GAAG,GAAG,eAAe,CAAC,oBAAoB,EAAE,8DAA8D,CAAC,CAAC;IAClH,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,mBAAmB,EAAE,yBAAyB,CAAC,CAAC,CAAC;AACjF,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,mCAAmC,EAAE,GAAG,EAAE;IAC7C,MAAM,GAAG,GAAG,eAAe,CAAC,qBAAqB,EAAE,kCAAkC,CAAC,CAAC;IACvF,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,gEAAgE,EAAE,GAAG,EAAE;IAC1E,MAAM,QAAQ,GAAG,eAAe,CAAC,qCAAqC,EAAE,8BAA8B,CAAC,CAAC;IACxG,iFAAiF;IACjF,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,yBAAyB,CAAC,CAAC;AACvD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,+BAA+B,EAAE,GAAG,EAAE;IACzC,MAAM,GAAG,GAAG,eAAe,CAAC,2BAA2B,EAAE,8DAA8D,CAAC,CAAC;IACzH,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,wBAAwB,EAAE,yBAAyB,CAAC,CAAC,CAAC;AACtF,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,wCAAwC,EAAE,GAAG,EAAE;IAClD,MAAM,GAAG,GAAG,eAAe,CAAC,qCAAqC,EAAE,gCAAgC,CAAC,CAAC;IACrG,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,mCAAmC,EAAE,GAAG,EAAE;IAC7C,MAAM,GAAG,GAAG,eAAe,CACzB,kBAAkB,EAClB,iHAAiH,CAClH,CAAC;IACF,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,iCAAiC,EAAE,kCAAkC,CAAC,CAAC,CAAC;AACxG,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,qBAAqB,EAAE,GAAG,EAAE;IAC/B,MAAM,GAAG,GAAG,eAAe,CAAC,gBAAgB,EAAE,+CAA+C,CAAC,CAAC;IAC/F,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,yCAAyC,EAAE,GAAG,EAAE;IACnD,MAAM,CAAC,SAAS,CAAC,eAAe,CAAC,aAAa,EAAE,sCAAsC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7F,MAAM,CAAC,SAAS,CAAC,eAAe,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;AAC7D,CAAC,CAAC,CAAC"}
|
package/dist/connect.d.ts
CHANGED
|
@@ -8,5 +8,5 @@ export declare function runConnect(opts: {
|
|
|
8
8
|
org?: string;
|
|
9
9
|
project?: string;
|
|
10
10
|
}): Promise<void>;
|
|
11
|
-
/** Invite a teammate by GitHub handle to
|
|
11
|
+
/** Invite a teammate by GitHub handle to the project THIS repo is connected to. */
|
|
12
12
|
export declare function runInvite(handle: string): Promise<void>;
|
package/dist/connect.js
CHANGED
|
@@ -15,12 +15,19 @@ export async function runConnect(opts) {
|
|
|
15
15
|
const r = await cloud.post("/connect", { gitRemote: remote, project: opts.project });
|
|
16
16
|
const verb = r.status === "created" ? "created and connected" : r.status === "joined" ? "joined" : "already connected to";
|
|
17
17
|
console.log(`✓ ${verb} project "${r.projectName}" (${remote})`);
|
|
18
|
+
if (r.createdOrg) {
|
|
19
|
+
// The repo landed in a brand-new workspace — likely NOT what you want if a teammate already has
|
|
20
|
+
// this project. Cross-service teammates join via an invite, not by naming the same project.
|
|
21
|
+
console.log(`\n⚠ This created a NEW workspace "${r.projectName}".`);
|
|
22
|
+
console.log(` If you meant to join a teammate's project, ask them to run`);
|
|
23
|
+
console.log(` \`lockstep invite ${process.env.USER ?? "<your-github-handle>"}\` first, then re-run \`lockstep connect\`.`);
|
|
24
|
+
}
|
|
18
25
|
console.log(`\nOpen this repo in Claude Code — Lockstep registers the session automatically.`);
|
|
19
26
|
if (r.status === "created") {
|
|
20
|
-
console.log(`
|
|
27
|
+
console.log(`Invite teammates with \`lockstep invite <github-handle>\`.`);
|
|
21
28
|
}
|
|
22
29
|
}
|
|
23
|
-
/** Invite a teammate by GitHub handle to
|
|
30
|
+
/** Invite a teammate by GitHub handle to the project THIS repo is connected to. */
|
|
24
31
|
export async function runInvite(handle) {
|
|
25
32
|
const remote = gitRemote(process.cwd());
|
|
26
33
|
if (!remote) {
|
|
@@ -28,19 +35,23 @@ export async function runInvite(handle) {
|
|
|
28
35
|
process.exit(1);
|
|
29
36
|
}
|
|
30
37
|
const me = await cloud.get("/me");
|
|
31
|
-
const
|
|
32
|
-
if (
|
|
38
|
+
const orgIds = [...new Set(me.memberships.map((m) => m.orgId))];
|
|
39
|
+
if (orgIds.length === 0) {
|
|
33
40
|
console.error("No workspace yet — run `lockstep connect` first.");
|
|
34
41
|
process.exit(1);
|
|
35
42
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
// Resolve the project by which one this repo's remote is actually connected to — not by guessing
|
|
44
|
+
// the name from the remote (which breaks when `connect --project` used a custom name).
|
|
45
|
+
for (const orgId of orgIds) {
|
|
46
|
+
const overview = await cloud.get(`/orgs/${orgId}/overview`);
|
|
47
|
+
const project = overview?.projects.find((p) => (p.repos ?? []).some((r) => r.gitRemote === remote));
|
|
48
|
+
if (project) {
|
|
49
|
+
await cloud.post(`/orgs/${orgId}/projects/${project.id}/invite`, { githubLogin: handle.replace(/^@/, "") });
|
|
50
|
+
console.log(`✓ invited @${handle.replace(/^@/, "")} to "${project.name}" — they'll be activated on their next login.`);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
42
53
|
}
|
|
43
|
-
|
|
44
|
-
|
|
54
|
+
console.error("This repo isn't connected yet — run `lockstep connect` first.");
|
|
55
|
+
process.exit(1);
|
|
45
56
|
}
|
|
46
57
|
//# sourceMappingURL=connect.js.map
|
package/dist/connect.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connect.js","sourceRoot":"","sources":["../src/connect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"connect.js","sourceRoot":"","sources":["../src/connect.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,9 @@ usage: lockstep <command>
|
|
|
19
19
|
init [--vendor claude|all] [--scope project|user] [--dry-run]
|
|
20
20
|
wire up hooks + MCP + skill for the detected agent(s)
|
|
21
21
|
connect [--project <name>] link this repo to a Lockstep project (creates one if needed)
|
|
22
|
+
onboard [--project <name>] one step: init + connect (for a teammate joining a repo)
|
|
23
|
+
scan [--json] [--apply] [--dry-run] scan the repo → propose lockstep.yaml (produces + graph-resolved consumes)
|
|
24
|
+
sync push lockstep.yaml (produces + consumes) to the graph, no rescan
|
|
22
25
|
invite <github-handle> invite a teammate to this repo's project
|
|
23
26
|
status show auth + config health
|
|
24
27
|
doctor diagnose vendor config
|
|
@@ -58,6 +61,23 @@ async function main() {
|
|
|
58
61
|
});
|
|
59
62
|
case "connect":
|
|
60
63
|
return runConnect({ org: val("org"), project: val("project") });
|
|
64
|
+
case "onboard": {
|
|
65
|
+
// One-step teammate onboarding: wire the repo (init) then link it (connect).
|
|
66
|
+
await runInit({ vendor: val("vendor"), scope: val("scope") ?? "project", dryRun: has("dry-run") });
|
|
67
|
+
if (has("dry-run"))
|
|
68
|
+
return;
|
|
69
|
+
await runConnect({ org: val("org"), project: val("project") });
|
|
70
|
+
console.log("\nOnboarded. Run `lockstep scan` to propose this repo's dependencies.");
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
case "scan": {
|
|
74
|
+
const { runScan } = await import("./scan.js");
|
|
75
|
+
return runScan({ json: has("json"), apply: has("apply"), dryRun: has("dry-run") });
|
|
76
|
+
}
|
|
77
|
+
case "sync": {
|
|
78
|
+
const { runSync } = await import("./scan.js");
|
|
79
|
+
return runSync();
|
|
80
|
+
}
|
|
61
81
|
case "invite": {
|
|
62
82
|
const handle = argv[1];
|
|
63
83
|
if (!handle) {
|
|
@@ -80,6 +100,11 @@ async function main() {
|
|
|
80
100
|
await runCapture(val("event") ?? "PostToolUse");
|
|
81
101
|
return;
|
|
82
102
|
}
|
|
103
|
+
case "statusline": {
|
|
104
|
+
const { runStatusLine } = await import("./statusline.js");
|
|
105
|
+
await runStatusLine();
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
83
108
|
case "help":
|
|
84
109
|
case "--help":
|
|
85
110
|
case "-h":
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGrD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,MAAM,GAAG,GAAG,CAAC,CAAS,EAAW,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAC5D,MAAM,GAAG,GAAG,CAAC,CAAS,EAAsB,EAAE;IAC5C,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACjC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1C,CAAC,CAAC;AAEF,SAAS,IAAI;IACX,OAAO,CAAC,GAAG,CAAC
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/init.js
CHANGED
|
@@ -16,7 +16,9 @@ export async function runInit(opts) {
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
if (!opts.dryRun && opts.scope === "project") {
|
|
19
|
-
console.log("\nCommit the
|
|
19
|
+
console.log("\nCommit the shared files (.mcp.json, CLAUDE.md, .claude/skills) so teammates get Lockstep on clone." +
|
|
20
|
+
"\n.claude/settings.local.json is personal (hooks + statusline) and auto-gitignored — each teammate" +
|
|
21
|
+
"\nruns `lockstep onboard` once to get their own.");
|
|
20
22
|
}
|
|
21
23
|
}
|
|
22
24
|
export async function runStatus() {
|
package/dist/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAwD;IACpF,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,0BAA0B,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACrF,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC3B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACjE,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC7C,OAAO,CAAC,GAAG,
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAwD;IACpF,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,0BAA0B,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACrF,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC3B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACjE,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC7C,OAAO,CAAC,GAAG,CACT,sGAAsG;YACpG,oGAAoG;YACpG,kDAAkD,CACrD,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,OAAO,CAAC,GAAG,CAAC,UAAU,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACtC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,qCAAqC,EAAE,CAAC,CAAC;IAClG,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,KAAK,MAAM,CAAC,IAAI,MAAM,WAAW,EAAE,EAAE,CAAC;QACpC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC,CAAC;QACrE,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO;YAAE,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,IAAI,EAAE,GAAG,IAAI,CAAC;IACd,KAAK,MAAM,CAAC,IAAI,MAAM,WAAW,EAAE,EAAE,CAAC;QACpC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QACzC,IAAI,CAAC,CAAC,CAAC,EAAE;YAAE,EAAE,GAAG,KAAK,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;QACpD,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO;YAAE,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3B,CAAC"}
|
package/dist/mcp/server.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The per-session MCP server (one process per agent session). Registers the session,
|
|
3
|
-
* then exposes the
|
|
3
|
+
* then exposes the tools as thin proxies to the core API. The core stays LLM-free —
|
|
4
4
|
* query() returns rows; the agent synthesizes. Identical across vendors (the seam).
|
|
5
5
|
*/
|
|
6
6
|
export declare function runMcpServer(): Promise<void>;
|
package/dist/mcp/server.js
CHANGED
|
@@ -3,15 +3,19 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { registerSession } from "./session.js";
|
|
5
5
|
import { call } from "./api.js";
|
|
6
|
+
import { gitRemote } from "./git.js";
|
|
7
|
+
import { writeFeatureContext } from "../capture/feature-context.js";
|
|
6
8
|
/**
|
|
7
9
|
* The per-session MCP server (one process per agent session). Registers the session,
|
|
8
|
-
* then exposes the
|
|
10
|
+
* then exposes the tools as thin proxies to the core API. The core stays LLM-free —
|
|
9
11
|
* query() returns rows; the agent synthesizes. Identical across vendors (the seam).
|
|
10
12
|
*/
|
|
11
13
|
export async function runMcpServer() {
|
|
12
14
|
const vendor = process.env.LOCKSTEP_VENDOR ?? "unknown";
|
|
13
15
|
const session = await registerSession(vendor); // stderr-safe: throws to caller on failure
|
|
14
16
|
const sid = session.sessionId;
|
|
17
|
+
let featureCtx = null; // set via set_feature_context; defaults capabilityRef on notify/propose
|
|
18
|
+
const remote = gitRemote(process.cwd());
|
|
15
19
|
const ok = (data) => ({ content: [{ type: "text", text: JSON.stringify(data) }] });
|
|
16
20
|
const server = new McpServer({ name: "lockstep", version: "0.0.1" });
|
|
17
21
|
server.tool("notify", {
|
|
@@ -22,7 +26,8 @@ export async function runMcpServer() {
|
|
|
22
26
|
verified: z.boolean().optional(),
|
|
23
27
|
verifiedAgainst: z.string().optional(),
|
|
24
28
|
diffHash: z.string().optional(),
|
|
25
|
-
|
|
29
|
+
capabilityRef: z.string().optional(),
|
|
30
|
+
}, async (a) => ok(await call("POST", "/changes", sid, { ...a, capabilityRef: a.capabilityRef ?? featureCtx ?? undefined })));
|
|
26
31
|
server.tool("inbox", {}, async () => ok(await call("GET", "/inbox", sid)));
|
|
27
32
|
server.tool("ack_inbox", { itemIds: z.array(z.string()).optional() }, async (a) => ok(await call("POST", "/inbox/ack", sid, { itemIds: a.itemIds })));
|
|
28
33
|
server.tool("query", { question: z.string(), scope: z.string().optional() }, async (a) => ok(await call("POST", "/query", sid, a)));
|
|
@@ -30,11 +35,29 @@ export async function runMcpServer() {
|
|
|
30
35
|
server.tool("answer", { questionId: z.string(), response: z.string() }, async (a) => ok(await call("POST", `/questions/${a.questionId}/answer`, sid, { response: a.response })));
|
|
31
36
|
server.tool("delegate", { to: z.string(), task: z.string(), refs: z.any().optional() }, async (a) => ok(await call("POST", "/tasks", sid, a)));
|
|
32
37
|
server.tool("complete", { taskId: z.string(), note: z.string().optional() }, async (a) => ok(await call("POST", `/tasks/${a.taskId}/complete`, sid, { note: a.note })));
|
|
33
|
-
server.tool("propose_decision", {
|
|
38
|
+
server.tool("propose_decision", {
|
|
39
|
+
scopeKind: z.string(),
|
|
40
|
+
scopeRef: z.string(),
|
|
41
|
+
ruleText: z.string(),
|
|
42
|
+
baseVersion: z.number(),
|
|
43
|
+
decisionType: z.enum(["rule", "architecture", "principle"]).optional(),
|
|
44
|
+
capabilityRef: z.string().optional(),
|
|
45
|
+
rationale: z.string().optional(), // the why, one or two sentences (ADR context)
|
|
46
|
+
alternatives: z.array(z.string()).optional(), // options considered and rejected
|
|
47
|
+
reviewAt: z.string().optional(), // ISO date — when this decision should be revisited
|
|
48
|
+
}, async (a) => ok(await call("POST", "/decisions", sid, { ...a, capabilityRef: a.capabilityRef ?? featureCtx ?? undefined })));
|
|
34
49
|
server.tool("ack_decision", { decisionId: z.string(), version: z.number(), verdict: z.string().optional() }, async (a) => ok(await call("POST", `/decisions/${a.decisionId}/ack`, sid, { version: a.version, verdict: a.verdict })));
|
|
35
50
|
server.tool("register_dependency", { producedSurface: z.string(), producedRepoId: z.string().optional() }, async (a) => ok(await call("POST", "/dependencies", sid, a)));
|
|
36
51
|
server.tool("decisions", { scope: z.string().optional() }, async (a) => ok(await call("GET", `/decisions${a.scope ? `?scope=${encodeURIComponent(a.scope)}` : ""}`, sid)));
|
|
37
52
|
server.tool("whoowns", { path: z.string() }, async (a) => ok(await call("GET", `/owners?path=${encodeURIComponent(a.path)}`, sid)));
|
|
53
|
+
server.tool("consumers", { surface: z.string() }, async (a) => ok(await call("GET", `/consumers?surface=${encodeURIComponent(a.surface)}`, sid)));
|
|
54
|
+
server.tool("get_product_context", { scope: z.string() }, async (a) => ok(await call("GET", `/product-context?scope=${encodeURIComponent(a.scope)}`, sid)));
|
|
55
|
+
server.tool("set_feature_context", { capabilityRef: z.string() }, async (a) => {
|
|
56
|
+
featureCtx = a.capabilityRef;
|
|
57
|
+
if (remote)
|
|
58
|
+
writeFeatureContext(remote, a.capabilityRef);
|
|
59
|
+
return ok({ ok: true, capabilityRef: a.capabilityRef });
|
|
60
|
+
});
|
|
38
61
|
await server.connect(new StdioServerTransport());
|
|
39
62
|
}
|
|
40
63
|
//# sourceMappingURL=server.js.map
|
package/dist/mcp/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
|
package/dist/scan.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { OutboundRef } from "./capture/outbound.js";
|
|
2
|
+
export interface CatalogEntry {
|
|
3
|
+
surface: string;
|
|
4
|
+
repoId: string;
|
|
5
|
+
gitRemote: string;
|
|
6
|
+
/** #4: producer lives in another (shared) project — shown so the human approves with attribution. */
|
|
7
|
+
crossProject?: boolean;
|
|
8
|
+
projectName?: string;
|
|
9
|
+
}
|
|
10
|
+
interface MatchedConsume {
|
|
11
|
+
surface: string;
|
|
12
|
+
producer: string;
|
|
13
|
+
}
|
|
14
|
+
interface ReviewItem {
|
|
15
|
+
ref: string;
|
|
16
|
+
via: string;
|
|
17
|
+
hint: string;
|
|
18
|
+
candidates: MatchedConsume[];
|
|
19
|
+
}
|
|
20
|
+
interface UnmatchedItem {
|
|
21
|
+
ref: string;
|
|
22
|
+
via: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The full onboarding/maintenance proposal `/lockstep-setup` renders. `produces` is deterministic
|
|
26
|
+
* (extracted from served routes); `consumes` is graph-resolved (outbound calls matched against the
|
|
27
|
+
* project's produced-surface catalog); `unmatched`/`review` are the fuzzy leftovers the human decides.
|
|
28
|
+
*/
|
|
29
|
+
export interface ScanProposal {
|
|
30
|
+
connected: boolean;
|
|
31
|
+
produces: string[];
|
|
32
|
+
consumes: MatchedConsume[];
|
|
33
|
+
unmatched: UnmatchedItem[];
|
|
34
|
+
review: ReviewItem[];
|
|
35
|
+
newProduces: string[];
|
|
36
|
+
newConsumes: string[];
|
|
37
|
+
}
|
|
38
|
+
/** Walk the whole repo → produced surfaces + outbound-call candidates. */
|
|
39
|
+
export declare function scanCode(cwd: string): {
|
|
40
|
+
produces: string[];
|
|
41
|
+
outbound: OutboundRef[];
|
|
42
|
+
};
|
|
43
|
+
export declare function classify(outbound: OutboundRef[], catalog: CatalogEntry[], ownRepoId: string | undefined): {
|
|
44
|
+
consumes: MatchedConsume[];
|
|
45
|
+
unmatched: UnmatchedItem[];
|
|
46
|
+
review: ReviewItem[];
|
|
47
|
+
};
|
|
48
|
+
export declare function report(p: ScanProposal): string;
|
|
49
|
+
/**
|
|
50
|
+
* `lockstep scan` — bootstrap/maintenance for `lockstep.yaml`. Default prints a proposal; `--json` emits
|
|
51
|
+
* it for the skill; `--apply` writes the manifest (merge-preserving) and syncs it to the graph.
|
|
52
|
+
*/
|
|
53
|
+
export declare function runScan(opts: {
|
|
54
|
+
json?: boolean;
|
|
55
|
+
apply?: boolean;
|
|
56
|
+
dryRun?: boolean;
|
|
57
|
+
}): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* `lockstep sync` — push lockstep.yaml as-is (produces + consumes) to the graph, no rescan. The
|
|
60
|
+
* explicit path for hand-authored manifest entries; unlike the capture hook (consumes-only,
|
|
61
|
+
* best-effort) this hard-errors when the repo isn't connected.
|
|
62
|
+
*/
|
|
63
|
+
export declare function runSync(): Promise<void>;
|
|
64
|
+
export {};
|