specrails-core 6.0.1 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/README.md +3 -3
  2. package/dist/agent-runtime/capabilities.js +3 -1
  3. package/dist/agent-runtime/change-scope.js +2 -0
  4. package/dist/agent-runtime/cli-executor.d.ts +3 -0
  5. package/dist/agent-runtime/cli-executor.js +52 -14
  6. package/dist/agent-runtime/cli-process.js +6 -2
  7. package/dist/agent-runtime/cli.d.ts +15 -0
  8. package/dist/agent-runtime/cli.js +43 -9
  9. package/dist/agent-runtime/compact/chat-client.js +2 -1
  10. package/dist/agent-runtime/config.d.ts +4 -1
  11. package/dist/agent-runtime/config.js +41 -3
  12. package/dist/agent-runtime/core-host.d.ts +9 -3
  13. package/dist/agent-runtime/core-host.js +21 -18
  14. package/dist/agent-runtime/efficiency-summary.d.ts +4 -1
  15. package/dist/agent-runtime/efficiency-summary.js +30 -27
  16. package/dist/agent-runtime/efficiency-types.d.ts +4 -4
  17. package/dist/agent-runtime/efficiency.d.ts +1 -1
  18. package/dist/agent-runtime/efficiency.js +7 -6
  19. package/dist/agent-runtime/engine/__fixtures__/implementation-component.json +90 -0
  20. package/dist/agent-runtime/engine/__fixtures__/implementation-fixture.d.ts +11 -0
  21. package/dist/agent-runtime/engine/__fixtures__/implementation-fixture.js +60 -0
  22. package/dist/agent-runtime/engine/__fixtures__/implementation.json +43 -0
  23. package/dist/agent-runtime/engine/budget.d.ts +9 -0
  24. package/dist/agent-runtime/engine/budget.js +33 -0
  25. package/dist/agent-runtime/engine/canonical-json.d.ts +9 -0
  26. package/dist/agent-runtime/engine/canonical-json.js +162 -0
  27. package/dist/agent-runtime/engine/checkpoint/database.d.ts +67 -0
  28. package/dist/agent-runtime/engine/checkpoint/database.js +304 -0
  29. package/dist/agent-runtime/engine/checkpoint/lease.d.ts +17 -0
  30. package/dist/agent-runtime/engine/checkpoint/lease.js +82 -0
  31. package/dist/agent-runtime/engine/checkpoint/ledger.d.ts +133 -0
  32. package/dist/agent-runtime/engine/checkpoint/ledger.js +510 -0
  33. package/dist/agent-runtime/engine/checkpoint/saver.d.ts +25 -0
  34. package/dist/agent-runtime/engine/checkpoint/saver.js +146 -0
  35. package/dist/agent-runtime/engine/cli.d.ts +10 -0
  36. package/dist/agent-runtime/engine/cli.js +172 -0
  37. package/dist/agent-runtime/engine/compiler.d.ts +23 -0
  38. package/dist/agent-runtime/engine/compiler.js +262 -0
  39. package/dist/agent-runtime/engine/composition.d.ts +16 -0
  40. package/dist/agent-runtime/engine/composition.js +28 -0
  41. package/dist/agent-runtime/engine/concurrency.d.ts +14 -0
  42. package/dist/agent-runtime/engine/concurrency.js +55 -0
  43. package/dist/agent-runtime/engine/contracts.d.ts +273 -0
  44. package/dist/agent-runtime/engine/contracts.js +11 -0
  45. package/dist/agent-runtime/engine/definition-schema.d.ts +250 -0
  46. package/dist/agent-runtime/engine/definition-schema.js +315 -0
  47. package/dist/agent-runtime/engine/definition-types.d.ts +84 -0
  48. package/dist/agent-runtime/engine/definition-types.js +3 -0
  49. package/dist/agent-runtime/engine/definition-validator.d.ts +7 -0
  50. package/dist/agent-runtime/engine/definition-validator.js +191 -0
  51. package/dist/agent-runtime/engine/efficiency-summary.d.ts +62 -0
  52. package/dist/agent-runtime/engine/efficiency-summary.js +31 -0
  53. package/dist/agent-runtime/engine/events.d.ts +19 -0
  54. package/dist/agent-runtime/engine/events.js +88 -0
  55. package/dist/agent-runtime/engine/execution.d.ts +29 -0
  56. package/dist/agent-runtime/engine/execution.js +121 -0
  57. package/dist/agent-runtime/engine/expressions.d.ts +11 -0
  58. package/dist/agent-runtime/engine/expressions.js +185 -0
  59. package/dist/agent-runtime/engine/fork.d.ts +28 -0
  60. package/dist/agent-runtime/engine/fork.js +253 -0
  61. package/dist/agent-runtime/engine/graph-description.d.ts +48 -0
  62. package/dist/agent-runtime/engine/graph-description.js +16 -0
  63. package/dist/agent-runtime/engine/implementation-compiler.d.ts +214 -0
  64. package/dist/agent-runtime/engine/implementation-compiler.js +91 -0
  65. package/dist/agent-runtime/engine/index.d.ts +14 -0
  66. package/dist/agent-runtime/engine/index.js +14 -0
  67. package/dist/agent-runtime/engine/invocation-context.d.ts +11 -0
  68. package/dist/agent-runtime/engine/invocation-context.js +130 -0
  69. package/dist/agent-runtime/engine/otel.d.ts +15 -0
  70. package/dist/agent-runtime/engine/otel.js +132 -0
  71. package/dist/agent-runtime/engine/output.d.ts +4 -0
  72. package/dist/agent-runtime/engine/output.js +73 -0
  73. package/dist/agent-runtime/engine/piece-dependencies.d.ts +54 -0
  74. package/dist/agent-runtime/engine/piece-dependencies.js +240 -0
  75. package/dist/agent-runtime/engine/piece-registry.d.ts +19 -0
  76. package/dist/agent-runtime/engine/piece-registry.js +62 -0
  77. package/dist/agent-runtime/engine/pieces/artifact-contract.d.ts +4 -0
  78. package/dist/agent-runtime/engine/pieces/artifact-contract.js +70 -0
  79. package/dist/agent-runtime/engine/pieces/assign.d.ts +4 -0
  80. package/dist/agent-runtime/engine/pieces/assign.js +35 -0
  81. package/dist/agent-runtime/engine/pieces/control.d.ts +5 -0
  82. package/dist/agent-runtime/engine/pieces/control.js +53 -0
  83. package/dist/agent-runtime/engine/pieces/decider.d.ts +5 -0
  84. package/dist/agent-runtime/engine/pieces/decider.js +70 -0
  85. package/dist/agent-runtime/engine/pieces/implementation-binding.d.ts +13 -0
  86. package/dist/agent-runtime/engine/pieces/implementation-binding.js +40 -0
  87. package/dist/agent-runtime/engine/pieces/implementation-journal.d.ts +25 -0
  88. package/dist/agent-runtime/engine/pieces/implementation-journal.js +192 -0
  89. package/dist/agent-runtime/engine/pieces/implementation-step.d.ts +5 -0
  90. package/dist/agent-runtime/engine/pieces/implementation-step.js +47 -0
  91. package/dist/agent-runtime/engine/pieces/implementation.d.ts +27 -0
  92. package/dist/agent-runtime/engine/pieces/implementation.js +177 -0
  93. package/dist/agent-runtime/engine/pieces/index.d.ts +7 -0
  94. package/dist/agent-runtime/engine/pieces/index.js +24 -0
  95. package/dist/agent-runtime/engine/pieces/openspec.d.ts +3 -0
  96. package/dist/agent-runtime/engine/pieces/openspec.js +75 -0
  97. package/dist/agent-runtime/engine/pieces/ports.d.ts +53 -0
  98. package/dist/agent-runtime/engine/pieces/ports.js +1 -0
  99. package/dist/agent-runtime/engine/pieces/project-memory.d.ts +3 -0
  100. package/dist/agent-runtime/engine/pieces/project-memory.js +13 -0
  101. package/dist/agent-runtime/engine/pieces/prompt.d.ts +5 -0
  102. package/dist/agent-runtime/engine/pieces/prompt.js +130 -0
  103. package/dist/agent-runtime/engine/pieces/role-turn.d.ts +7 -0
  104. package/dist/agent-runtime/engine/pieces/role-turn.js +73 -0
  105. package/dist/agent-runtime/engine/pieces/shared.d.ts +67 -0
  106. package/dist/agent-runtime/engine/pieces/shared.js +40 -0
  107. package/dist/agent-runtime/engine/pieces/shell.d.ts +6 -0
  108. package/dist/agent-runtime/engine/pieces/shell.js +47 -0
  109. package/dist/agent-runtime/engine/pieces/verify.d.ts +7 -0
  110. package/dist/agent-runtime/engine/pieces/verify.js +102 -0
  111. package/dist/agent-runtime/engine/preflight.d.ts +27 -0
  112. package/dist/agent-runtime/engine/preflight.js +54 -0
  113. package/dist/agent-runtime/engine/regex.d.ts +3 -0
  114. package/dist/agent-runtime/engine/regex.js +19 -0
  115. package/dist/agent-runtime/engine/run-status.d.ts +563 -0
  116. package/dist/agent-runtime/engine/run-status.js +61 -0
  117. package/dist/agent-runtime/engine/runs.d.ts +605 -0
  118. package/dist/agent-runtime/engine/runs.js +247 -0
  119. package/dist/agent-runtime/engine/state.d.ts +64 -0
  120. package/dist/agent-runtime/engine/state.js +98 -0
  121. package/dist/agent-runtime/engine/steering/inbox.d.ts +54 -0
  122. package/dist/agent-runtime/engine/steering/inbox.js +113 -0
  123. package/dist/agent-runtime/engine/storage/fork-allocation.d.ts +21 -0
  124. package/dist/agent-runtime/engine/storage/fork-allocation.js +143 -0
  125. package/dist/agent-runtime/engine/storage/private-path.d.ts +11 -0
  126. package/dist/agent-runtime/engine/storage/private-path.js +74 -0
  127. package/dist/agent-runtime/engine/store/sqlite-store.d.ts +26 -0
  128. package/dist/agent-runtime/engine/store/sqlite-store.js +227 -0
  129. package/dist/agent-runtime/evaluation-corpus.d.ts +125 -0
  130. package/dist/agent-runtime/evaluation-corpus.js +4 -0
  131. package/dist/agent-runtime/evaluation.d.ts +9 -3
  132. package/dist/agent-runtime/evaluation.js +50 -8
  133. package/dist/agent-runtime/executor-types.d.ts +53 -3
  134. package/dist/agent-runtime/executor-types.js +35 -2
  135. package/dist/agent-runtime/executors.js +2 -2
  136. package/dist/agent-runtime/graph/artifacts.d.ts +7 -0
  137. package/dist/agent-runtime/graph/artifacts.js +82 -9
  138. package/dist/agent-runtime/graph/nodes.d.ts +2 -0
  139. package/dist/agent-runtime/graph/nodes.js +2 -2
  140. package/dist/agent-runtime/graph/roles.d.ts +8 -0
  141. package/dist/agent-runtime/graph/roles.js +25 -17
  142. package/dist/agent-runtime/kimi-acp.js +6 -6
  143. package/dist/agent-runtime/openai-executor.js +17 -12
  144. package/dist/agent-runtime/openspec.d.ts +17 -2
  145. package/dist/agent-runtime/openspec.js +54 -20
  146. package/dist/agent-runtime/prompts.d.ts +4 -3
  147. package/dist/agent-runtime/prompts.js +27 -6
  148. package/dist/agent-runtime/recovery.d.ts +1 -1
  149. package/dist/agent-runtime/repository-context.js +1 -1
  150. package/dist/agent-runtime/role-routing.js +4 -2
  151. package/dist/agent-runtime/role-state.d.ts +5 -0
  152. package/dist/agent-runtime/verification-plan.d.ts +2 -0
  153. package/dist/agent-runtime/verification-plan.js +10 -0
  154. package/dist/agent-runtime/workflow-types.d.ts +2 -0
  155. package/dist/agent-runtime/workflow.d.ts +3 -1
  156. package/dist/agent-runtime/workflow.js +7 -3
  157. package/dist/agent-runtime/workspace-tools.d.ts +2 -2
  158. package/dist/agent-runtime/workspace-tools.js +6 -6
  159. package/dist/installer/cli.js +5 -0
  160. package/dist/installer/phases/scaffold.d.ts +2 -2
  161. package/dist/installer/phases/scaffold.js +3 -7
  162. package/dist/pipeline/pipeline-state.d.ts +38 -4
  163. package/dist/pipeline/pipeline-state.js +96 -21
  164. package/integration-contract.json +111 -19
  165. package/package.json +13 -6
  166. package/schemas/agent-runtime.schema.json +93 -1
  167. package/schemas/workflow-definition.schema.json +314 -0
  168. package/templates/kimi/specrails/run-skill.mjs +15 -1
  169. package/templates/commands/specrails/batch-implement.md +0 -32
@@ -0,0 +1,102 @@
1
+ import { contentDigest } from '../canonical-json.js';
2
+ import { advisoryMemory } from './project-memory.js';
3
+ import { executeVerification, validateVerificationRequest } from '../../../pipeline/pipeline-state.js';
4
+ import { withScopeDefault } from '../../change-scope.js';
5
+ import { boundedText, json, paramsSchema, positiveInteger } from './shared.js';
6
+ /** Keep real subprocess diagnostics in committed outputs for subsequent agents.
7
+ * The full command evidence remains in the receipt; prioritize failed checks
8
+ * when the output budget is exhausted. */
9
+ function verificationDiagnostics(receipt) {
10
+ let remaining = 32_000;
11
+ const outputs = new Map();
12
+ const priority = receipt.commands.map((command, index) => ({ command, index }))
13
+ .sort((a, b) => Number(b.command.exitCode !== 0) - Number(a.command.exitCode !== 0));
14
+ for (const { command, index } of priority) {
15
+ const output = command.output.slice(-Math.min(8_000, remaining));
16
+ // slice(-0) would include all the original text.
17
+ outputs.set(index, remaining > 0 ? output : '');
18
+ remaining -= remaining > 0 ? output.length : 0;
19
+ }
20
+ let budget = 64_000;
21
+ const commands = [];
22
+ for (const { index, command } of priority) {
23
+ const output = outputs.get(index) ?? '';
24
+ const args = command.args.slice(0, 16).map(arg => boundedText(arg, 128));
25
+ const diagnostic = { repositoryId: command.repositoryId, command: boundedText(command.command, 512),
26
+ args, cwd: boundedText(command.cwd, 512),
27
+ exitCode: command.exitCode, durationMs: command.durationMs, output,
28
+ truncated: output.length < command.output.length || command.outputTruncated === true
29
+ || command.command.length > 512 || command.cwd.length > 512 || command.args.length > 16 || command.args.some(arg => arg.length > 128) };
30
+ const size = JSON.stringify(diagnostic).length;
31
+ if (size > budget)
32
+ break;
33
+ budget -= size;
34
+ commands.push(diagnostic);
35
+ }
36
+ return { commands, ...(commands.length < receipt.commands.length ? { omittedCommands: receipt.commands.length - commands.length } : {}) };
37
+ }
38
+ export const verificationCommandSchema = paramsSchema({
39
+ repositoryId: { type: 'string', minLength: 1, maxLength: 128 }, command: { type: 'string', minLength: 1, maxLength: 4096 },
40
+ args: { type: 'array', maxItems: 1024, items: { type: 'string', maxLength: 32_000 } }, cwd: { type: 'string', maxLength: 4096 },
41
+ env: { type: 'object', additionalProperties: { type: 'string', maxLength: 32_000 } }, timeoutMs: { ...positiveInteger, maximum: 7_200_000 },
42
+ key: { type: 'string', maxLength: 128 }, label: { type: 'string', minLength: 1, maxLength: 256 }, policy: { type: 'object' },
43
+ }, ['repositoryId', 'command', 'args']);
44
+ export function receiptEvidence(receipt) {
45
+ return { id: receipt.id, candidateHash: receipt.candidateHash, valid: receipt.valid, scope: receipt.kind, evidence: json(receipt) };
46
+ }
47
+ export function verificationDeadline(deps, context) {
48
+ const budget = deps.stepContext(context).remainingBudget();
49
+ return budget.maxDurationMs === undefined ? undefined : Date.now() + Math.max(0, budget.maxDurationMs);
50
+ }
51
+ export function verifyPiece(bindings) {
52
+ return {
53
+ descriptor: { kind: 'verify', paramsSchema: paramsSchema({ commands: { oneOf: [{ const: 'configured' }, { type: 'array', maxItems: 100, items: verificationCommandSchema }] },
54
+ additionalCommandsFrom: { type: 'string', minLength: 1, maxLength: 128 }, unverified: { type: 'boolean' }, maxConcurrency: { type: 'integer', minimum: 1, maximum: 4 } }, ['commands']), outcomes: ['pass', 'fail', 'failed'], effect: 'write', requiresAI: false, storeAccess: 'write' },
55
+ async execute(params, context) {
56
+ const deps = bindings();
57
+ const commands = (params.commands === 'configured' ? deps.config.verification : params.commands).map(command => withScopeDefault(deps.context, command));
58
+ const hostRepositories = new Set(commands.map(command => command.repositoryId));
59
+ if (typeof params.additionalCommandsFrom === 'string') {
60
+ const source = context.state.$outputs[params.additionalCommandsFrom];
61
+ const proposals = source?.structured?.verification;
62
+ if (!Array.isArray(proposals) || proposals.length > 20)
63
+ throw new Error('Verification proposals must be a bounded array from a committed agent output');
64
+ // Host checks always stay mandatory. The same scoped command validation
65
+ // applies to these actual subprocesses and to configured checks below.
66
+ for (const proposal of proposals) {
67
+ if (!proposal || typeof proposal !== 'object' || Array.isArray(proposal))
68
+ throw new Error('Invalid verification proposal');
69
+ const raw = proposal;
70
+ if (!deps.context.repositories.some(repository => repository.id === raw.repositoryId))
71
+ throw new Error('Unknown verification repository');
72
+ if (!hostRepositories.has(raw.repositoryId))
73
+ commands.push(withScopeDefault(deps.context, raw));
74
+ }
75
+ }
76
+ const coversAll = deps.context.repositories.every(repository => commands.some(command => command.repositoryId === repository.id));
77
+ const request = { kind: coversAll || params.unverified === true ? 'full' : 'scoped', commands, ...(params.unverified === true ? { unverified: true } : {}) };
78
+ validateVerificationRequest(deps.context, request);
79
+ const identity = { candidateHash: deps.executionSnapshot(context).candidate?.hash ?? null, scopeId: context.frame.scope.id,
80
+ repositories: deps.context.repositories.map(repository => ({ id: repository.id, path: repository.path })),
81
+ planHash: contentDigest(json(request)), concurrency: params.maxConcurrency ?? deps.config.efficiency?.verification?.maxConcurrency ?? 1 };
82
+ const memoryKey = contentDigest(identity);
83
+ const known = await advisoryMemory(context, () => deps.memory(context).get(['verification', 'known-commands'], memoryKey));
84
+ const receipt = await executeVerification(deps.context, request, deps.verification(context), output => context.progress({ type: 'verification-output', payload: { text: output } }), context.signal, {
85
+ deadline: verificationDeadline(deps, context), maxConcurrency: params.maxConcurrency ?? deps.config.efficiency?.verification?.maxConcurrency,
86
+ idleTimeoutMs: deps.config.guardrails?.['verify-idle-timeout'] === false ? 0 : undefined,
87
+ onEvidence: async (kind, payload) => context.progress({ type: 'runtime-efficiency-event', payload: { kind, ...payload } }),
88
+ });
89
+ await advisoryMemory(context, () => deps.memory(context).put(['verification', 'known-commands'], memoryKey, {
90
+ ...identity, observations: Math.min(1_000_000, typeof known?.value.observations === 'number' ? known.value.observations + 1 : 1),
91
+ lastAttemptId: context.frame.attemptId, lastReceiptId: receipt.id, lastValid: receipt.valid,
92
+ commands: receipt.commands.map(command => ({ repositoryId: command.repositoryId, command: command.command, exitCode: command.exitCode })),
93
+ }));
94
+ const infrastructure = receipt.commands.some(command => command.exitCode === -1 && command.outcome !== 'cancelled');
95
+ const outcome = infrastructure ? 'failed' : receipt.valid ? 'pass' : 'fail';
96
+ const verified = receipt.valid && receipt.commands.length > 0 && !receipt.unverifiedRepositories?.length;
97
+ return { outcome, ...(infrastructure ? { status: 'failed', error: { code: 'verification_execution_error', message: receipt.reason ?? 'A verification command could not complete' } } : {}),
98
+ output: { receiptId: receipt.id, valid: receipt.valid, ...(receipt.reason ? { reason: receipt.reason } : {}), ...verificationDiagnostics(receipt) },
99
+ receipt: receiptEvidence(receipt), ...(verified ? { verified: { receiptId: receipt.id, candidateHash: receipt.candidateHash, atTransition: context.frame.transition, revision: context.frame.transition } } : { verified: null }) };
100
+ },
101
+ };
102
+ }
@@ -0,0 +1,27 @@
1
+ import { type PipelineContext } from '../../pipeline/pipeline-state.js';
2
+ import { type ExecutorRegistry } from '../executors.js';
3
+ import type { RuntimeConfig } from '../executor-types.js';
4
+ import type { RoleCatalog, WorkflowDefinition } from './definition-types.js';
5
+ export interface DefinitionRunRequest {
6
+ context: PipelineContext;
7
+ config: RuntimeConfig;
8
+ change?: string;
9
+ }
10
+ export interface DefinitionRunInput {
11
+ context: unknown;
12
+ config: unknown;
13
+ definition: unknown;
14
+ change?: string;
15
+ registry?: ExecutorRegistry;
16
+ }
17
+ export declare function configuredRoles(config: RuntimeConfig): RoleCatalog;
18
+ /** Complete admission is read-only; no run, journal, provider turn or skill is created. */
19
+ export declare function preflightDefinition(input: DefinitionRunInput): Promise<{
20
+ request: DefinitionRunRequest;
21
+ definition: WorkflowDefinition;
22
+ registry: ExecutorRegistry;
23
+ budget: import("./contracts.js").WorkflowBudget;
24
+ roles: Readonly<Record<string, {
25
+ access: import("./contracts.js").EngineEffect;
26
+ }>>;
27
+ }>;
@@ -0,0 +1,54 @@
1
+ import { validatePipelineContext, validateVerificationRequest } from '../../pipeline/pipeline-state.js';
2
+ import { normalizeRuntimeConfig, resolveRoleDescriptor, roleIds } from '../config.js';
3
+ import { assertEffortSupported } from '../capabilities.js';
4
+ import { createExecutorRegistry } from '../executors.js';
5
+ import { EngineError } from './contracts.js';
6
+ import { intersectBudgets } from './budget.js';
7
+ import { validateWorkflowDefinition } from './definition-validator.js';
8
+ import { validationPieceRegistry } from './pieces/index.js';
9
+ export function configuredRoles(config) {
10
+ return Object.fromEntries(roleIds(config).map(id => [id, { access: resolveRoleDescriptor(config, id).access }]));
11
+ }
12
+ /** Complete admission is read-only; no run, journal, provider turn or skill is created. */
13
+ export async function preflightDefinition(input) {
14
+ const context = validatePipelineContext(input.context);
15
+ const config = normalizeRuntimeConfig(input.config, { registeredProviderIds: input.registry?.ids() });
16
+ if (config.enabled === false)
17
+ throw new EngineError('runtime_disabled', 'The project runtime is disabled');
18
+ if (context.ownership.git !== 'host')
19
+ throw new EngineError('invalid_ownership', 'Definition delivery must be owned by the host');
20
+ const roles = configuredRoles(config), validation = validateWorkflowDefinition(input.definition, validationPieceRegistry(), roles, { published: true });
21
+ if (!validation.ok)
22
+ throw new EngineError('invalid_definition', 'Definition failed admission', validation.errors.map(error => ({ ...error })));
23
+ const definition = validation.definition;
24
+ if (definition.roles.some(id => resolveRoleDescriptor(config, id).openspecSkill) && !input.change)
25
+ throw new EngineError('invalid_arguments', 'OpenSpec roles require a frozen change name');
26
+ if (definition.change !== 'none' && (!input.change || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(input.change) || input.change.length > 64))
27
+ throw new EngineError('invalid_arguments', 'This definition requires a change name of at most 64 characters');
28
+ if (definition.journal === 'implementation' && !context.specs.length)
29
+ throw new EngineError('invalid_scope', 'Implementation requires frozen specs or a goal');
30
+ if (config.verification.length)
31
+ validateVerificationRequest(context, { kind: 'scoped', commands: config.verification });
32
+ const budget = intersectBudgets(definition.budget, config.limits);
33
+ const registry = input.registry ?? createExecutorRegistry(config);
34
+ const engines = definition.roles.flatMap(id => {
35
+ const role = resolveRoleDescriptor(config, id);
36
+ return [role, ...(role.escalation ? [{ ...role, ...role.escalation }] : [])];
37
+ });
38
+ for (const body of [definition, ...Object.values(definition.components ?? {})])
39
+ for (const node of Object.values(body.nodes)) {
40
+ if (node.kind !== 'prompt')
41
+ continue;
42
+ const engine = node.params.engine;
43
+ registry.validateLimits(engine.provider, budget);
44
+ if (engine.effort)
45
+ assertEffortSupported(engine, await registry.capabilities(engine.provider, engine.model));
46
+ }
47
+ for (const engine of engines) {
48
+ registry.validateLimits(engine.provider, budget);
49
+ if (engine.effort)
50
+ assertEffortSupported(engine, await registry.capabilities(engine.provider, engine.model));
51
+ }
52
+ const request = { context, config, ...(input.change ? { change: input.change } : {}) };
53
+ return { request, definition, registry, budget, roles };
54
+ }
@@ -0,0 +1,3 @@
1
+ /** Regex is data in a constant script. V8 interrupts even catastrophic matching. */
2
+ export declare function capturePattern(pattern: string, text: string): Array<string | undefined> | null;
3
+ export declare function matchesPattern(pattern: string, text: string): boolean;
@@ -0,0 +1,19 @@
1
+ import { Script } from 'node:vm';
2
+ import { EngineError } from './contracts.js';
3
+ const matchScript = new Script('new RegExp(pattern).exec(text)', { filename: 'core-bounded-pattern' });
4
+ /** Regex is data in a constant script. V8 interrupts even catastrophic matching. */
5
+ export function capturePattern(pattern, text) {
6
+ if (pattern.length > 200)
7
+ throw new EngineError('invalid_expression', 'Pattern exceeds 200 characters');
8
+ try {
9
+ const match = matchScript.runInNewContext({ pattern, text: text.slice(0, 32_000) }, {
10
+ timeout: 50, contextCodeGeneration: { strings: false, wasm: false },
11
+ });
12
+ return match ? Array.from(match) : null;
13
+ }
14
+ catch (error) {
15
+ throw new EngineError('invalid_expression', error !== null && typeof error === 'object' && 'code' in error && error.code === 'ERR_SCRIPT_EXECUTION_TIMEOUT'
16
+ ? 'Regular expression exceeded 50 ms' : 'Invalid regular expression');
17
+ }
18
+ }
19
+ export function matchesPattern(pattern, text) { return capturePattern(pattern, text) !== null; }