specrails-core 6.5.0 → 6.6.1
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/agent-runtime/capabilities.d.ts +2 -2
- package/dist/agent-runtime/cli-executor.js +1 -1
- package/dist/agent-runtime/cli.d.ts +4 -4
- package/dist/agent-runtime/compact/environment.d.ts +20 -2
- package/dist/agent-runtime/compact/environment.js +63 -4
- package/dist/agent-runtime/compact/step.d.ts +1 -1
- package/dist/agent-runtime/efficiency-summary.d.ts +1 -1
- package/dist/agent-runtime/efficiency-types.d.ts +1 -1
- package/dist/agent-runtime/engine/checkpoint/database.d.ts +15 -15
- package/dist/agent-runtime/engine/contracts.d.ts +2 -1
- package/dist/agent-runtime/engine/definition-types.d.ts +1 -1
- package/dist/agent-runtime/engine/efficiency-summary.d.ts +8 -8
- package/dist/agent-runtime/engine/fork.d.ts +1 -1
- package/dist/agent-runtime/engine/graph-description.d.ts +16 -16
- package/dist/agent-runtime/engine/implementation-compiler.d.ts +68 -68
- package/dist/agent-runtime/engine/piece-dependencies.js +4 -4
- package/dist/agent-runtime/engine/pieces/implementation-step.d.ts +1 -1
- package/dist/agent-runtime/engine/pieces/role-turn.js +10 -1
- package/dist/agent-runtime/engine/pieces/shared.d.ts +2 -2
- package/dist/agent-runtime/engine/pieces/verify.js +43 -8
- package/dist/agent-runtime/engine/run-status.d.ts +165 -165
- package/dist/agent-runtime/engine/runs.d.ts +168 -168
- package/dist/agent-runtime/engine/state.d.ts +16 -16
- package/dist/agent-runtime/evaluation.d.ts +3 -3
- package/dist/agent-runtime/executor-types.d.ts +10 -10
- package/dist/agent-runtime/graph/convergence.d.ts +2 -2
- package/dist/agent-runtime/graph/convergence.js +11 -0
- package/dist/agent-runtime/graph/nodes.js +35 -4
- package/dist/agent-runtime/graph/review-policy.d.ts +1 -1
- package/dist/agent-runtime/graph/state.d.ts +6 -2
- package/dist/agent-runtime/guardrails.d.ts +1 -1
- package/dist/agent-runtime/guardrails.js +4 -1
- package/dist/agent-runtime/index.d.ts +3 -2
- package/dist/agent-runtime/index.js +1 -0
- package/dist/agent-runtime/openai-executor.d.ts +9 -9
- package/dist/agent-runtime/openspec.d.ts +4 -4
- package/dist/agent-runtime/prompts.d.ts +6 -0
- package/dist/agent-runtime/prompts.js +32 -8
- package/dist/agent-runtime/recovery.d.ts +12 -12
- package/dist/agent-runtime/session/drivers/claude/argv.d.ts +2 -2
- package/dist/agent-runtime/verification-repair.d.ts +31 -2
- package/dist/agent-runtime/verification-repair.js +58 -3
- package/dist/installer/commands/init.d.ts +1 -1
- package/dist/installer/phases/install-config.js +10 -3
- package/dist/installer/util/paths.d.ts +25 -1
- package/dist/pipeline/pipeline-state.d.ts +42 -11
- package/dist/pipeline/pipeline-state.js +47 -8
- package/package.json +13 -11
- package/schemas/agent-runtime.schema.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import
|
|
2
|
+
import { dump, loadAll } from 'js-yaml';
|
|
3
3
|
import { FilesystemError, InstallerError } from '../util/errors.js';
|
|
4
4
|
import { pathExists, readTextFile, writeFileLf } from '../util/fs.js';
|
|
5
5
|
import { warn } from '../util/logger.js';
|
|
@@ -72,7 +72,14 @@ export function loadInstallConfig(configPath) {
|
|
|
72
72
|
const raw = readTextFile(configPath);
|
|
73
73
|
let parsed;
|
|
74
74
|
try {
|
|
75
|
-
|
|
75
|
+
// js-yaml 5 `load()` throws on a stream with no document (empty or
|
|
76
|
+
// comment-only file). Keep reporting that as a non-mapping config, and
|
|
77
|
+
// keep rejecting multi-document streams as `load()` did.
|
|
78
|
+
const documents = loadAll(raw);
|
|
79
|
+
if (documents.length > 1) {
|
|
80
|
+
throw new Error('expected a single document in the stream, but found more');
|
|
81
|
+
}
|
|
82
|
+
parsed = documents[0];
|
|
76
83
|
}
|
|
77
84
|
catch (err) {
|
|
78
85
|
throw new InvalidConfigError([`YAML parse error: ${err.message}`]);
|
|
@@ -258,7 +265,7 @@ function isExactModelIdentifier(value) {
|
|
|
258
265
|
*/
|
|
259
266
|
export function writeInstallConfig(configPath, config) {
|
|
260
267
|
try {
|
|
261
|
-
const text =
|
|
268
|
+
const text = dump(config, { lineWidth: 120, noRefs: true });
|
|
262
269
|
writeFileLf(configPath, text);
|
|
263
270
|
}
|
|
264
271
|
catch (err) {
|
|
@@ -6,7 +6,31 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Audited by vitest spec `reserved-paths.test.ts`.
|
|
8
8
|
*/
|
|
9
|
-
export declare const RESERVED_PATHS: readonly [
|
|
9
|
+
export declare const RESERVED_PATHS: readonly [
|
|
10
|
+
/**
|
|
11
|
+
* .specrails/profiles/** — project + desktop-app-authored profile JSON.
|
|
12
|
+
* specrails-desktop writes profile files here and expects them preserved
|
|
13
|
+
* across specrails-core updates.
|
|
14
|
+
*/
|
|
15
|
+
'.specrails/profiles/',
|
|
16
|
+
/**
|
|
17
|
+
* .claude/agents/custom-*.md — user-authored custom agents, kept
|
|
18
|
+
* distinct from the bundled sr-* agents so updates never overwrite
|
|
19
|
+
* them.
|
|
20
|
+
*/
|
|
21
|
+
'.claude/agents/custom-',
|
|
22
|
+
/**
|
|
23
|
+
* `.kimi-code/skills/custom-<id>/...` — user-authored Kimi role skills.
|
|
24
|
+
* Kimi discovers skills only one directory below `skills/`, so custom roles
|
|
25
|
+
* share the flat namespace with managed `sr-*` and workflow skills.
|
|
26
|
+
*/
|
|
27
|
+
'.kimi-code/skills/custom-',
|
|
28
|
+
/**
|
|
29
|
+
* Pre-release compatibility: preserve a legacy nested custom role until the
|
|
30
|
+
* installer can atomically migrate it to the flat path. A destination
|
|
31
|
+
* collision is never overwritten or deleted automatically.
|
|
32
|
+
*/
|
|
33
|
+
'.kimi-code/skills/rails/custom-'];
|
|
10
34
|
/**
|
|
11
35
|
* Returns true when a repo-relative path falls inside a reserved
|
|
12
36
|
* region. Accepts both POSIX (/) and Windows (\) separators; the
|
|
@@ -107,6 +107,22 @@ export interface VerificationReceipt {
|
|
|
107
107
|
reason?: string;
|
|
108
108
|
/** Repositories in scope that this receipt ran no command for (explicitly admitted by the request). */
|
|
109
109
|
unverifiedRepositories?: string[];
|
|
110
|
+
/** Candidate files the verification commands themselves added, modified or removed (absent when the candidate did not move). */
|
|
111
|
+
selfMutation?: VerificationSelfMutation;
|
|
112
|
+
}
|
|
113
|
+
export interface CandidateFileChange {
|
|
114
|
+
repositoryId: string;
|
|
115
|
+
path: string;
|
|
116
|
+
change: 'added' | 'modified' | 'removed';
|
|
117
|
+
}
|
|
118
|
+
/** What verification wrote into its own candidate: the files (bounded, `omittedFiles` counts the rest) and the commands that executed in the run. */
|
|
119
|
+
export interface VerificationSelfMutation {
|
|
120
|
+
files: CandidateFileChange[];
|
|
121
|
+
omittedFiles?: number;
|
|
122
|
+
commands: Array<{
|
|
123
|
+
repositoryId: string;
|
|
124
|
+
label: string;
|
|
125
|
+
}>;
|
|
110
126
|
}
|
|
111
127
|
export interface AcceptanceCriterion {
|
|
112
128
|
specId: string;
|
|
@@ -232,7 +248,19 @@ export interface CandidateManifest {
|
|
|
232
248
|
}>;
|
|
233
249
|
}
|
|
234
250
|
export declare function candidateManifest(state: CandidateScope): CandidateManifest;
|
|
251
|
+
export declare function candidateManifestHash(manifest: CandidateManifest): string;
|
|
235
252
|
export declare function fingerprintCandidate(state: CandidateScope): string;
|
|
253
|
+
/** Files that differ between two manifests of the same scope, sorted by repository, then path. */
|
|
254
|
+
export declare function diffCandidateManifests(before: CandidateManifest, after: CandidateManifest): CandidateFileChange[];
|
|
255
|
+
/** `1 candidate file: a` / `4 candidate files: a, b, c and 1 more`, shared by receipts and failure summaries. */
|
|
256
|
+
export declare function describeModifiedFiles(mutation: Pick<VerificationSelfMutation, 'files' | 'omittedFiles'>): string;
|
|
257
|
+
/**
|
|
258
|
+
* A receipt whose candidate moved while it ran. During a verify step no role
|
|
259
|
+
* turn runs, so a manifest diff around the run attributes the change to the
|
|
260
|
+
* verification commands themselves (a lint pre-step regenerating a tracked
|
|
261
|
+
* file); without both manifests the generic reason stays.
|
|
262
|
+
*/
|
|
263
|
+
export declare function candidateChangedReceipt(receipt: VerificationReceipt, before: CandidateManifest | undefined, after: (() => CandidateManifest) | undefined): VerificationReceipt;
|
|
236
264
|
export declare function initializePipeline(contextInput: unknown, change: string): PipelineState;
|
|
237
265
|
/** Host-owned binding, including immutable harness bytes outside the candidate. */
|
|
238
266
|
export declare function bindVerificationPlan(contextInput: PipelineContext, hash: string, files: Array<{
|
|
@@ -309,6 +337,9 @@ export interface VerificationRunOptions {
|
|
|
309
337
|
/** Persistence and candidate ownership are bound by the host, never inferred from a journal path. */
|
|
310
338
|
export interface VerificationEvidencePort {
|
|
311
339
|
candidateHash: string;
|
|
340
|
+
/** The manifest `candidateHash` was computed from; with `currentManifest`, an invalidated receipt names the files verification modified. */
|
|
341
|
+
candidateManifest?: CandidateManifest;
|
|
342
|
+
currentManifest?(): CandidateManifest;
|
|
312
343
|
scopeHash: string;
|
|
313
344
|
planHash?: string;
|
|
314
345
|
previous?: VerificationReceipt;
|
|
@@ -335,21 +366,15 @@ export interface VerificationEvidenceQuery {
|
|
|
335
366
|
export declare function persistCheckEvidence(context: PipelineContext, result: CommandReceipt, planHash: string, candidateHash: string): void;
|
|
336
367
|
/** Historical read: no live repository validation, source execution or lifecycle mutation. */
|
|
337
368
|
export declare function readVerificationEvidence(context: Pick<PipelineContext, 'backlogRoot' | 'runId'>, query?: VerificationEvidenceQuery): {
|
|
338
|
-
nextCursor?: string | undefined;
|
|
339
369
|
schemaVersion: number;
|
|
340
370
|
available: boolean;
|
|
341
371
|
items: Record<string, unknown>[];
|
|
342
372
|
truncated: boolean;
|
|
373
|
+
nextCursor?: string | undefined;
|
|
343
374
|
} | {
|
|
344
375
|
schemaVersion: number;
|
|
345
376
|
available: boolean;
|
|
346
377
|
items: {
|
|
347
|
-
sources: {
|
|
348
|
-
id: string;
|
|
349
|
-
displayPath: string;
|
|
350
|
-
byteCount: number;
|
|
351
|
-
hash: string;
|
|
352
|
-
}[];
|
|
353
378
|
schemaVersion: 1;
|
|
354
379
|
runId: string;
|
|
355
380
|
id: string;
|
|
@@ -358,9 +383,9 @@ export declare function readVerificationEvidence(context: Pick<PipelineContext,
|
|
|
358
383
|
label: string;
|
|
359
384
|
origin: string[];
|
|
360
385
|
required: true;
|
|
361
|
-
disposition:
|
|
386
|
+
disposition: 'executed' | 'reused' | 'not-run';
|
|
362
387
|
reusedFrom?: string;
|
|
363
|
-
status:
|
|
388
|
+
status: 'passed' | 'failed' | 'cancelled' | 'interrupted' | 'unavailable';
|
|
364
389
|
reuseReason?: string;
|
|
365
390
|
recordedAt: string;
|
|
366
391
|
execution: {
|
|
@@ -382,16 +407,22 @@ export declare function readVerificationEvidence(context: Pick<PipelineContext,
|
|
|
382
407
|
stderrBytes: number;
|
|
383
408
|
stdoutHash: string;
|
|
384
409
|
stderrHash: string;
|
|
410
|
+
sources: {
|
|
411
|
+
id: string;
|
|
412
|
+
displayPath: string;
|
|
413
|
+
byteCount: number;
|
|
414
|
+
hash: string;
|
|
415
|
+
}[];
|
|
385
416
|
}[];
|
|
386
417
|
truncated: boolean;
|
|
387
418
|
} | {
|
|
388
|
-
|
|
419
|
+
items?: undefined;
|
|
389
420
|
schemaVersion: number;
|
|
390
421
|
available: boolean;
|
|
391
422
|
text: string;
|
|
392
423
|
byteCount: number;
|
|
393
424
|
totalBytes: number;
|
|
394
425
|
truncated: boolean;
|
|
395
|
-
|
|
426
|
+
nextCursor?: string | undefined;
|
|
396
427
|
};
|
|
397
428
|
export {};
|
|
@@ -407,7 +407,45 @@ export function candidateManifest(state) {
|
|
|
407
407
|
}));
|
|
408
408
|
return { schemaVersion: 1, scopeHash: state.scopeHash, repositories: entries };
|
|
409
409
|
}
|
|
410
|
-
export function
|
|
410
|
+
export function candidateManifestHash(manifest) { return digest(canonical(manifest.repositories)); }
|
|
411
|
+
export function fingerprintCandidate(state) { return candidateManifestHash(candidateManifest(state)); }
|
|
412
|
+
/** Files that differ between two manifests of the same scope, sorted by repository, then path. */
|
|
413
|
+
export function diffCandidateManifests(before, after) {
|
|
414
|
+
const changes = [];
|
|
415
|
+
for (const repositoryId of [...new Set([...before.repositories, ...after.repositories].map(repo => repo.id))].sort()) {
|
|
416
|
+
const old = new Map(before.repositories.find(repo => repo.id === repositoryId)?.files ?? []);
|
|
417
|
+
const current = new Map(after.repositories.find(repo => repo.id === repositoryId)?.files ?? []);
|
|
418
|
+
for (const file of [...new Set([...old.keys(), ...current.keys()])].sort()) {
|
|
419
|
+
const change = !old.has(file) ? 'added' : !current.has(file) ? 'removed' : old.get(file) !== current.get(file) ? 'modified' : undefined;
|
|
420
|
+
if (change)
|
|
421
|
+
changes.push({ repositoryId, path: file, change });
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return changes;
|
|
425
|
+
}
|
|
426
|
+
const SELF_MUTATION_FILE_LIMIT = 200;
|
|
427
|
+
/** `1 candidate file: a` / `4 candidate files: a, b, c and 1 more`, shared by receipts and failure summaries. */
|
|
428
|
+
export function describeModifiedFiles(mutation) {
|
|
429
|
+
const total = mutation.files.length + (mutation.omittedFiles ?? 0), shown = mutation.files.slice(0, 3).map(file => file.path);
|
|
430
|
+
return `${total} candidate file${total === 1 ? '' : 's'}: ${shown.join(', ')}${total > shown.length ? ` and ${total - shown.length} more` : ''}`;
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* A receipt whose candidate moved while it ran. During a verify step no role
|
|
434
|
+
* turn runs, so a manifest diff around the run attributes the change to the
|
|
435
|
+
* verification commands themselves (a lint pre-step regenerating a tracked
|
|
436
|
+
* file); without both manifests the generic reason stays.
|
|
437
|
+
*/
|
|
438
|
+
export function candidateChangedReceipt(receipt, before, after) {
|
|
439
|
+
if (receipt.selfMutation)
|
|
440
|
+
return { ...receipt, valid: false };
|
|
441
|
+
const files = before && after ? diffCandidateManifests(before, after()) : [];
|
|
442
|
+
if (!files.length)
|
|
443
|
+
return { ...receipt, valid: false, reason: 'Candidate changed during verification' };
|
|
444
|
+
const selfMutation = { files: files.slice(0, SELF_MUTATION_FILE_LIMIT), ...(files.length > SELF_MUTATION_FILE_LIMIT ? { omittedFiles: files.length - SELF_MUTATION_FILE_LIMIT } : {}),
|
|
445
|
+
commands: receipt.commands.filter(command => command.disposition !== 'reused' && command.disposition !== 'not-run').map(command => ({ repositoryId: command.repositoryId, label: command.label ?? command.key ?? [command.command, ...command.args].join(' ').slice(0, 256) })) };
|
|
446
|
+
const failed = receipt.commands.some(command => command.exitCode !== 0);
|
|
447
|
+
return { ...receipt, valid: false, reason: `${failed ? 'A verification command failed. ' : ''}Verification commands modified ${describeModifiedFiles(selfMutation)}`, selfMutation };
|
|
448
|
+
}
|
|
411
449
|
function activeArtifactPath(state) { return state.archivePath ?? path.join(state.context.artifactRoot, 'openspec', 'changes', state.change); }
|
|
412
450
|
function artifactFingerprint(state) {
|
|
413
451
|
const root = activeArtifactPath(state);
|
|
@@ -1154,19 +1192,19 @@ export async function verifyPipeline(contextInput, raw, log = () => { }, signal,
|
|
|
1154
1192
|
const identityProblems = planReasons(state, typeof request.planHash === 'string' ? request.planHash : undefined);
|
|
1155
1193
|
if (identityProblems.length)
|
|
1156
1194
|
fail(identityProblems.join('; '));
|
|
1157
|
-
const
|
|
1195
|
+
const manifest = candidateManifest(state), candidateHash = candidateManifestHash(manifest);
|
|
1158
1196
|
const isCurrent = () => {
|
|
1159
1197
|
const current = readState(context);
|
|
1160
1198
|
return fingerprintCandidate(current) === candidateHash && current.revision === state.revision && planReasons(current, request.planHash).length === 0;
|
|
1161
1199
|
};
|
|
1162
1200
|
return executeVerification(context, raw, {
|
|
1163
|
-
candidateHash, scopeHash: state.scopeHash, planHash: state.verificationPlan?.hash, previous,
|
|
1201
|
+
candidateHash, candidateManifest: manifest, currentManifest: () => candidateManifest(readState(context)), scopeHash: state.scopeHash, planHash: state.verificationPlan?.hash, previous,
|
|
1164
1202
|
isCurrent: () => locked(context, isCurrent),
|
|
1165
1203
|
persistCheck: (result, planHash, candidate) => persistCheckEvidence(context, result, planHash, candidate),
|
|
1166
1204
|
commitReceipt: receipt => locked(context, () => {
|
|
1167
1205
|
const current = readState(context);
|
|
1168
1206
|
if (!isCurrent())
|
|
1169
|
-
receipt =
|
|
1207
|
+
receipt = candidateChangedReceipt(receipt, manifest, () => candidateManifest(current));
|
|
1170
1208
|
atomicJson(safeChild(pipelineStateDirectory(context), 'receipts/' + receipt.id + '.json'), receipt);
|
|
1171
1209
|
if (receipt.kind === 'full' || !receipt.valid || !current.verification)
|
|
1172
1210
|
current.verification = receipt;
|
|
@@ -1249,12 +1287,13 @@ export async function executeVerification(contextInput, raw, evidence, log = ()
|
|
|
1249
1287
|
notRunEvidenceIds.push(id);
|
|
1250
1288
|
}
|
|
1251
1289
|
const changed = !evidence.isCurrent();
|
|
1252
|
-
const
|
|
1290
|
+
const draft = {
|
|
1253
1291
|
id: randomUUID(), ...(evidence.planHash ? { planHash: evidence.planHash } : {}), kind: request.kind, scopeHash: evidence.scopeHash, candidateHash, commands: results, ...(notRunEvidenceIds.length ? { notRunEvidenceIds } : {}),
|
|
1254
|
-
completedAt: new Date().toISOString(), valid: !
|
|
1255
|
-
...(
|
|
1292
|
+
completedAt: new Date().toISOString(), valid: !signal?.aborted && (options.deadline === undefined || Date.now() <= options.deadline) && results.length === commands.length && results.every((result) => result.exitCode === 0),
|
|
1293
|
+
...(results.some((result) => result.exitCode !== 0) ? { reason: 'A verification command failed' } : {}),
|
|
1256
1294
|
...(unverifiedRepositories.length ? { unverifiedRepositories } : {}),
|
|
1257
|
-
}
|
|
1295
|
+
};
|
|
1296
|
+
const receipt = await evidence.commitReceipt(changed ? candidateChangedReceipt(draft, evidence.candidateManifest, evidence.currentManifest && (() => evidence.currentManifest())) : draft);
|
|
1258
1297
|
if (!receipt.valid)
|
|
1259
1298
|
for (const result of results) {
|
|
1260
1299
|
await options.onEvidence?.('check-invalidated', { executionId: result.evidenceId ?? '', repositoryId: result.repositoryId, checkId: result.key ?? '', label: result.label ?? result.command, reason: receipt.reason ?? 'Verification did not complete successfully' });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specrails-core",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.6.1",
|
|
4
4
|
"description": "Agent workflow engine for specrails-desktop: provider-independent installer and programmatic agent runtime for Claude Code and Codex",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -89,23 +89,25 @@
|
|
|
89
89
|
},
|
|
90
90
|
"dependencies": {
|
|
91
91
|
"@fission-ai/openspec": "1.4.1",
|
|
92
|
-
"@langchain/core": "1.2.
|
|
93
|
-
"@langchain/langgraph": "1.4.
|
|
92
|
+
"@langchain/core": "1.2.14",
|
|
93
|
+
"@langchain/langgraph": "1.4.18",
|
|
94
94
|
"@langchain/langgraph-checkpoint": "1.1.5",
|
|
95
|
-
"@modelcontextprotocol/sdk": "1.
|
|
95
|
+
"@modelcontextprotocol/sdk": "1.31.0",
|
|
96
96
|
"ajv": "^8.20.0",
|
|
97
97
|
"cross-spawn": "7.0.6",
|
|
98
|
-
"js-yaml": "^4.
|
|
98
|
+
"js-yaml": "^5.4.3",
|
|
99
99
|
"picocolors": "^1.1.1",
|
|
100
|
-
"
|
|
100
|
+
"semver": "^7.8.5",
|
|
101
|
+
"zod": "4.6.5"
|
|
101
102
|
},
|
|
102
103
|
"devDependencies": {
|
|
103
104
|
"@types/cross-spawn": "6.0.6",
|
|
104
|
-
"@types/
|
|
105
|
-
"@types/
|
|
106
|
-
"@vitest/coverage-v8": "^
|
|
107
|
-
"
|
|
108
|
-
"
|
|
105
|
+
"@types/node": "^26.6.5",
|
|
106
|
+
"@types/semver": "^7.8.0",
|
|
107
|
+
"@vitest/coverage-v8": "^5.0.3",
|
|
108
|
+
"js-yaml-4": "npm:js-yaml@^4.3.2",
|
|
109
|
+
"typescript": "^7.0.2",
|
|
110
|
+
"vitest": "^5.0.3"
|
|
109
111
|
},
|
|
110
112
|
"license": "MIT",
|
|
111
113
|
"author": "fjpulidop"
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"planning": { "enum": ["full", "proportional"] }, "acceptDeveloperChecks": { "type": "boolean" },
|
|
13
13
|
"verification": { "type": "object", "additionalProperties": false, "properties": { "maxConcurrency": { "type": "integer", "minimum": 1, "maximum": 4 } } }
|
|
14
14
|
} },
|
|
15
|
-
"guardrails": { "type": "object", "additionalProperties": false, "properties": { "plan-validation": { "type": "boolean" }, "genuine-blocking-question": { "type": "boolean" }, "plan-language-hint": { "type": "boolean" }, "frozen-plan-writes": { "type": "boolean" }, "primary-language": { "type": "boolean" }, "duplicate-sibling": { "type": "boolean" }, "one-test-per-module": { "type": "boolean" }, "empty-write": { "type": "boolean" }, "evidence-gated-ticking": { "type": "boolean" }, "inventory-retry": { "type": "boolean" }, "synthetic-corrections": { "type": "boolean" }, "silent-group-closure": { "type": "boolean" }, "verify-per-group": { "type": "boolean" }, "test-reachability": { "type": "boolean" }, "exit-code-honesty": { "type": "boolean" }, "environment-repair": { "type": "boolean" }, "lockfile-repair": { "type": "boolean" }, "verify-idle-timeout": { "type": "boolean" } } },
|
|
15
|
+
"guardrails": { "type": "object", "additionalProperties": false, "properties": { "plan-validation": { "type": "boolean" }, "genuine-blocking-question": { "type": "boolean" }, "plan-language-hint": { "type": "boolean" }, "frozen-plan-writes": { "type": "boolean" }, "primary-language": { "type": "boolean" }, "duplicate-sibling": { "type": "boolean" }, "one-test-per-module": { "type": "boolean" }, "empty-write": { "type": "boolean" }, "evidence-gated-ticking": { "type": "boolean" }, "inventory-retry": { "type": "boolean" }, "synthetic-corrections": { "type": "boolean" }, "silent-group-closure": { "type": "boolean" }, "verify-per-group": { "type": "boolean" }, "test-reachability": { "type": "boolean" }, "exit-code-honesty": { "type": "boolean" }, "environment-repair": { "type": "boolean" }, "lockfile-repair": { "type": "boolean" }, "verify-idle-timeout": { "type": "boolean" }, "verification-output-adoption": { "type": "boolean" } } },
|
|
16
16
|
"rolePrompts": { "type": "object", "propertyNames": { "pattern": "^[a-z][a-z0-9-]{0,63}$" }, "additionalProperties": { "type": "string", "minLength": 1, "maxLength": 20000, "pattern": "\\S" }, "properties": {
|
|
17
17
|
"architect": { "type": "string", "minLength": 1, "maxLength": 20000, "pattern": "\\S" },
|
|
18
18
|
"developer": { "type": "string", "minLength": 1, "maxLength": 20000, "pattern": "\\S" },
|