@selvakumaresra/specship 0.7.0 → 0.10.0
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/commands/ss-domain.md +98 -0
- package/commands/ss-triage.md +177 -0
- package/dist/bin/specship.js +308 -0
- package/dist/bin/specship.js.map +1 -1
- package/dist/db/migrations.d.ts +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +28 -1
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/schema.sql +26 -2
- package/dist/db/spec-queries.d.ts +29 -0
- package/dist/db/spec-queries.d.ts.map +1 -1
- package/dist/db/spec-queries.js +63 -0
- package/dist/db/spec-queries.js.map +1 -1
- package/dist/enforce/enforce.d.ts +70 -0
- package/dist/enforce/enforce.d.ts.map +1 -0
- package/dist/enforce/enforce.js +125 -0
- package/dist/enforce/enforce.js.map +1 -0
- package/dist/extraction/specs/markdown-spec-extractor.d.ts +21 -0
- package/dist/extraction/specs/markdown-spec-extractor.d.ts.map +1 -1
- package/dist/extraction/specs/markdown-spec-extractor.js +144 -0
- package/dist/extraction/specs/markdown-spec-extractor.js.map +1 -1
- package/dist/fitness/fitness.d.ts +75 -0
- package/dist/fitness/fitness.d.ts.map +1 -0
- package/dist/fitness/fitness.js +204 -0
- package/dist/fitness/fitness.js.map +1 -0
- package/dist/graph/maintainability.d.ts +101 -0
- package/dist/graph/maintainability.d.ts.map +1 -0
- package/dist/graph/maintainability.js +278 -0
- package/dist/graph/maintainability.js.map +1 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +149 -1
- package/dist/index.js.map +1 -1
- package/dist/installer/instructions-template.d.ts +5 -4
- package/dist/installer/instructions-template.d.ts.map +1 -1
- package/dist/installer/instructions-template.js +10 -4
- package/dist/installer/instructions-template.js.map +1 -1
- package/dist/installer/targets/claude.d.ts.map +1 -1
- package/dist/installer/targets/claude.js +4 -0
- package/dist/installer/targets/claude.js.map +1 -1
- package/dist/installer/targets/shared.d.ts.map +1 -1
- package/dist/installer/targets/shared.js +4 -0
- package/dist/installer/targets/shared.js.map +1 -1
- package/dist/mcp/fitness-tool.d.ts +12 -0
- package/dist/mcp/fitness-tool.d.ts.map +1 -0
- package/dist/mcp/fitness-tool.js +46 -0
- package/dist/mcp/fitness-tool.js.map +1 -0
- package/dist/mcp/maintainability-tool.d.ts +13 -0
- package/dist/mcp/maintainability-tool.d.ts.map +1 -0
- package/dist/mcp/maintainability-tool.js +64 -0
- package/dist/mcp/maintainability-tool.js.map +1 -0
- package/dist/mcp/server-instructions.d.ts +1 -1
- package/dist/mcp/server-instructions.d.ts.map +1 -1
- package/dist/mcp/server-instructions.js +3 -2
- package/dist/mcp/server-instructions.js.map +1 -1
- package/dist/mcp/spec-tools.d.ts.map +1 -1
- package/dist/mcp/spec-tools.js +115 -1
- package/dist/mcp/spec-tools.js.map +1 -1
- package/dist/mcp/tools.d.ts +13 -0
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +75 -0
- package/dist/mcp/tools.js.map +1 -1
- package/dist/reflect/apply.d.ts +31 -0
- package/dist/reflect/apply.d.ts.map +1 -0
- package/dist/reflect/apply.js +286 -0
- package/dist/reflect/apply.js.map +1 -0
- package/dist/reflect/hash.d.ts +20 -0
- package/dist/reflect/hash.d.ts.map +1 -0
- package/dist/reflect/hash.js +36 -0
- package/dist/reflect/hash.js.map +1 -0
- package/dist/reflect/index.d.ts +16 -0
- package/dist/reflect/index.d.ts.map +1 -0
- package/dist/reflect/index.js +43 -0
- package/dist/reflect/index.js.map +1 -0
- package/dist/reflect/miner.d.ts +21 -0
- package/dist/reflect/miner.d.ts.map +1 -0
- package/dist/reflect/miner.js +463 -0
- package/dist/reflect/miner.js.map +1 -0
- package/dist/reflect/store.d.ts +31 -0
- package/dist/reflect/store.d.ts.map +1 -0
- package/dist/reflect/store.js +101 -0
- package/dist/reflect/store.js.map +1 -0
- package/dist/reflect/sweep.d.ts +26 -0
- package/dist/reflect/sweep.d.ts.map +1 -0
- package/dist/reflect/sweep.js +42 -0
- package/dist/reflect/sweep.js.map +1 -0
- package/dist/reflect/targets.d.ts +52 -0
- package/dist/reflect/targets.d.ts.map +1 -0
- package/dist/reflect/targets.js +192 -0
- package/dist/reflect/targets.js.map +1 -0
- package/dist/reflect/types.d.ts +96 -0
- package/dist/reflect/types.d.ts.map +1 -0
- package/dist/reflect/types.js +13 -0
- package/dist/reflect/types.js.map +1 -0
- package/dist/resolution/domain-gap-seed.d.ts +60 -0
- package/dist/resolution/domain-gap-seed.d.ts.map +1 -0
- package/dist/resolution/domain-gap-seed.js +87 -0
- package/dist/resolution/domain-gap-seed.js.map +1 -0
- package/dist/resolution/spec-link-resolver.d.ts +46 -1
- package/dist/resolution/spec-link-resolver.d.ts.map +1 -1
- package/dist/resolution/spec-link-resolver.js +78 -0
- package/dist/resolution/spec-link-resolver.js.map +1 -1
- package/dist/server/routes/domain.js +0 -0
- package/dist/server/routes/events.js +20 -0
- package/dist/server/routes/maintainability.js +18 -0
- package/dist/server/routes/reflect.js +93 -0
- package/dist/server/server.js +6 -0
- package/dist/types.d.ts +4 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -1
- package/dist/web/chunk-EZZBWC7Z.js +1 -0
- package/dist/web/chunk-ITHLF4GI.js +1 -0
- package/dist/web/{chunk-UBOZGQNK.js → chunk-IZQXYQNQ.js} +1 -1
- package/dist/web/chunk-JBO7ZIPO.js +1 -0
- package/dist/web/chunk-JQXCRIK2.js +1 -0
- package/dist/web/{chunk-ASZ77FMZ.js → chunk-JT2YIHPL.js} +1 -1
- package/dist/web/{chunk-WLIMNDS3.js → chunk-ONKHTXHJ.js} +1 -1
- package/dist/web/{chunk-FHZHD2ZG.js → chunk-P5JX67LT.js} +1 -1
- package/dist/web/chunk-PDTQX2UL.js +6 -0
- package/dist/web/chunk-TPDB5GJN.js +1 -0
- package/dist/web/{chunk-RASJHUXS.js → chunk-XWDR6MPC.js} +1 -1
- package/dist/web/chunk-Y6WWDS4R.js +1 -0
- package/dist/web/chunk-Z5L3T5EO.js +1 -0
- package/dist/web/{chunk-D5OCNEJA.js → chunk-ZG7H3XPL.js} +1 -1
- package/dist/web/index.html +1 -1
- package/dist/web/main-GYPY5V5H.js +1 -0
- package/dist/workflows/executor.d.ts.map +1 -1
- package/dist/workflows/executor.js +3 -0
- package/dist/workflows/executor.js.map +1 -1
- package/dist/workflows/runners/prompt.d.ts +31 -8
- package/dist/workflows/runners/prompt.d.ts.map +1 -1
- package/dist/workflows/runners/prompt.js +117 -23
- package/dist/workflows/runners/prompt.js.map +1 -1
- package/dist/workflows/runners/types.d.ts +7 -1
- package/dist/workflows/runners/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/web/chunk-HGBF7AY5.js +0 -1
- package/dist/web/chunk-JQ534IB6.js +0 -6
- package/dist/web/chunk-MVOMVPYB.js +0 -1
- package/dist/web/chunk-NZEZCT65.js +0 -1
- package/dist/web/chunk-WQWYTRFN.js +0 -1
- package/dist/web/main-LHCYPOXF.js +0 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Reflection orchestration (REQ-REFLECT-001 / 006).
|
|
4
|
+
*
|
|
5
|
+
* `analyze` runs the miner and persists the batch, returning the current open
|
|
6
|
+
* proposals — this is what the on-demand button and `specship reflect` call.
|
|
7
|
+
*
|
|
8
|
+
* `sweep` does the same but additionally returns the proposals that should fire
|
|
9
|
+
* a notification: freshly-inserted (not previously seen, applied, or dismissed)
|
|
10
|
+
* AND high-severity. Already-seen and lower-severity findings are persisted and
|
|
11
|
+
* listed, but never re-notified.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.analyze = analyze;
|
|
15
|
+
exports.sweep = sweep;
|
|
16
|
+
const miner_1 = require("./miner");
|
|
17
|
+
const store_1 = require("./store");
|
|
18
|
+
function analyze(db, ctx, now = () => Date.now()) {
|
|
19
|
+
const store = new store_1.ReflectStore(db, now);
|
|
20
|
+
const mined = (0, miner_1.mineProposals)(db, ctx);
|
|
21
|
+
if (mined.length > 0)
|
|
22
|
+
store.upsertMined(mined);
|
|
23
|
+
return { open: store.list('open'), empty: mined.length === 0 };
|
|
24
|
+
}
|
|
25
|
+
function sweep(db, ctx, now = () => Date.now()) {
|
|
26
|
+
const store = new store_1.ReflectStore(db, now);
|
|
27
|
+
const mined = (0, miner_1.mineProposals)(db, ctx);
|
|
28
|
+
const notify = [];
|
|
29
|
+
if (mined.length > 0) {
|
|
30
|
+
const { stored, insertedHashes } = store.upsertMined(mined);
|
|
31
|
+
for (const p of stored) {
|
|
32
|
+
// Notify only on a brand-new, still-open, high-severity proposal. A row
|
|
33
|
+
// that already existed (even if re-mined) is not "new"; an applied or
|
|
34
|
+
// dismissed one is filtered by the open check.
|
|
35
|
+
if (insertedHashes.has(p.contentHash) && p.severity === 'high' && p.state === 'open') {
|
|
36
|
+
notify.push(p);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return { open: store.list('open'), empty: mined.length === 0, notify };
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=sweep.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sweep.js","sourceRoot":"","sources":["../../src/reflect/sweep.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;AAmBH,0BASC;AAED,sBAoBC;AA/CD,mCAAwC;AACxC,mCAAuC;AAevC,SAAgB,OAAO,CACrB,EAAkB,EAClB,GAAmB,EACnB,MAAoB,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;IAEpC,MAAM,KAAK,GAAG,IAAI,oBAAY,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACxC,MAAM,KAAK,GAAG,IAAA,qBAAa,EAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACrC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAC/C,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;AACjE,CAAC;AAED,SAAgB,KAAK,CACnB,EAAkB,EAClB,GAAmB,EACnB,MAAoB,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;IAEpC,MAAM,KAAK,GAAG,IAAI,oBAAY,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACxC,MAAM,KAAK,GAAG,IAAA,qBAAa,EAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACrC,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5D,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,wEAAwE;YACxE,sEAAsE;YACtE,+CAA+C;YAC/C,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,QAAQ,KAAK,MAAM,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;gBACrF,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjB,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;AACzE,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Target resolution (REQ-REFLECT-002).
|
|
3
|
+
*
|
|
4
|
+
* Each proposal type maps to a concrete write target with its own marker
|
|
5
|
+
* convention so the apply can be idempotent (re-apply = no-op) and reversible
|
|
6
|
+
* (undo strips exactly what apply added — REQ-REFLECT-004):
|
|
7
|
+
*
|
|
8
|
+
* - memory_rule, project scope → a `<!-- SPECSHIP_LEARNING:<id> -->` block in
|
|
9
|
+
* the project CLAUDE.md
|
|
10
|
+
* - memory_rule, portable scope → a new `~/.claude/memory/<slug>.md` note
|
|
11
|
+
* (carrying a `specship_proposal:` frontmatter
|
|
12
|
+
* marker) + a one-line `MEMORY.md` pointer
|
|
13
|
+
* - skill → a new `commands/ss-<name>.md` (carrying a
|
|
14
|
+
* leading marker comment)
|
|
15
|
+
* - hook → a hook entry merged into `.claude/settings.json`
|
|
16
|
+
*
|
|
17
|
+
* This module is pure: it builds the payload + path, it does not touch disk.
|
|
18
|
+
*/
|
|
19
|
+
import { Proposal, ProposalEvidence, ProposalSeverity, ProposalType, ReflectContext } from './types';
|
|
20
|
+
/** Marker bounding an engine-written block in CLAUDE.md / command files. */
|
|
21
|
+
export declare function learningMarkers(id: string): {
|
|
22
|
+
start: string;
|
|
23
|
+
end: string;
|
|
24
|
+
};
|
|
25
|
+
/** Frontmatter marker line stamped into an engine-created memory note. */
|
|
26
|
+
export declare function memoryNoteMarker(id: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Assemble a fully-formed Proposal from a rule's raw inputs. Computes the target
|
|
29
|
+
* path, builds the type-specific payload (including its markers), and derives the
|
|
30
|
+
* stable content hash. `createdAt`/`updatedAt` are stamped by the caller (the
|
|
31
|
+
* store) — here they default to 0 so the object is pure/deterministic.
|
|
32
|
+
*/
|
|
33
|
+
export declare function buildProposal(ctx: ReflectContext, input: {
|
|
34
|
+
type: ProposalType;
|
|
35
|
+
severity: ProposalSeverity;
|
|
36
|
+
title: string;
|
|
37
|
+
body: string;
|
|
38
|
+
evidence: ProposalEvidence;
|
|
39
|
+
/** memory_rule scope: 'project' → CLAUDE.md, 'portable' → ~/.claude/memory note. */
|
|
40
|
+
scope?: 'project' | 'portable';
|
|
41
|
+
/** The durable rule/skill/hook content, type-dependent. */
|
|
42
|
+
content: string;
|
|
43
|
+
/** Hook-only: the settings.json event + matcher + command. */
|
|
44
|
+
hook?: {
|
|
45
|
+
event: string;
|
|
46
|
+
matcher: string;
|
|
47
|
+
command: string;
|
|
48
|
+
};
|
|
49
|
+
/** A short name seed (for slug / command name). */
|
|
50
|
+
nameSeed: string;
|
|
51
|
+
}): Proposal;
|
|
52
|
+
//# sourceMappingURL=targets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"targets.d.ts","sourceRoot":"","sources":["../../src/reflect/targets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,EACL,QAAQ,EACR,gBAAgB,EAEhB,gBAAgB,EAChB,YAAY,EACZ,cAAc,EAEf,MAAM,SAAS,CAAC;AAEjB,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAK1E;AAED,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEnD;AAUD;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,cAAc,EACnB,KAAK,EAAE;IACL,IAAI,EAAE,YAAY,CAAC;IACnB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,oFAAoF;IACpF,KAAK,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IAC/B,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;CAClB,GACA,QAAQ,CAsEV"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Target resolution (REQ-REFLECT-002).
|
|
4
|
+
*
|
|
5
|
+
* Each proposal type maps to a concrete write target with its own marker
|
|
6
|
+
* convention so the apply can be idempotent (re-apply = no-op) and reversible
|
|
7
|
+
* (undo strips exactly what apply added — REQ-REFLECT-004):
|
|
8
|
+
*
|
|
9
|
+
* - memory_rule, project scope → a `<!-- SPECSHIP_LEARNING:<id> -->` block in
|
|
10
|
+
* the project CLAUDE.md
|
|
11
|
+
* - memory_rule, portable scope → a new `~/.claude/memory/<slug>.md` note
|
|
12
|
+
* (carrying a `specship_proposal:` frontmatter
|
|
13
|
+
* marker) + a one-line `MEMORY.md` pointer
|
|
14
|
+
* - skill → a new `commands/ss-<name>.md` (carrying a
|
|
15
|
+
* leading marker comment)
|
|
16
|
+
* - hook → a hook entry merged into `.claude/settings.json`
|
|
17
|
+
*
|
|
18
|
+
* This module is pure: it builds the payload + path, it does not touch disk.
|
|
19
|
+
*/
|
|
20
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
23
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
24
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
25
|
+
}
|
|
26
|
+
Object.defineProperty(o, k2, desc);
|
|
27
|
+
}) : (function(o, m, k, k2) {
|
|
28
|
+
if (k2 === undefined) k2 = k;
|
|
29
|
+
o[k2] = m[k];
|
|
30
|
+
}));
|
|
31
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
32
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
33
|
+
}) : function(o, v) {
|
|
34
|
+
o["default"] = v;
|
|
35
|
+
});
|
|
36
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
37
|
+
var ownKeys = function(o) {
|
|
38
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
39
|
+
var ar = [];
|
|
40
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
41
|
+
return ar;
|
|
42
|
+
};
|
|
43
|
+
return ownKeys(o);
|
|
44
|
+
};
|
|
45
|
+
return function (mod) {
|
|
46
|
+
if (mod && mod.__esModule) return mod;
|
|
47
|
+
var result = {};
|
|
48
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
49
|
+
__setModuleDefault(result, mod);
|
|
50
|
+
return result;
|
|
51
|
+
};
|
|
52
|
+
})();
|
|
53
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
54
|
+
exports.learningMarkers = learningMarkers;
|
|
55
|
+
exports.memoryNoteMarker = memoryNoteMarker;
|
|
56
|
+
exports.buildProposal = buildProposal;
|
|
57
|
+
const path = __importStar(require("path"));
|
|
58
|
+
const hash_1 = require("./hash");
|
|
59
|
+
/** Marker bounding an engine-written block in CLAUDE.md / command files. */
|
|
60
|
+
function learningMarkers(id) {
|
|
61
|
+
return {
|
|
62
|
+
start: `<!-- SPECSHIP_LEARNING:${id} -->`,
|
|
63
|
+
end: `<!-- /SPECSHIP_LEARNING:${id} -->`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/** Frontmatter marker line stamped into an engine-created memory note. */
|
|
67
|
+
function memoryNoteMarker(id) {
|
|
68
|
+
return `specship_proposal: ${id}`;
|
|
69
|
+
}
|
|
70
|
+
function slugify(s) {
|
|
71
|
+
return s
|
|
72
|
+
.toLowerCase()
|
|
73
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
74
|
+
.replace(/(^-|-$)/g, '')
|
|
75
|
+
.slice(0, 48) || 'learning';
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Assemble a fully-formed Proposal from a rule's raw inputs. Computes the target
|
|
79
|
+
* path, builds the type-specific payload (including its markers), and derives the
|
|
80
|
+
* stable content hash. `createdAt`/`updatedAt` are stamped by the caller (the
|
|
81
|
+
* store) — here they default to 0 so the object is pure/deterministic.
|
|
82
|
+
*/
|
|
83
|
+
function buildProposal(ctx, input) {
|
|
84
|
+
let targetKind;
|
|
85
|
+
let targetPath;
|
|
86
|
+
let payload;
|
|
87
|
+
if (input.type === 'memory_rule') {
|
|
88
|
+
if (input.scope === 'portable') {
|
|
89
|
+
const slug = slugify(input.nameSeed);
|
|
90
|
+
targetKind = 'memory_note';
|
|
91
|
+
targetPath = path.join(ctx.homeDir, '.claude', 'memory', `${slug}.md`);
|
|
92
|
+
// Hash needs a deterministic id; derive a provisional one from the slug so
|
|
93
|
+
// the marker is stable, then fold everything into the final hash below.
|
|
94
|
+
const note = renderMemoryNote(slug, input.title, input.content);
|
|
95
|
+
const indexLine = `- [${input.title}](${slug}.md) — ${firstSentence(input.body)}`;
|
|
96
|
+
payload = { kind: 'memory_note', slug, note, indexLine };
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
targetKind = 'claude_md';
|
|
100
|
+
targetPath = path.join(ctx.projectRoot, 'CLAUDE.md');
|
|
101
|
+
// markerId is finalized after we know the hash; use a placeholder then
|
|
102
|
+
// re-render once hashed (below) so the block carries its own id.
|
|
103
|
+
payload = { kind: 'claude_md', markerId: '', block: '' };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else if (input.type === 'skill') {
|
|
107
|
+
const name = slugify(input.nameSeed).replace(/^ss-/, '');
|
|
108
|
+
targetKind = 'command';
|
|
109
|
+
targetPath = path.join(ctx.projectRoot, 'commands', `ss-${name}.md`);
|
|
110
|
+
payload = { kind: 'command', name: `ss-${name}`, content: '' };
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
// hook
|
|
114
|
+
targetKind = 'settings_hook';
|
|
115
|
+
targetPath = path.join(ctx.projectRoot, '.claude', 'settings.json');
|
|
116
|
+
const h = input.hook;
|
|
117
|
+
payload = {
|
|
118
|
+
kind: 'settings_hook',
|
|
119
|
+
event: h.event,
|
|
120
|
+
matcher: h.matcher,
|
|
121
|
+
entry: { type: 'command', command: h.command },
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// First-pass hash over the (still-placeholder) identity, then bake the id into
|
|
125
|
+
// marker-bearing payloads and re-hash so the persisted hash matches the bytes.
|
|
126
|
+
let contentHash = (0, hash_1.proposalHash)({ type: input.type, targetKind, targetPath, payload });
|
|
127
|
+
if (payload.kind === 'claude_md') {
|
|
128
|
+
const { start, end } = learningMarkers(contentHash);
|
|
129
|
+
const block = `${start}\n${renderClaudeRule(input.title, input.content)}\n${end}`;
|
|
130
|
+
payload = { kind: 'claude_md', markerId: contentHash, block };
|
|
131
|
+
contentHash = (0, hash_1.proposalHash)({ type: input.type, targetKind, targetPath, payload });
|
|
132
|
+
}
|
|
133
|
+
else if (payload.kind === 'command') {
|
|
134
|
+
const content = renderCommand(contentHash, payload.name, input.title, input.content);
|
|
135
|
+
payload = { kind: 'command', name: payload.name, content };
|
|
136
|
+
contentHash = (0, hash_1.proposalHash)({ type: input.type, targetKind, targetPath, payload });
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
contentHash,
|
|
140
|
+
type: input.type,
|
|
141
|
+
severity: input.severity,
|
|
142
|
+
title: input.title,
|
|
143
|
+
body: input.body,
|
|
144
|
+
targetKind,
|
|
145
|
+
targetPath,
|
|
146
|
+
payload,
|
|
147
|
+
evidence: input.evidence,
|
|
148
|
+
state: 'open',
|
|
149
|
+
createdAt: 0,
|
|
150
|
+
updatedAt: 0,
|
|
151
|
+
appliedAt: null,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function firstSentence(s) {
|
|
155
|
+
const m = s.split(/(?<=[.!?])\s/)[0] ?? s;
|
|
156
|
+
return m.length > 100 ? m.slice(0, 100) + '…' : m;
|
|
157
|
+
}
|
|
158
|
+
/** The rule body written inside a CLAUDE.md marked block. */
|
|
159
|
+
function renderClaudeRule(title, content) {
|
|
160
|
+
return `## ${title}\n\n${content}\n\n_(Added by SpecShip reflection — edit or remove freely.)_`;
|
|
161
|
+
}
|
|
162
|
+
/** A self-contained memory note matching the user's memory-file convention. */
|
|
163
|
+
function renderMemoryNote(slug, title, content) {
|
|
164
|
+
return [
|
|
165
|
+
'---',
|
|
166
|
+
`name: ${slug}`,
|
|
167
|
+
`description: ${firstSentence(title)}`,
|
|
168
|
+
`${memoryNoteMarker(slug)}`,
|
|
169
|
+
'metadata:',
|
|
170
|
+
' type: feedback',
|
|
171
|
+
'---',
|
|
172
|
+
'',
|
|
173
|
+
content,
|
|
174
|
+
'',
|
|
175
|
+
].join('\n');
|
|
176
|
+
}
|
|
177
|
+
/** A minimal slash-command skill file. */
|
|
178
|
+
function renderCommand(id, name, title, content) {
|
|
179
|
+
const { start, end } = learningMarkers(id);
|
|
180
|
+
return [
|
|
181
|
+
start,
|
|
182
|
+
`# ${title}`,
|
|
183
|
+
'',
|
|
184
|
+
`> \`/${name}\` — proposed by SpecShip reflection from a recurring pattern.`,
|
|
185
|
+
'',
|
|
186
|
+
content,
|
|
187
|
+
'',
|
|
188
|
+
end,
|
|
189
|
+
'',
|
|
190
|
+
].join('\n');
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=targets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"targets.js","sourceRoot":"","sources":["../../src/reflect/targets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reflection engine types (REFLECT-DOC).
|
|
3
|
+
*
|
|
4
|
+
* A Proposal is a durable, human-gated self-improvement suggestion mined from
|
|
5
|
+
* the ingested `claude_*` transcript tables. It is never advisory text alone —
|
|
6
|
+
* it resolves to a concrete, previewable file change (REQ-REFLECT-002), keyed by
|
|
7
|
+
* a stable `contentHash` so re-mining the same pattern converges to one row
|
|
8
|
+
* (REQ-REFLECT-007). The engine PROPOSES; bytes reach disk only on an explicit
|
|
9
|
+
* per-proposal apply (REQ-REFLECT-005).
|
|
10
|
+
*/
|
|
11
|
+
/** The kind of durable artifact a proposal produces. */
|
|
12
|
+
export type ProposalType = 'memory_rule' | 'skill' | 'hook';
|
|
13
|
+
/** Severity, reusing the tips engine's scale. `high` drives sweep notifications. */
|
|
14
|
+
export type ProposalSeverity = 'high' | 'warn' | 'info';
|
|
15
|
+
/** Persisted lifecycle state (REQ-REFLECT-007). */
|
|
16
|
+
export type ProposalState = 'open' | 'applied' | 'undone' | 'dismissed';
|
|
17
|
+
/** The concrete file the apply writes. */
|
|
18
|
+
export type TargetKind = 'claude_md' | 'memory_note' | 'command' | 'settings_hook';
|
|
19
|
+
/** What the proposal was derived from, so the user can judge it (REQ-REFLECT-001). */
|
|
20
|
+
export interface ProposalEvidence {
|
|
21
|
+
/** Contributing session ids. */
|
|
22
|
+
sessions: string[];
|
|
23
|
+
/** Contributing prompt ids. */
|
|
24
|
+
prompts: string[];
|
|
25
|
+
/** Human-readable one-line summary of the observed pattern. */
|
|
26
|
+
detail: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Artifact-type-specific payload — the exact intended content the preview
|
|
30
|
+
* renders and the apply writes (REQ-REFLECT-002.A4). Discriminated on `kind`,
|
|
31
|
+
* which matches the proposal's `targetKind`.
|
|
32
|
+
*/
|
|
33
|
+
export type ProposalPayload = {
|
|
34
|
+
kind: 'claude_md';
|
|
35
|
+
markerId: string;
|
|
36
|
+
block: string;
|
|
37
|
+
} | {
|
|
38
|
+
kind: 'memory_note';
|
|
39
|
+
slug: string;
|
|
40
|
+
note: string;
|
|
41
|
+
indexLine: string;
|
|
42
|
+
} | {
|
|
43
|
+
kind: 'command';
|
|
44
|
+
name: string;
|
|
45
|
+
content: string;
|
|
46
|
+
} | {
|
|
47
|
+
kind: 'settings_hook';
|
|
48
|
+
event: string;
|
|
49
|
+
matcher: string;
|
|
50
|
+
entry: Record<string, unknown>;
|
|
51
|
+
};
|
|
52
|
+
/** A single reflection proposal. */
|
|
53
|
+
export interface Proposal {
|
|
54
|
+
/** Stable id over (type, targetKind, targetPath, payload) — excludes evidence/timestamps. */
|
|
55
|
+
contentHash: string;
|
|
56
|
+
type: ProposalType;
|
|
57
|
+
severity: ProposalSeverity;
|
|
58
|
+
title: string;
|
|
59
|
+
body: string;
|
|
60
|
+
targetKind: TargetKind;
|
|
61
|
+
/** Absolute path the apply will write. */
|
|
62
|
+
targetPath: string;
|
|
63
|
+
payload: ProposalPayload;
|
|
64
|
+
evidence: ProposalEvidence;
|
|
65
|
+
state: ProposalState;
|
|
66
|
+
createdAt: number;
|
|
67
|
+
updatedAt: number;
|
|
68
|
+
appliedAt: number | null;
|
|
69
|
+
}
|
|
70
|
+
/** Result of applying a proposal (REQ-REFLECT-004). */
|
|
71
|
+
export type ApplyOutcome = 'applied' | 'unchanged' | 'conflict';
|
|
72
|
+
/** Result of undoing a proposal (REQ-REFLECT-004.A3). */
|
|
73
|
+
export type UndoOutcome = 'undone' | 'noop';
|
|
74
|
+
/** A non-mutating preview of the change a proposal would make (REQ-REFLECT-003). */
|
|
75
|
+
export interface PreviewResult {
|
|
76
|
+
targetPath: string;
|
|
77
|
+
targetKind: TargetKind;
|
|
78
|
+
/** Whether the target file already exists on disk. */
|
|
79
|
+
exists: boolean;
|
|
80
|
+
/** Current file content (empty string when the file is absent). */
|
|
81
|
+
before: string;
|
|
82
|
+
/** File content after the change would be applied. */
|
|
83
|
+
after: string;
|
|
84
|
+
/** A line-based unified-style diff of before → after. */
|
|
85
|
+
diff: string;
|
|
86
|
+
/** Set when the apply would be refused — a non-marked file already occupies the path. */
|
|
87
|
+
conflict?: boolean;
|
|
88
|
+
}
|
|
89
|
+
/** Options the engine needs to resolve target paths. */
|
|
90
|
+
export interface ReflectContext {
|
|
91
|
+
/** Absolute project root (for project CLAUDE.md / commands / .claude/settings.json). */
|
|
92
|
+
projectRoot: string;
|
|
93
|
+
/** Home directory (for ~/.claude/memory notes). */
|
|
94
|
+
homeDir: string;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/reflect/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,wDAAwD;AACxD,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC;AAE5D,oFAAoF;AACpF,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAExD,mDAAmD;AACnD,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAC;AAExE,0CAA0C;AAC1C,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,aAAa,GAAG,SAAS,GAAG,eAAe,CAAC;AAEnF,sFAAsF;AACtF,MAAM,WAAW,gBAAgB;IAC/B,gCAAgC;IAChC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,+BAA+B;IAC/B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,+DAA+D;IAC/D,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC;AAE9F,oCAAoC;AACpC,MAAM,WAAW,QAAQ;IACvB,6FAA6F;IAC7F,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,YAAY,CAAC;IACnB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,UAAU,CAAC;IACvB,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,eAAe,CAAC;IACzB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,uDAAuD;AACvD,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;AAEhE,yDAAyD;AACzD,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE5C,oFAAoF;AACpF,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;IACvB,sDAAsD;IACtD,MAAM,EAAE,OAAO,CAAC;IAChB,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,yFAAyF;IACzF,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wDAAwD;AACxD,MAAM,WAAW,cAAc;IAC7B,wFAAwF;IACxF,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;CACjB"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Reflection engine types (REFLECT-DOC).
|
|
4
|
+
*
|
|
5
|
+
* A Proposal is a durable, human-gated self-improvement suggestion mined from
|
|
6
|
+
* the ingested `claude_*` transcript tables. It is never advisory text alone —
|
|
7
|
+
* it resolves to a concrete, previewable file change (REQ-REFLECT-002), keyed by
|
|
8
|
+
* a stable `contentHash` so re-mining the same pattern converges to one row
|
|
9
|
+
* (REQ-REFLECT-007). The engine PROPOSES; bytes reach disk only on an explicit
|
|
10
|
+
* per-proposal apply (REQ-REFLECT-005).
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/reflect/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain gap-seed (REQ-DOMAIN-003).
|
|
3
|
+
*
|
|
4
|
+
* A read-only pass that surfaces what the domain knowledge layer does NOT yet
|
|
5
|
+
* cover, so an author (or the `/ss-domain` command, REQ-DOMAIN-004) can decide
|
|
6
|
+
* what to document next. It answers two questions against current DB state:
|
|
7
|
+
*
|
|
8
|
+
* - which structural code entities (classes, structs, interfaces, routes,
|
|
9
|
+
* components) are reached by NO domain fact; and
|
|
10
|
+
* - which non-domain specs (documents, requirements, …) have NO domain fact
|
|
11
|
+
* hanging off them.
|
|
12
|
+
*
|
|
13
|
+
* A domain fact carries no direct domain→code rows. It reaches code transitively
|
|
14
|
+
* through its spec-tier chain (`parentId` + `metadata.depends_on`), resolved by
|
|
15
|
+
* {@link SpecLinkResolver.getInheritedLinks} (REQ-DOMAIN-002). An entity is
|
|
16
|
+
* "documented" when some domain fact's inherited links resolve to that entity's
|
|
17
|
+
* node; a spec is "documented" when some domain fact's spec-tier chain reaches
|
|
18
|
+
* it. Everything else is a gap.
|
|
19
|
+
*
|
|
20
|
+
* COMPUTED from live state — writes nothing. Like the spec funnel
|
|
21
|
+
* (`computeSpecFunnel`), the result is always fresh and needs no bookkeeping.
|
|
22
|
+
*/
|
|
23
|
+
import { NodeKind, SpecKind } from '../types';
|
|
24
|
+
import { QueryBuilder } from '../db/queries';
|
|
25
|
+
import { SpecQueries } from '../db/spec-queries';
|
|
26
|
+
import { SpecLinkResolver } from './spec-link-resolver';
|
|
27
|
+
/** A code entity not yet reached by any domain fact. */
|
|
28
|
+
export interface GapSeedEntity {
|
|
29
|
+
nodeId: string;
|
|
30
|
+
name: string;
|
|
31
|
+
qualifiedName: string;
|
|
32
|
+
kind: NodeKind;
|
|
33
|
+
filePath: string;
|
|
34
|
+
}
|
|
35
|
+
/** A non-domain spec with no domain fact hanging off it. */
|
|
36
|
+
export interface GapSeedSpec {
|
|
37
|
+
id: string;
|
|
38
|
+
title: string;
|
|
39
|
+
kind: SpecKind;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Coverage tally over the entity ∪ spec universe. `documented + gaps` always
|
|
43
|
+
* equals the total count of in-scope entities plus non-domain specs.
|
|
44
|
+
*/
|
|
45
|
+
export interface DomainCoverage {
|
|
46
|
+
documented: number;
|
|
47
|
+
gaps: number;
|
|
48
|
+
}
|
|
49
|
+
export interface DomainGapSeed {
|
|
50
|
+
entities: GapSeedEntity[];
|
|
51
|
+
specs: GapSeedSpec[];
|
|
52
|
+
coverage: DomainCoverage;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Compute the domain gap-seed: the in-scope entities and non-domain specs that
|
|
56
|
+
* no domain fact yet covers. Read-only — issues only `SELECT`s through the
|
|
57
|
+
* passed query objects and the resolver's read-time `getInheritedLinks`.
|
|
58
|
+
*/
|
|
59
|
+
export declare function computeDomainGapSeed(queries: QueryBuilder, specQueries: SpecQueries, resolver: SpecLinkResolver): DomainGapSeed;
|
|
60
|
+
//# sourceMappingURL=domain-gap-seed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain-gap-seed.d.ts","sourceRoot":"","sources":["../../src/resolution/domain-gap-seed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAQ,QAAQ,EAAQ,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAWxD,wDAAwD;AACxD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,4DAA4D;AAC5D,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC;CAChB;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,YAAY,EACrB,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,gBAAgB,GACzB,aAAa,CAqDf"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Domain gap-seed (REQ-DOMAIN-003).
|
|
4
|
+
*
|
|
5
|
+
* A read-only pass that surfaces what the domain knowledge layer does NOT yet
|
|
6
|
+
* cover, so an author (or the `/ss-domain` command, REQ-DOMAIN-004) can decide
|
|
7
|
+
* what to document next. It answers two questions against current DB state:
|
|
8
|
+
*
|
|
9
|
+
* - which structural code entities (classes, structs, interfaces, routes,
|
|
10
|
+
* components) are reached by NO domain fact; and
|
|
11
|
+
* - which non-domain specs (documents, requirements, …) have NO domain fact
|
|
12
|
+
* hanging off them.
|
|
13
|
+
*
|
|
14
|
+
* A domain fact carries no direct domain→code rows. It reaches code transitively
|
|
15
|
+
* through its spec-tier chain (`parentId` + `metadata.depends_on`), resolved by
|
|
16
|
+
* {@link SpecLinkResolver.getInheritedLinks} (REQ-DOMAIN-002). An entity is
|
|
17
|
+
* "documented" when some domain fact's inherited links resolve to that entity's
|
|
18
|
+
* node; a spec is "documented" when some domain fact's spec-tier chain reaches
|
|
19
|
+
* it. Everything else is a gap.
|
|
20
|
+
*
|
|
21
|
+
* COMPUTED from live state — writes nothing. Like the spec funnel
|
|
22
|
+
* (`computeSpecFunnel`), the result is always fresh and needs no bookkeeping.
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.computeDomainGapSeed = computeDomainGapSeed;
|
|
26
|
+
/** The structural node kinds the gap-seed considers "domain-worthy" entities. */
|
|
27
|
+
const IN_SCOPE_ENTITY_KINDS = [
|
|
28
|
+
'class',
|
|
29
|
+
'struct',
|
|
30
|
+
'interface',
|
|
31
|
+
'route',
|
|
32
|
+
'component',
|
|
33
|
+
];
|
|
34
|
+
/**
|
|
35
|
+
* Compute the domain gap-seed: the in-scope entities and non-domain specs that
|
|
36
|
+
* no domain fact yet covers. Read-only — issues only `SELECT`s through the
|
|
37
|
+
* passed query objects and the resolver's read-time `getInheritedLinks`.
|
|
38
|
+
*/
|
|
39
|
+
function computeDomainGapSeed(queries, specQueries, resolver) {
|
|
40
|
+
// In-scope entities: every structural code symbol a domain fact could document.
|
|
41
|
+
const entities = IN_SCOPE_ENTITY_KINDS.flatMap((k) => queries.getNodesByKind(k));
|
|
42
|
+
// Build the documented sets by walking each domain fact's spec-tier chain.
|
|
43
|
+
const allSpecs = specQueries.getAllSpecs();
|
|
44
|
+
const documentedNodeIds = new Set();
|
|
45
|
+
const documentedSpecIds = new Set();
|
|
46
|
+
for (const spec of allSpecs) {
|
|
47
|
+
if (spec.kind !== 'domain')
|
|
48
|
+
continue;
|
|
49
|
+
const inherited = resolver.getInheritedLinks(spec);
|
|
50
|
+
for (const { link } of inherited.links) {
|
|
51
|
+
if (link.resolvedNodeId)
|
|
52
|
+
documentedNodeIds.add(link.resolvedNodeId);
|
|
53
|
+
}
|
|
54
|
+
// Every indexed spec the fact reaches counts as documented — even one that
|
|
55
|
+
// contributes no code link of its own (REQ-DOMAIN-003.A2).
|
|
56
|
+
for (const reached of inherited.visitedSpecIds) {
|
|
57
|
+
documentedSpecIds.add(reached);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Gap entities: in-scope entities no domain fact resolves to (A1, A2).
|
|
61
|
+
const gapEntities = entities
|
|
62
|
+
.filter((n) => !documentedNodeIds.has(n.id))
|
|
63
|
+
.map((n) => ({
|
|
64
|
+
nodeId: n.id,
|
|
65
|
+
name: n.name,
|
|
66
|
+
qualifiedName: n.qualifiedName,
|
|
67
|
+
kind: n.kind,
|
|
68
|
+
filePath: n.filePath,
|
|
69
|
+
}));
|
|
70
|
+
// Non-domain specs are the spec-side universe; a domain fact is never its own
|
|
71
|
+
// documentation target.
|
|
72
|
+
const nonDomainSpecs = allSpecs.filter((s) => s.kind !== 'domain');
|
|
73
|
+
const gapSpecs = nonDomainSpecs
|
|
74
|
+
.filter((s) => !documentedSpecIds.has(s.id))
|
|
75
|
+
.map((s) => ({ id: s.id, title: s.title, kind: s.kind }));
|
|
76
|
+
// Coverage over the entity ∪ spec universe (A3): the denominator is the total
|
|
77
|
+
// count of in-scope entities plus non-domain specs, so documented + gaps
|
|
78
|
+
// always reconstitutes it exactly.
|
|
79
|
+
const gaps = gapEntities.length + gapSpecs.length;
|
|
80
|
+
const documented = entities.length + nonDomainSpecs.length - gaps;
|
|
81
|
+
return {
|
|
82
|
+
entities: gapEntities,
|
|
83
|
+
specs: gapSpecs,
|
|
84
|
+
coverage: { documented, gaps },
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=domain-gap-seed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain-gap-seed.js","sourceRoot":"","sources":["../../src/resolution/domain-gap-seed.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;;AAoDH,oDAyDC;AAtGD,iFAAiF;AACjF,MAAM,qBAAqB,GAAe;IACxC,OAAO;IACP,QAAQ;IACR,WAAW;IACX,OAAO;IACP,WAAW;CACZ,CAAC;AAiCF;;;;GAIG;AACH,SAAgB,oBAAoB,CAClC,OAAqB,EACrB,WAAwB,EACxB,QAA0B;IAE1B,gFAAgF;IAChF,MAAM,QAAQ,GAAW,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAC3D,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAC1B,CAAC;IAEF,2EAA2E;IAC3E,MAAM,QAAQ,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC;IAC3C,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC5C,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAU,CAAC;IAE5C,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ;YAAE,SAAS;QACrC,MAAM,SAAS,GAAG,QAAQ,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACnD,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;YACvC,IAAI,IAAI,CAAC,cAAc;gBAAE,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACtE,CAAC;QACD,2EAA2E;QAC3E,2DAA2D;QAC3D,KAAK,MAAM,OAAO,IAAI,SAAS,CAAC,cAAc,EAAE,CAAC;YAC/C,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED,uEAAuE;IACvE,MAAM,WAAW,GAAoB,QAAQ;SAC1C,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SAC3C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACX,MAAM,EAAE,CAAC,CAAC,EAAE;QACZ,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,aAAa,EAAE,CAAC,CAAC,aAAa;QAC9B,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ;KACrB,CAAC,CAAC,CAAC;IAEN,8EAA8E;IAC9E,wBAAwB;IACxB,MAAM,cAAc,GAAW,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;IAC3E,MAAM,QAAQ,GAAkB,cAAc;SAC3C,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SAC3C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAE5D,8EAA8E;IAC9E,yEAAyE;IACzE,mCAAmC;IACnC,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;IAClD,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,GAAG,cAAc,CAAC,MAAM,GAAG,IAAI,CAAC;IAElE,OAAO;QACL,QAAQ,EAAE,WAAW;QACrB,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE;KAC/B,CAAC;AACJ,CAAC"}
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* Highest-confidence signal wins per logical key — `upsertSpecLink` enforces
|
|
28
28
|
* this.
|
|
29
29
|
*/
|
|
30
|
-
import { Spec } from '../types';
|
|
30
|
+
import { Spec, SpecLink } from '../types';
|
|
31
31
|
import { QueryBuilder } from '../db/queries';
|
|
32
32
|
import { SpecQueries } from '../db/spec-queries';
|
|
33
33
|
import { SpecLinkCandidate } from '../extraction/specs/types';
|
|
@@ -45,6 +45,35 @@ export interface SpecLinkResolverStats {
|
|
|
45
45
|
candidatesApplied: number;
|
|
46
46
|
commentLinksApplied: number;
|
|
47
47
|
}
|
|
48
|
+
/** One code link inherited by a spec through a spec→spec dependency edge. */
|
|
49
|
+
export interface InheritedLink {
|
|
50
|
+
/** The dependency spec id whose `implements` link this is. */
|
|
51
|
+
viaSpecId: string;
|
|
52
|
+
/** The inherited link itself (carries live `state` / `driftAxis`). */
|
|
53
|
+
link: SpecLink;
|
|
54
|
+
}
|
|
55
|
+
/** Result of {@link SpecLinkResolver.getInheritedLinks}. */
|
|
56
|
+
export interface InheritedLinksResult {
|
|
57
|
+
/** Code links reached transitively through the spec's parent / depends_on chain. */
|
|
58
|
+
links: InheritedLink[];
|
|
59
|
+
/** Declared dependency spec ids that don't resolve to an indexed spec (gaps). */
|
|
60
|
+
gaps: string[];
|
|
61
|
+
/**
|
|
62
|
+
* Every *indexed* spec id reached through the spec-tier chain (excludes the
|
|
63
|
+
* originating spec and the unresolved `gaps`). A spec a fact reaches but that
|
|
64
|
+
* contributes no code link still appears here, so consumers like the domain
|
|
65
|
+
* gap-seed (REQ-DOMAIN-003) can treat "reached by a domain fact" as documented
|
|
66
|
+
* even when the reached spec carries no `spec_links` of its own.
|
|
67
|
+
*/
|
|
68
|
+
visitedSpecIds: string[];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The spec ids a spec links to at the spec tier: its `parentId` plus every
|
|
72
|
+
* entry of `metadata.depends_on` (REQ-DOMAIN-002). `depends_on` may be a
|
|
73
|
+
* single string or a string[]; both normalize to a deduped list of non-empty
|
|
74
|
+
* ids.
|
|
75
|
+
*/
|
|
76
|
+
export declare function sourceSpecIds(spec: Spec): string[];
|
|
48
77
|
export declare class SpecLinkResolver {
|
|
49
78
|
private queries;
|
|
50
79
|
private specQueries;
|
|
@@ -98,6 +127,22 @@ export declare class SpecLinkResolver {
|
|
|
98
127
|
* needed, call specship_link_verify to take state back to `verified`.
|
|
99
128
|
*/
|
|
100
129
|
markSpecDrifted(specId: string, newSpecHash: string): number;
|
|
130
|
+
/**
|
|
131
|
+
* Compute the code links a spec inherits transitively through its
|
|
132
|
+
* spec→spec edges (`parentId` + `metadata.depends_on`). A `domain` fact
|
|
133
|
+
* carries NO direct domain→code rows; its code association and drift state
|
|
134
|
+
* are derived here by following those spec edges to requirement specs and
|
|
135
|
+
* reusing *their* `spec_links` — whose `resolved_node_id`/`state` the normal
|
|
136
|
+
* `resolveAll`/`resolveLinksForFiles` pass already refreshed this sync. So
|
|
137
|
+
* "re-resolved after each sync" holds with no stored domain rows, and drift
|
|
138
|
+
* surfaces automatically through each inherited link's live `state`.
|
|
139
|
+
*
|
|
140
|
+
* Read-time derivation only — writes nothing. Cycle-guarded via a visited
|
|
141
|
+
* `Set`, depth-capped (default {@link INHERITED_LINK_MAX_DEPTH}). A declared
|
|
142
|
+
* dependency that doesn't resolve to an indexed spec is returned in `gaps`
|
|
143
|
+
* (an unlinked/proposed fact, never an error — REQ-DOMAIN-002.A3).
|
|
144
|
+
*/
|
|
145
|
+
getInheritedLinks(spec: Spec, maxDepth?: number): InheritedLinksResult;
|
|
101
146
|
private makeStats;
|
|
102
147
|
}
|
|
103
148
|
//# sourceMappingURL=spec-link-resolver.d.ts.map
|