@neurcode-ai/contracts 0.1.2 → 0.2.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/dist/admission/framing.d.ts +38 -0
- package/dist/admission/framing.d.ts.map +1 -0
- package/dist/admission/framing.js +78 -0
- package/dist/admission/framing.js.map +1 -0
- package/dist/admission/index.d.ts +4 -0
- package/dist/admission/index.d.ts.map +1 -0
- package/dist/admission/index.js +37 -0
- package/dist/admission/index.js.map +1 -0
- package/dist/admission/privacy.d.ts +23 -0
- package/dist/admission/privacy.d.ts.map +1 -0
- package/dist/admission/privacy.js +99 -0
- package/dist/admission/privacy.js.map +1 -0
- package/dist/admission/schema.d.ts +277 -0
- package/dist/admission/schema.d.ts.map +1 -0
- package/dist/admission/schema.js +156 -0
- package/dist/admission/schema.js.map +1 -0
- package/dist/index.d.ts +93 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +185 -18
- package/dist/index.js.map +1 -1
- package/dist/intelligence.d.ts +522 -0
- package/dist/intelligence.d.ts.map +1 -0
- package/dist/intelligence.js +5 -0
- package/dist/intelligence.js.map +1 -0
- package/dist/proposed-change-validation.d.ts +20 -0
- package/dist/proposed-change-validation.d.ts.map +1 -0
- package/dist/proposed-change-validation.js +582 -0
- package/dist/proposed-change-validation.js.map +1 -0
- package/dist/remediation/capabilities.d.ts +36 -0
- package/dist/remediation/capabilities.d.ts.map +1 -0
- package/dist/remediation/capabilities.js +7 -0
- package/dist/remediation/capabilities.js.map +1 -0
- package/dist/remediation/index.d.ts +5 -0
- package/dist/remediation/index.d.ts.map +1 -0
- package/dist/remediation/index.js +3 -0
- package/dist/remediation/index.js.map +1 -0
- package/dist/remediation/request.d.ts +183 -0
- package/dist/remediation/request.d.ts.map +1 -0
- package/dist/remediation/request.js +15 -0
- package/dist/remediation/request.js.map +1 -0
- package/dist/remediation/response.d.ts +100 -0
- package/dist/remediation/response.d.ts.map +1 -0
- package/dist/remediation/response.js +11 -0
- package/dist/remediation/response.js.map +1 -0
- package/dist/remediation/validation.d.ts +87 -0
- package/dist/remediation/validation.d.ts.map +1 -0
- package/dist/remediation/validation.js +15 -0
- package/dist/remediation/validation.js.map +1 -0
- package/dist/repo-intelligence-v2.d.ts +562 -0
- package/dist/repo-intelligence-v2.d.ts.map +1 -0
- package/dist/repo-intelligence-v2.js +94 -0
- package/dist/repo-intelligence-v2.js.map +1 -0
- package/dist/status-vocabulary.d.ts +45 -0
- package/dist/status-vocabulary.d.ts.map +1 -0
- package/dist/status-vocabulary.js +101 -0
- package/dist/status-vocabulary.js.map +1 -0
- package/dist/verification/canonical-finding.d.ts +171 -0
- package/dist/verification/canonical-finding.d.ts.map +1 -0
- package/dist/verification/canonical-finding.js +3 -0
- package/dist/verification/canonical-finding.js.map +1 -0
- package/dist/verification/index.d.ts +6 -0
- package/dist/verification/index.d.ts.map +1 -0
- package/dist/verification/index.js +11 -0
- package/dist/verification/index.js.map +1 -0
- package/dist/verification/pipeline.d.ts +134 -0
- package/dist/verification/pipeline.d.ts.map +1 -0
- package/dist/verification/pipeline.js +57 -0
- package/dist/verification/pipeline.js.map +1 -0
- package/dist/verification/taxonomy.d.ts +10 -0
- package/dist/verification/taxonomy.d.ts.map +1 -0
- package/dist/verification/taxonomy.js +16 -0
- package/dist/verification/taxonomy.js.map +1 -0
- package/package.json +7 -1
- package/src/index.ts +0 -566
- package/src/runtime-compatibility-manifest.test.ts +0 -43
- package/tsconfig.json +0 -19
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical Governance Pipeline Contracts
|
|
4
|
+
* ----------------------------------------
|
|
5
|
+
* Shared, immutable types describing the staged decomposition of the verify runtime.
|
|
6
|
+
*
|
|
7
|
+
* These contracts are ADDITIVE. They do not replace, mutate, or re-encode the canonical
|
|
8
|
+
* governance envelope (`GovernanceVerificationEnvelope`), the finding identity scheme,
|
|
9
|
+
* or the replay checksum. Stage metadata flows alongside the envelope as an
|
|
10
|
+
* out-of-band observability + replay-reconstruction surface.
|
|
11
|
+
*
|
|
12
|
+
* Design invariants:
|
|
13
|
+
* - Stage IDs are a closed set. Adding a new stage requires bumping the schema version.
|
|
14
|
+
* - Stage metadata never carries excerpts, file content, or PII.
|
|
15
|
+
* - Stage fingerprints are computed from stable identifiers — never wall-clock timestamps.
|
|
16
|
+
* - A stage's `replay.outputFingerprint` is independent of `replayChecksum`; the two
|
|
17
|
+
* are consistent but serve different audiences (stage lineage vs. envelope identity).
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.GOVERNANCE_STAGE_ORDER = exports.GOVERNANCE_PIPELINE_SCHEMA_VERSION = void 0;
|
|
21
|
+
exports.isGovernanceStageId = isGovernanceStageId;
|
|
22
|
+
exports.GOVERNANCE_PIPELINE_SCHEMA_VERSION = '2026-05-14.1';
|
|
23
|
+
/**
|
|
24
|
+
* Type guard: is the given string a known stage identifier?
|
|
25
|
+
*/
|
|
26
|
+
function isGovernanceStageId(value) {
|
|
27
|
+
return exports.GOVERNANCE_STAGE_ORDER.includes(value);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Canonical execution order. Mirror of the union above — exported as a runtime
|
|
31
|
+
* value for iteration, indexing, and stage-ordering invariants.
|
|
32
|
+
*/
|
|
33
|
+
exports.GOVERNANCE_STAGE_ORDER = [
|
|
34
|
+
'diff-normalization',
|
|
35
|
+
'plan-sync',
|
|
36
|
+
'policy-lock',
|
|
37
|
+
'compiled-policy',
|
|
38
|
+
'policy-exceptions',
|
|
39
|
+
'structural-analysis',
|
|
40
|
+
'runtime-guard',
|
|
41
|
+
'intent-evaluation',
|
|
42
|
+
'semantic-analysis',
|
|
43
|
+
'policy-evaluation',
|
|
44
|
+
'suppression-evaluation',
|
|
45
|
+
'advisory-signals',
|
|
46
|
+
'change-contract',
|
|
47
|
+
'ai-debt-budget',
|
|
48
|
+
'governance-synthesis',
|
|
49
|
+
'provenance-generation',
|
|
50
|
+
'replay-integrity',
|
|
51
|
+
'remediation-export-preparation',
|
|
52
|
+
'evidence-generation',
|
|
53
|
+
'telemetry-harvest',
|
|
54
|
+
'ci-shaping',
|
|
55
|
+
'output-rendering',
|
|
56
|
+
];
|
|
57
|
+
//# sourceMappingURL=pipeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/verification/pipeline.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG;;;AAuJH,kDAEC;AAPY,QAAA,kCAAkC,GAAG,cAAuB,CAAC;AAE1E;;GAEG;AACH,SAAgB,mBAAmB,CAAC,KAAa;IAC/C,OAAO,8BAAsB,CAAC,QAAQ,CAAC,KAA0B,CAAC,CAAC;AACrE,CAAC;AAED;;;GAGG;AACU,QAAA,sBAAsB,GAAiC;IAClE,oBAAoB;IACpB,WAAW;IACX,aAAa;IACb,iBAAiB;IACjB,mBAAmB;IACnB,qBAAqB;IACrB,eAAe;IACf,mBAAmB;IACnB,mBAAmB;IACnB,mBAAmB;IACnB,wBAAwB;IACxB,kBAAkB;IAClB,iBAAiB;IACjB,gBAAgB;IAChB,sBAAsB;IACtB,uBAAuB;IACvB,kBAAkB;IAClB,gCAAgC;IAChC,qBAAqB;IACrB,mBAAmB;IACnB,YAAY;IACZ,kBAAkB;CACV,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical determinism taxonomy — every governance finding MUST map to exactly one.
|
|
3
|
+
* Do not blur or infer across these buckets in consumer UIs.
|
|
4
|
+
*/
|
|
5
|
+
export type DeterminismClassification = 'deterministic-structural' | 'deterministic-semantic' | 'heuristic-advisory' | 'llm-assisted-planning';
|
|
6
|
+
export type GovernanceFindingCategory = 'structural' | 'semantic-advisory' | 'policy-engine' | 'governance-constraint' | 'intent-conditioned' | 'flow-connectivity' | 'regression' | 'scope' | 'replay' | 'ci' | 'pilot-metric' | 'workspace-federation';
|
|
7
|
+
export type GovernanceSourceSystem = 'structural-rules' | 'policy-engine' | 'governance-runtime' | 'intent-engine' | 'semantic-index' | 'workspace-federation' | 'replay-runtime' | 'ci-adapter' | 'pilot-metrics';
|
|
8
|
+
export declare const GOVERNANCE_FINDINGS_SCHEMA_VERSION: "2026-05-11.1";
|
|
9
|
+
export declare function isDeterminismClassification(value: string): value is DeterminismClassification;
|
|
10
|
+
//# sourceMappingURL=taxonomy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"taxonomy.d.ts","sourceRoot":"","sources":["../../src/verification/taxonomy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,yBAAyB,GACjC,0BAA0B,GAC1B,wBAAwB,GACxB,oBAAoB,GACpB,uBAAuB,CAAC;AAE5B,MAAM,MAAM,yBAAyB,GACjC,YAAY,GACZ,mBAAmB,GACnB,eAAe,GACf,uBAAuB,GACvB,oBAAoB,GACpB,mBAAmB,GACnB,YAAY,GACZ,OAAO,GACP,QAAQ,GACR,IAAI,GACJ,cAAc,GACd,sBAAsB,CAAC;AAE3B,MAAM,MAAM,sBAAsB,GAC9B,kBAAkB,GAClB,eAAe,GACf,oBAAoB,GACpB,eAAe,GACf,gBAAgB,GAChB,sBAAsB,GACtB,gBAAgB,GAChB,YAAY,GACZ,eAAe,CAAC;AAEpB,eAAO,MAAM,kCAAkC,EAAG,cAAuB,CAAC;AAE1E,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,yBAAyB,CAO7F"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical determinism taxonomy — every governance finding MUST map to exactly one.
|
|
4
|
+
* Do not blur or infer across these buckets in consumer UIs.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.GOVERNANCE_FINDINGS_SCHEMA_VERSION = void 0;
|
|
8
|
+
exports.isDeterminismClassification = isDeterminismClassification;
|
|
9
|
+
exports.GOVERNANCE_FINDINGS_SCHEMA_VERSION = '2026-05-11.1';
|
|
10
|
+
function isDeterminismClassification(value) {
|
|
11
|
+
return (value === 'deterministic-structural'
|
|
12
|
+
|| value === 'deterministic-semantic'
|
|
13
|
+
|| value === 'heuristic-advisory'
|
|
14
|
+
|| value === 'llm-assisted-planning');
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=taxonomy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"taxonomy.js","sourceRoot":"","sources":["../../src/verification/taxonomy.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAmCH,kEAOC;AATY,QAAA,kCAAkC,GAAG,cAAuB,CAAC;AAE1E,SAAgB,2BAA2B,CAAC,KAAa;IACvD,OAAO,CACL,KAAK,KAAK,0BAA0B;WACjC,KAAK,KAAK,wBAAwB;WAClC,KAAK,KAAK,oBAAoB;WAC9B,KAAK,KAAK,uBAAuB,CACrC,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neurcode-ai/contracts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Shared JSON contracts for Neurcode CLI, API, action, IDE, and MCP surfaces",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
7
10
|
"scripts": {
|
|
8
11
|
"build": "tsc",
|
|
9
12
|
"dev": "tsc --watch",
|
|
@@ -12,6 +15,9 @@
|
|
|
12
15
|
},
|
|
13
16
|
"license": "MIT",
|
|
14
17
|
"dependencies": {},
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public"
|
|
20
|
+
},
|
|
15
21
|
"devDependencies": {
|
|
16
22
|
"@types/node": "^20.10.0",
|
|
17
23
|
"tsx": "^4.20.6",
|
package/src/index.ts
DELETED
|
@@ -1,566 +0,0 @@
|
|
|
1
|
-
export const CLI_JSON_CONTRACT_VERSION = '2026-04-04';
|
|
2
|
-
export const RUNTIME_COMPATIBILITY_CONTRACT_ID = 'neurcode-runtime-compatibility';
|
|
3
|
-
export const RUNTIME_COMPATIBILITY_CONTRACT_VERSION = '2026-04-04';
|
|
4
|
-
export const RUNTIME_COMPATIBILITY_MANIFEST_VERSION = '2026-04-04.1';
|
|
5
|
-
export const RUNTIME_COMPATIBILITY_MANIFEST_SCHEMA_VERSION = 1;
|
|
6
|
-
|
|
7
|
-
export type RuntimeComponent = 'cli' | 'action' | 'api';
|
|
8
|
-
|
|
9
|
-
export type RuntimeMinimumPeerVersions = Partial<Record<RuntimeComponent, string>>;
|
|
10
|
-
|
|
11
|
-
export interface RuntimeCompatibilityTriplet {
|
|
12
|
-
id: string;
|
|
13
|
-
channel: 'current' | 'support-floor' | 'compat-canary';
|
|
14
|
-
versions: Record<RuntimeComponent, string>;
|
|
15
|
-
notes?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface RuntimeCompatibilityManifest {
|
|
19
|
-
schemaVersion: number;
|
|
20
|
-
manifestVersion: string;
|
|
21
|
-
contractId: string;
|
|
22
|
-
runtimeContractVersion: string;
|
|
23
|
-
cliJsonContractVersion: string;
|
|
24
|
-
minimumPeerVersions: Record<RuntimeComponent, RuntimeMinimumPeerVersions>;
|
|
25
|
-
validatedTriplets: RuntimeCompatibilityTriplet[];
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const RUNTIME_COMPATIBILITY_MANIFEST: RuntimeCompatibilityManifest = {
|
|
29
|
-
schemaVersion: RUNTIME_COMPATIBILITY_MANIFEST_SCHEMA_VERSION,
|
|
30
|
-
manifestVersion: RUNTIME_COMPATIBILITY_MANIFEST_VERSION,
|
|
31
|
-
contractId: RUNTIME_COMPATIBILITY_CONTRACT_ID,
|
|
32
|
-
runtimeContractVersion: RUNTIME_COMPATIBILITY_CONTRACT_VERSION,
|
|
33
|
-
cliJsonContractVersion: CLI_JSON_CONTRACT_VERSION,
|
|
34
|
-
minimumPeerVersions: {
|
|
35
|
-
cli: {
|
|
36
|
-
action: '0.2.1',
|
|
37
|
-
api: '0.2.0',
|
|
38
|
-
},
|
|
39
|
-
action: {
|
|
40
|
-
cli: '0.9.35',
|
|
41
|
-
api: '0.2.0',
|
|
42
|
-
},
|
|
43
|
-
api: {
|
|
44
|
-
cli: '0.9.35',
|
|
45
|
-
action: '0.2.1',
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
validatedTriplets: [
|
|
49
|
-
{
|
|
50
|
-
id: 'current',
|
|
51
|
-
channel: 'current',
|
|
52
|
-
versions: {
|
|
53
|
-
cli: '0.9.42',
|
|
54
|
-
action: '0.2.2',
|
|
55
|
-
api: '0.2.0',
|
|
56
|
-
},
|
|
57
|
-
notes: 'Current release train validated in monorepo CI.',
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
id: 'support-floor',
|
|
61
|
-
channel: 'support-floor',
|
|
62
|
-
versions: {
|
|
63
|
-
cli: '0.9.35',
|
|
64
|
-
action: '0.2.1',
|
|
65
|
-
api: '0.2.0',
|
|
66
|
-
},
|
|
67
|
-
notes: 'Minimum supported compatibility floor for enterprise rollout.',
|
|
68
|
-
},
|
|
69
|
-
],
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const RUNTIME_MINIMUM_PEER_VERSIONS: Record<RuntimeComponent, RuntimeMinimumPeerVersions> =
|
|
73
|
-
RUNTIME_COMPATIBILITY_MANIFEST.minimumPeerVersions;
|
|
74
|
-
|
|
75
|
-
export function getRuntimeCompatibilityManifest(): RuntimeCompatibilityManifest {
|
|
76
|
-
return {
|
|
77
|
-
...RUNTIME_COMPATIBILITY_MANIFEST,
|
|
78
|
-
minimumPeerVersions: {
|
|
79
|
-
cli: { ...RUNTIME_COMPATIBILITY_MANIFEST.minimumPeerVersions.cli },
|
|
80
|
-
action: { ...RUNTIME_COMPATIBILITY_MANIFEST.minimumPeerVersions.action },
|
|
81
|
-
api: { ...RUNTIME_COMPATIBILITY_MANIFEST.minimumPeerVersions.api },
|
|
82
|
-
},
|
|
83
|
-
validatedTriplets: RUNTIME_COMPATIBILITY_MANIFEST.validatedTriplets.map((triplet) => ({
|
|
84
|
-
...triplet,
|
|
85
|
-
versions: { ...triplet.versions },
|
|
86
|
-
})),
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export interface RuntimeCompatibilityDescriptor {
|
|
91
|
-
contractId: string;
|
|
92
|
-
runtimeContractVersion: string;
|
|
93
|
-
cliJsonContractVersion: string;
|
|
94
|
-
manifestVersion?: string;
|
|
95
|
-
component: RuntimeComponent;
|
|
96
|
-
componentVersion: string;
|
|
97
|
-
minimumPeerVersions: RuntimeMinimumPeerVersions;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export interface CliContractBase {
|
|
101
|
-
contractVersion?: string;
|
|
102
|
-
[key: string]: unknown;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export interface CliPlanJsonPayload extends CliContractBase {
|
|
106
|
-
success: boolean;
|
|
107
|
-
cached: boolean;
|
|
108
|
-
mode: string;
|
|
109
|
-
planId: string | null;
|
|
110
|
-
sessionId: string | null;
|
|
111
|
-
timestamp: string;
|
|
112
|
-
message: string;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export interface CliApplyJsonPayload extends CliContractBase {
|
|
116
|
-
success: boolean;
|
|
117
|
-
planId: string;
|
|
118
|
-
filesGenerated: number;
|
|
119
|
-
files: unknown[];
|
|
120
|
-
writtenFiles: unknown[];
|
|
121
|
-
message: string;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export interface CliVerifyJsonPayload extends CliContractBase {
|
|
125
|
-
grade: string;
|
|
126
|
-
score: number;
|
|
127
|
-
verdict: string;
|
|
128
|
-
violations: unknown[];
|
|
129
|
-
message: string;
|
|
130
|
-
scopeGuardPassed: boolean;
|
|
131
|
-
verificationSource?: 'api' | 'local_fallback' | 'policy_only' | string;
|
|
132
|
-
policyCompilation?: Record<string, unknown>;
|
|
133
|
-
changeContract?: Record<string, unknown>;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export interface CliPromptJsonPayload extends CliContractBase {
|
|
137
|
-
success: boolean;
|
|
138
|
-
planId: string | null;
|
|
139
|
-
intent: string | null;
|
|
140
|
-
prompt: string | null;
|
|
141
|
-
copied: boolean;
|
|
142
|
-
outputPath: string | null;
|
|
143
|
-
message: string;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export interface CliContractImportJsonPayload extends CliContractBase {
|
|
147
|
-
success: boolean;
|
|
148
|
-
provider: string | null;
|
|
149
|
-
planId: string | null;
|
|
150
|
-
sessionId: string | null;
|
|
151
|
-
projectId: string | null;
|
|
152
|
-
parseMode: 'json' | 'text' | null;
|
|
153
|
-
importedFiles: number;
|
|
154
|
-
warnings: unknown[];
|
|
155
|
-
changeContract?: Record<string, unknown> | null;
|
|
156
|
-
message: string;
|
|
157
|
-
timestamp: string;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
export interface CliShipJsonPayload extends CliContractBase {
|
|
161
|
-
success: boolean;
|
|
162
|
-
status: string;
|
|
163
|
-
finalPlanId: string | null;
|
|
164
|
-
audit?: Record<string, unknown>;
|
|
165
|
-
error?: Record<string, unknown>;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export interface CliShipRunsJsonPayload extends CliContractBase {
|
|
169
|
-
runs: unknown[];
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
export interface CliShipResumeJsonPayload extends CliContractBase {
|
|
173
|
-
success: boolean;
|
|
174
|
-
status: string;
|
|
175
|
-
error?: Record<string, unknown>;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
export interface CliShipAttestationVerifyJsonPayload extends CliContractBase {
|
|
179
|
-
pass: boolean;
|
|
180
|
-
message?: string;
|
|
181
|
-
digest?: Record<string, unknown>;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
export interface CliCompatJsonPayload extends CliContractBase {
|
|
185
|
-
success: boolean;
|
|
186
|
-
timestamp: string;
|
|
187
|
-
component: 'cli';
|
|
188
|
-
componentVersion: string;
|
|
189
|
-
compatibility: RuntimeCompatibilityDescriptor;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function asRecord(value: unknown, label: string): Record<string, unknown> {
|
|
193
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
194
|
-
throw new Error(`${label}: expected object`);
|
|
195
|
-
}
|
|
196
|
-
return value as Record<string, unknown>;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function asBoolean(record: Record<string, unknown>, key: string, label: string): boolean {
|
|
200
|
-
if (typeof record[key] !== 'boolean') {
|
|
201
|
-
throw new Error(`${label}: expected ${key}:boolean`);
|
|
202
|
-
}
|
|
203
|
-
return record[key] as boolean;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
function asNumber(record: Record<string, unknown>, key: string, label: string): number {
|
|
207
|
-
if (typeof record[key] !== 'number' || Number.isNaN(record[key])) {
|
|
208
|
-
throw new Error(`${label}: expected ${key}:number`);
|
|
209
|
-
}
|
|
210
|
-
return record[key] as number;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function asString(record: Record<string, unknown>, key: string, label: string): string {
|
|
214
|
-
if (typeof record[key] !== 'string') {
|
|
215
|
-
throw new Error(`${label}: expected ${key}:string`);
|
|
216
|
-
}
|
|
217
|
-
return record[key] as string;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
function asNullableString(record: Record<string, unknown>, key: string, label: string): string | null {
|
|
221
|
-
const value = record[key];
|
|
222
|
-
if (value === null || typeof value === 'string') {
|
|
223
|
-
return value as string | null;
|
|
224
|
-
}
|
|
225
|
-
throw new Error(`${label}: expected ${key}:string|null`);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function asArray(record: Record<string, unknown>, key: string, label: string): unknown[] {
|
|
229
|
-
if (!Array.isArray(record[key])) {
|
|
230
|
-
throw new Error(`${label}: expected ${key}:array`);
|
|
231
|
-
}
|
|
232
|
-
return record[key] as unknown[];
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function asOptionalRecord(record: Record<string, unknown>, key: string, label: string): Record<string, unknown> | undefined {
|
|
236
|
-
const value = record[key];
|
|
237
|
-
if (value === undefined) return undefined;
|
|
238
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
239
|
-
throw new Error(`${label}: expected ${key}:object`);
|
|
240
|
-
}
|
|
241
|
-
return value as Record<string, unknown>;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
function asOptionalString(record: Record<string, unknown>, key: string, label: string): string | undefined {
|
|
245
|
-
const value = record[key];
|
|
246
|
-
if (value === undefined) return undefined;
|
|
247
|
-
if (typeof value !== 'string') {
|
|
248
|
-
throw new Error(`${label}: expected ${key}:string`);
|
|
249
|
-
}
|
|
250
|
-
return value;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
function asContractVersion(record: Record<string, unknown>): string | undefined {
|
|
254
|
-
const value = record.contractVersion;
|
|
255
|
-
if (value === undefined) return undefined;
|
|
256
|
-
if (typeof value !== 'string') {
|
|
257
|
-
throw new Error('contractVersion: expected string when present');
|
|
258
|
-
}
|
|
259
|
-
return value;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
function asRuntimeComponent(record: Record<string, unknown>, key: string, label: string): RuntimeComponent {
|
|
263
|
-
const value = asString(record, key, label);
|
|
264
|
-
if (value === 'cli' || value === 'action' || value === 'api') {
|
|
265
|
-
return value;
|
|
266
|
-
}
|
|
267
|
-
throw new Error(`${label}: expected ${key}:("cli"|"action"|"api")`);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
function parseRuntimeMinimumPeerVersions(
|
|
271
|
-
value: unknown,
|
|
272
|
-
label: string
|
|
273
|
-
): RuntimeMinimumPeerVersions {
|
|
274
|
-
if (value === undefined || value === null) return {};
|
|
275
|
-
const record = asRecord(value, `${label}.minimumPeerVersions`);
|
|
276
|
-
const next: RuntimeMinimumPeerVersions = {};
|
|
277
|
-
for (const component of ['cli', 'action', 'api'] as const) {
|
|
278
|
-
const componentValue = record[component];
|
|
279
|
-
if (componentValue === undefined) continue;
|
|
280
|
-
if (typeof componentValue !== 'string' || !componentValue.trim()) {
|
|
281
|
-
throw new Error(`${label}.minimumPeerVersions: expected ${component}:string`);
|
|
282
|
-
}
|
|
283
|
-
next[component] = componentValue.trim();
|
|
284
|
-
}
|
|
285
|
-
return next;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
function parseRuntimeCompatibilityDescriptor(
|
|
289
|
-
value: unknown,
|
|
290
|
-
label: string
|
|
291
|
-
): RuntimeCompatibilityDescriptor {
|
|
292
|
-
const record = asRecord(value, `${label}.compatibility`);
|
|
293
|
-
return {
|
|
294
|
-
contractId: asString(record, 'contractId', `${label}.compatibility`),
|
|
295
|
-
runtimeContractVersion: asString(record, 'runtimeContractVersion', `${label}.compatibility`),
|
|
296
|
-
cliJsonContractVersion: asString(record, 'cliJsonContractVersion', `${label}.compatibility`),
|
|
297
|
-
manifestVersion: asOptionalString(record, 'manifestVersion', `${label}.compatibility`),
|
|
298
|
-
component: asRuntimeComponent(record, 'component', `${label}.compatibility`),
|
|
299
|
-
componentVersion: asString(record, 'componentVersion', `${label}.compatibility`),
|
|
300
|
-
minimumPeerVersions: parseRuntimeMinimumPeerVersions(record.minimumPeerVersions, `${label}.compatibility`),
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
function parseSemver(value: string): [number, number, number] | null {
|
|
305
|
-
const normalized = value.trim().replace(/^v/i, '').split('+')[0].split('-')[0];
|
|
306
|
-
const match = normalized.match(/^(\d+)\.(\d+)\.(\d+)$/);
|
|
307
|
-
if (!match) return null;
|
|
308
|
-
const major = Number(match[1]);
|
|
309
|
-
const minor = Number(match[2]);
|
|
310
|
-
const patch = Number(match[3]);
|
|
311
|
-
if (!Number.isFinite(major) || !Number.isFinite(minor) || !Number.isFinite(patch)) {
|
|
312
|
-
return null;
|
|
313
|
-
}
|
|
314
|
-
return [major, minor, patch];
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
export function compareSemver(left: string, right: string): number | null {
|
|
318
|
-
const l = parseSemver(left);
|
|
319
|
-
const r = parseSemver(right);
|
|
320
|
-
if (!l || !r) return null;
|
|
321
|
-
for (let idx = 0; idx < 3; idx += 1) {
|
|
322
|
-
if (l[idx] > r[idx]) return 1;
|
|
323
|
-
if (l[idx] < r[idx]) return -1;
|
|
324
|
-
}
|
|
325
|
-
return 0;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
export function isSemverAtLeast(actual: string, minimum: string): boolean | null {
|
|
329
|
-
const compare = compareSemver(actual, minimum);
|
|
330
|
-
if (compare === null) return null;
|
|
331
|
-
return compare >= 0;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
export function getMinimumCompatiblePeerVersion(
|
|
335
|
-
component: RuntimeComponent,
|
|
336
|
-
peer: RuntimeComponent
|
|
337
|
-
): string | undefined {
|
|
338
|
-
return RUNTIME_MINIMUM_PEER_VERSIONS[component][peer];
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
export function getRuntimeMinimumPeerVersionMatrix(): Record<RuntimeComponent, RuntimeMinimumPeerVersions> {
|
|
342
|
-
return {
|
|
343
|
-
cli: { ...RUNTIME_MINIMUM_PEER_VERSIONS.cli },
|
|
344
|
-
action: { ...RUNTIME_MINIMUM_PEER_VERSIONS.action },
|
|
345
|
-
api: { ...RUNTIME_MINIMUM_PEER_VERSIONS.api },
|
|
346
|
-
};
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
export function buildRuntimeCompatibilityDescriptor(
|
|
350
|
-
component: RuntimeComponent,
|
|
351
|
-
componentVersion: string
|
|
352
|
-
): RuntimeCompatibilityDescriptor {
|
|
353
|
-
return {
|
|
354
|
-
contractId: RUNTIME_COMPATIBILITY_CONTRACT_ID,
|
|
355
|
-
runtimeContractVersion: RUNTIME_COMPATIBILITY_CONTRACT_VERSION,
|
|
356
|
-
cliJsonContractVersion: CLI_JSON_CONTRACT_VERSION,
|
|
357
|
-
manifestVersion: RUNTIME_COMPATIBILITY_MANIFEST_VERSION,
|
|
358
|
-
component,
|
|
359
|
-
componentVersion,
|
|
360
|
-
minimumPeerVersions: { ...RUNTIME_MINIMUM_PEER_VERSIONS[component] },
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
export interface RuntimePeerCompatibilityIssue {
|
|
365
|
-
component: RuntimeComponent;
|
|
366
|
-
peer: RuntimeComponent;
|
|
367
|
-
required: string;
|
|
368
|
-
actual: string;
|
|
369
|
-
code: 'UNPARSABLE_VERSION' | 'VERSION_BELOW_MINIMUM';
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
export function evaluateRuntimePeerCompatibility(versions: Record<RuntimeComponent, string>): RuntimePeerCompatibilityIssue[] {
|
|
373
|
-
const issues: RuntimePeerCompatibilityIssue[] = [];
|
|
374
|
-
for (const component of ['cli', 'action', 'api'] as const) {
|
|
375
|
-
for (const peer of ['cli', 'action', 'api'] as const) {
|
|
376
|
-
if (peer === component) continue;
|
|
377
|
-
const required = getMinimumCompatiblePeerVersion(component, peer);
|
|
378
|
-
if (!required) continue;
|
|
379
|
-
const actual = versions[peer];
|
|
380
|
-
const compatible = isSemverAtLeast(actual, required);
|
|
381
|
-
if (compatible === null) {
|
|
382
|
-
issues.push({
|
|
383
|
-
component,
|
|
384
|
-
peer,
|
|
385
|
-
required,
|
|
386
|
-
actual,
|
|
387
|
-
code: 'UNPARSABLE_VERSION',
|
|
388
|
-
});
|
|
389
|
-
} else if (!compatible) {
|
|
390
|
-
issues.push({
|
|
391
|
-
component,
|
|
392
|
-
peer,
|
|
393
|
-
required,
|
|
394
|
-
actual,
|
|
395
|
-
code: 'VERSION_BELOW_MINIMUM',
|
|
396
|
-
});
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
return issues;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
export function parseCliPlanJsonPayload(value: unknown, label = 'plan'): CliPlanJsonPayload {
|
|
404
|
-
const record = asRecord(value, label);
|
|
405
|
-
return {
|
|
406
|
-
...record,
|
|
407
|
-
contractVersion: asContractVersion(record),
|
|
408
|
-
success: asBoolean(record, 'success', label),
|
|
409
|
-
cached: asBoolean(record, 'cached', label),
|
|
410
|
-
mode: asString(record, 'mode', label),
|
|
411
|
-
planId: asNullableString(record, 'planId', label),
|
|
412
|
-
sessionId: asNullableString(record, 'sessionId', label),
|
|
413
|
-
timestamp: asString(record, 'timestamp', label),
|
|
414
|
-
message: asString(record, 'message', label),
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
export function parseCliApplyJsonPayload(value: unknown, label = 'apply'): CliApplyJsonPayload {
|
|
419
|
-
const record = asRecord(value, label);
|
|
420
|
-
return {
|
|
421
|
-
...record,
|
|
422
|
-
contractVersion: asContractVersion(record),
|
|
423
|
-
success: asBoolean(record, 'success', label),
|
|
424
|
-
planId: asString(record, 'planId', label),
|
|
425
|
-
filesGenerated: asNumber(record, 'filesGenerated', label),
|
|
426
|
-
files: asArray(record, 'files', label),
|
|
427
|
-
writtenFiles: asArray(record, 'writtenFiles', label),
|
|
428
|
-
message: asString(record, 'message', label),
|
|
429
|
-
};
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
export function parseCliVerifyJsonPayload(value: unknown, label = 'verify'): CliVerifyJsonPayload {
|
|
433
|
-
const record = asRecord(value, label);
|
|
434
|
-
const verificationSourceRaw = record.verificationSource;
|
|
435
|
-
const verificationSource = verificationSourceRaw === undefined
|
|
436
|
-
? undefined
|
|
437
|
-
: asString(record, 'verificationSource', label);
|
|
438
|
-
return {
|
|
439
|
-
...record,
|
|
440
|
-
contractVersion: asContractVersion(record),
|
|
441
|
-
grade: asString(record, 'grade', label),
|
|
442
|
-
score: asNumber(record, 'score', label),
|
|
443
|
-
verdict: asString(record, 'verdict', label),
|
|
444
|
-
violations: asArray(record, 'violations', label),
|
|
445
|
-
message: asString(record, 'message', label),
|
|
446
|
-
scopeGuardPassed: asBoolean(record, 'scopeGuardPassed', label),
|
|
447
|
-
verificationSource,
|
|
448
|
-
};
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
export function parseCliPromptJsonPayload(value: unknown, label = 'prompt'): CliPromptJsonPayload {
|
|
452
|
-
const record = asRecord(value, label);
|
|
453
|
-
return {
|
|
454
|
-
...record,
|
|
455
|
-
contractVersion: asContractVersion(record),
|
|
456
|
-
success: asBoolean(record, 'success', label),
|
|
457
|
-
planId: asNullableString(record, 'planId', label),
|
|
458
|
-
intent: asNullableString(record, 'intent', label),
|
|
459
|
-
prompt: asNullableString(record, 'prompt', label),
|
|
460
|
-
copied: asBoolean(record, 'copied', label),
|
|
461
|
-
outputPath: asNullableString(record, 'outputPath', label),
|
|
462
|
-
message: asString(record, 'message', label),
|
|
463
|
-
};
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
export function parseCliContractImportJsonPayload(
|
|
467
|
-
value: unknown,
|
|
468
|
-
label = 'contract-import'
|
|
469
|
-
): CliContractImportJsonPayload {
|
|
470
|
-
const record = asRecord(value, label);
|
|
471
|
-
const parseModeRaw = record.parseMode;
|
|
472
|
-
let parseMode: 'json' | 'text' | null = null;
|
|
473
|
-
if (parseModeRaw !== undefined && parseModeRaw !== null) {
|
|
474
|
-
const parseModeValue = asString(record, 'parseMode', label);
|
|
475
|
-
if (parseModeValue !== 'json' && parseModeValue !== 'text') {
|
|
476
|
-
throw new Error(`${label}: expected parseMode:"json"|"text"|null`);
|
|
477
|
-
}
|
|
478
|
-
parseMode = parseModeValue;
|
|
479
|
-
}
|
|
480
|
-
const changeContractValue = record.changeContract;
|
|
481
|
-
let changeContract: Record<string, unknown> | null | undefined;
|
|
482
|
-
if (changeContractValue === null) {
|
|
483
|
-
changeContract = null;
|
|
484
|
-
} else if (changeContractValue !== undefined) {
|
|
485
|
-
changeContract = asOptionalRecord(record, 'changeContract', label);
|
|
486
|
-
}
|
|
487
|
-
return {
|
|
488
|
-
...record,
|
|
489
|
-
contractVersion: asContractVersion(record),
|
|
490
|
-
success: asBoolean(record, 'success', label),
|
|
491
|
-
provider: asNullableString(record, 'provider', label),
|
|
492
|
-
planId: asNullableString(record, 'planId', label),
|
|
493
|
-
sessionId: asNullableString(record, 'sessionId', label),
|
|
494
|
-
projectId: asNullableString(record, 'projectId', label),
|
|
495
|
-
parseMode,
|
|
496
|
-
importedFiles: asNumber(record, 'importedFiles', label),
|
|
497
|
-
warnings: asArray(record, 'warnings', label),
|
|
498
|
-
changeContract,
|
|
499
|
-
message: asString(record, 'message', label),
|
|
500
|
-
timestamp: asString(record, 'timestamp', label),
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
export function parseCliShipJsonPayload(value: unknown, label = 'ship'): CliShipJsonPayload {
|
|
505
|
-
const record = asRecord(value, label);
|
|
506
|
-
return {
|
|
507
|
-
...record,
|
|
508
|
-
contractVersion: asContractVersion(record),
|
|
509
|
-
success: asBoolean(record, 'success', label),
|
|
510
|
-
status: asString(record, 'status', label),
|
|
511
|
-
finalPlanId: asNullableString(record, 'finalPlanId', label),
|
|
512
|
-
audit: asOptionalRecord(record, 'audit', label),
|
|
513
|
-
error: asOptionalRecord(record, 'error', label),
|
|
514
|
-
};
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
export function parseCliShipRunsJsonPayload(value: unknown, label = 'ship-runs'): CliShipRunsJsonPayload {
|
|
518
|
-
const record = asRecord(value, label);
|
|
519
|
-
return {
|
|
520
|
-
...record,
|
|
521
|
-
contractVersion: asContractVersion(record),
|
|
522
|
-
runs: asArray(record, 'runs', label),
|
|
523
|
-
};
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
export function parseCliShipResumeJsonPayload(value: unknown, label = 'ship-resume'): CliShipResumeJsonPayload {
|
|
527
|
-
const record = asRecord(value, label);
|
|
528
|
-
return {
|
|
529
|
-
...record,
|
|
530
|
-
contractVersion: asContractVersion(record),
|
|
531
|
-
success: asBoolean(record, 'success', label),
|
|
532
|
-
status: asString(record, 'status', label),
|
|
533
|
-
error: asOptionalRecord(record, 'error', label),
|
|
534
|
-
};
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
export function parseCliShipAttestationVerifyJsonPayload(
|
|
538
|
-
value: unknown,
|
|
539
|
-
label = 'ship-attestation-verify'
|
|
540
|
-
): CliShipAttestationVerifyJsonPayload {
|
|
541
|
-
const record = asRecord(value, label);
|
|
542
|
-
return {
|
|
543
|
-
...record,
|
|
544
|
-
contractVersion: asContractVersion(record),
|
|
545
|
-
pass: asBoolean(record, 'pass', label),
|
|
546
|
-
message: record.message === undefined ? undefined : asString(record, 'message', label),
|
|
547
|
-
digest: asOptionalRecord(record, 'digest', label),
|
|
548
|
-
};
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
export function parseCliCompatJsonPayload(value: unknown, label = 'compat'): CliCompatJsonPayload {
|
|
552
|
-
const record = asRecord(value, label);
|
|
553
|
-
const component = asString(record, 'component', label);
|
|
554
|
-
if (component !== 'cli') {
|
|
555
|
-
throw new Error(`${label}: expected component:"cli"`);
|
|
556
|
-
}
|
|
557
|
-
return {
|
|
558
|
-
...record,
|
|
559
|
-
contractVersion: asContractVersion(record),
|
|
560
|
-
success: asBoolean(record, 'success', label),
|
|
561
|
-
timestamp: asString(record, 'timestamp', label),
|
|
562
|
-
component: 'cli',
|
|
563
|
-
componentVersion: asString(record, 'componentVersion', label),
|
|
564
|
-
compatibility: parseRuntimeCompatibilityDescriptor(record.compatibility, label),
|
|
565
|
-
};
|
|
566
|
-
}
|