@jeger-ai/opengantry 3.3.0 → 3.5.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/README.md +7 -2
- package/dist/cli/commands/arch.js +3 -3
- package/dist/cli/commands/arch.js.map +1 -1
- package/dist/cli/commands/audit-rigor.js +2 -2
- package/dist/cli/commands/audit-rigor.js.map +1 -1
- package/dist/cli/commands/contract.d.ts +28 -0
- package/dist/cli/commands/contract.d.ts.map +1 -0
- package/dist/cli/commands/contract.js +134 -0
- package/dist/cli/commands/contract.js.map +1 -0
- package/dist/cli/commands/interrogate.js +2 -2
- package/dist/cli/commands/interrogate.js.map +1 -1
- package/dist/cli/commands/status.js +2 -2
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/tmvc-guard.d.ts.map +1 -1
- package/dist/cli/commands/tmvc-guard.js +1 -0
- package/dist/cli/commands/tmvc-guard.js.map +1 -1
- package/dist/cli/commands/verify.d.ts.map +1 -1
- package/dist/cli/commands/verify.js +44 -24
- package/dist/cli/commands/verify.js.map +1 -1
- package/dist/cli/lib/cli-io.d.ts +2 -0
- package/dist/cli/lib/cli-io.d.ts.map +1 -1
- package/dist/cli/lib/cli-io.js +9 -1
- package/dist/cli/lib/cli-io.js.map +1 -1
- package/dist/cli/lib/command-boundary.js +2 -2
- package/dist/cli/lib/command-boundary.js.map +1 -1
- package/dist/cli/lib/command-reporter.d.ts +0 -2
- package/dist/cli/lib/command-reporter.d.ts.map +1 -1
- package/dist/cli/lib/command-reporter.js +0 -5
- package/dist/cli/lib/command-reporter.js.map +1 -1
- package/dist/cli/lib/contract/approve-prompt.d.ts +22 -0
- package/dist/cli/lib/contract/approve-prompt.d.ts.map +1 -0
- package/dist/cli/lib/contract/approve-prompt.js +71 -0
- package/dist/cli/lib/contract/approve-prompt.js.map +1 -0
- package/dist/cli/lib/contract/contract-hash.d.ts +19 -0
- package/dist/cli/lib/contract/contract-hash.d.ts.map +1 -0
- package/dist/cli/lib/contract/contract-hash.js +67 -0
- package/dist/cli/lib/contract/contract-hash.js.map +1 -0
- package/dist/cli/lib/contract/contract-scan.d.ts +27 -0
- package/dist/cli/lib/contract/contract-scan.d.ts.map +1 -0
- package/dist/cli/lib/contract/contract-scan.js +167 -0
- package/dist/cli/lib/contract/contract-scan.js.map +1 -0
- package/dist/cli/lib/contract/contract-types.d.ts +38 -0
- package/dist/cli/lib/contract/contract-types.d.ts.map +1 -0
- package/dist/cli/lib/contract/contract-types.js +11 -0
- package/dist/cli/lib/contract/contract-types.js.map +1 -0
- package/dist/cli/lib/contract/effective-scope.d.ts +21 -0
- package/dist/cli/lib/contract/effective-scope.d.ts.map +1 -0
- package/dist/cli/lib/contract/effective-scope.js +77 -0
- package/dist/cli/lib/contract/effective-scope.js.map +1 -0
- package/dist/cli/lib/contract/format.d.ts +20 -0
- package/dist/cli/lib/contract/format.d.ts.map +1 -0
- package/dist/cli/lib/contract/format.js +48 -0
- package/dist/cli/lib/contract/format.js.map +1 -0
- package/dist/cli/lib/contract/intent-path-tokens.d.ts +7 -0
- package/dist/cli/lib/contract/intent-path-tokens.d.ts.map +1 -0
- package/dist/cli/lib/contract/intent-path-tokens.js +30 -0
- package/dist/cli/lib/contract/intent-path-tokens.js.map +1 -0
- package/dist/cli/lib/contract/preflight-heuristic.d.ts +11 -0
- package/dist/cli/lib/contract/preflight-heuristic.d.ts.map +1 -0
- package/dist/cli/lib/contract/preflight-heuristic.js +38 -0
- package/dist/cli/lib/contract/preflight-heuristic.js.map +1 -0
- package/dist/cli/lib/contract/preflight-jev.d.ts +54 -0
- package/dist/cli/lib/contract/preflight-jev.d.ts.map +1 -0
- package/dist/cli/lib/contract/preflight-jev.js +247 -0
- package/dist/cli/lib/contract/preflight-jev.js.map +1 -0
- package/dist/cli/lib/contract/preflight-types.d.ts +19 -0
- package/dist/cli/lib/contract/preflight-types.d.ts.map +1 -0
- package/dist/cli/lib/contract/preflight-types.js +9 -0
- package/dist/cli/lib/contract/preflight-types.js.map +1 -0
- package/dist/cli/lib/contract/preflight.d.ts +16 -0
- package/dist/cli/lib/contract/preflight.d.ts.map +1 -0
- package/dist/cli/lib/contract/preflight.js +34 -0
- package/dist/cli/lib/contract/preflight.js.map +1 -0
- package/dist/cli/lib/contract/propose-gate.d.ts +21 -0
- package/dist/cli/lib/contract/propose-gate.d.ts.map +1 -0
- package/dist/cli/lib/contract/propose-gate.js +57 -0
- package/dist/cli/lib/contract/propose-gate.js.map +1 -0
- package/dist/cli/lib/contract/propose-imports.d.ts +26 -0
- package/dist/cli/lib/contract/propose-imports.d.ts.map +1 -0
- package/dist/cli/lib/contract/propose-imports.js +128 -0
- package/dist/cli/lib/contract/propose-imports.js.map +1 -0
- package/dist/cli/lib/contract/propose.d.ts +25 -0
- package/dist/cli/lib/contract/propose.d.ts.map +1 -0
- package/dist/cli/lib/contract/propose.js +79 -0
- package/dist/cli/lib/contract/propose.js.map +1 -0
- package/dist/cli/lib/contract/resolve-specifier.d.ts +34 -0
- package/dist/cli/lib/contract/resolve-specifier.d.ts.map +1 -0
- package/dist/cli/lib/contract/resolve-specifier.js +93 -0
- package/dist/cli/lib/contract/resolve-specifier.js.map +1 -0
- package/dist/cli/lib/draft-token.d.ts +5 -2
- package/dist/cli/lib/draft-token.d.ts.map +1 -1
- package/dist/cli/lib/draft-token.js +18 -3
- package/dist/cli/lib/draft-token.js.map +1 -1
- package/dist/cli/lib/errors.d.ts +2 -0
- package/dist/cli/lib/errors.d.ts.map +1 -1
- package/dist/cli/lib/errors.js +15 -2
- package/dist/cli/lib/errors.js.map +1 -1
- package/dist/cli/lib/git.d.ts +6 -0
- package/dist/cli/lib/git.d.ts.map +1 -1
- package/dist/cli/lib/git.js +10 -2
- package/dist/cli/lib/git.js.map +1 -1
- package/dist/cli/lib/gxt-error-codes.d.ts +5 -0
- package/dist/cli/lib/gxt-error-codes.d.ts.map +1 -1
- package/dist/cli/lib/gxt-error-codes.js +6 -0
- package/dist/cli/lib/gxt-error-codes.js.map +1 -1
- package/dist/cli/lib/import-scanner.d.ts +13 -3
- package/dist/cli/lib/import-scanner.d.ts.map +1 -1
- package/dist/cli/lib/import-scanner.js +185 -23
- package/dist/cli/lib/import-scanner.js.map +1 -1
- package/dist/cli/lib/interrogate/gaps.d.ts +2 -0
- package/dist/cli/lib/interrogate/gaps.d.ts.map +1 -1
- package/dist/cli/lib/interrogate/gaps.js +3 -4
- package/dist/cli/lib/interrogate/gaps.js.map +1 -1
- package/dist/cli/lib/interrogate/run.d.ts +1 -0
- package/dist/cli/lib/interrogate/run.d.ts.map +1 -1
- package/dist/cli/lib/interrogate/run.js +1 -0
- package/dist/cli/lib/interrogate/run.js.map +1 -1
- package/dist/cli/lib/legislate-from-intent.d.ts +9 -0
- package/dist/cli/lib/legislate-from-intent.d.ts.map +1 -0
- package/dist/cli/lib/legislate-from-intent.js +59 -0
- package/dist/cli/lib/legislate-from-intent.js.map +1 -0
- package/dist/cli/lib/legislate.d.ts +3 -1
- package/dist/cli/lib/legislate.d.ts.map +1 -1
- package/dist/cli/lib/legislate.js +24 -0
- package/dist/cli/lib/legislate.js.map +1 -1
- package/dist/cli/lib/mcp-draft-legislation.d.ts.map +1 -1
- package/dist/cli/lib/mcp-draft-legislation.js +28 -10
- package/dist/cli/lib/mcp-draft-legislation.js.map +1 -1
- package/dist/cli/lib/mcp-execute-legislation.d.ts.map +1 -1
- package/dist/cli/lib/mcp-execute-legislation.js +1 -0
- package/dist/cli/lib/mcp-execute-legislation.js.map +1 -1
- package/dist/cli/lib/mcp-governance-shared.d.ts +2 -1
- package/dist/cli/lib/mcp-governance-shared.d.ts.map +1 -1
- package/dist/cli/lib/mcp-governance-shared.js.map +1 -1
- package/dist/cli/lib/mcp-preflight-contract.d.ts +19 -0
- package/dist/cli/lib/mcp-preflight-contract.d.ts.map +1 -0
- package/dist/cli/lib/mcp-preflight-contract.js +31 -0
- package/dist/cli/lib/mcp-preflight-contract.js.map +1 -0
- package/dist/cli/lib/mcp-propose-contract.d.ts +22 -0
- package/dist/cli/lib/mcp-propose-contract.d.ts.map +1 -0
- package/dist/cli/lib/mcp-propose-contract.js +51 -0
- package/dist/cli/lib/mcp-propose-contract.js.map +1 -0
- package/dist/cli/lib/mcp-tools-register.d.ts.map +1 -1
- package/dist/cli/lib/mcp-tools-register.js +29 -0
- package/dist/cli/lib/mcp-tools-register.js.map +1 -1
- package/dist/cli/lib/missions/formatter.d.ts.map +1 -1
- package/dist/cli/lib/missions/formatter.js +2 -0
- package/dist/cli/lib/missions/formatter.js.map +1 -1
- package/dist/cli/lib/missions/parser.d.ts.map +1 -1
- package/dist/cli/lib/missions/parser.js +14 -0
- package/dist/cli/lib/missions/parser.js.map +1 -1
- package/dist/cli/lib/output-context.d.ts +7 -2
- package/dist/cli/lib/output-context.d.ts.map +1 -1
- package/dist/cli/lib/output-context.js +17 -9
- package/dist/cli/lib/output-context.js.map +1 -1
- package/dist/cli/lib/runtime-env.d.ts +3 -0
- package/dist/cli/lib/runtime-env.d.ts.map +1 -1
- package/dist/cli/lib/runtime-env.js +12 -2
- package/dist/cli/lib/runtime-env.js.map +1 -1
- package/dist/cli/lib/runtime-exec.d.ts +5 -1
- package/dist/cli/lib/runtime-exec.d.ts.map +1 -1
- package/dist/cli/lib/runtime-exec.js +18 -1
- package/dist/cli/lib/runtime-exec.js.map +1 -1
- package/dist/cli/lib/sarif-uri.d.ts +3 -0
- package/dist/cli/lib/sarif-uri.d.ts.map +1 -0
- package/dist/cli/lib/sarif-uri.js +15 -0
- package/dist/cli/lib/sarif-uri.js.map +1 -0
- package/dist/cli/lib/staged-tmvc-guard.d.ts +3 -0
- package/dist/cli/lib/staged-tmvc-guard.d.ts.map +1 -1
- package/dist/cli/lib/staged-tmvc-guard.js +4 -2
- package/dist/cli/lib/staged-tmvc-guard.js.map +1 -1
- package/dist/cli/lib/types.d.ts +7 -0
- package/dist/cli/lib/types.d.ts.map +1 -1
- package/dist/cli/lib/types.js.map +1 -1
- package/dist/cli/lib/verify-contract.d.ts +22 -0
- package/dist/cli/lib/verify-contract.d.ts.map +1 -0
- package/dist/cli/lib/verify-contract.js +110 -0
- package/dist/cli/lib/verify-contract.js.map +1 -0
- package/dist/cli/lib/verify-engine.d.ts.map +1 -1
- package/dist/cli/lib/verify-engine.js +6 -0
- package/dist/cli/lib/verify-engine.js.map +1 -1
- package/dist/cli/lib/verify-export.d.ts +19 -3
- package/dist/cli/lib/verify-export.d.ts.map +1 -1
- package/dist/cli/lib/verify-export.js +47 -24
- package/dist/cli/lib/verify-export.js.map +1 -1
- package/dist/cli/lib/verify-failure-normalize.d.ts.map +1 -1
- package/dist/cli/lib/verify-failure-normalize.js +10 -0
- package/dist/cli/lib/verify-failure-normalize.js.map +1 -1
- package/dist/cli/lib/verify-failure.d.ts +7 -2
- package/dist/cli/lib/verify-failure.d.ts.map +1 -1
- package/dist/cli/lib/verify-finding.d.ts +1 -1
- package/dist/cli/lib/verify-finding.d.ts.map +1 -1
- package/dist/cli/lib/verify-finding.js.map +1 -1
- package/dist/cli/lib/verify-hints.d.ts.map +1 -1
- package/dist/cli/lib/verify-hints.js +13 -0
- package/dist/cli/lib/verify-hints.js.map +1 -1
- package/dist/cli/lib/verify-interrogation.d.ts +2 -0
- package/dist/cli/lib/verify-interrogation.d.ts.map +1 -1
- package/dist/cli/lib/verify-interrogation.js +2 -2
- package/dist/cli/lib/verify-interrogation.js.map +1 -1
- package/dist/cli/lib/verify-payload.d.ts.map +1 -1
- package/dist/cli/lib/verify-payload.js +1 -0
- package/dist/cli/lib/verify-payload.js.map +1 -1
- package/dist/cli/lib/verify-phase-clock.d.ts +1 -1
- package/dist/cli/lib/verify-phase-clock.d.ts.map +1 -1
- package/dist/cli/lib/verify-phase-clock.js +1 -0
- package/dist/cli/lib/verify-phase-clock.js.map +1 -1
- package/dist/cli/lib/verify-presenters.d.ts +6 -2
- package/dist/cli/lib/verify-presenters.d.ts.map +1 -1
- package/dist/cli/lib/verify-presenters.js +34 -12
- package/dist/cli/lib/verify-presenters.js.map +1 -1
- package/dist/cli/lib/version.gen.d.ts +1 -1
- package/dist/cli/lib/version.gen.js +1 -1
- package/dist/cli/program-audience-hook.d.ts +4 -0
- package/dist/cli/program-audience-hook.d.ts.map +1 -0
- package/dist/cli/program-audience-hook.js +85 -0
- package/dist/cli/program-audience-hook.js.map +1 -0
- package/dist/cli/program-mission.d.ts.map +1 -1
- package/dist/cli/program-mission.js +53 -0
- package/dist/cli/program-mission.js.map +1 -1
- package/dist/cli/program-workflow.d.ts +4 -1
- package/dist/cli/program-workflow.d.ts.map +1 -1
- package/dist/cli/program-workflow.js +27 -6
- package/dist/cli/program-workflow.js.map +1 -1
- package/dist/cli/program.js +1 -1
- package/dist/cli/program.js.map +1 -1
- package/package.json +1 -1
- package/templates/.cursor/mcp.json +1 -2
- package/templates/.cursor/rules/opengantry-gxt-substrate.mdc +1 -1
- package/templates/.gitagent/foreman/SUBSTRATE.version.json +1 -1
- package/templates/.gitagent/planner/MISSION-ARCHITECT.md +28 -5
- package/templates/.gitagent/planner/MISSION.schema.yaml +52 -0
- package/templates/.gitagent/planner/RULES.md +55 -36
- package/templates/.githooks/pre-commit +12 -0
- package/templates/integrations/asset-catalog.json +1 -0
- package/templates/integrations/compatibility.json +1 -1
- package/templates/integrations/recipes/cursor.md +1 -1
- package/templates/scripts/mcp-launcher.sh +11 -0
- package/templates/scripts/validate-mcp-dogfood.mjs +7 -2
- package/dist/cli/lib/program-audience-hook.d.ts +0 -4
- package/dist/cli/lib/program-audience-hook.d.ts.map +0 -1
- package/dist/cli/lib/program-audience-hook.js +0 -35
- package/dist/cli/lib/program-audience-hook.js.map +0 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { SkillEntry } from "../types.js";
|
|
2
|
+
export interface ProposedGate {
|
|
3
|
+
command: string;
|
|
4
|
+
successSubstring: string | null;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Prefer a skill allowlist entry whose text names a proposed TMVC root segment (e.g. `test:billing`),
|
|
8
|
+
* else the first allowlisted command. `package.json` script names are a secondary signal when no
|
|
9
|
+
* allowlist exists. Falls back to `echo OK` so interrogation can raise `missing_test_criteria`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function proposeGate(input: {
|
|
12
|
+
root: string;
|
|
13
|
+
skill: SkillEntry | undefined;
|
|
14
|
+
proposedRoots: readonly string[];
|
|
15
|
+
explicitCommand?: string;
|
|
16
|
+
explicitSuccess?: string;
|
|
17
|
+
}): {
|
|
18
|
+
gate: ProposedGate;
|
|
19
|
+
rationale: string;
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=propose-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"propose-gate.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/contract/propose-gate.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAsBD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,UAAU,GAAG,SAAS,CAAC;IAC9B,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,GAAG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CA8B5C"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
function packageScripts(root) {
|
|
4
|
+
const abs = path.join(root, "package.json");
|
|
5
|
+
if (!fs.existsSync(abs))
|
|
6
|
+
return [];
|
|
7
|
+
try {
|
|
8
|
+
const scripts = JSON.parse(fs.readFileSync(abs, "utf8")).scripts;
|
|
9
|
+
return scripts ? Object.keys(scripts).sort() : [];
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function rootSegmentHits(command, roots) {
|
|
16
|
+
let hits = 0;
|
|
17
|
+
for (const root of roots) {
|
|
18
|
+
const seg = root.replace(/\/$/, "").split("/").filter(Boolean).pop();
|
|
19
|
+
if (seg && command.includes(seg))
|
|
20
|
+
hits += 1;
|
|
21
|
+
}
|
|
22
|
+
return hits;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Prefer a skill allowlist entry whose text names a proposed TMVC root segment (e.g. `test:billing`),
|
|
26
|
+
* else the first allowlisted command. `package.json` script names are a secondary signal when no
|
|
27
|
+
* allowlist exists. Falls back to `echo OK` so interrogation can raise `missing_test_criteria`.
|
|
28
|
+
*/
|
|
29
|
+
export function proposeGate(input) {
|
|
30
|
+
if (input.explicitCommand?.trim()) {
|
|
31
|
+
const command = input.explicitCommand.trim();
|
|
32
|
+
return {
|
|
33
|
+
gate: {
|
|
34
|
+
command,
|
|
35
|
+
successSubstring: input.explicitSuccess !== undefined ? input.explicitSuccess.trim() || null : null,
|
|
36
|
+
},
|
|
37
|
+
rationale: `gate_command from --gate-command: ${command}`,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const allow = input.skill?.gate_commands ?? [];
|
|
41
|
+
if (allow.length > 0) {
|
|
42
|
+
const ranked = [...allow].sort((a, b) => rootSegmentHits(b, input.proposedRoots) - rootSegmentHits(a, input.proposedRoots) || a.localeCompare(b));
|
|
43
|
+
const command = ranked[0];
|
|
44
|
+
return { gate: { command, successSubstring: null }, rationale: `gate_command from skill allowlist: ${command}` };
|
|
45
|
+
}
|
|
46
|
+
const scripts = packageScripts(input.root);
|
|
47
|
+
const scriptHit = scripts.find((s) => rootSegmentHits(`npm run ${s}`, input.proposedRoots) > 0);
|
|
48
|
+
if (scriptHit) {
|
|
49
|
+
const command = `npm run ${scriptHit}`;
|
|
50
|
+
return { gate: { command, successSubstring: null }, rationale: `gate_command from package.json script matching a TMVC segment: ${command}` };
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
gate: { command: "echo OK", successSubstring: "OK" },
|
|
54
|
+
rationale: "gate_command fallback echo OK (no skill allowlist; interrogation may raise missing_test_criteria)",
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=propose-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"propose-gate.js","sourceRoot":"","sources":["../../../../src/cli/lib/contract/propose-gate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { OrgPolicyBundle } from "../policy/policy-types.js";
|
|
2
|
+
export interface WorkspacePackage {
|
|
3
|
+
name: string;
|
|
4
|
+
dir: string;
|
|
5
|
+
}
|
|
6
|
+
/** Workspace packages from root `package.json` `workspaces` (no npm expand). */
|
|
7
|
+
export declare function listWorkspacePackages(root: string): WorkspacePackage[];
|
|
8
|
+
export interface ProposeImportsInput {
|
|
9
|
+
root: string;
|
|
10
|
+
proposedRoots: readonly string[];
|
|
11
|
+
forbiddenZones: readonly string[];
|
|
12
|
+
policy: OrgPolicyBundle | null;
|
|
13
|
+
}
|
|
14
|
+
export interface ProposeImportsResult {
|
|
15
|
+
allowed_imports: string[];
|
|
16
|
+
banned_imports: string[];
|
|
17
|
+
extraForbidden: string[];
|
|
18
|
+
rationale: string[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Allowed = bare specifiers already imported under proposed roots. Banned = policy ∪ arch
|
|
22
|
+
* substring rules ∪ specifiers seen only in forbidden zones. Workspace packages named by a
|
|
23
|
+
* banned specifier have their directory appended so relative traversal cannot substitute.
|
|
24
|
+
*/
|
|
25
|
+
export declare function proposeImports(input: ProposeImportsInput): ProposeImportsResult;
|
|
26
|
+
//# sourceMappingURL=propose-imports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"propose-imports.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/contract/propose-imports.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAuBD,gFAAgF;AAChF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAsBtE;AAoCD,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,oBAAoB;IACnC,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,oBAAoB,CA0B/E"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { importMatchesBan } from "../ast-discovery.js";
|
|
4
|
+
import { layerForFile, loadTargetArchitecture } from "../arch/cage/target-architecture.js";
|
|
5
|
+
import { extractImportSites } from "../import-scanner.js";
|
|
6
|
+
import { isBuiltinSpecifier } from "./resolve-specifier.js";
|
|
7
|
+
import { listSourcesUnderRoots } from "./contract-scan.js";
|
|
8
|
+
import { normalizeRepoRelativePath } from "../tmvc-path.js";
|
|
9
|
+
function tryLoadArch(root) {
|
|
10
|
+
try {
|
|
11
|
+
return loadTargetArchitecture(root);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function expandWorkspaceGlob(root, glob) {
|
|
18
|
+
const trimmed = glob.replace(/\/\*$/, "").replace(/\/\*\*$/, "");
|
|
19
|
+
const abs = path.join(root, trimmed);
|
|
20
|
+
if (!fs.existsSync(abs) || !fs.statSync(abs).isDirectory())
|
|
21
|
+
return [];
|
|
22
|
+
const out = [];
|
|
23
|
+
for (const ent of fs.readdirSync(abs, { withFileTypes: true })) {
|
|
24
|
+
if (!ent.isDirectory())
|
|
25
|
+
continue;
|
|
26
|
+
const pkgJson = path.join(abs, ent.name, "package.json");
|
|
27
|
+
if (fs.existsSync(pkgJson))
|
|
28
|
+
out.push(path.posix.join(normalizeRepoRelativePath(trimmed), ent.name));
|
|
29
|
+
}
|
|
30
|
+
return out;
|
|
31
|
+
}
|
|
32
|
+
/** Workspace packages from root `package.json` `workspaces` (no npm expand). */
|
|
33
|
+
export function listWorkspacePackages(root) {
|
|
34
|
+
const abs = path.join(root, "package.json");
|
|
35
|
+
if (!fs.existsSync(abs))
|
|
36
|
+
return [];
|
|
37
|
+
let parsed;
|
|
38
|
+
try {
|
|
39
|
+
parsed = JSON.parse(fs.readFileSync(abs, "utf8"));
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
const globs = Array.isArray(parsed.workspaces) ? parsed.workspaces : (parsed.workspaces?.packages ?? []);
|
|
45
|
+
const out = [];
|
|
46
|
+
for (const glob of globs) {
|
|
47
|
+
for (const dir of expandWorkspaceGlob(root, glob)) {
|
|
48
|
+
try {
|
|
49
|
+
const name = JSON.parse(fs.readFileSync(path.join(root, dir, "package.json"), "utf8")).name;
|
|
50
|
+
if (name)
|
|
51
|
+
out.push({ name, dir: `${dir.replace(/\/$/, "")}/` });
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
/* skip malformed workspace package */
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return out.sort((a, b) => a.name.localeCompare(b.name));
|
|
59
|
+
}
|
|
60
|
+
function collectBareSpecs(root, files) {
|
|
61
|
+
const specs = new Set();
|
|
62
|
+
for (const file of files) {
|
|
63
|
+
const abs = path.join(root, file);
|
|
64
|
+
if (!fs.existsSync(abs))
|
|
65
|
+
continue;
|
|
66
|
+
for (const site of extractImportSites(fs.readFileSync(abs, "utf8"))) {
|
|
67
|
+
if (!site.spec || site.spec.startsWith(".") || site.spec.startsWith("/") || isBuiltinSpecifier(site.spec))
|
|
68
|
+
continue;
|
|
69
|
+
specs.add(site.spec);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return [...specs].sort();
|
|
73
|
+
}
|
|
74
|
+
function bareSpecifiersUnder(root, roots) {
|
|
75
|
+
return collectBareSpecs(root, listSourcesUnderRoots(root, roots));
|
|
76
|
+
}
|
|
77
|
+
function specifiersInForbidden(root, forbidden) {
|
|
78
|
+
return collectBareSpecs(root, listSourcesUnderRoots(root, forbidden));
|
|
79
|
+
}
|
|
80
|
+
function archBannedForRoots(root, proposedRoots) {
|
|
81
|
+
const spec = tryLoadArch(root);
|
|
82
|
+
if (!spec)
|
|
83
|
+
return [];
|
|
84
|
+
const layers = new Set();
|
|
85
|
+
for (const r of proposedRoots)
|
|
86
|
+
layers.add(layerForFile(spec, r.endsWith("/") ? `${r}index.ts` : `${r}/index.ts`));
|
|
87
|
+
const out = new Set();
|
|
88
|
+
for (const rule of spec.rules) {
|
|
89
|
+
if (!rule.forbid_specifier_substring)
|
|
90
|
+
continue;
|
|
91
|
+
if (layers.has(rule.from_layer) || rule.from_layer === "*")
|
|
92
|
+
out.add(rule.forbid_specifier_substring);
|
|
93
|
+
}
|
|
94
|
+
return [...out].sort();
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Allowed = bare specifiers already imported under proposed roots. Banned = policy ∪ arch
|
|
98
|
+
* substring rules ∪ specifiers seen only in forbidden zones. Workspace packages named by a
|
|
99
|
+
* banned specifier have their directory appended so relative traversal cannot substitute.
|
|
100
|
+
*/
|
|
101
|
+
export function proposeImports(input) {
|
|
102
|
+
const rationale = [];
|
|
103
|
+
const allowed = bareSpecifiersUnder(input.root, input.proposedRoots);
|
|
104
|
+
if (allowed.length > 0)
|
|
105
|
+
rationale.push(`allowed_imports from imports under ${input.proposedRoots.join(", ")}`);
|
|
106
|
+
const policyBanned = (input.policy?.banned_imports ?? []).map((b) => b.specifier.trim()).filter(Boolean);
|
|
107
|
+
const archBanned = archBannedForRoots(input.root, input.proposedRoots);
|
|
108
|
+
const forbiddenOnly = specifiersInForbidden(input.root, input.forbiddenZones).filter((s) => !allowed.some((a) => importMatchesBan(s, a) || importMatchesBan(a, s)));
|
|
109
|
+
const banned = [...new Set([...policyBanned, ...archBanned, ...forbiddenOnly])].sort();
|
|
110
|
+
if (policyBanned.length > 0)
|
|
111
|
+
rationale.push(`banned_imports from org policy: ${policyBanned.join(", ")}`);
|
|
112
|
+
if (archBanned.length > 0)
|
|
113
|
+
rationale.push(`banned_imports from TARGET_ARCHITECTURE: ${archBanned.join(", ")}`);
|
|
114
|
+
if (forbiddenOnly.length > 0)
|
|
115
|
+
rationale.push(`banned_imports observed only in forbidden zones: ${forbiddenOnly.join(", ")}`);
|
|
116
|
+
const extraForbidden = [];
|
|
117
|
+
for (const pkg of listWorkspacePackages(input.root)) {
|
|
118
|
+
if (!banned.some((b) => importMatchesBan(pkg.name, b) || importMatchesBan(b, pkg.name)))
|
|
119
|
+
continue;
|
|
120
|
+
extraForbidden.push(pkg.dir);
|
|
121
|
+
}
|
|
122
|
+
extraForbidden.sort();
|
|
123
|
+
if (extraForbidden.length > 0) {
|
|
124
|
+
rationale.push(`forbidden_zones += workspace packages of banned specifiers: ${extraForbidden.join(", ")}`);
|
|
125
|
+
}
|
|
126
|
+
return { allowed_imports: allowed, banned_imports: banned, extraForbidden, rationale };
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=propose-imports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"propose-imports.js","sourceRoot":"","sources":["../../../../src/cli/lib/contract/propose-imports.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { MissionContract } from "./contract-types.js";
|
|
2
|
+
import { type ProposedGate } from "./propose-gate.js";
|
|
3
|
+
import type { Manifest } from "../types.js";
|
|
4
|
+
import type { OrgPolicyBundle as PolicyBundle } from "../policy/policy-types.js";
|
|
5
|
+
export interface ProposeContractInput {
|
|
6
|
+
root: string;
|
|
7
|
+
manifest: Manifest;
|
|
8
|
+
intent: string;
|
|
9
|
+
skillKey: string;
|
|
10
|
+
paths?: string[];
|
|
11
|
+
policy?: PolicyBundle | null;
|
|
12
|
+
gateCommand?: string;
|
|
13
|
+
gateSuccessSubstring?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ProposeContractResult {
|
|
16
|
+
contract: MissionContract;
|
|
17
|
+
gate: ProposedGate;
|
|
18
|
+
rationale: string[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Deterministic contract proposal (ADR-0030: no LLM). Same inputs always yield the same
|
|
22
|
+
* normalized contract, gate, and sorted rationale.
|
|
23
|
+
*/
|
|
24
|
+
export declare function proposeContract(input: ProposeContractInput): ProposeContractResult;
|
|
25
|
+
//# sourceMappingURL=propose.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"propose.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/contract/propose.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,eAAe,IAAI,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGjF,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,eAAe,CAAC;IAC1B,IAAI,EAAE,YAAY,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAsCD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,qBAAqB,CAmClF"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { loadPolicyBundleQuiet } from "./effective-scope.js";
|
|
2
|
+
import { normalizeContract, normalizeContractPath } from "./contract-hash.js";
|
|
3
|
+
import { existingHintedPaths } from "./intent-path-tokens.js";
|
|
4
|
+
import { proposeGate } from "./propose-gate.js";
|
|
5
|
+
import { proposeImports } from "./propose-imports.js";
|
|
6
|
+
import { isPathUnderRoot } from "../tmvc-path.js";
|
|
7
|
+
import { resolveManifestSkillKey } from "../skill-key.js";
|
|
8
|
+
function proposeTmvcRoots(input, skillRoots) {
|
|
9
|
+
const narrowed = existingHintedPaths(input.root, input.intent, input.paths, skillRoots);
|
|
10
|
+
if (narrowed.length > 0) {
|
|
11
|
+
return {
|
|
12
|
+
roots: narrowed,
|
|
13
|
+
rationale: `tmvc_roots from intent/--path that exist on disk (intersect skill roots): ${narrowed.join(", ")}`,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
if (skillRoots.length > 0) {
|
|
17
|
+
return { roots: [...skillRoots].sort(), rationale: `tmvc_roots fallback to skill roots: ${skillRoots.join(", ")}` };
|
|
18
|
+
}
|
|
19
|
+
return { roots: [], rationale: "tmvc_roots empty (substrate skill; Planner must declare roots)" };
|
|
20
|
+
}
|
|
21
|
+
function proposeForbidden(skillForbidden, policy, manifest, proposedRoots) {
|
|
22
|
+
const rationale = [];
|
|
23
|
+
const policyAdd = (policy?.manifest_constraints?.forbidden_zones_add ?? []).map(normalizeContractPath);
|
|
24
|
+
const tier3 = [];
|
|
25
|
+
for (const [prefix, tier] of Object.entries(manifest.path_risks)) {
|
|
26
|
+
if (tier !== "Tier-3")
|
|
27
|
+
continue;
|
|
28
|
+
const norm = normalizeContractPath(prefix);
|
|
29
|
+
const covered = proposedRoots.some((r) => isPathUnderRoot(norm, r) || isPathUnderRoot(r, norm));
|
|
30
|
+
if (!covered)
|
|
31
|
+
tier3.push(norm);
|
|
32
|
+
}
|
|
33
|
+
const zones = [...new Set([...skillForbidden, ...policyAdd, ...tier3])].sort();
|
|
34
|
+
if (skillForbidden.length > 0)
|
|
35
|
+
rationale.push(`forbidden_zones from skill: ${skillForbidden.join(", ")}`);
|
|
36
|
+
if (policyAdd.length > 0)
|
|
37
|
+
rationale.push(`forbidden_zones from policy: ${policyAdd.join(", ")}`);
|
|
38
|
+
if (tier3.length > 0)
|
|
39
|
+
rationale.push(`forbidden_zones from Tier-3 path_risks outside proposed roots: ${tier3.join(", ")}`);
|
|
40
|
+
return { zones, rationale };
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Deterministic contract proposal (ADR-0030: no LLM). Same inputs always yield the same
|
|
44
|
+
* normalized contract, gate, and sorted rationale.
|
|
45
|
+
*/
|
|
46
|
+
export function proposeContract(input) {
|
|
47
|
+
const skillKey = resolveManifestSkillKey(input.manifest, input.skillKey);
|
|
48
|
+
const skill = input.manifest.skills[skillKey];
|
|
49
|
+
const skillRoots = (skill?.tmvc_roots ?? []).map(normalizeContractPath);
|
|
50
|
+
const skillForbidden = (skill?.forbidden_zones ?? []).map(normalizeContractPath);
|
|
51
|
+
const policy = input.policy !== undefined ? input.policy : loadPolicyBundleQuiet(input.root);
|
|
52
|
+
const tmvc = proposeTmvcRoots(input, skillRoots);
|
|
53
|
+
const forbidden = proposeForbidden(skillForbidden, policy, input.manifest, tmvc.roots);
|
|
54
|
+
const imports = proposeImports({
|
|
55
|
+
root: input.root,
|
|
56
|
+
proposedRoots: tmvc.roots,
|
|
57
|
+
forbiddenZones: forbidden.zones,
|
|
58
|
+
policy,
|
|
59
|
+
});
|
|
60
|
+
const gate = proposeGate({
|
|
61
|
+
root: input.root,
|
|
62
|
+
skill,
|
|
63
|
+
proposedRoots: tmvc.roots,
|
|
64
|
+
explicitCommand: input.gateCommand,
|
|
65
|
+
explicitSuccess: input.gateSuccessSubstring,
|
|
66
|
+
});
|
|
67
|
+
const contract = normalizeContract({
|
|
68
|
+
...(tmvc.roots.length > 0 ? { tmvc_roots: tmvc.roots } : {}),
|
|
69
|
+
forbidden_zones: [...forbidden.zones, ...imports.extraForbidden],
|
|
70
|
+
allowed_imports: imports.allowed_imports,
|
|
71
|
+
banned_imports: imports.banned_imports,
|
|
72
|
+
});
|
|
73
|
+
return {
|
|
74
|
+
contract,
|
|
75
|
+
gate: gate.gate,
|
|
76
|
+
rationale: [tmvc.rationale, ...forbidden.rationale, ...imports.rationale, gate.rationale],
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=propose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"propose.js","sourceRoot":"","sources":["../../../../src/cli/lib/contract/propose.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type SpecifierClass = {
|
|
2
|
+
kind: "builtin";
|
|
3
|
+
specifier: string;
|
|
4
|
+
} | {
|
|
5
|
+
kind: "bare";
|
|
6
|
+
specifier: string;
|
|
7
|
+
packageName: string;
|
|
8
|
+
} | {
|
|
9
|
+
kind: "relative";
|
|
10
|
+
specifier: string;
|
|
11
|
+
resolvedRepoRel: string;
|
|
12
|
+
} | {
|
|
13
|
+
kind: "alias";
|
|
14
|
+
specifier: string;
|
|
15
|
+
resolvedRepoRel: string;
|
|
16
|
+
};
|
|
17
|
+
export interface TsconfigPaths {
|
|
18
|
+
/** Repo-relative directory that `paths` targets resolve against. */
|
|
19
|
+
baseDirRel: string;
|
|
20
|
+
/** Alias pattern → target patterns (tsconfig `compilerOptions.paths`). */
|
|
21
|
+
paths: Record<string, string[]>;
|
|
22
|
+
}
|
|
23
|
+
export declare function isBuiltinSpecifier(spec: string): boolean;
|
|
24
|
+
/** `@scope/name/sub` → `@scope/name`; `name/sub` → `name`. */
|
|
25
|
+
export declare function bareSpecifierPackage(spec: string): string;
|
|
26
|
+
/** Read `compilerOptions.paths` from `<repo>/tsconfig.json` (no `extends` chasing). Null when absent. */
|
|
27
|
+
export declare function loadTsconfigPaths(repoRoot: string, tsconfigRel?: string): TsconfigPaths | null;
|
|
28
|
+
/**
|
|
29
|
+
* Classify a module specifier for contract checks. Relative and alias specifiers resolve to a
|
|
30
|
+
* repo-relative path (extension left as written; directory prefix checks do not need it). Alias
|
|
31
|
+
* specifiers that match no tsconfig path are treated as bare packages.
|
|
32
|
+
*/
|
|
33
|
+
export declare function classifySpecifier(spec: string, importerRepoRel: string, tsconfigPaths: TsconfigPaths | null): SpecifierClass;
|
|
34
|
+
//# sourceMappingURL=resolve-specifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-specifier.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/contract/resolve-specifier.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GAChE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,CAAC;AAElE,MAAM,WAAW,aAAa;IAC5B,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACjC;AAID,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAIxD;AAED,8DAA8D;AAC9D,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIzD;AAQD,yGAAyG;AACzG,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,SAAkB,GAAG,aAAa,GAAG,IAAI,CAevG;AA6BD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,MAAM,EACvB,aAAa,EAAE,aAAa,GAAG,IAAI,GAClC,cAAc,CAahB"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { builtinModules } from "node:module";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { normalizeRepoRelativePath } from "../tmvc-path.js";
|
|
5
|
+
const BUILTINS = new Set(builtinModules);
|
|
6
|
+
export function isBuiltinSpecifier(spec) {
|
|
7
|
+
if (spec.startsWith("node:"))
|
|
8
|
+
return true;
|
|
9
|
+
const base = spec.split("/")[0] ?? spec;
|
|
10
|
+
return BUILTINS.has(base);
|
|
11
|
+
}
|
|
12
|
+
/** `@scope/name/sub` → `@scope/name`; `name/sub` → `name`. */
|
|
13
|
+
export function bareSpecifierPackage(spec) {
|
|
14
|
+
const parts = spec.split("/");
|
|
15
|
+
if (spec.startsWith("@") && parts.length >= 2)
|
|
16
|
+
return `${parts[0]}/${parts[1]}`;
|
|
17
|
+
return parts[0] ?? spec;
|
|
18
|
+
}
|
|
19
|
+
function stripJsonComments(raw) {
|
|
20
|
+
const noBlock = raw.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
21
|
+
const noLine = noBlock.replace(/(^|[^:"'\\])\/\/[^\n]*/g, "$1");
|
|
22
|
+
return noLine.replace(/,(\s*[}\]])/g, "$1");
|
|
23
|
+
}
|
|
24
|
+
/** Read `compilerOptions.paths` from `<repo>/tsconfig.json` (no `extends` chasing). Null when absent. */
|
|
25
|
+
export function loadTsconfigPaths(repoRoot, tsconfigRel = "tsconfig.json") {
|
|
26
|
+
const abs = path.join(repoRoot, tsconfigRel);
|
|
27
|
+
if (!fs.existsSync(abs))
|
|
28
|
+
return null;
|
|
29
|
+
let parsed;
|
|
30
|
+
try {
|
|
31
|
+
parsed = JSON.parse(stripJsonComments(fs.readFileSync(abs, "utf8")));
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const paths = parsed.compilerOptions?.paths;
|
|
37
|
+
if (!paths || Object.keys(paths).length === 0)
|
|
38
|
+
return null;
|
|
39
|
+
const tsconfigDir = path.posix.dirname(normalizeRepoRelativePath(tsconfigRel));
|
|
40
|
+
const baseUrl = parsed.compilerOptions?.baseUrl ?? ".";
|
|
41
|
+
const baseDirRel = normalizeRepoRelativePath(path.posix.normalize(path.posix.join(tsconfigDir === "." ? "" : tsconfigDir, baseUrl)));
|
|
42
|
+
return { baseDirRel: baseDirRel === "." ? "" : baseDirRel, paths };
|
|
43
|
+
}
|
|
44
|
+
function matchAliasPattern(spec, pattern) {
|
|
45
|
+
const star = pattern.indexOf("*");
|
|
46
|
+
if (star === -1)
|
|
47
|
+
return spec === pattern ? "" : null;
|
|
48
|
+
const prefix = pattern.slice(0, star);
|
|
49
|
+
const suffix = pattern.slice(star + 1);
|
|
50
|
+
if (!spec.startsWith(prefix) || !spec.endsWith(suffix) || spec.length < prefix.length + suffix.length)
|
|
51
|
+
return null;
|
|
52
|
+
return spec.slice(prefix.length, spec.length - suffix.length);
|
|
53
|
+
}
|
|
54
|
+
function resolveAlias(spec, ts) {
|
|
55
|
+
for (const [pattern, targets] of Object.entries(ts.paths)) {
|
|
56
|
+
const wildcard = matchAliasPattern(spec, pattern);
|
|
57
|
+
if (wildcard === null)
|
|
58
|
+
continue;
|
|
59
|
+
const target = targets[0];
|
|
60
|
+
if (!target)
|
|
61
|
+
continue;
|
|
62
|
+
const substituted = target.replace("*", wildcard);
|
|
63
|
+
const joined = path.posix.join(ts.baseDirRel, substituted);
|
|
64
|
+
return normalizeRepoRelativePath(path.posix.normalize(joined));
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
function resolveRelative(importerRepoRel, spec) {
|
|
69
|
+
const dir = path.posix.dirname(normalizeRepoRelativePath(importerRepoRel));
|
|
70
|
+
return normalizeRepoRelativePath(path.posix.normalize(path.posix.join(dir, spec)));
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Classify a module specifier for contract checks. Relative and alias specifiers resolve to a
|
|
74
|
+
* repo-relative path (extension left as written; directory prefix checks do not need it). Alias
|
|
75
|
+
* specifiers that match no tsconfig path are treated as bare packages.
|
|
76
|
+
*/
|
|
77
|
+
export function classifySpecifier(spec, importerRepoRel, tsconfigPaths) {
|
|
78
|
+
if (spec.startsWith(".")) {
|
|
79
|
+
return { kind: "relative", specifier: spec, resolvedRepoRel: resolveRelative(importerRepoRel, spec) };
|
|
80
|
+
}
|
|
81
|
+
if (spec.startsWith("/")) {
|
|
82
|
+
return { kind: "relative", specifier: spec, resolvedRepoRel: normalizeRepoRelativePath(spec.slice(1)) };
|
|
83
|
+
}
|
|
84
|
+
if (isBuiltinSpecifier(spec))
|
|
85
|
+
return { kind: "builtin", specifier: spec };
|
|
86
|
+
if (tsconfigPaths) {
|
|
87
|
+
const resolved = resolveAlias(spec, tsconfigPaths);
|
|
88
|
+
if (resolved !== null)
|
|
89
|
+
return { kind: "alias", specifier: spec, resolvedRepoRel: resolved };
|
|
90
|
+
}
|
|
91
|
+
return { kind: "bare", specifier: spec, packageName: bareSpecifierPackage(spec) };
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=resolve-specifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-specifier.js","sourceRoot":"","sources":["../../../../src/cli/lib/contract/resolve-specifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type GateAdapterId } from "./types.js";
|
|
1
|
+
import { type GateAdapterId, type MissionContract } from "./types.js";
|
|
2
2
|
export declare const DRAFT_TOKEN_TTL_SECONDS_DEFAULT = 600;
|
|
3
3
|
export declare const DRAFT_TOKEN_TTL_SECONDS_MIN = 120;
|
|
4
4
|
export declare const DRAFT_TOKEN_TTL_SECONDS_MAX = 1800;
|
|
@@ -6,7 +6,7 @@ export declare const DRAFT_TOKEN_KEY_REL = ".gitagent/foreman/DRAFT_TOKEN.key";
|
|
|
6
6
|
export declare const DRAFT_TOKEN_REPLAY_REL = ".gitagent/history/.draft-token-replay.json";
|
|
7
7
|
import type { InterrogationRow } from "./interrogate/findings.js";
|
|
8
8
|
export interface DraftLegislationPayload {
|
|
9
|
-
v: 2;
|
|
9
|
+
v: 2 | 3;
|
|
10
10
|
draft_id: string;
|
|
11
11
|
iat: number;
|
|
12
12
|
exp: number;
|
|
@@ -21,6 +21,9 @@ export interface DraftLegislationPayload {
|
|
|
21
21
|
interrogation: InterrogationRow[];
|
|
22
22
|
interrogation_sha256: string;
|
|
23
23
|
declared_paths: string[];
|
|
24
|
+
/** v3: Planner-sealed cage. */
|
|
25
|
+
contract?: MissionContract;
|
|
26
|
+
contract_sha256?: string;
|
|
24
27
|
}
|
|
25
28
|
export type DraftTokenErrorCode = "TOKEN_MALFORMED" | "TOKEN_SIGNATURE_INVALID" | "TOKEN_EXPIRED" | "TOKEN_REPO_MISMATCH" | "TOKEN_REPLAYED" | "TOKEN_KEY_MISSING";
|
|
26
29
|
export declare class DraftTokenError extends Error {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"draft-token.d.ts","sourceRoot":"","sources":["../../../src/cli/lib/draft-token.ts"],"names":[],"mappings":"AAOA,OAAO,EAAyC,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"draft-token.d.ts","sourceRoot":"","sources":["../../../src/cli/lib/draft-token.ts"],"names":[],"mappings":"AAOA,OAAO,EAAyC,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAG7G,eAAO,MAAM,+BAA+B,MAAM,CAAC;AACnD,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAC/C,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAChD,eAAO,MAAM,mBAAmB,sCAAsC,CAAC;AACvE,eAAO,MAAM,sBAAsB,+CAA+C,CAAC;AAEnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAElE,MAAM,WAAW,uBAAuB;IACtC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACT,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,kDAAkD;IAClD,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,aAAa,EAAE,gBAAgB,EAAE,CAAC;IAClC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,mBAAmB,GAC3B,iBAAiB,GACjB,yBAAyB,GACzB,eAAe,GACf,qBAAqB,GACrB,gBAAgB,GAChB,mBAAmB,CAAC;AAExB,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;gBAEhB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,UAAO;CAKzE;AASD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO3D;AAoDD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,IAAI,CAAC,uBAAuB,EAAE,GAAG,GAAG,UAAU,GAAG,KAAK,GAAG,KAAK,GAAG,kBAAkB,CAAC,GAAG;IAC5F,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GACA;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,uBAAuB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAyC/E;AAwCD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,uBAAuB,CAkE3H"}
|
|
@@ -6,6 +6,7 @@ import { CLI_NAME } from "./constants.js";
|
|
|
6
6
|
import { canonicalJson } from "./canonical-json.js";
|
|
7
7
|
import { gitRun } from "./git.js";
|
|
8
8
|
import { DEFAULT_GATE_ADAPTER, isGateAdapterId } from "./types.js";
|
|
9
|
+
import { contractSha256, normalizeContract } from "./contract/contract-hash.js";
|
|
9
10
|
export const DRAFT_TOKEN_TTL_SECONDS_DEFAULT = 600;
|
|
10
11
|
export const DRAFT_TOKEN_TTL_SECONDS_MIN = 120;
|
|
11
12
|
export const DRAFT_TOKEN_TTL_SECONDS_MAX = 1800;
|
|
@@ -86,8 +87,9 @@ export function createDraftToken(root, input) {
|
|
|
86
87
|
const ttlRaw = input.ttlSeconds ?? DRAFT_TOKEN_TTL_SECONDS_DEFAULT;
|
|
87
88
|
const ttl = Math.min(DRAFT_TOKEN_TTL_SECONDS_MAX, Math.max(DRAFT_TOKEN_TTL_SECONDS_MIN, ttlRaw));
|
|
88
89
|
const now = Math.floor(Date.now() / 1000);
|
|
90
|
+
const contract = input.contract ? normalizeContract(input.contract) : undefined;
|
|
89
91
|
const payload = {
|
|
90
|
-
v:
|
|
92
|
+
v: 3,
|
|
91
93
|
draft_id: crypto.randomUUID(),
|
|
92
94
|
iat: now,
|
|
93
95
|
exp: now + ttl,
|
|
@@ -106,6 +108,10 @@ export function createDraftToken(root, input) {
|
|
|
106
108
|
if (input.gate_adapter !== undefined && input.gate_adapter !== DEFAULT_GATE_ADAPTER) {
|
|
107
109
|
payload.gate_adapter = input.gate_adapter;
|
|
108
110
|
}
|
|
111
|
+
if (contract) {
|
|
112
|
+
payload.contract = contract;
|
|
113
|
+
payload.contract_sha256 = contractSha256(contract);
|
|
114
|
+
}
|
|
109
115
|
const key = ensureDraftTokenKey(root);
|
|
110
116
|
const encoded = base64UrlEncode(Buffer.from(canonicalJson(payload), "utf8"));
|
|
111
117
|
const signature = signPayload(payload, key);
|
|
@@ -129,6 +135,15 @@ function assertDraftPayloadShape(payload) {
|
|
|
129
135
|
if (payload.gate_adapter !== undefined && !isGateAdapterId(payload.gate_adapter)) {
|
|
130
136
|
throw new DraftTokenError("TOKEN_MALFORMED", `${CLI_NAME} draft token gate_adapter must be generic|eslint|tsc`, false);
|
|
131
137
|
}
|
|
138
|
+
if (payload.v === 2 && (payload.contract !== undefined || payload.contract_sha256 !== undefined)) {
|
|
139
|
+
throw new DraftTokenError("TOKEN_MALFORMED", `${CLI_NAME} draft token v2 cannot carry a contract (require v3)`, false);
|
|
140
|
+
}
|
|
141
|
+
if (payload.v === 3 && payload.contract) {
|
|
142
|
+
const expected = contractSha256(normalizeContract(payload.contract));
|
|
143
|
+
if (payload.contract_sha256 !== expected) {
|
|
144
|
+
throw new DraftTokenError("TOKEN_MALFORMED", `${CLI_NAME} draft token contract_sha256 does not match contract`, false);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
132
147
|
}
|
|
133
148
|
export function verifyDraftToken(root, draftToken, options) {
|
|
134
149
|
const parts = draftToken.trim().split(".");
|
|
@@ -149,8 +164,8 @@ export function verifyDraftToken(root, draftToken, options) {
|
|
|
149
164
|
catch {
|
|
150
165
|
throw new DraftTokenError("TOKEN_MALFORMED", `${CLI_NAME} draft token payload JSON invalid`, true);
|
|
151
166
|
}
|
|
152
|
-
if (payload.v !== 2) {
|
|
153
|
-
throw new DraftTokenError("TOKEN_MALFORMED", `${CLI_NAME} draft token version unsupported (require v2)`, false);
|
|
167
|
+
if (payload.v !== 2 && payload.v !== 3) {
|
|
168
|
+
throw new DraftTokenError("TOKEN_MALFORMED", `${CLI_NAME} draft token version unsupported (require v2 or v3)`, false);
|
|
154
169
|
}
|
|
155
170
|
assertDraftPayloadShape(payload);
|
|
156
171
|
const keyPath = draftTokenKeyPath(root);
|