@principles/pd-cli 1.118.0 → 1.120.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/__tests__/legacy-cleanup.test.d.ts +18 -0
- package/dist/commands/__tests__/legacy-cleanup.test.d.ts.map +1 -0
- package/dist/commands/__tests__/legacy-cleanup.test.js +459 -0
- package/dist/commands/__tests__/legacy-cleanup.test.js.map +1 -0
- package/dist/commands/__tests__/rulecode-flag-wiring.test.d.ts +21 -0
- package/dist/commands/__tests__/rulecode-flag-wiring.test.d.ts.map +1 -0
- package/dist/commands/__tests__/rulecode-flag-wiring.test.js +179 -0
- package/dist/commands/__tests__/rulecode-flag-wiring.test.js.map +1 -0
- package/dist/commands/__tests__/rulecode-handler.test.d.ts +16 -0
- package/dist/commands/__tests__/rulecode-handler.test.d.ts.map +1 -0
- package/dist/commands/__tests__/rulecode-handler.test.js +285 -0
- package/dist/commands/__tests__/rulecode-handler.test.js.map +1 -0
- package/dist/commands/candidate.d.ts +1 -0
- package/dist/commands/candidate.d.ts.map +1 -1
- package/dist/commands/candidate.js +32 -6
- package/dist/commands/candidate.js.map +1 -1
- package/dist/commands/legacy-cleanup.d.ts +72 -6
- package/dist/commands/legacy-cleanup.d.ts.map +1 -1
- package/dist/commands/legacy-cleanup.js +243 -23
- package/dist/commands/legacy-cleanup.js.map +1 -1
- package/dist/commands/rulecode.d.ts +85 -0
- package/dist/commands/rulecode.d.ts.map +1 -0
- package/dist/commands/rulecode.js +356 -0
- package/dist/commands/rulecode.js.map +1 -0
- package/dist/commands/runtime-internalization-run-rulehost.d.ts.map +1 -1
- package/dist/commands/runtime-internalization-run-rulehost.js +4 -7
- package/dist/commands/runtime-internalization-run-rulehost.js.map +1 -1
- package/dist/index.js +30 -9
- package/dist/index.js.map +1 -1
- package/dist/services/rulehost-pipeline-runner.d.ts.map +1 -1
- package/dist/services/rulehost-pipeline-runner.js +31 -15
- package/dist/services/rulehost-pipeline-runner.js.map +1 -1
- package/package.json +1 -1
- package/scripts/llm-dogfood.ts +8 -12
- package/src/commands/__tests__/legacy-cleanup.test.ts +596 -0
- package/src/commands/__tests__/rulecode-flag-wiring.test.ts +230 -0
- package/src/commands/__tests__/rulecode-handler.test.ts +369 -0
- package/src/commands/candidate.ts +29 -7
- package/src/commands/legacy-cleanup.ts +335 -27
- package/src/commands/rulecode.ts +434 -0
- package/src/commands/runtime-internalization-run-rulehost.ts +3 -8
- package/src/index.ts +31 -9
- package/src/services/rulehost-pipeline-runner.ts +36 -18
- package/tests/commands/candidate-internalize-lineage.test.ts +44 -0
- package/tests/commands/cli-command-tree.test.ts +40 -0
- package/tests/commands/runtime.test.ts +9 -3
- package/tests/e2e/cross-package-acceptance.test.ts +1 -1
- package/tests/services/rulehost-pipeline-runner.test.ts +86 -2
|
@@ -76,4 +76,44 @@ describe('CLI command tree structure', () => {
|
|
|
76
76
|
const output = runPdHelp(['runtime', 'activation', '--help']);
|
|
77
77
|
expect(output).toMatch(/edit\s/);
|
|
78
78
|
});
|
|
79
|
+
|
|
80
|
+
it('rulecode command exists with spec/validate/replay subcommands (pd rulecode --help)', () => {
|
|
81
|
+
const output = runPdHelp(['rulecode', '--help']);
|
|
82
|
+
expect(output).toContain('spec');
|
|
83
|
+
expect(output).toContain('validate');
|
|
84
|
+
expect(output).toContain('replay');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('rulecode spec subcommand has --json and --workspace (pd rulecode spec --help)', () => {
|
|
88
|
+
const output = runPdHelp(['rulecode', 'spec', '--help']);
|
|
89
|
+
expect(output).toContain('--json');
|
|
90
|
+
expect(output).toContain('--workspace');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('rulecode validate subcommand has --code, --code-file, --json (pd rulecode validate --help)', () => {
|
|
94
|
+
const output = runPdHelp(['rulecode', 'validate', '--help']);
|
|
95
|
+
expect(output).toContain('--code');
|
|
96
|
+
expect(output).toContain('--code-file');
|
|
97
|
+
expect(output).toContain('--json');
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('rulecode replay subcommand has --golden-trace (required), --code, --json (pd rulecode replay --help)', () => {
|
|
101
|
+
const output = runPdHelp(['rulecode', 'replay', '--help']);
|
|
102
|
+
expect(output).toContain('--golden-trace');
|
|
103
|
+
expect(output).toContain('--code');
|
|
104
|
+
expect(output).toContain('--json');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('legacy cleanup subcommand has --dry-run, --apply, --json (pd legacy cleanup --help)', () => {
|
|
108
|
+
const output = runPdHelp(['legacy', 'cleanup', '--help']);
|
|
109
|
+
expect(output).toContain('--dry-run');
|
|
110
|
+
expect(output).toContain('--apply');
|
|
111
|
+
expect(output).toContain('--json');
|
|
112
|
+
expect(output).toContain('--workspace');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('legacy cleanup description mentions V1 Artificer artifacts', () => {
|
|
116
|
+
const output = runPdHelp(['legacy', 'cleanup', '--help']);
|
|
117
|
+
expect(output).toContain('V1 Artificer');
|
|
118
|
+
});
|
|
79
119
|
});
|
|
@@ -365,7 +365,7 @@ describe('pd runtime probe', () => {
|
|
|
365
365
|
// Ensure NONEXISTENT_VAR is NOT set
|
|
366
366
|
delete process.env.NONEXISTENT_VAR;
|
|
367
367
|
|
|
368
|
-
const
|
|
368
|
+
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
369
369
|
const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => undefined) as () => never);
|
|
370
370
|
|
|
371
371
|
await handleRuntimeProbe({
|
|
@@ -376,11 +376,17 @@ describe('pd runtime probe', () => {
|
|
|
376
376
|
json: true,
|
|
377
377
|
} as RuntimeProbeOptions);
|
|
378
378
|
|
|
379
|
-
|
|
379
|
+
const output = consoleSpy.mock.calls.map(([chunk]) => String(chunk)).join('');
|
|
380
|
+
expect(JSON.parse(output)).toEqual(expect.objectContaining({
|
|
381
|
+
status: 'failed',
|
|
382
|
+
reason: 'api_key_not_set',
|
|
383
|
+
message: expect.stringContaining('NONEXISTENT_VAR'),
|
|
384
|
+
nextAction: expect.any(String),
|
|
385
|
+
}));
|
|
380
386
|
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
381
387
|
expect(vi.mocked(probeRuntime)).not.toHaveBeenCalled();
|
|
382
388
|
|
|
383
|
-
|
|
389
|
+
consoleSpy.mockRestore();
|
|
384
390
|
exitSpy.mockRestore();
|
|
385
391
|
});
|
|
386
392
|
});
|
|
@@ -208,7 +208,7 @@ function makeTmpDir(): string {
|
|
|
208
208
|
|
|
209
209
|
async function seedDreamerWithId(sm: RuntimeStateManager, taskId: string, painId: string): Promise<void> {
|
|
210
210
|
const baseMetadata = JSON.parse(createPITaskDiagnosticJson({
|
|
211
|
-
dependencyTaskIds: [], channel: '
|
|
211
|
+
dependencyTaskIds: [], channel: 'code_tool_hook', timeoutMs: 1000, inputArtifactRefs: [], outputArtifactRefs: [],
|
|
212
212
|
})) as Record<string, unknown>;
|
|
213
213
|
const diagnosticJson = JSON.stringify({ ...baseMetadata, sourcePainId: painId });
|
|
214
214
|
await sm.createTask({ taskId, taskKind: 'dreamer', status: 'pending', attemptCount: 0, maxAttempts: 3, diagnosticJson });
|
|
@@ -197,9 +197,14 @@ function makeAdapter(opts?: { evaluator?: EvaluatorFactory }): ScriptedAdapter {
|
|
|
197
197
|
* diagnosticJson (outside the pi_metadata envelope). This mirrors the pattern
|
|
198
198
|
* from source-trace-locator.test.ts and PainSignalBridge.
|
|
199
199
|
*/
|
|
200
|
-
async function seedDreamerWithId(
|
|
200
|
+
async function seedDreamerWithId(
|
|
201
|
+
sm: RuntimeStateManager,
|
|
202
|
+
taskId: string,
|
|
203
|
+
painId: string,
|
|
204
|
+
channel: 'prompt' | 'code_tool_hook' | 'defer_archive' = 'code_tool_hook',
|
|
205
|
+
): Promise<void> {
|
|
201
206
|
const baseMetadata = JSON.parse(createPITaskDiagnosticJson({
|
|
202
|
-
dependencyTaskIds: [], channel
|
|
207
|
+
dependencyTaskIds: [], channel, timeoutMs: 1000, inputArtifactRefs: [], outputArtifactRefs: [],
|
|
203
208
|
})) as Record<string, unknown>;
|
|
204
209
|
const diagnosticJson = JSON.stringify({ ...baseMetadata, sourcePainId: painId });
|
|
205
210
|
await sm.createTask({ taskId, taskKind: 'dreamer', status: 'pending', attemptCount: 0, maxAttempts: 3, diagnosticJson });
|
|
@@ -441,6 +446,85 @@ describe('runRuleHostPipeline (PRI-429) — atomic capability + exact pain match
|
|
|
441
446
|
expect(result.stages[0]?.status).toBe('failed');
|
|
442
447
|
}, 60_000);
|
|
443
448
|
|
|
449
|
+
it('selects the Dreamer task matching the requested activation channel', async () => {
|
|
450
|
+
tmpDir = makeTmpDir();
|
|
451
|
+
const sm = new RuntimeStateManager({ workspaceDir: tmpDir });
|
|
452
|
+
await sm.initialize();
|
|
453
|
+
await seedDreamerWithId(sm, 'dreamer-prompt', 'pain-multi-channel', 'prompt');
|
|
454
|
+
await seedDreamerWithId(sm, 'dreamer-code-hook', 'pain-multi-channel', 'code_tool_hook');
|
|
455
|
+
await sm.close();
|
|
456
|
+
|
|
457
|
+
const adapter = makeAdapter();
|
|
458
|
+
const result = await runRuleHostPipeline({
|
|
459
|
+
workspaceDir: tmpDir,
|
|
460
|
+
painId: 'pain-multi-channel',
|
|
461
|
+
runtimeAdapter: adapter,
|
|
462
|
+
channel: 'code_tool_hook',
|
|
463
|
+
pollIntervalMs: 5,
|
|
464
|
+
timeoutMs: 1000,
|
|
465
|
+
onStoreReady: (store) => { adapter.artifactStore = store; },
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
expect(result.stages[0]).toMatchObject({
|
|
469
|
+
name: 'pain_lookup',
|
|
470
|
+
status: 'succeeded',
|
|
471
|
+
taskId: 'dreamer-code-hook',
|
|
472
|
+
});
|
|
473
|
+
}, 60_000);
|
|
474
|
+
|
|
475
|
+
it('uses the sole pain-linked Dreamer seed when its source channel differs from the target channel', async () => {
|
|
476
|
+
tmpDir = makeTmpDir();
|
|
477
|
+
const sm = new RuntimeStateManager({ workspaceDir: tmpDir });
|
|
478
|
+
await sm.initialize();
|
|
479
|
+
await seedDreamerWithId(sm, 'dreamer-prompt-seed', 'pain-cross-channel', 'prompt');
|
|
480
|
+
await sm.close();
|
|
481
|
+
|
|
482
|
+
const adapter = makeAdapter();
|
|
483
|
+
const result = await runRuleHostPipeline({
|
|
484
|
+
workspaceDir: tmpDir,
|
|
485
|
+
painId: 'pain-cross-channel',
|
|
486
|
+
runtimeAdapter: adapter,
|
|
487
|
+
channel: 'code_tool_hook',
|
|
488
|
+
pollIntervalMs: 5,
|
|
489
|
+
timeoutMs: 1000,
|
|
490
|
+
onStoreReady: (store) => { adapter.artifactStore = store; },
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
expect(result.stages[0]).toMatchObject({
|
|
494
|
+
name: 'pain_lookup',
|
|
495
|
+
status: 'succeeded',
|
|
496
|
+
taskId: 'dreamer-prompt-seed',
|
|
497
|
+
});
|
|
498
|
+
}, 60_000);
|
|
499
|
+
|
|
500
|
+
it('resumes from a succeeded Dreamer seed instead of trying to lease it again', async () => {
|
|
501
|
+
tmpDir = makeTmpDir();
|
|
502
|
+
const sm = new RuntimeStateManager({ workspaceDir: tmpDir });
|
|
503
|
+
await sm.initialize();
|
|
504
|
+
await seedDreamerWithId(sm, 'dreamer-resume', 'pain-resume');
|
|
505
|
+
await sm.close();
|
|
506
|
+
|
|
507
|
+
const firstAdapter = makeAdapter();
|
|
508
|
+
await runRuleHostPipeline({
|
|
509
|
+
workspaceDir: tmpDir, painId: 'pain-resume', runtimeAdapter: firstAdapter,
|
|
510
|
+
pollIntervalMs: 5, timeoutMs: 1000,
|
|
511
|
+
onStoreReady: (store) => { firstAdapter.artifactStore = store; },
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
const resumedAdapter = makeAdapter();
|
|
515
|
+
const resumed = await runRuleHostPipeline({
|
|
516
|
+
workspaceDir: tmpDir, painId: 'pain-resume', runtimeAdapter: resumedAdapter,
|
|
517
|
+
pollIntervalMs: 5, timeoutMs: 1000,
|
|
518
|
+
onStoreReady: (store) => { resumedAdapter.artifactStore = store; },
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
expect(resumed.stages.slice(0, 2)).toEqual([
|
|
522
|
+
{ name: 'pain_lookup', status: 'succeeded', taskId: 'dreamer-resume' },
|
|
523
|
+
{ name: 'dreamer', taskId: 'dreamer-resume', status: 'succeeded' },
|
|
524
|
+
]);
|
|
525
|
+
expect(resumed.degradationReason).not.toContain('lease');
|
|
526
|
+
}, 60_000);
|
|
527
|
+
|
|
444
528
|
// ── Test 8 (E fix): retried status is NOT terminal — bounded retry succeeds ──
|
|
445
529
|
it('retried status triggers bounded retry and eventually succeeds (E fix)', async () => {
|
|
446
530
|
tmpDir = makeTmpDir();
|