@ornexus/neocortex 4.60.21 → 4.60.23
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/sbom.cdx.json +24 -24
- package/install.ps1 +1 -1
- package/install.sh +1 -1
- package/package.json +6 -3
- package/packages/client/dist/cli.js +0 -0
- package/packages/client/dist/commands/invoke.d.ts +19 -5
- package/packages/client/dist/commands/invoke.js +55 -53
- package/packages/client/dist/continuity/invoke-hooks.js +1 -1
- package/packages/client/dist/fs/atomic-state-replace.d.ts +16 -0
- package/packages/client/dist/fs/atomic-state-replace.js +1 -0
- package/packages/client/dist/generated/command-registry.generated.d.ts +53 -19
- package/packages/client/dist/generated/command-registry.generated.js +1 -1
- package/packages/client/dist/graph-retrieval/pre-command-hook.d.ts +11 -0
- package/packages/client/dist/graph-retrieval/pre-command-hook.js +1 -1
- package/packages/client/dist/graph-retrieval/shared-graph-retrieval-contract.js +1 -1
- package/packages/client/dist/invocation/invoke-input.d.ts +9 -0
- package/packages/client/dist/invocation/invoke-input.js +1 -0
- package/packages/client/dist/migrations/project-identity-capability.d.ts +13 -0
- package/packages/client/dist/migrations/project-identity-capability.js +1 -0
- package/packages/client/dist/migrations/project-identity.d.ts +41 -0
- package/packages/client/dist/migrations/project-identity.js +7 -0
- package/packages/client/dist/runner-cli.js +0 -0
- package/packages/client/dist/state/invocation-shape.d.ts +9 -0
- package/packages/client/dist/state/invocation-shape.js +1 -0
- package/packages/client/dist/state/project-state-snapshot.d.ts +9 -3
- package/packages/client/dist/state/project-state-snapshot.js +1 -1
- package/packages/client/dist/state/structural-dag-projection.d.ts +24 -0
- package/packages/client/dist/state/structural-dag-projection.js +1 -0
- package/packages/shared/dist/generated/command-registry.generated.js +66 -19
- package/packages/shared/dist/generated/invocation-schema.generated.js +16 -4
- package/packages/shared/dist/invocation/index.d.ts +6 -2
- package/packages/shared/dist/invocation/index.js +12 -2
- package/packages/shared/dist/invocation/input-envelope.d.ts +37 -0
- package/packages/shared/dist/invocation/input-envelope.js +98 -0
- package/packages/shared/dist/invocation/project-identity-migration.d.ts +28 -0
- package/packages/shared/dist/invocation/project-identity-migration.js +83 -0
- package/packages/shared/dist/invocation/public-diagnostics.d.ts +87 -0
- package/packages/shared/dist/invocation/public-diagnostics.js +181 -0
- package/packages/shared/dist/invocation/state-projection.d.ts +21 -0
- package/packages/shared/dist/invocation/state-projection.js +1 -0
- package/packages/shared/dist/invocation/strict-effect-receipt.d.ts +12 -0
- package/packages/shared/dist/invocation/strict-effect-receipt.js +43 -0
- package/targets-stubs/antigravity/gemini.md +1 -1
- package/targets-stubs/antigravity/skill/SKILL.md +1 -1
- package/targets-stubs/claude-code/neocortex-root.agent.yaml +1 -1
- package/targets-stubs/claude-code/neocortex-root.md +2 -2
- package/targets-stubs/claude-code/neocortex.agent.yaml +1 -1
- package/targets-stubs/claude-code/neocortex.md +2 -2
- package/targets-stubs/codex/AGENTS.md +1 -1
- package/targets-stubs/cursor/agent.md +2 -2
- package/targets-stubs/gemini-cli/agent.md +2 -2
- package/targets-stubs/opencode/neocortex-root.md +1 -1
- package/targets-stubs/vscode/neocortex.agent.md +2 -2
|
@@ -1,41 +1,41 @@
|
|
|
1
1
|
/** Generated by scripts/generate-command-registry.mjs. Do not edit. */
|
|
2
2
|
export const COMMAND_REGISTRY_SCHEMA_VERSION = 1;
|
|
3
3
|
export const COMMAND_REGISTRY_VERSION = "1.0.0";
|
|
4
|
-
export const COMMAND_REGISTRY_CHECKSUM = "
|
|
4
|
+
export const COMMAND_REGISTRY_CHECKSUM = "39c74bfd2ec67a12b19bda587ffcf6a987dfca1b6d33142a28988c574f7eb7c0";
|
|
5
5
|
export const COMMAND_REGISTRY_PROJECTION_MANIFEST = {
|
|
6
6
|
"schemaVersion": 1,
|
|
7
7
|
"registryVersion": "1.0.0",
|
|
8
|
-
"registryChecksum": "
|
|
8
|
+
"registryChecksum": "39c74bfd2ec67a12b19bda587ffcf6a987dfca1b6d33142a28988c574f7eb7c0",
|
|
9
9
|
"projections": [
|
|
10
10
|
{
|
|
11
11
|
"kind": "admin",
|
|
12
|
-
"entryCount":
|
|
13
|
-
"sha256": "
|
|
12
|
+
"entryCount": 63,
|
|
13
|
+
"sha256": "ca4b20573423f84de80a5664c0171d01b48d43fb3cb2041597a48ab44374dd5d"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"kind": "client",
|
|
17
|
-
"entryCount":
|
|
18
|
-
"sha256": "
|
|
17
|
+
"entryCount": 63,
|
|
18
|
+
"sha256": "ca4b20573423f84de80a5664c0171d01b48d43fb3cb2041597a48ab44374dd5d"
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
"kind": "docs",
|
|
22
|
-
"entryCount":
|
|
23
|
-
"sha256": "
|
|
22
|
+
"entryCount": 63,
|
|
23
|
+
"sha256": "ca4b20573423f84de80a5664c0171d01b48d43fb3cb2041597a48ab44374dd5d"
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
"kind": "metrics",
|
|
27
|
-
"entryCount":
|
|
28
|
-
"sha256": "
|
|
27
|
+
"entryCount": 63,
|
|
28
|
+
"sha256": "ca4b20573423f84de80a5664c0171d01b48d43fb3cb2041597a48ab44374dd5d"
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
31
|
"kind": "server",
|
|
32
|
-
"entryCount":
|
|
33
|
-
"sha256": "
|
|
32
|
+
"entryCount": 68,
|
|
33
|
+
"sha256": "4c10d04de88c08d694d1eaa6f43b688897dfaafd60dcdf155389a1903121465b"
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
36
|
"kind": "shared",
|
|
37
|
-
"entryCount":
|
|
38
|
-
"sha256": "
|
|
37
|
+
"entryCount": 68,
|
|
38
|
+
"sha256": "3b9bde2f873434594c1aedebaa608d401f29729f14e962a9639760f0139bc60b"
|
|
39
39
|
}
|
|
40
40
|
]
|
|
41
41
|
};
|
|
@@ -1130,14 +1130,14 @@ export const GENERATED_SHARED_COMMANDS = [
|
|
|
1130
1130
|
"name": "Diagnosticar Story ou Contexto",
|
|
1131
1131
|
"number": 25,
|
|
1132
1132
|
"policy": {
|
|
1133
|
-
"billingClass": "billable",
|
|
1134
|
-
"idempotencyClass": "
|
|
1133
|
+
"billingClass": "non-billable",
|
|
1134
|
+
"idempotencyClass": "none",
|
|
1135
1135
|
"minimumTier": "free",
|
|
1136
|
-
"mutationClass": "
|
|
1136
|
+
"mutationClass": "read-only",
|
|
1137
1137
|
"privilege": "authenticated",
|
|
1138
|
-
"quotaClass": "
|
|
1138
|
+
"quotaClass": "none",
|
|
1139
1139
|
"replayClass": "signed-request",
|
|
1140
|
-
"strictReadOnly": "
|
|
1140
|
+
"strictReadOnly": "allow"
|
|
1141
1141
|
},
|
|
1142
1142
|
"projections": [
|
|
1143
1143
|
"admin",
|
|
@@ -2746,6 +2746,53 @@ export const GENERATED_SHARED_COMMANDS = [
|
|
|
2746
2746
|
"visibility": "public",
|
|
2747
2747
|
"subcommands": []
|
|
2748
2748
|
},
|
|
2749
|
+
{
|
|
2750
|
+
"aliases": [
|
|
2751
|
+
"migrate-project",
|
|
2752
|
+
"project-id-migrate"
|
|
2753
|
+
],
|
|
2754
|
+
"category": "recovery",
|
|
2755
|
+
"compatibility": {
|
|
2756
|
+
"deprecatedIn": null,
|
|
2757
|
+
"introducedIn": "1.0.0",
|
|
2758
|
+
"removedIn": null,
|
|
2759
|
+
"replacement": null
|
|
2760
|
+
},
|
|
2761
|
+
"description": {
|
|
2762
|
+
"en": "Migrate stable project identity with backup and remote seed.",
|
|
2763
|
+
"es": "Migra la identidad estable del proyecto con respaldo y seed remoto.",
|
|
2764
|
+
"pt-BR": "Migra a identidade estavel do projeto com backup e seed remoto."
|
|
2765
|
+
},
|
|
2766
|
+
"examples": [
|
|
2767
|
+
"@neocortex *migrate-project-id"
|
|
2768
|
+
],
|
|
2769
|
+
"id": "migrate-project-id",
|
|
2770
|
+
"inputShape": "standalone",
|
|
2771
|
+
"mode": "utility",
|
|
2772
|
+
"name": "Migrate Project Identity",
|
|
2773
|
+
"number": 63,
|
|
2774
|
+
"policy": {
|
|
2775
|
+
"billingClass": "non-billable",
|
|
2776
|
+
"idempotencyClass": "logical-required",
|
|
2777
|
+
"minimumTier": "free",
|
|
2778
|
+
"mutationClass": "stateful",
|
|
2779
|
+
"privilege": "authenticated",
|
|
2780
|
+
"quotaClass": "none",
|
|
2781
|
+
"replayClass": "signed-request",
|
|
2782
|
+
"strictReadOnly": "deny"
|
|
2783
|
+
},
|
|
2784
|
+
"projections": [
|
|
2785
|
+
"admin",
|
|
2786
|
+
"client",
|
|
2787
|
+
"docs",
|
|
2788
|
+
"metrics",
|
|
2789
|
+
"server",
|
|
2790
|
+
"shared"
|
|
2791
|
+
],
|
|
2792
|
+
"stepId": "step-u-migrate-project-id",
|
|
2793
|
+
"visibility": "public",
|
|
2794
|
+
"subcommands": []
|
|
2795
|
+
},
|
|
2749
2796
|
{
|
|
2750
2797
|
"aliases": [
|
|
2751
2798
|
"migrate",
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
export const GENERATED_INVOCATION_SCHEMA_MANIFEST = {
|
|
3
3
|
"schemaVersion": "p205-invocation-schema-v1",
|
|
4
4
|
"registryVersion": "1.0.0",
|
|
5
|
-
"registryChecksum": "
|
|
6
|
-
"schemaChecksum": "
|
|
7
|
-
"commandCount":
|
|
5
|
+
"registryChecksum": "39c74bfd2ec67a12b19bda587ffcf6a987dfca1b6d33142a28988c574f7eb7c0",
|
|
6
|
+
"schemaChecksum": "14ea14ebfd79941609426b34690c0fade17034a4b1b166b14d985cb097ee7128",
|
|
7
|
+
"commandCount": 63,
|
|
8
8
|
"optionCount": 47,
|
|
9
9
|
"positionalCount": 44,
|
|
10
10
|
"operationCount": 33,
|
|
11
|
-
"projectionSha256": "
|
|
11
|
+
"projectionSha256": "3052d8fa2bdfcfcc8bca17ba1a5ad5ec39270064ca68760f691b36a9eb2b0ed0",
|
|
12
12
|
"commands": [
|
|
13
13
|
{
|
|
14
14
|
"commandId": "arch-api-contracts",
|
|
@@ -1128,6 +1128,18 @@ export const GENERATED_INVOCATION_SCHEMA_MANIFEST = {
|
|
|
1128
1128
|
],
|
|
1129
1129
|
"terminator": true
|
|
1130
1130
|
},
|
|
1131
|
+
{
|
|
1132
|
+
"commandId": "migrate-project-id",
|
|
1133
|
+
"inputShape": "standalone",
|
|
1134
|
+
"operation": {
|
|
1135
|
+
"required": false,
|
|
1136
|
+
"unknownAsPositional": false,
|
|
1137
|
+
"operations": []
|
|
1138
|
+
},
|
|
1139
|
+
"options": [],
|
|
1140
|
+
"positionals": [],
|
|
1141
|
+
"terminator": true
|
|
1142
|
+
},
|
|
1131
1143
|
{
|
|
1132
1144
|
"commandId": "migrate-state",
|
|
1133
1145
|
"inputShape": "standalone",
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
export * from './input-envelope.js';
|
|
2
|
+
export * from './project-identity-migration.js';
|
|
3
|
+
export * from './state-projection.js';
|
|
4
|
+
export * from './strict-effect-receipt.js';
|
|
5
|
+
export * from './public-diagnostics.js';
|
|
1
6
|
export declare const EXACT_INVOCATION_POLICY: "p205-exact-invocation-v1";
|
|
2
7
|
export declare const INVOCATION_SCHEMA_VERSION: "p205-invocation-schema-v1";
|
|
3
8
|
export declare const INVOCATION_LIMITS: Readonly<{
|
|
@@ -115,7 +120,7 @@ export interface InvocationCommandSchemaV1 {
|
|
|
115
120
|
readonly positionals: readonly InvocationPositionalSchemaV1[];
|
|
116
121
|
readonly terminator: true;
|
|
117
122
|
}
|
|
118
|
-
export declare const INVOCATION_SCHEMA_CHECKSUM: "
|
|
123
|
+
export declare const INVOCATION_SCHEMA_CHECKSUM: "14ea14ebfd79941609426b34690c0fade17034a4b1b166b14d985cb097ee7128";
|
|
119
124
|
export interface InvocationSchemaManifestV1 {
|
|
120
125
|
readonly schemaVersion: typeof INVOCATION_SCHEMA_VERSION;
|
|
121
126
|
readonly registryVersion: string;
|
|
@@ -172,4 +177,3 @@ export interface InvocationDeprecationCountV1 {
|
|
|
172
177
|
}
|
|
173
178
|
/** Count-only migration telemetry; raw input is intentionally not accepted. */
|
|
174
179
|
export declare function createInvocationDeprecationCount(result: RejectedInvocationAdmissionV1): InvocationDeprecationCountV1;
|
|
175
|
-
export {};
|
|
@@ -9,10 +9,18 @@ import { createHash } from 'node:crypto';
|
|
|
9
9
|
import { COMMAND_REGISTRY_CHECKSUM, COMMAND_REGISTRY_VERSION, GENERATED_SHARED_COMMANDS, } from '../generated/command-registry.generated.js';
|
|
10
10
|
import { GENERATED_INVOCATION_SCHEMA_MANIFEST, GENERATED_INVOCATION_SCHEMAS, } from '../generated/invocation-schema.generated.js';
|
|
11
11
|
import { canonicalizeCommandRegistryJcs } from '../command-registry-contract.js';
|
|
12
|
+
export * from './input-envelope.js';
|
|
13
|
+
export * from './project-identity-migration.js';
|
|
14
|
+
export * from './state-projection.js';
|
|
15
|
+
export * from './strict-effect-receipt.js';
|
|
16
|
+
export * from './public-diagnostics.js';
|
|
12
17
|
export const EXACT_INVOCATION_POLICY = 'p205-exact-invocation-v1';
|
|
13
18
|
export const INVOCATION_SCHEMA_VERSION = 'p205-invocation-schema-v1';
|
|
14
19
|
export const INVOCATION_LIMITS = Object.freeze({
|
|
15
|
-
|
|
20
|
+
// Keep exact admission bounded while allowing the client args-file/stdin
|
|
21
|
+
// materialization path to carry requests that exceed the 256 KiB HTTP body
|
|
22
|
+
// once envelope metadata is added.
|
|
23
|
+
inputBytes: 256 * 1024,
|
|
16
24
|
tokens: 512,
|
|
17
25
|
tokenBytes: 16 * 1024,
|
|
18
26
|
briefBytes: 16 * 1024,
|
|
@@ -99,7 +107,9 @@ function bucket(bytes) {
|
|
|
99
107
|
return '1025-4096';
|
|
100
108
|
if (bytes <= 16384)
|
|
101
109
|
return '4097-16384';
|
|
102
|
-
|
|
110
|
+
if (bytes <= 65536)
|
|
111
|
+
return '16385-65536';
|
|
112
|
+
return '65537-262144';
|
|
103
113
|
}
|
|
104
114
|
export function lexInvocationEnvelope(input) {
|
|
105
115
|
const inputBytes = byteLength(input);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export declare const INVOKE_INPUT_ENVELOPE_VERSION: 2;
|
|
2
|
+
export declare const INVOKE_HTTP_BODY_LIMIT_BYTES: number;
|
|
3
|
+
export type InvokeInputSourceV2 = 'args' | 'stdin' | 'args-file';
|
|
4
|
+
export type InvokeNewlineStyleV2 = 'none' | 'lf' | 'crlf' | 'mixed';
|
|
5
|
+
export interface InvokeInputEnvelopeV2 {
|
|
6
|
+
readonly version: typeof INVOKE_INPUT_ENVELOPE_VERSION;
|
|
7
|
+
readonly source: InvokeInputSourceV2;
|
|
8
|
+
readonly rawArgs: string;
|
|
9
|
+
readonly byteLength: number;
|
|
10
|
+
readonly sha256: string;
|
|
11
|
+
readonly newlineStyle: InvokeNewlineStyleV2;
|
|
12
|
+
readonly admissionView: string;
|
|
13
|
+
}
|
|
14
|
+
export declare const INVOKE_INPUT_EVIDENCE_VERSION: 1;
|
|
15
|
+
/** Public-safe transport projection; rawArgs remains the single args field. */
|
|
16
|
+
export interface InvokeInputEvidenceV1 {
|
|
17
|
+
readonly version: typeof INVOKE_INPUT_EVIDENCE_VERSION;
|
|
18
|
+
readonly source: InvokeInputSourceV2;
|
|
19
|
+
readonly byteLength: number;
|
|
20
|
+
readonly sha256: string;
|
|
21
|
+
readonly newlineStyle: InvokeNewlineStyleV2;
|
|
22
|
+
}
|
|
23
|
+
export type InvocationMalformedInputReasonV1 = 'multiple-input-sources' | 'missing-input-value' | 'unexpected-cli-token' | 'invalid-utf8' | 'invalid-control-character' | 'unterminated-quote' | 'input-limit-exceeded';
|
|
24
|
+
export interface InvocationInputDiagnosticV1 {
|
|
25
|
+
readonly code: 'INVOCATION_MALFORMED_INPUT';
|
|
26
|
+
readonly reason: InvocationMalformedInputReasonV1;
|
|
27
|
+
readonly source?: InvokeInputSourceV2;
|
|
28
|
+
readonly byteLength?: number;
|
|
29
|
+
readonly remediation: string;
|
|
30
|
+
}
|
|
31
|
+
export declare function classifyNewlineStyle(value: string): InvokeNewlineStyleV2;
|
|
32
|
+
export declare function isInvokeHttpBodyBelowLimit(byteLength: number): boolean;
|
|
33
|
+
export declare function invokeInputSha256(rawArgs: string): string;
|
|
34
|
+
export declare function createInvokeInputEnvelopeV2(source: InvokeInputSourceV2, rawArgs: string): InvokeInputEnvelopeV2;
|
|
35
|
+
export declare function projectInvokeInputEvidenceV1(envelope: InvokeInputEnvelopeV2): InvokeInputEvidenceV1;
|
|
36
|
+
export declare function assertInvokeInputEvidenceV1(value: unknown, rawArgs?: string): asserts value is InvokeInputEvidenceV1;
|
|
37
|
+
export declare function assertInvokeInputEnvelopeV2(value: unknown): asserts value is InvokeInputEnvelopeV2;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { SHA256_HEX_PATTERN } from './project-identity-migration.js';
|
|
3
|
+
export const INVOKE_INPUT_ENVELOPE_VERSION = 2;
|
|
4
|
+
export const INVOKE_HTTP_BODY_LIMIT_BYTES = 256 * 1024;
|
|
5
|
+
export const INVOKE_INPUT_EVIDENCE_VERSION = 1;
|
|
6
|
+
export function classifyNewlineStyle(value) {
|
|
7
|
+
const withoutCrlf = value.replaceAll('\r\n', '');
|
|
8
|
+
const hasCrlf = withoutCrlf.length !== value.length;
|
|
9
|
+
const hasLf = withoutCrlf.includes('\n');
|
|
10
|
+
const hasBareCr = withoutCrlf.includes('\r');
|
|
11
|
+
if (!hasCrlf && !hasLf && !hasBareCr)
|
|
12
|
+
return 'none';
|
|
13
|
+
if (hasCrlf && !hasLf && !hasBareCr)
|
|
14
|
+
return 'crlf';
|
|
15
|
+
if (!hasCrlf && hasLf && !hasBareCr)
|
|
16
|
+
return 'lf';
|
|
17
|
+
return 'mixed';
|
|
18
|
+
}
|
|
19
|
+
export function isInvokeHttpBodyBelowLimit(byteLength) {
|
|
20
|
+
return Number.isSafeInteger(byteLength) && byteLength >= 0 && byteLength < INVOKE_HTTP_BODY_LIMIT_BYTES;
|
|
21
|
+
}
|
|
22
|
+
export function invokeInputSha256(rawArgs) {
|
|
23
|
+
return createHash('sha256').update(rawArgs, 'utf8').digest('hex');
|
|
24
|
+
}
|
|
25
|
+
export function createInvokeInputEnvelopeV2(source, rawArgs) {
|
|
26
|
+
return Object.freeze({
|
|
27
|
+
version: INVOKE_INPUT_ENVELOPE_VERSION,
|
|
28
|
+
source,
|
|
29
|
+
rawArgs,
|
|
30
|
+
byteLength: Buffer.byteLength(rawArgs, 'utf8'),
|
|
31
|
+
sha256: invokeInputSha256(rawArgs),
|
|
32
|
+
newlineStyle: classifyNewlineStyle(rawArgs),
|
|
33
|
+
admissionView: rawArgs.trim(),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export function projectInvokeInputEvidenceV1(envelope) {
|
|
37
|
+
assertInvokeInputEnvelopeV2(envelope);
|
|
38
|
+
return Object.freeze({
|
|
39
|
+
version: INVOKE_INPUT_EVIDENCE_VERSION,
|
|
40
|
+
source: envelope.source,
|
|
41
|
+
byteLength: envelope.byteLength,
|
|
42
|
+
sha256: envelope.sha256,
|
|
43
|
+
newlineStyle: envelope.newlineStyle,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
export function assertInvokeInputEvidenceV1(value, rawArgs) {
|
|
47
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
48
|
+
throw new Error('INVOKE_INPUT_EVIDENCE_INVALID');
|
|
49
|
+
}
|
|
50
|
+
const candidate = value;
|
|
51
|
+
const expectedKeys = ['byteLength', 'newlineStyle', 'sha256', 'source', 'version'];
|
|
52
|
+
const actualKeys = Object.keys(candidate).sort();
|
|
53
|
+
if (actualKeys.length !== expectedKeys.length
|
|
54
|
+
|| actualKeys.some((key, index) => key !== expectedKeys[index])
|
|
55
|
+
|| candidate.version !== INVOKE_INPUT_EVIDENCE_VERSION
|
|
56
|
+
|| !['args', 'stdin', 'args-file'].includes(String(candidate.source))
|
|
57
|
+
|| !Number.isSafeInteger(candidate.byteLength)
|
|
58
|
+
|| candidate.byteLength < 0
|
|
59
|
+
|| typeof candidate.sha256 !== 'string'
|
|
60
|
+
|| !SHA256_HEX_PATTERN.test(candidate.sha256)
|
|
61
|
+
|| !['none', 'lf', 'crlf', 'mixed'].includes(String(candidate.newlineStyle))) {
|
|
62
|
+
throw new Error('INVOKE_INPUT_EVIDENCE_INVALID');
|
|
63
|
+
}
|
|
64
|
+
if (rawArgs !== undefined
|
|
65
|
+
&& (candidate.byteLength !== Buffer.byteLength(rawArgs, 'utf8')
|
|
66
|
+
|| candidate.sha256 !== invokeInputSha256(rawArgs)
|
|
67
|
+
|| candidate.newlineStyle !== classifyNewlineStyle(rawArgs))) {
|
|
68
|
+
throw new Error('INVOKE_INPUT_EVIDENCE_CONFLICT');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
export function assertInvokeInputEnvelopeV2(value) {
|
|
72
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
73
|
+
throw new Error('INVOKE_INPUT_ENVELOPE_INVALID');
|
|
74
|
+
}
|
|
75
|
+
const candidate = value;
|
|
76
|
+
if (candidate.version !== INVOKE_INPUT_ENVELOPE_VERSION) {
|
|
77
|
+
throw new Error('INVOKE_INPUT_ENVELOPE_VERSION_UNSUPPORTED');
|
|
78
|
+
}
|
|
79
|
+
const expectedKeys = ['admissionView', 'byteLength', 'newlineStyle', 'rawArgs', 'sha256', 'source', 'version'];
|
|
80
|
+
const actualKeys = Object.keys(candidate).sort();
|
|
81
|
+
if (actualKeys.length !== expectedKeys.length
|
|
82
|
+
|| actualKeys.some((key, index) => key !== expectedKeys[index])
|
|
83
|
+
|| !['args', 'stdin', 'args-file'].includes(String(candidate.source))
|
|
84
|
+
|| typeof candidate.rawArgs !== 'string'
|
|
85
|
+
|| !Number.isSafeInteger(candidate.byteLength)
|
|
86
|
+
|| typeof candidate.sha256 !== 'string'
|
|
87
|
+
|| !SHA256_HEX_PATTERN.test(candidate.sha256)
|
|
88
|
+
|| !['none', 'lf', 'crlf', 'mixed'].includes(String(candidate.newlineStyle))
|
|
89
|
+
|| typeof candidate.admissionView !== 'string') {
|
|
90
|
+
throw new Error('INVOKE_INPUT_ENVELOPE_INVALID');
|
|
91
|
+
}
|
|
92
|
+
if (candidate.byteLength !== Buffer.byteLength(candidate.rawArgs, 'utf8')
|
|
93
|
+
|| candidate.sha256 !== invokeInputSha256(candidate.rawArgs)
|
|
94
|
+
|| candidate.newlineStyle !== classifyNewlineStyle(candidate.rawArgs)
|
|
95
|
+
|| candidate.admissionView !== candidate.rawArgs.trim()) {
|
|
96
|
+
throw new Error('INVOKE_INPUT_ENVELOPE_INTEGRITY');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare const PROJECT_IDENTITY_MIGRATION_VERSION: 1;
|
|
2
|
+
export declare const PROJECT_IDENTITY_MIGRATION_CAPABILITY: "project-identity-migration-v1";
|
|
3
|
+
export declare const PROJECT_ID_PATTERN: RegExp;
|
|
4
|
+
export declare const PROJECT_IDENTITY_OPERATION_PATTERN: RegExp;
|
|
5
|
+
export declare const SHA256_HEX_PATTERN: RegExp;
|
|
6
|
+
export declare const MAX_LEGACY_EPIC_FLOOR: number;
|
|
7
|
+
export interface ProjectIdentityMigrationRequestV1 {
|
|
8
|
+
readonly version: typeof PROJECT_IDENTITY_MIGRATION_VERSION;
|
|
9
|
+
readonly operationId: string;
|
|
10
|
+
readonly projectId: string;
|
|
11
|
+
readonly localStateDigest: string;
|
|
12
|
+
readonly legacyEpicFloor: number;
|
|
13
|
+
readonly phase: 'prepare' | 'seed';
|
|
14
|
+
}
|
|
15
|
+
export interface ProjectIdentityMigrationReceiptV1 {
|
|
16
|
+
readonly version: typeof PROJECT_IDENTITY_MIGRATION_VERSION;
|
|
17
|
+
readonly operationId: string;
|
|
18
|
+
readonly projectId: string;
|
|
19
|
+
readonly status: 'seeded' | 'already-seeded';
|
|
20
|
+
readonly acceptedLegacyFloor: number;
|
|
21
|
+
readonly nextEpicNumber: number;
|
|
22
|
+
readonly serverCapability: typeof PROJECT_IDENTITY_MIGRATION_CAPABILITY;
|
|
23
|
+
readonly receiptDigest: string;
|
|
24
|
+
}
|
|
25
|
+
export type ProjectIdentityMigrationReceiptBodyV1 = Omit<ProjectIdentityMigrationReceiptV1, 'receiptDigest'>;
|
|
26
|
+
export declare function computeProjectIdentityMigrationReceiptDigestV1(receipt: ProjectIdentityMigrationReceiptBodyV1): string;
|
|
27
|
+
export declare function assertProjectIdentityMigrationRequestV1(value: unknown): asserts value is ProjectIdentityMigrationRequestV1;
|
|
28
|
+
export declare function assertProjectIdentityMigrationReceiptV1(value: unknown): asserts value is ProjectIdentityMigrationReceiptV1;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export const PROJECT_IDENTITY_MIGRATION_VERSION = 1;
|
|
2
|
+
export const PROJECT_IDENTITY_MIGRATION_CAPABILITY = 'project-identity-migration-v1';
|
|
3
|
+
export const PROJECT_ID_PATTERN = /^prj_[a-f0-9]{32}$/;
|
|
4
|
+
export const PROJECT_IDENTITY_OPERATION_PATTERN = /^mig_[a-f0-9]{32}$/;
|
|
5
|
+
export const SHA256_HEX_PATTERN = /^[a-f0-9]{64}$/;
|
|
6
|
+
export const MAX_LEGACY_EPIC_FLOOR = Number.MAX_SAFE_INTEGER - 1;
|
|
7
|
+
export function computeProjectIdentityMigrationReceiptDigestV1(receipt) {
|
|
8
|
+
const canonicalBody = {
|
|
9
|
+
version: receipt.version,
|
|
10
|
+
operationId: receipt.operationId,
|
|
11
|
+
projectId: receipt.projectId,
|
|
12
|
+
status: receipt.status,
|
|
13
|
+
acceptedLegacyFloor: receipt.acceptedLegacyFloor,
|
|
14
|
+
nextEpicNumber: receipt.nextEpicNumber,
|
|
15
|
+
serverCapability: receipt.serverCapability,
|
|
16
|
+
};
|
|
17
|
+
return createHash('sha256')
|
|
18
|
+
.update(`nx-project-identity-migration-receipt-v1\0${JSON.stringify(canonicalBody)}`, 'utf8')
|
|
19
|
+
.digest('hex');
|
|
20
|
+
}
|
|
21
|
+
function record(value) {
|
|
22
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
23
|
+
? value
|
|
24
|
+
: null;
|
|
25
|
+
}
|
|
26
|
+
function exactKeys(value, expected) {
|
|
27
|
+
const actual = Object.keys(value).sort();
|
|
28
|
+
return actual.length === expected.length && actual.every((key, index) => key === expected[index]);
|
|
29
|
+
}
|
|
30
|
+
function validFloor(value) {
|
|
31
|
+
return Number.isSafeInteger(value) && value >= 0;
|
|
32
|
+
}
|
|
33
|
+
export function assertProjectIdentityMigrationRequestV1(value) {
|
|
34
|
+
const candidate = record(value);
|
|
35
|
+
if (candidate?.version !== PROJECT_IDENTITY_MIGRATION_VERSION) {
|
|
36
|
+
throw new Error('PROJECT_IDENTITY_MIGRATION_VERSION_UNSUPPORTED');
|
|
37
|
+
}
|
|
38
|
+
const keys = ['legacyEpicFloor', 'localStateDigest', 'operationId', 'phase', 'projectId', 'version'];
|
|
39
|
+
if (!exactKeys(candidate, keys)
|
|
40
|
+
|| typeof candidate.operationId !== 'string'
|
|
41
|
+
|| !PROJECT_IDENTITY_OPERATION_PATTERN.test(candidate.operationId)
|
|
42
|
+
|| typeof candidate.projectId !== 'string'
|
|
43
|
+
|| !PROJECT_ID_PATTERN.test(candidate.projectId)
|
|
44
|
+
|| typeof candidate.localStateDigest !== 'string'
|
|
45
|
+
|| !SHA256_HEX_PATTERN.test(candidate.localStateDigest)
|
|
46
|
+
|| (candidate.phase !== 'prepare' && candidate.phase !== 'seed')
|
|
47
|
+
|| !validFloor(candidate.legacyEpicFloor)) {
|
|
48
|
+
throw new Error('PROJECT_IDENTITY_MIGRATION_INVALID');
|
|
49
|
+
}
|
|
50
|
+
if (candidate.legacyEpicFloor > MAX_LEGACY_EPIC_FLOOR) {
|
|
51
|
+
throw new Error('PROJECT_IDENTITY_MIGRATION_FLOOR_LIMIT');
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export function assertProjectIdentityMigrationReceiptV1(value) {
|
|
55
|
+
const candidate = record(value);
|
|
56
|
+
if (candidate?.version !== PROJECT_IDENTITY_MIGRATION_VERSION) {
|
|
57
|
+
throw new Error('PROJECT_IDENTITY_MIGRATION_RECEIPT_VERSION_UNSUPPORTED');
|
|
58
|
+
}
|
|
59
|
+
const keys = [
|
|
60
|
+
'acceptedLegacyFloor', 'nextEpicNumber', 'operationId', 'projectId',
|
|
61
|
+
'receiptDigest', 'serverCapability', 'status', 'version',
|
|
62
|
+
];
|
|
63
|
+
if (!exactKeys(candidate, keys)
|
|
64
|
+
|| typeof candidate.operationId !== 'string'
|
|
65
|
+
|| !PROJECT_IDENTITY_OPERATION_PATTERN.test(candidate.operationId)
|
|
66
|
+
|| typeof candidate.projectId !== 'string'
|
|
67
|
+
|| !PROJECT_ID_PATTERN.test(candidate.projectId)
|
|
68
|
+
|| (candidate.status !== 'seeded' && candidate.status !== 'already-seeded')
|
|
69
|
+
|| !validFloor(candidate.acceptedLegacyFloor)
|
|
70
|
+
|| candidate.acceptedLegacyFloor > MAX_LEGACY_EPIC_FLOOR
|
|
71
|
+
|| !Number.isSafeInteger(candidate.nextEpicNumber)
|
|
72
|
+
|| candidate.nextEpicNumber <= candidate.acceptedLegacyFloor
|
|
73
|
+
|| candidate.serverCapability !== PROJECT_IDENTITY_MIGRATION_CAPABILITY
|
|
74
|
+
|| typeof candidate.receiptDigest !== 'string'
|
|
75
|
+
|| !SHA256_HEX_PATTERN.test(candidate.receiptDigest)) {
|
|
76
|
+
throw new Error('PROJECT_IDENTITY_MIGRATION_RECEIPT_INVALID');
|
|
77
|
+
}
|
|
78
|
+
const receipt = candidate;
|
|
79
|
+
if (receipt.receiptDigest !== computeProjectIdentityMigrationReceiptDigestV1(receipt)) {
|
|
80
|
+
throw new Error('PROJECT_IDENTITY_MIGRATION_RECEIPT_INVALID');
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
import { createHash } from 'node:crypto';
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { InvokeInputEvidenceV1 } from './input-envelope.js';
|
|
2
|
+
import type { InvocationShapeV2 } from './state-projection.js';
|
|
3
|
+
export declare const INVOCATION_PUBLIC_DIAGNOSTIC_VERSION: 1;
|
|
4
|
+
export declare const INVOCATION_DIGEST_PREFIX_LENGTH = 12;
|
|
5
|
+
export type InvocationPublicDiagnosticV1 = {
|
|
6
|
+
readonly version: 1;
|
|
7
|
+
readonly event: 'invoke.input';
|
|
8
|
+
readonly source: InvokeInputEvidenceV1['source'];
|
|
9
|
+
readonly bytesBucket: string;
|
|
10
|
+
readonly newlineStyle: InvokeInputEvidenceV1['newlineStyle'];
|
|
11
|
+
readonly digestPrefix: string;
|
|
12
|
+
readonly outcome: 'accepted' | 'rejected';
|
|
13
|
+
readonly reasonCode?: string;
|
|
14
|
+
readonly publicSafe: true;
|
|
15
|
+
} | {
|
|
16
|
+
readonly version: 1;
|
|
17
|
+
readonly event: 'invoke.projection';
|
|
18
|
+
readonly shape: InvocationShapeV2;
|
|
19
|
+
readonly bytesBucket: string;
|
|
20
|
+
readonly includedEpics: number;
|
|
21
|
+
readonly includedStories: number;
|
|
22
|
+
readonly omittedEpics: number;
|
|
23
|
+
readonly omittedStories: number;
|
|
24
|
+
readonly nodes: number;
|
|
25
|
+
readonly edges: number;
|
|
26
|
+
readonly cycles: number;
|
|
27
|
+
readonly outcome: 'accepted' | 'rejected';
|
|
28
|
+
readonly reasonCode?: string;
|
|
29
|
+
readonly publicSafe: true;
|
|
30
|
+
} | {
|
|
31
|
+
readonly version: 1;
|
|
32
|
+
readonly event: 'invoke.project-identity';
|
|
33
|
+
readonly phase: 'prepare' | 'seed' | 'remote-acknowledged' | 'finalize' | 'reconcile';
|
|
34
|
+
readonly outcome: 'prepared' | 'seeded' | 'already-seeded' | 'finalized' | 'rejected' | 'retry';
|
|
35
|
+
readonly floorBucket: string;
|
|
36
|
+
readonly scopeDigestPrefix: string;
|
|
37
|
+
readonly capability: 'project-identity-migration-v1';
|
|
38
|
+
readonly publicSafe: true;
|
|
39
|
+
} | {
|
|
40
|
+
readonly version: 1;
|
|
41
|
+
readonly event: 'invoke.diagnose';
|
|
42
|
+
readonly authority: 'strict-read-only';
|
|
43
|
+
readonly receiptStatus: 'verified' | 'rejected';
|
|
44
|
+
readonly attemptedEffectCount: number;
|
|
45
|
+
readonly suppressedEffectCount: number;
|
|
46
|
+
readonly publicSafe: true;
|
|
47
|
+
} | {
|
|
48
|
+
readonly version: 1;
|
|
49
|
+
readonly event: 'invoke.trace';
|
|
50
|
+
readonly stages: readonly ('admission' | 'input' | 'shape' | 'projection' | 'size-guard' | 'send')[];
|
|
51
|
+
readonly outcome: 'accepted' | 'rejected';
|
|
52
|
+
readonly reasonCode?: string;
|
|
53
|
+
readonly publicSafe: true;
|
|
54
|
+
};
|
|
55
|
+
export declare function invocationByteBucket(bytes: number): string;
|
|
56
|
+
export declare function invocationFloorBucket(floor: number): string;
|
|
57
|
+
export declare function invocationDigestPrefix(domain: string, value: string): string;
|
|
58
|
+
export declare function buildInputPublicDiagnostic(evidence: InvokeInputEvidenceV1, outcome?: 'accepted' | 'rejected', reasonCode?: string): InvocationPublicDiagnosticV1;
|
|
59
|
+
export declare function buildProjectionPublicDiagnostic(input: {
|
|
60
|
+
readonly shape: InvocationShapeV2;
|
|
61
|
+
readonly bytes: number;
|
|
62
|
+
readonly includedEpics: number;
|
|
63
|
+
readonly includedStories: number;
|
|
64
|
+
readonly omittedEpics: number;
|
|
65
|
+
readonly omittedStories: number;
|
|
66
|
+
readonly nodes?: number;
|
|
67
|
+
readonly edges?: number;
|
|
68
|
+
readonly cycles?: number;
|
|
69
|
+
readonly outcome?: 'accepted' | 'rejected';
|
|
70
|
+
readonly reasonCode?: string;
|
|
71
|
+
}): InvocationPublicDiagnosticV1;
|
|
72
|
+
export declare function buildProjectIdentityPublicDiagnostic(input: {
|
|
73
|
+
readonly phase: Extract<InvocationPublicDiagnosticV1, {
|
|
74
|
+
event: 'invoke.project-identity';
|
|
75
|
+
}>['phase'];
|
|
76
|
+
readonly outcome: Extract<InvocationPublicDiagnosticV1, {
|
|
77
|
+
event: 'invoke.project-identity';
|
|
78
|
+
}>['outcome'];
|
|
79
|
+
readonly floor: number;
|
|
80
|
+
readonly licenseId: string;
|
|
81
|
+
readonly projectId: string;
|
|
82
|
+
}): InvocationPublicDiagnosticV1;
|
|
83
|
+
export declare function buildDiagnosePublicDiagnostic(receiptStatus: 'verified' | 'rejected', attemptedEffectCount: number, suppressedEffectCount: number): InvocationPublicDiagnosticV1;
|
|
84
|
+
export declare function buildInvokeTracePublicDiagnostic(stages: Extract<InvocationPublicDiagnosticV1, {
|
|
85
|
+
event: 'invoke.trace';
|
|
86
|
+
}>['stages'], outcome: 'accepted' | 'rejected', reasonCode?: string): InvocationPublicDiagnosticV1;
|
|
87
|
+
export declare function assertInvocationPublicDiagnosticV1(value: unknown): asserts value is InvocationPublicDiagnosticV1;
|