@empire-builder-kit/nx 1.0.0-rc.41 → 1.0.0-rc.43
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/package.json +5 -5
- package/src/cli/agent-runtime.js +11 -1
- package/src/cli/deploy-runtime.d.ts +9 -1
- package/src/developer-agent/context.d.ts +30 -0
- package/src/developer-agent/context.js +142 -9
- package/src/developer-agent/handoff.js +20 -5
- package/src/developer-agent/model.d.ts +10 -0
- package/src/developer-agent/operation-registry.js +5 -3
- package/src/developer-agent/planning.js +8 -0
- package/src/developer-agent/validation.d.ts +13 -1
- package/src/developer-agent/validation.js +98 -6
- package/src/executors/developer-context/developer-context.js +4 -4
- package/src/generators/preset/workspace-files-adopter-skills.js +11 -1
- package/src/generators/preset/workspace-files-developer-agent.js +13 -4
- package/src/generators/preset/workspace-files.js +1 -1
- package/src/generators/slice/built-in-plan-shared.d.ts +2 -2
- package/src/generators/slice/built-in-plan-shared.js +2 -2
- package/src/git-policy/action-pins.d.ts +2 -2
- package/src/git-policy/action-pins.js +2 -2
- package/src/local-dev/fleet-client.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@empire-builder-kit/nx",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.43",
|
|
4
4
|
"description": "Nx generators, executors, and Blueprint contracts for Empire Builder Kit",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"aws",
|
|
@@ -145,12 +145,12 @@
|
|
|
145
145
|
"provenance": false
|
|
146
146
|
},
|
|
147
147
|
"dependencies": {
|
|
148
|
-
"@empire-builder-kit/runtime": "1.0.0-rc.
|
|
148
|
+
"@empire-builder-kit/runtime": "1.0.0-rc.43",
|
|
149
149
|
"@aws-sdk/client-cloudfront": "^3.700.0",
|
|
150
150
|
"@aws-sdk/client-cloudwatch": "^3.700.0",
|
|
151
151
|
"@aws-sdk/client-cloudwatch-logs": "^3.700.0",
|
|
152
152
|
"@aws-sdk/client-iam": "^3.700.0",
|
|
153
|
-
"@nx/devkit": "23.1
|
|
153
|
+
"@nx/devkit": "23.2.1",
|
|
154
154
|
"@aws-sdk/client-rds": "^3.700.0",
|
|
155
155
|
"@aws-sdk/client-s3": "^3.700.0",
|
|
156
156
|
"@aws-sdk/client-secrets-manager": "^3.700.0",
|
|
@@ -159,7 +159,7 @@
|
|
|
159
159
|
"@aws-sdk/client-wafv2": "^3.700.0",
|
|
160
160
|
"@aws-sdk/credential-providers": "^3.700.0",
|
|
161
161
|
"ajv": "8.20.0",
|
|
162
|
-
"nx": "23.1
|
|
162
|
+
"nx": "23.2.1",
|
|
163
163
|
"prettier": "^3.8.2",
|
|
164
164
|
"semver": "7.7.4",
|
|
165
165
|
"tslib": "^2.3.0",
|
|
@@ -178,5 +178,5 @@
|
|
|
178
178
|
"engines": {
|
|
179
179
|
"node": ">=22.13.0"
|
|
180
180
|
},
|
|
181
|
-
"gitHead": "
|
|
181
|
+
"gitHead": "7703b131fbcd59bc364ce7f914a1ff22250378c9"
|
|
182
182
|
}
|
package/src/cli/agent-runtime.js
CHANGED
|
@@ -259,7 +259,11 @@ async function executeDeveloperAgentCommand(command, workspaceRoot, overrides =
|
|
|
259
259
|
...overrides,
|
|
260
260
|
};
|
|
261
261
|
if (command.command === 'context') {
|
|
262
|
-
const
|
|
262
|
+
const inspected = await dependencies.inspectContext(workspaceRoot, command.query);
|
|
263
|
+
// The context leaves the process here, so this is where the transport
|
|
264
|
+
// byte bound applies; plan, upgrade preview and resume keep the complete
|
|
265
|
+
// in-process context.
|
|
266
|
+
const { context } = (0, context_js_1.serializeDeveloperAgentContextForTransport)(inspected);
|
|
263
267
|
const blockingClassification = model_js_1.DEVELOPER_AGENT_CONTEXT_BLOCKING_FAILURES.find((classification) => context.warnings.some((warning) => warning.classification === classification));
|
|
264
268
|
return {
|
|
265
269
|
human: (0, context_js_1.formatDeveloperAgentContext)(context),
|
|
@@ -446,6 +450,12 @@ async function executeDeveloperAgentCommand(command, workspaceRoot, overrides =
|
|
|
446
450
|
};
|
|
447
451
|
}
|
|
448
452
|
function classifyDeveloperAgentCliError(error) {
|
|
453
|
+
// Must precede the generic DeveloperAgentContextError branch, which would
|
|
454
|
+
// redact this tool-internal-error message. The bound message carries only
|
|
455
|
+
// counts, byte sizes and the selection remedy.
|
|
456
|
+
if (error instanceof context_js_1.DeveloperAgentContextBoundError) {
|
|
457
|
+
return { classification: error.classification, message: error.message };
|
|
458
|
+
}
|
|
449
459
|
if (error instanceof DeveloperAgentCliError ||
|
|
450
460
|
error instanceof context_js_1.DeveloperAgentContextError ||
|
|
451
461
|
error instanceof handoff_js_1.DeveloperAgentHandoffError ||
|
|
@@ -9,7 +9,15 @@ export interface DeployResultProject {
|
|
|
9
9
|
}
|
|
10
10
|
/** The development-only `--json` result: the executor's own written receipt
|
|
11
11
|
* (already secret-free evidence) and per-project status. It is printed after
|
|
12
|
-
* the run and carries no authority; protected stages never produce it.
|
|
12
|
+
* the run and carries no authority; protected stages never produce it.
|
|
13
|
+
*
|
|
14
|
+
* `outcome` and `exitCode` are two independent facts and are never
|
|
15
|
+
* reconciled. `outcome` is the verdict of this run's fresh receipt (or
|
|
16
|
+
* `receipt-unavailable`); `exitCode` is the lifecycle process's own exit
|
|
17
|
+
* status, 128 plus the signal number when it was signalled, and is also the
|
|
18
|
+
* command's exit status. They can disagree, for example when the process is
|
|
19
|
+
* interrupted after the executor wrote a `succeeded` receipt. Success
|
|
20
|
+
* requires both `exitCode` 0 and `outcome` `succeeded`. */
|
|
13
21
|
export interface DeployJsonResult {
|
|
14
22
|
exitCode: number;
|
|
15
23
|
kind: typeof DEPLOY_RESULT_KIND;
|
|
@@ -22,6 +22,36 @@ export declare class DeveloperAgentContextError extends Error {
|
|
|
22
22
|
readonly classification: DeveloperAgentFailureClassification;
|
|
23
23
|
constructor(classification: DeveloperAgentFailureClassification, message: string);
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* The framework produced a context larger than its fixed transport bound even
|
|
27
|
+
* after bounding the concurrent-change list. This is not a missing local
|
|
28
|
+
* prerequisite and not caller input: the message carries only counts and
|
|
29
|
+
* byte sizes (never paths) plus the selection remedy, so the CLI may pass it
|
|
30
|
+
* through instead of the generic internal-failure text.
|
|
31
|
+
*/
|
|
32
|
+
export declare class DeveloperAgentContextBoundError extends DeveloperAgentContextError {
|
|
33
|
+
constructor(message: string);
|
|
34
|
+
}
|
|
25
35
|
export declare function resolveAffectedProjectsWithNx(workspaceRoot: string, baseCommit: string, headCommit: string): Promise<readonly string[]>;
|
|
26
36
|
export declare function inspectDeveloperAgentContext(cwd: string, query?: DeveloperAgentContextQuery, dependencyOverrides?: Partial<DeveloperAgentContextDependencies>): Promise<DeveloperAgentContext>;
|
|
37
|
+
/**
|
|
38
|
+
* Projects the complete in-process context into its emitted form. When the
|
|
39
|
+
* complete context fits the transport bound it is emitted unchanged apart
|
|
40
|
+
* from the summary fields. Otherwise concurrent changes inside the
|
|
41
|
+
* selection's coverage are retained first, then the rest, filling the byte
|
|
42
|
+
* budget exactly; the retained subset stays in canonical order and the
|
|
43
|
+
* count, digest and truncation flag describe the complete list. A context
|
|
44
|
+
* that cannot fit even with every concurrent change omitted raises
|
|
45
|
+
* DeveloperAgentContextBoundError.
|
|
46
|
+
*/
|
|
47
|
+
export declare function projectDeveloperAgentContextForTransport(context: DeveloperAgentContext): DeveloperAgentContext;
|
|
48
|
+
/**
|
|
49
|
+
* The single emit-point serializer: projects, then serializes under the
|
|
50
|
+
* transport bound. Every emitted context (CLI JSON payload and executor
|
|
51
|
+
* fingerprint) goes through here.
|
|
52
|
+
*/
|
|
53
|
+
export declare function serializeDeveloperAgentContextForTransport(context: DeveloperAgentContext): {
|
|
54
|
+
context: DeveloperAgentContext;
|
|
55
|
+
serialized: string;
|
|
56
|
+
};
|
|
27
57
|
export declare function formatDeveloperAgentContext(context: DeveloperAgentContext): string;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DeveloperAgentContextError = exports.DEVELOPER_AGENT_CONTEXT_HUMAN_MAX_BYTES = void 0;
|
|
3
|
+
exports.DeveloperAgentContextBoundError = exports.DeveloperAgentContextError = exports.DEVELOPER_AGENT_CONTEXT_HUMAN_MAX_BYTES = void 0;
|
|
4
4
|
exports.resolveAffectedProjectsWithNx = resolveAffectedProjectsWithNx;
|
|
5
5
|
exports.inspectDeveloperAgentContext = inspectDeveloperAgentContext;
|
|
6
|
+
exports.projectDeveloperAgentContextForTransport = projectDeveloperAgentContextForTransport;
|
|
7
|
+
exports.serializeDeveloperAgentContextForTransport = serializeDeveloperAgentContextForTransport;
|
|
6
8
|
exports.formatDeveloperAgentContext = formatDeveloperAgentContext;
|
|
7
9
|
const devkit_1 = require("@nx/devkit");
|
|
8
10
|
const node_child_process_1 = require("node:child_process");
|
|
@@ -10,11 +12,13 @@ const node_crypto_1 = require("node:crypto");
|
|
|
10
12
|
const node_fs_1 = require("node:fs");
|
|
11
13
|
const node_path_1 = require("node:path");
|
|
12
14
|
const node_util_1 = require("node:util");
|
|
15
|
+
const canonical_json_1 = require("@empire-builder-kit/runtime/canonical-json");
|
|
13
16
|
const nx_workspace_js_1 = require("../local-dev/nx-workspace.js");
|
|
14
17
|
const resolver_js_1 = require("../blueprints/resolver.js");
|
|
15
18
|
const blueprint_trust_git_js_1 = require("../supply-chain/blueprint-trust-git.js");
|
|
16
19
|
const blueprint_verification_authority_js_1 = require("../supply-chain/blueprint-verification-authority.js");
|
|
17
20
|
const git_inspection_js_1 = require("./git-inspection.js");
|
|
21
|
+
const model_js_1 = require("./model.js");
|
|
18
22
|
const ordering_js_1 = require("./ordering.js");
|
|
19
23
|
const validation_js_1 = require("./validation.js");
|
|
20
24
|
const workspace_inspection_js_1 = require("./workspace-inspection.js");
|
|
@@ -43,6 +47,20 @@ class DeveloperAgentContextError extends Error {
|
|
|
43
47
|
}
|
|
44
48
|
}
|
|
45
49
|
exports.DeveloperAgentContextError = DeveloperAgentContextError;
|
|
50
|
+
/**
|
|
51
|
+
* The framework produced a context larger than its fixed transport bound even
|
|
52
|
+
* after bounding the concurrent-change list. This is not a missing local
|
|
53
|
+
* prerequisite and not caller input: the message carries only counts and
|
|
54
|
+
* byte sizes (never paths) plus the selection remedy, so the CLI may pass it
|
|
55
|
+
* through instead of the generic internal-failure text.
|
|
56
|
+
*/
|
|
57
|
+
class DeveloperAgentContextBoundError extends DeveloperAgentContextError {
|
|
58
|
+
constructor(message) {
|
|
59
|
+
super('tool-internal-error', message);
|
|
60
|
+
this.name = 'DeveloperAgentContextBoundError';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.DeveloperAgentContextBoundError = DeveloperAgentContextBoundError;
|
|
46
64
|
function contained(root, path) {
|
|
47
65
|
const fromRoot = (0, node_path_1.relative)(root, path);
|
|
48
66
|
return (fromRoot === '' ||
|
|
@@ -178,10 +196,24 @@ async function resolveAffectedProjectsWithNx(workspaceRoot, baseCommit, headComm
|
|
|
178
196
|
return fail('prerequisite-missing', 'Workspace-pinned Nx affected inspection failed for the exact base/head pair.');
|
|
179
197
|
}
|
|
180
198
|
}
|
|
199
|
+
function concurrentChangeSummary(concurrentChanges) {
|
|
200
|
+
return {
|
|
201
|
+
concurrentChangeCount: concurrentChanges.length,
|
|
202
|
+
concurrentChangesDigest: `sha256:${(0, node_crypto_1.createHash)('sha256')
|
|
203
|
+
.update((0, canonical_json_1.canonicalJson)(concurrentChanges), 'utf8')
|
|
204
|
+
.digest('hex')}`,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
181
207
|
function gitContext(inspection) {
|
|
182
208
|
if (!inspection.defaultBase) {
|
|
183
209
|
return fail('tool-internal-error', 'Git inspection omitted the workspace default-base binding.');
|
|
184
210
|
}
|
|
211
|
+
const concurrentChanges = inspection.concurrentChanges.map(({ committed, dirty, path, worktreeRoots }) => ({
|
|
212
|
+
committed,
|
|
213
|
+
dirty,
|
|
214
|
+
path,
|
|
215
|
+
worktreeCount: worktreeRoots.length,
|
|
216
|
+
}));
|
|
185
217
|
return {
|
|
186
218
|
ahead: inspection.worktree.upstream?.ahead ?? 0,
|
|
187
219
|
...(inspection.comparison
|
|
@@ -192,13 +224,10 @@ function gitContext(inspection) {
|
|
|
192
224
|
? { branch: inspection.worktree.branch }
|
|
193
225
|
: {}),
|
|
194
226
|
commit: inspection.worktree.commit,
|
|
227
|
+
...concurrentChangeSummary(concurrentChanges),
|
|
195
228
|
concurrentChangeInspectionComplete: inspection.concurrentChangeInspectionComplete,
|
|
196
|
-
concurrentChanges
|
|
197
|
-
|
|
198
|
-
dirty,
|
|
199
|
-
path,
|
|
200
|
-
worktreeCount: worktreeRoots.length,
|
|
201
|
-
})),
|
|
229
|
+
concurrentChanges,
|
|
230
|
+
concurrentChangesTruncated: false,
|
|
202
231
|
defaultBaseCommit: inspection.defaultBase.commit,
|
|
203
232
|
defaultBaseRef: inspection.defaultBase.ref,
|
|
204
233
|
dirty: inspection.worktree.dirtyPaths.length > 0,
|
|
@@ -308,6 +337,12 @@ function boundedAffectedFiles(paths) {
|
|
|
308
337
|
function classifyWorkspaceFailure(error) {
|
|
309
338
|
if (error instanceof DeveloperAgentContextError)
|
|
310
339
|
throw error;
|
|
340
|
+
if (error instanceof validation_js_1.DeveloperAgentContractValidationError) {
|
|
341
|
+
// The framework assembled a context that breaks its own contract. That is
|
|
342
|
+
// neither caller input nor a missing local prerequisite, so it must not
|
|
343
|
+
// reach the message-pattern classification below.
|
|
344
|
+
return fail('tool-internal-error', INTERNAL_CONTEXT_FAILURE_MESSAGE);
|
|
345
|
+
}
|
|
311
346
|
const message = error instanceof Error ? error.message : String(error);
|
|
312
347
|
if (/policy/i.test(message)) {
|
|
313
348
|
return fail('policy-conflict', 'Developer-Agent workspace policy inspection reported a conflict.');
|
|
@@ -445,13 +480,111 @@ async function inspectDeveloperAgentContext(cwd, query = {}, dependencyOverrides
|
|
|
445
480
|
? 'dirty-worktree'
|
|
446
481
|
: 'stale-base', 'Git state changed while Developer-Agent context was inspected.');
|
|
447
482
|
}
|
|
448
|
-
|
|
449
|
-
|
|
483
|
+
// Structure only: the transport byte bound applies where the context
|
|
484
|
+
// leaves the process (serializeDeveloperAgentContextForTransport), so
|
|
485
|
+
// plan, upgrade preview and handoff resume keep every inspected fact.
|
|
486
|
+
return (0, validation_js_1.assertDeveloperAgentContextStructure)(result);
|
|
450
487
|
}
|
|
451
488
|
catch (error) {
|
|
452
489
|
return classifyWorkspaceFailure(error);
|
|
453
490
|
}
|
|
454
491
|
}
|
|
492
|
+
function canonicalByteLength(value) {
|
|
493
|
+
return Buffer.byteLength((0, canonical_json_1.canonicalJson)(value), 'utf8');
|
|
494
|
+
}
|
|
495
|
+
function withConcurrentChanges(context, concurrentChanges, complete, truncated) {
|
|
496
|
+
return {
|
|
497
|
+
...context,
|
|
498
|
+
git: {
|
|
499
|
+
...context.git,
|
|
500
|
+
...concurrentChangeSummary(complete),
|
|
501
|
+
concurrentChanges,
|
|
502
|
+
concurrentChangesTruncated: truncated,
|
|
503
|
+
},
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Paths most relevant to the selection: anything under a selected project's
|
|
508
|
+
* root, root-level files, and the workspace `.ebk/` directory. A project
|
|
509
|
+
* rooted at the workspace root contributes only those root-level paths rather
|
|
510
|
+
* than the whole tree.
|
|
511
|
+
*/
|
|
512
|
+
function concurrentChangeCoverage(context) {
|
|
513
|
+
const prefixes = context.projects
|
|
514
|
+
.map(({ root }) => root.replace(/\/+$/, ''))
|
|
515
|
+
.filter((root) => root !== '' && root !== '.')
|
|
516
|
+
.map((root) => `${root}/`);
|
|
517
|
+
return (path) => !path.includes('/') ||
|
|
518
|
+
path.startsWith('.ebk/') ||
|
|
519
|
+
prefixes.some((prefix) => path.startsWith(prefix));
|
|
520
|
+
}
|
|
521
|
+
function contextBoundError(context, projectedBytes, retainedConcurrentChanges) {
|
|
522
|
+
const complete = context.git.concurrentChanges;
|
|
523
|
+
return new DeveloperAgentContextBoundError(`Developer-Agent context exceeds its ${model_js_1.DEVELOPER_AGENT_CONTEXT_MAX_BYTES}-byte transport bound: it needs ${projectedBytes} canonical bytes with ${retainedConcurrentChanges} of ${complete.length} concurrent change(s) retained (${canonicalByteLength(complete)} bytes complete); ${context.supportedOperations.length} supported operation(s) use ${canonicalByteLength(context.supportedOperations)} bytes. Narrow the selection with --projects=<slice[,slice]>.`);
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Projects the complete in-process context into its emitted form. When the
|
|
527
|
+
* complete context fits the transport bound it is emitted unchanged apart
|
|
528
|
+
* from the summary fields. Otherwise concurrent changes inside the
|
|
529
|
+
* selection's coverage are retained first, then the rest, filling the byte
|
|
530
|
+
* budget exactly; the retained subset stays in canonical order and the
|
|
531
|
+
* count, digest and truncation flag describe the complete list. A context
|
|
532
|
+
* that cannot fit even with every concurrent change omitted raises
|
|
533
|
+
* DeveloperAgentContextBoundError.
|
|
534
|
+
*/
|
|
535
|
+
function projectDeveloperAgentContextForTransport(context) {
|
|
536
|
+
const complete = context.git.concurrentChanges;
|
|
537
|
+
const untruncated = withConcurrentChanges(context, complete, complete, false);
|
|
538
|
+
if (canonicalByteLength(untruncated) <= model_js_1.DEVELOPER_AGENT_CONTEXT_MAX_BYTES) {
|
|
539
|
+
return untruncated;
|
|
540
|
+
}
|
|
541
|
+
// Measure the empty projection with the longer `false` literal so that a
|
|
542
|
+
// budget which admits every entry is impossible here: the complete list
|
|
543
|
+
// was already shown not to fit, so the emitted flag is always honest.
|
|
544
|
+
const minimumBytes = canonicalByteLength(withConcurrentChanges(context, [], complete, false));
|
|
545
|
+
if (minimumBytes > model_js_1.DEVELOPER_AGENT_CONTEXT_MAX_BYTES) {
|
|
546
|
+
throw contextBoundError(context, minimumBytes, 0);
|
|
547
|
+
}
|
|
548
|
+
const covered = concurrentChangeCoverage(context);
|
|
549
|
+
const prioritized = [
|
|
550
|
+
...complete.filter(({ path }) => covered(path)),
|
|
551
|
+
...complete.filter(({ path }) => !covered(path)),
|
|
552
|
+
];
|
|
553
|
+
const retained = new Set();
|
|
554
|
+
let remaining = model_js_1.DEVELOPER_AGENT_CONTEXT_MAX_BYTES - minimumBytes;
|
|
555
|
+
for (const entry of prioritized) {
|
|
556
|
+
const cost = canonicalByteLength(entry) + (retained.size > 0 ? 1 : 0);
|
|
557
|
+
if (cost > remaining)
|
|
558
|
+
break;
|
|
559
|
+
remaining -= cost;
|
|
560
|
+
retained.add(entry);
|
|
561
|
+
}
|
|
562
|
+
return withConcurrentChanges(context, complete.filter((entry) => retained.has(entry)), complete, true);
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* The single emit-point serializer: projects, then serializes under the
|
|
566
|
+
* transport bound. Every emitted context (CLI JSON payload and executor
|
|
567
|
+
* fingerprint) goes through here.
|
|
568
|
+
*/
|
|
569
|
+
function serializeDeveloperAgentContextForTransport(context) {
|
|
570
|
+
const projected = projectDeveloperAgentContextForTransport(context);
|
|
571
|
+
try {
|
|
572
|
+
return {
|
|
573
|
+
context: projected,
|
|
574
|
+
serialized: (0, validation_js_1.serializeDeveloperAgentContext)(projected),
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
catch (error) {
|
|
578
|
+
if (error instanceof validation_js_1.DeveloperAgentContractValidationError) {
|
|
579
|
+
if (error.issues.length > 0 &&
|
|
580
|
+
error.issues.every(({ message, path }) => path === '$' && message.startsWith('must serialize to at most'))) {
|
|
581
|
+
throw contextBoundError(context, canonicalByteLength(projected), projected.git.concurrentChanges.length);
|
|
582
|
+
}
|
|
583
|
+
return fail('tool-internal-error', INTERNAL_CONTEXT_FAILURE_MESSAGE);
|
|
584
|
+
}
|
|
585
|
+
throw error;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
455
588
|
function formatDeveloperAgentContext(context) {
|
|
456
589
|
const branch = context.git.branch ?? '(detached)';
|
|
457
590
|
const selection = context.selection.slice
|
|
@@ -207,6 +207,19 @@ function inspectRetainedEvidence(workspaceRoot, handoff) {
|
|
|
207
207
|
function invalidInput(message) {
|
|
208
208
|
throw new DeveloperAgentHandoffError('invalid-input', message);
|
|
209
209
|
}
|
|
210
|
+
/** Issue paths named in one invalid-handoff message; the rest are counted. */
|
|
211
|
+
const MAX_REPORTED_HANDOFF_ISSUE_PATHS = 16;
|
|
212
|
+
/**
|
|
213
|
+
* Names every distinct validation issue path, sorted and bounded, so one
|
|
214
|
+
* attempt surfaces all refusals. Paths carry only fixed property names and
|
|
215
|
+
* array indexes (unknown properties are reported as `.*`), never values.
|
|
216
|
+
*/
|
|
217
|
+
function invalidHandoff(issues) {
|
|
218
|
+
const paths = [...new Set(issues.map(({ path }) => path))].sort(ordering_js_1.compareDeveloperAgentStrings);
|
|
219
|
+
const reported = paths.slice(0, MAX_REPORTED_HANDOFF_ISSUE_PATHS);
|
|
220
|
+
const omitted = paths.length - reported.length;
|
|
221
|
+
return invalidInput(`Retained Developer-Agent handoff is invalid at ${reported.length > 0 ? reported.join(', ') : '$'}${omitted > 0 ? ` and ${omitted} more issue paths` : ''}.`);
|
|
222
|
+
}
|
|
210
223
|
function compareStrings(left, right) {
|
|
211
224
|
if (left.length !== right.length)
|
|
212
225
|
return false;
|
|
@@ -331,8 +344,7 @@ function parseDeveloperAgentHandoff(serialized) {
|
|
|
331
344
|
}
|
|
332
345
|
const validation = (0, validation_js_1.validateDeveloperAgentHandoff)(value);
|
|
333
346
|
if (!validation.valid) {
|
|
334
|
-
|
|
335
|
-
return invalidInput(`Retained Developer-Agent handoff is invalid at ${firstPath}.`);
|
|
347
|
+
return invalidHandoff(validation.issues);
|
|
336
348
|
}
|
|
337
349
|
const handoff = validation.value;
|
|
338
350
|
const sentinelPath = /^(?:0{40}|0{64})$/.test(handoff.repository.baseCommit)
|
|
@@ -368,10 +380,13 @@ function parseDeveloperAgentHandoff(serialized) {
|
|
|
368
380
|
function assessDeveloperAgentHandoffResumeInternal(handoff, current, evidenceInspection) {
|
|
369
381
|
const validation = (0, validation_js_1.validateDeveloperAgentHandoff)(handoff);
|
|
370
382
|
if (!validation.valid) {
|
|
371
|
-
|
|
372
|
-
return invalidInput(`Retained Developer-Agent handoff is invalid at ${firstPath}.`);
|
|
383
|
+
return invalidHandoff(validation.issues);
|
|
373
384
|
}
|
|
374
|
-
|
|
385
|
+
// Resume consumes the in-process context and never emits it, so only its
|
|
386
|
+
// structure is checked; the transport byte bound applies at emit points.
|
|
387
|
+
const contextValidation = (0, validation_js_1.validateDeveloperAgentContext)(current, {
|
|
388
|
+
transportBound: false,
|
|
389
|
+
});
|
|
375
390
|
if (!contextValidation.valid) {
|
|
376
391
|
return createAssessment(validation.value, [
|
|
377
392
|
{
|
|
@@ -161,8 +161,18 @@ export interface DeveloperAgentGitContext {
|
|
|
161
161
|
branch?: string;
|
|
162
162
|
/** Null means a verified unborn symbolic branch, never a placeholder SHA. */
|
|
163
163
|
commit: string | null;
|
|
164
|
+
/** Number of entries in the complete inspected concurrent-change list. */
|
|
165
|
+
concurrentChangeCount?: number;
|
|
164
166
|
concurrentChangeInspectionComplete: boolean;
|
|
167
|
+
/**
|
|
168
|
+
* The in-process context carries every inspected entry. An emitted context
|
|
169
|
+
* may carry a byte-bounded subset; count, digest and truncation then
|
|
170
|
+
* describe the complete list.
|
|
171
|
+
*/
|
|
165
172
|
concurrentChanges: readonly DeveloperAgentConcurrentChangeContext[];
|
|
173
|
+
/** SHA-256 of the canonical JSON of the complete concurrent-change list. */
|
|
174
|
+
concurrentChangesDigest?: string;
|
|
175
|
+
concurrentChangesTruncated?: boolean;
|
|
166
176
|
/** An implicit base may be absent during local first-use orientation. */
|
|
167
177
|
defaultBaseCommit: string | null;
|
|
168
178
|
defaultBaseRef: string;
|
|
@@ -603,9 +603,11 @@ const TARGET_RULES = [
|
|
|
603
603
|
matches: exact('github-bootstrap', 'secret-initialize'),
|
|
604
604
|
requiredVerification: ['source', 'protected-proof'],
|
|
605
605
|
},
|
|
606
|
-
// Report-first plans
|
|
607
|
-
//
|
|
608
|
-
//
|
|
606
|
+
// Report-first plans and collectors read and propose only. Deployed
|
|
607
|
+
// verification (smoke-deployed) is bounded synthetic verification that
|
|
608
|
+
// creates and deletes synthetic users and data. Staging and production
|
|
609
|
+
// reach stays bounded by the deployment role, not by a plan-time approval
|
|
610
|
+
// point.
|
|
609
611
|
{
|
|
610
612
|
approvalRequired: false,
|
|
611
613
|
authority: 'protected-propose',
|
|
@@ -144,6 +144,14 @@ function concurrentPathBlockers(context, plannedPaths, readOnly) {
|
|
|
144
144
|
sanitizedSummary: 'Committed-path inspection for another linked worktree is incomplete, so mutation planning cannot exclude an overlap.',
|
|
145
145
|
});
|
|
146
146
|
}
|
|
147
|
+
if (context.git.concurrentChangesTruncated === true) {
|
|
148
|
+
// Planning consumes the complete in-process context. A byte-bounded
|
|
149
|
+
// emitted projection cannot exclude an overlap, so it fails closed.
|
|
150
|
+
blockers.push({
|
|
151
|
+
classification: 'stale-base',
|
|
152
|
+
sanitizedSummary: 'The concurrent-change list is a truncated transport projection, so mutation planning cannot exclude an overlap.',
|
|
153
|
+
});
|
|
154
|
+
}
|
|
147
155
|
const plannedKeys = new Set(plannedPaths.map((path) => path.normalize('NFC').toLocaleLowerCase('en-US')));
|
|
148
156
|
const overlaps = (context.git.concurrentChanges ?? []).filter(({ path }) => plannedKeys.has(path.normalize('NFC').toLocaleLowerCase('en-US')));
|
|
149
157
|
if (overlaps.length > 0) {
|
|
@@ -4,13 +4,25 @@ export declare class DeveloperAgentContractValidationError extends Error {
|
|
|
4
4
|
readonly issues: readonly ValidationIssue[];
|
|
5
5
|
constructor(label: string, issues: readonly ValidationIssue[]);
|
|
6
6
|
}
|
|
7
|
-
export
|
|
7
|
+
export interface DeveloperAgentContextValidationOptions {
|
|
8
|
+
/**
|
|
9
|
+
* The byte bound applies where a context leaves the process (the context
|
|
10
|
+
* CLI JSON payload and the developer-context executor). The in-process
|
|
11
|
+
* context that planning, upgrade preview and handoff resume consume keeps
|
|
12
|
+
* every inspected fact and is validated for structure only.
|
|
13
|
+
*/
|
|
14
|
+
transportBound?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function validateDeveloperAgentContext(value: unknown, options?: DeveloperAgentContextValidationOptions): ValidationResult<DeveloperAgentContext>;
|
|
8
17
|
export declare function validateDeveloperAgentGeneratorPreview(value: unknown): ValidationResult<DeveloperAgentGeneratorPreview>;
|
|
9
18
|
export declare function validateDeveloperAgentGeneratorPreviewReceipt(value: unknown): ValidationResult<DeveloperAgentGeneratorPreviewReceipt>;
|
|
10
19
|
export declare function validateDeveloperAgentPlan(value: unknown): ValidationResult<DeveloperAgentPlan>;
|
|
11
20
|
export declare function validateDeveloperAgentResult(value: unknown): ValidationResult<DeveloperAgentResult>;
|
|
12
21
|
export declare function validateDeveloperAgentHandoff(value: unknown): ValidationResult<DeveloperAgentHandoff>;
|
|
22
|
+
/** Serializes an emitted context and enforces its transport byte bound. */
|
|
13
23
|
export declare function serializeDeveloperAgentContext(value: unknown): string;
|
|
24
|
+
/** Validates the in-process context for structure only and returns it. */
|
|
25
|
+
export declare function assertDeveloperAgentContextStructure(value: unknown): DeveloperAgentContext;
|
|
14
26
|
export declare function serializeDeveloperAgentGeneratorPreview(value: unknown): string;
|
|
15
27
|
export declare function serializeDeveloperAgentGeneratorPreviewReceipt(value: unknown): string;
|
|
16
28
|
export declare function serializeDeveloperAgentPlan(value: unknown): string;
|
|
@@ -8,6 +8,7 @@ exports.validateDeveloperAgentPlan = validateDeveloperAgentPlan;
|
|
|
8
8
|
exports.validateDeveloperAgentResult = validateDeveloperAgentResult;
|
|
9
9
|
exports.validateDeveloperAgentHandoff = validateDeveloperAgentHandoff;
|
|
10
10
|
exports.serializeDeveloperAgentContext = serializeDeveloperAgentContext;
|
|
11
|
+
exports.assertDeveloperAgentContextStructure = assertDeveloperAgentContextStructure;
|
|
11
12
|
exports.serializeDeveloperAgentGeneratorPreview = serializeDeveloperAgentGeneratorPreview;
|
|
12
13
|
exports.serializeDeveloperAgentGeneratorPreviewReceipt = serializeDeveloperAgentGeneratorPreviewReceipt;
|
|
13
14
|
exports.serializeDeveloperAgentPlan = serializeDeveloperAgentPlan;
|
|
@@ -466,6 +467,37 @@ function validateOwnershipVersionStates(value, path, issues) {
|
|
|
466
467
|
});
|
|
467
468
|
return true;
|
|
468
469
|
}
|
|
470
|
+
const CONCURRENT_CHANGE_SUMMARY_KEYS = [
|
|
471
|
+
'concurrentChangeCount',
|
|
472
|
+
'concurrentChangesDigest',
|
|
473
|
+
'concurrentChangesTruncated',
|
|
474
|
+
];
|
|
475
|
+
/**
|
|
476
|
+
* The complete concurrent-change list is summarized by an exact count, a
|
|
477
|
+
* digest and a truncation flag. The three fields appear together or not at
|
|
478
|
+
* all, and an emitted subset must state honestly that it is a subset.
|
|
479
|
+
*/
|
|
480
|
+
function validateConcurrentChangeSummary(record, concurrentChanges, path, issues) {
|
|
481
|
+
const present = CONCURRENT_CHANGE_SUMMARY_KEYS.filter((key) => has(record, key));
|
|
482
|
+
if (present.length === 0)
|
|
483
|
+
return;
|
|
484
|
+
if (present.length !== CONCURRENT_CHANGE_SUMMARY_KEYS.length) {
|
|
485
|
+
addIssue(issues, path, 'must carry concurrentChangeCount, concurrentChangesDigest and concurrentChangesTruncated together');
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
const countValid = requireInteger(record.concurrentChangeCount, `${path}.concurrentChangeCount`, issues, 0, MAX_CONCURRENT_PATHS);
|
|
489
|
+
requireSafeString(record.concurrentChangesDigest, `${path}.concurrentChangesDigest`, issues, { maximumLength: 71, pattern: SHA256_DIGEST_PATTERN });
|
|
490
|
+
const truncatedValid = requireBoolean(record.concurrentChangesTruncated, `${path}.concurrentChangesTruncated`, issues);
|
|
491
|
+
if (!countValid || !truncatedValid || !concurrentChanges)
|
|
492
|
+
return;
|
|
493
|
+
const count = record.concurrentChangeCount;
|
|
494
|
+
if ((record.concurrentChangesTruncated === false &&
|
|
495
|
+
count !== concurrentChanges.length) ||
|
|
496
|
+
(record.concurrentChangesTruncated === true &&
|
|
497
|
+
count <= concurrentChanges.length)) {
|
|
498
|
+
addIssue(issues, path, 'must retain an exact concurrent-change count and an honest truncation state');
|
|
499
|
+
}
|
|
500
|
+
}
|
|
469
501
|
function validateGitContext(value, path, issues) {
|
|
470
502
|
const record = requireRecord(value, path, [
|
|
471
503
|
'ahead',
|
|
@@ -477,7 +509,15 @@ function validateGitContext(value, path, issues) {
|
|
|
477
509
|
'defaultBaseRef',
|
|
478
510
|
'dirty',
|
|
479
511
|
'worktreeRoot',
|
|
480
|
-
], [
|
|
512
|
+
], [
|
|
513
|
+
'baseCommit',
|
|
514
|
+
'branch',
|
|
515
|
+
'concurrentChangeCount',
|
|
516
|
+
'concurrentChangesDigest',
|
|
517
|
+
'concurrentChangesTruncated',
|
|
518
|
+
'headCommit',
|
|
519
|
+
'upstream',
|
|
520
|
+
], issues);
|
|
481
521
|
if (!record)
|
|
482
522
|
return false;
|
|
483
523
|
requireInteger(record.ahead, `${path}.ahead`, issues, 0, 1_000_000);
|
|
@@ -530,6 +570,7 @@ function validateGitContext(value, path, issues) {
|
|
|
530
570
|
}
|
|
531
571
|
requireInteger(concurrent.worktreeCount, `${entryPath}.worktreeCount`, issues, 1, 64);
|
|
532
572
|
});
|
|
573
|
+
validateConcurrentChangeSummary(record, concurrentChanges, path, issues);
|
|
533
574
|
if (record.defaultBaseCommit !== null) {
|
|
534
575
|
requireSafeString(record.defaultBaseCommit, `${path}.defaultBaseCommit`, issues, {
|
|
535
576
|
maximumLength: 64,
|
|
@@ -1023,9 +1064,11 @@ function validateSerializedBound(value, path, maximumBytes, issues) {
|
|
|
1023
1064
|
addIssue(issues, path, 'must be canonically JSON serializable');
|
|
1024
1065
|
}
|
|
1025
1066
|
}
|
|
1026
|
-
function validateDeveloperAgentContext(value) {
|
|
1067
|
+
function validateDeveloperAgentContext(value, options = {}) {
|
|
1027
1068
|
const issues = [];
|
|
1028
|
-
|
|
1069
|
+
if (options.transportBound !== false) {
|
|
1070
|
+
validateSerializedBound(value, '$', model_js_1.DEVELOPER_AGENT_CONTEXT_MAX_BYTES, issues);
|
|
1071
|
+
}
|
|
1029
1072
|
const record = requireRecord(value, '$', [
|
|
1030
1073
|
'authenticatedTargets',
|
|
1031
1074
|
'documentationPaths',
|
|
@@ -2297,8 +2340,15 @@ function validateHandoffCoherence(record, issues) {
|
|
|
2297
2340
|
const affectedProjects = Array.isArray(affected?.projects)
|
|
2298
2341
|
? affected.projects.filter((value) => typeof value === 'string')
|
|
2299
2342
|
: [];
|
|
2343
|
+
// Generated native producers record the workspace's exact
|
|
2344
|
+
// @empire-builder-kit/runtime pin, which the preset keeps equal to the
|
|
2345
|
+
// installed @empire-builder-kit/nx version; the package-qualified form
|
|
2346
|
+
// stays accepted for hand-composed evidence. Both are exact equality to
|
|
2347
|
+
// the retained framework version, so evidence from another candidate is
|
|
2348
|
+
// refused.
|
|
2300
2349
|
if (testingSource &&
|
|
2301
2350
|
typeof versions?.frameworkVersion === 'string' &&
|
|
2351
|
+
testingSource.frameworkCandidate !== versions.frameworkVersion &&
|
|
2302
2352
|
testingSource.frameworkCandidate !==
|
|
2303
2353
|
`@empire-builder-kit/nx@${versions.frameworkVersion}`) {
|
|
2304
2354
|
addIssue(issues, `$.results[${index}].testingEvidence.result.source.frameworkCandidate`, 'must match the retained framework candidate');
|
|
@@ -2360,15 +2410,46 @@ function validateHandoffCoherence(record, issues) {
|
|
|
2360
2410
|
testingEnvironment.stage !== versions.canonicalStage))) {
|
|
2361
2411
|
addIssue(issues, `$.results[${index}].testingEvidence.result.environment.stage`, 'must be present for deployed proof and exactly match the retained canonical stage');
|
|
2362
2412
|
}
|
|
2413
|
+
// Registered target operations scope requiredVerification by proof
|
|
2414
|
+
// class (for example local-integration), so their own native evidence is
|
|
2415
|
+
// bound by operation identity instead; proofLayer stays bound to the
|
|
2416
|
+
// retained required evidence below. Source-edit results keep the
|
|
2417
|
+
// project:target verification vocabulary.
|
|
2418
|
+
const resultOperation = (0, validation_js_1.isRecord)(result.operation)
|
|
2419
|
+
? result.operation
|
|
2420
|
+
: undefined;
|
|
2421
|
+
const evidenceIsOwnOperation = typeof testingOperation?.project === 'string' &&
|
|
2422
|
+
typeof testingOperation.target === 'string' &&
|
|
2423
|
+
resultOperation?.name ===
|
|
2424
|
+
`target:${testingOperation.project}:${testingOperation.target}`;
|
|
2363
2425
|
if (typeof testingOperation?.target === 'string' &&
|
|
2426
|
+
!evidenceIsOwnOperation &&
|
|
2364
2427
|
!requiredVerification.some((value) => typeof value === 'string' &&
|
|
2365
2428
|
(value === testingOperation.target ||
|
|
2366
2429
|
value.endsWith(`:${testingOperation.target}`)))) {
|
|
2367
2430
|
addIssue(issues, `$.results[${index}].testingEvidence.result.operation.target`, 'must be accounted for by retained required verification');
|
|
2368
2431
|
}
|
|
2432
|
+
// An own registered target's proof class is bound to that operation's
|
|
2433
|
+
// retained evidence scope, never to a class another operation
|
|
2434
|
+
// contributes to the handoff-wide union. Resume separately requires the
|
|
2435
|
+
// retained scope to equal the current registry scope.
|
|
2436
|
+
const ownRetainedOperation = evidenceIsOwnOperation
|
|
2437
|
+
? operations.find((operation) => operation.id === resultOperation?.name)
|
|
2438
|
+
: undefined;
|
|
2439
|
+
const ownRetainedScope = (0, validation_js_1.isRecord)(ownRetainedOperation?.scope)
|
|
2440
|
+
? ownRetainedOperation.scope
|
|
2441
|
+
: undefined;
|
|
2442
|
+
const proofLayerScope = evidenceIsOwnOperation
|
|
2443
|
+
? Array.isArray(ownRetainedScope?.evidenceClasses)
|
|
2444
|
+
? ownRetainedScope.evidenceClasses
|
|
2445
|
+
: []
|
|
2446
|
+
: requiredEvidence;
|
|
2369
2447
|
if (typeof testingOperation?.proofLayer === 'string' &&
|
|
2370
|
-
!requiredEvidence.includes(testingOperation.proofLayer)
|
|
2371
|
-
|
|
2448
|
+
(!requiredEvidence.includes(testingOperation.proofLayer) ||
|
|
2449
|
+
!proofLayerScope.includes(testingOperation.proofLayer))) {
|
|
2450
|
+
addIssue(issues, `$.results[${index}].testingEvidence.result.operation.proofLayer`, evidenceIsOwnOperation
|
|
2451
|
+
? 'must be accounted for by the retained evidence scope of its own operation'
|
|
2452
|
+
: 'must be accounted for by retained required evidence');
|
|
2372
2453
|
}
|
|
2373
2454
|
if (testingEvidence && testingResult) {
|
|
2374
2455
|
const outerArtifacts = Array.isArray(result.artifacts)
|
|
@@ -2612,8 +2693,19 @@ function serializeValidated(label, value, validate) {
|
|
|
2612
2693
|
}
|
|
2613
2694
|
return (0, canonical_json_1.canonicalJson)(result.value);
|
|
2614
2695
|
}
|
|
2696
|
+
/** Serializes an emitted context and enforces its transport byte bound. */
|
|
2615
2697
|
function serializeDeveloperAgentContext(value) {
|
|
2616
|
-
return serializeValidated('Developer-Agent context', value, validateDeveloperAgentContext);
|
|
2698
|
+
return serializeValidated('Developer-Agent context', value, (candidate) => validateDeveloperAgentContext(candidate));
|
|
2699
|
+
}
|
|
2700
|
+
/** Validates the in-process context for structure only and returns it. */
|
|
2701
|
+
function assertDeveloperAgentContextStructure(value) {
|
|
2702
|
+
const result = validateDeveloperAgentContext(value, {
|
|
2703
|
+
transportBound: false,
|
|
2704
|
+
});
|
|
2705
|
+
if (!result.valid) {
|
|
2706
|
+
throw new DeveloperAgentContractValidationError('Developer-Agent context', result.issues);
|
|
2707
|
+
}
|
|
2708
|
+
return result.value;
|
|
2617
2709
|
}
|
|
2618
2710
|
function serializeDeveloperAgentGeneratorPreview(value) {
|
|
2619
2711
|
return serializeValidated('Developer-Agent generator preview', value, validateDeveloperAgentGeneratorPreview);
|
|
@@ -10,7 +10,6 @@ const node_buffer_1 = require("node:buffer");
|
|
|
10
10
|
const node_crypto_1 = require("node:crypto");
|
|
11
11
|
const context_js_1 = require("../../developer-agent/context.js");
|
|
12
12
|
const model_js_1 = require("../../developer-agent/model.js");
|
|
13
|
-
const validation_js_1 = require("../../developer-agent/validation.js");
|
|
14
13
|
exports.DEVELOPER_AGENT_CONTEXT_FINGERPRINT_KIND = 'developer-agent-context-fingerprint';
|
|
15
14
|
exports.DEVELOPER_AGENT_CONTEXT_FINGERPRINT_SCHEMA_VERSION = 1;
|
|
16
15
|
exports.DEVELOPER_AGENT_CONTEXT_FINGERPRINT_MAX_BYTES = 1024;
|
|
@@ -34,7 +33,9 @@ async function inspectDeveloperContextExecutor(options, workspaceRoot, dependenc
|
|
|
34
33
|
};
|
|
35
34
|
}
|
|
36
35
|
function serializeDeveloperAgentContextFingerprint(context) {
|
|
37
|
-
|
|
36
|
+
// The fingerprint binds the emitted (byte-bounded) context, the same bytes
|
|
37
|
+
// `ebk agent context --json` returns.
|
|
38
|
+
const canonicalContext = (0, context_js_1.serializeDeveloperAgentContextForTransport)(context).serialized;
|
|
38
39
|
const fingerprint = {
|
|
39
40
|
canonicalContextBytes: node_buffer_1.Buffer.byteLength(canonicalContext, 'utf8'),
|
|
40
41
|
canonicalContextDigest: `sha256:${(0, node_crypto_1.createHash)('sha256')
|
|
@@ -53,8 +54,7 @@ function serializeDeveloperAgentContextFingerprint(context) {
|
|
|
53
54
|
function renderDeveloperContextExecutorOutput(context, json) {
|
|
54
55
|
if (json)
|
|
55
56
|
return serializeDeveloperAgentContextFingerprint(context);
|
|
56
|
-
(0,
|
|
57
|
-
return (0, context_js_1.formatDeveloperAgentContext)(context);
|
|
57
|
+
return (0, context_js_1.formatDeveloperAgentContext)((0, context_js_1.serializeDeveloperAgentContextForTransport)(context).context);
|
|
58
58
|
}
|
|
59
59
|
async function executeDeveloperContextExecutor(options, workspaceRoot, dependencies = {}) {
|
|
60
60
|
const result = await inspectDeveloperContextExecutor(options, workspaceRoot, dependencies);
|
|
@@ -45,7 +45,17 @@ Read \`AGENTS.md\`, \`docs/architecture.md\` and the user's requested acceptance
|
|
|
45
45
|
Run \`pnpm nx run ${name}:work-markers\`, then narrow discovery to the relevant
|
|
46
46
|
Slice: \`ebk agent context --projects billing --json\` (replace billing with an
|
|
47
47
|
actual project). Use \`--slice=billing --feature=<registered-id>\` when relevant.
|
|
48
|
-
|
|
48
|
+
For cross-Slice work, name exactly the Slices in scope, such as
|
|
49
|
+
\`--projects=billing,notifications\`. Without a known owner, inspect the project
|
|
50
|
+
list first; do not read every target.
|
|
51
|
+
|
|
52
|
+
The emitted context has a fixed byte bound. A full-workspace context, run
|
|
53
|
+
without \`--projects\`, can exceed it in a workspace with three or more Slices.
|
|
54
|
+
An overflow fails as \`tool-internal-error\` and reports the byte counts. It is
|
|
55
|
+
not a missing prerequisite: narrow \`--projects\` instead of repairing installs,
|
|
56
|
+
stores or worktrees. When many linked worktrees exist, the emitted list of
|
|
57
|
+
concurrent changes may be truncated (\`concurrentChangesTruncated\`); \`ebk agent
|
|
58
|
+
plan\` still checks overlaps against the complete list.
|
|
49
59
|
|
|
50
60
|
Find its \`.ebk/ownership.json\`, feature registry, published contracts and
|
|
51
61
|
\`project.json\`. Managed mechanics change through their owning generator;
|
|
@@ -143,9 +143,13 @@ or IDE command) that only invokes these same commands with \`--json\` is permitt
|
|
|
143
143
|
## Canonical loop
|
|
144
144
|
|
|
145
145
|
1. Run \`pnpm nx run ${name}:work-markers\`.
|
|
146
|
-
2. Run \`ebk agent context
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
2. Run \`ebk agent context --projects=<slice[,slice]>\`, naming the Slices in scope, to inspect
|
|
147
|
+
bounded repository, Git, project, ownership, policy, marker, contract, and verification
|
|
148
|
+
facts. A full-workspace context without \`--projects\` can exceed the fixed context byte
|
|
149
|
+
bound in a workspace with three or more Slices; that fails as \`tool-internal-error\` with
|
|
150
|
+
the byte counts and is fixed by narrowing the selection, not by repairing local setup.
|
|
151
|
+
Select an explicit base and head when affected calculation is required.
|
|
152
|
+
This CLI is the sole full structured context transport. The root
|
|
149
153
|
\`pnpm nx run ${name}:developer-context\` target is a compatibility and graph-authority
|
|
150
154
|
route: its human mode emits concise prose, and \`--json\` emits only the canonical context
|
|
151
155
|
byte length and digest in a bounded fingerprint.
|
|
@@ -282,7 +286,12 @@ or prerequisite-layer drift remains blocking. Prerelease consumers regenerate cl
|
|
|
282
286
|
instead of using this stable-line transition as beta compatibility.
|
|
283
287
|
|
|
284
288
|
Bound inspection with \`--projects=<names>\`, \`--slice=<name>\`, and optional
|
|
285
|
-
\`--feature=<name>\`.
|
|
289
|
+
\`--feature=<name>\`. The emitted JSON context is at most 128 KiB. When linked worktrees
|
|
290
|
+
carry more concurrent changes than fit, it keeps those under the selected projects,
|
|
291
|
+
root-level files and \`.ebk/\` first, and reports \`concurrentChangeCount\`,
|
|
292
|
+
\`concurrentChangesDigest\` and \`concurrentChangesTruncated\` for the complete list.
|
|
293
|
+
\`ebk agent plan\`, \`ebk agent upgrade-preview\` and \`ebk agent resume\` always use the
|
|
294
|
+
complete in-process list. Affected inspection requires the complete
|
|
286
295
|
\`--base=<ref> --head=<ref>\` pair; \`--targets=<names>\` is valid only with that pair.
|
|
287
296
|
Reference an existing generated or separately retained candidate document explicitly with
|
|
288
297
|
\`--candidate-provenance=<workspace-relative-path>\`; context records only its path and
|
|
@@ -15,9 +15,9 @@ export declare const PRODUCT_VERSIONS: {
|
|
|
15
15
|
readonly awsSqs: "^3.700.0";
|
|
16
16
|
readonly awsSsm: "^3.700.0";
|
|
17
17
|
readonly awsSts: "^3.700.0";
|
|
18
|
-
readonly drizzle: "^0.45.
|
|
18
|
+
readonly drizzle: "^0.45.2";
|
|
19
19
|
readonly drizzleKit: "^0.31.4";
|
|
20
|
-
readonly next: "16.3.
|
|
20
|
+
readonly next: "16.3.6";
|
|
21
21
|
readonly pg: "^8.22.0";
|
|
22
22
|
readonly playwright: "^1.59.1";
|
|
23
23
|
readonly react: "19.2.8";
|
|
@@ -25,9 +25,9 @@ exports.PRODUCT_VERSIONS = {
|
|
|
25
25
|
awsSqs: '^3.700.0',
|
|
26
26
|
awsSsm: '^3.700.0',
|
|
27
27
|
awsSts: '^3.700.0',
|
|
28
|
-
drizzle: '^0.45.
|
|
28
|
+
drizzle: '^0.45.2',
|
|
29
29
|
drizzleKit: '^0.31.4',
|
|
30
|
-
next: '16.3.
|
|
30
|
+
next: '16.3.6',
|
|
31
31
|
pg: '^8.22.0',
|
|
32
32
|
playwright: '^1.59.1',
|
|
33
33
|
react: '19.2.8',
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export declare const GITHUB_ACTION_PINS: {
|
|
2
2
|
readonly cache: {
|
|
3
3
|
readonly action: "actions/cache";
|
|
4
|
-
readonly sha: "
|
|
5
|
-
readonly tag: "
|
|
4
|
+
readonly sha: "caa296126883cff596d87d8935842f9db880ef25";
|
|
5
|
+
readonly tag: "v5.1.0";
|
|
6
6
|
};
|
|
7
7
|
readonly checkout: {
|
|
8
8
|
readonly action: "actions/checkout";
|
|
@@ -5,8 +5,8 @@ exports.pinnedAction = pinnedAction;
|
|
|
5
5
|
exports.GITHUB_ACTION_PINS = {
|
|
6
6
|
cache: {
|
|
7
7
|
action: 'actions/cache',
|
|
8
|
-
sha: '
|
|
9
|
-
tag: '
|
|
8
|
+
sha: 'caa296126883cff596d87d8935842f9db880ef25',
|
|
9
|
+
tag: 'v5.1.0',
|
|
10
10
|
},
|
|
11
11
|
checkout: {
|
|
12
12
|
action: 'actions/checkout',
|
|
@@ -47,7 +47,7 @@ function validateOperation(value) {
|
|
|
47
47
|
: '/validation/.git',
|
|
48
48
|
heartbeatAt: '1970-01-01T00:00:00.000Z',
|
|
49
49
|
identitySource: 'worktree-task',
|
|
50
|
-
nxVersion: '23.1
|
|
50
|
+
nxVersion: '23.2.1',
|
|
51
51
|
operations: [value],
|
|
52
52
|
origin: 'https://validation.ebk.localhost',
|
|
53
53
|
resolvedStage: 'personal-validation',
|