@principles/pd-cli 1.101.0 → 1.102.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 (28) hide show
  1. package/dist/commands/diagnose.js +27 -27
  2. package/dist/commands/diagnose.js.map +1 -1
  3. package/dist/commands/pain-retry.d.ts.map +1 -1
  4. package/dist/commands/pain-retry.js +22 -27
  5. package/dist/commands/pain-retry.js.map +1 -1
  6. package/dist/commands/runtime-internalization-run-once.d.ts.map +1 -1
  7. package/dist/commands/runtime-internalization-run-once.js +11 -9
  8. package/dist/commands/runtime-internalization-run-once.js.map +1 -1
  9. package/dist/commands/runtime.d.ts +1 -1
  10. package/dist/commands/runtime.d.ts.map +1 -1
  11. package/dist/commands/runtime.js +92 -25
  12. package/dist/commands/runtime.js.map +1 -1
  13. package/dist/services/resolve-runtime-from-pd-config.d.ts +59 -0
  14. package/dist/services/resolve-runtime-from-pd-config.d.ts.map +1 -0
  15. package/dist/services/resolve-runtime-from-pd-config.js +96 -0
  16. package/dist/services/resolve-runtime-from-pd-config.js.map +1 -0
  17. package/package.json +1 -1
  18. package/src/commands/diagnose.ts +26 -26
  19. package/src/commands/pain-retry.ts +21 -25
  20. package/src/commands/runtime-internalization-run-once.ts +10 -9
  21. package/src/commands/runtime.ts +96 -24
  22. package/src/services/resolve-runtime-from-pd-config.ts +142 -0
  23. package/tests/commands/console-launcher-edge-cases.test.ts +14 -47
  24. package/tests/commands/diagnose.test.ts +91 -39
  25. package/tests/commands/pain-retry.test.ts +130 -15
  26. package/tests/commands/pri-393-runtime-config-unification.test.ts +284 -0
  27. package/tests/commands/runtime-internalization-run-once.test.ts +59 -53
  28. package/tests/commands/runtime.test.ts +124 -1
@@ -1,7 +1,36 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest';
2
2
  import { handleRuntimeProbe, type RuntimeProbeOptions } from '../../src/commands/runtime.js';
3
3
 
4
- // Mock probeRuntime
4
+ // Mock resolveRuntimeWithOverrides
5
+ const { mockResolveRuntimeWithOverrides } = vi.hoisted(() => {
6
+ const fn = vi.fn().mockReturnValue({
7
+ result: {
8
+ runtimeKind: 'pi-ai',
9
+ provider: 'test-provider',
10
+ model: 'test-model',
11
+ apiKeyEnv: 'TEST_API_KEY',
12
+ maxRetries: 2,
13
+ timeoutMs: 180_000,
14
+ },
15
+ mergedConfig: {
16
+ runtimeKind: 'pi-ai',
17
+ provider: 'test-provider',
18
+ model: 'test-model',
19
+ apiKeyEnv: 'TEST_API_KEY',
20
+ maxRetries: 2,
21
+ timeoutMs: 180_000,
22
+ },
23
+ legacyWarnings: [],
24
+ configSource: '.pd/config.yaml',
25
+ configLoadResult: { ok: true, effective: {}, defaults: {}, legacyFilesDetected: [] },
26
+ });
27
+ return { mockResolveRuntimeWithOverrides: fn };
28
+ });
29
+
30
+ vi.mock('../../src/services/resolve-runtime-from-pd-config.js', () => ({
31
+ resolveRuntimeWithOverrides: mockResolveRuntimeWithOverrides,
32
+ }));
33
+
5
34
  vi.mock('@principles/core/runtime-v2', () => ({
6
35
  probeRuntime: vi.fn().mockResolvedValue({
7
36
  runtimeKind: 'openclaw-cli',
@@ -260,4 +289,98 @@ describe('pd runtime probe', () => {
260
289
  consoleErrorSpy.mockRestore();
261
290
  exitSpy.mockRestore();
262
291
  });
292
+
293
+ // ── pi-ai probe: maxRetries backfill from .pd/config.yaml ───────────────
294
+ it('PRI-393: pi-ai probe reads maxRetries from .pd/config.yaml when --maxRetries not passed', async () => {
295
+ process.env.TEST_API_KEY = 'test-value';
296
+ const { probeRuntime } = await import('@principles/core/runtime-v2');
297
+ vi.mocked(probeRuntime).mockResolvedValue({
298
+ runtimeKind: 'pi-ai',
299
+ provider: 'test-provider',
300
+ model: 'test-model',
301
+ health: { healthy: true, degraded: false, warnings: [], lastCheckedAt: '2026-06-14T00:00:00.000Z' },
302
+ capabilities: {},
303
+ });
304
+
305
+ const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
306
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => undefined) as () => never);
307
+
308
+ // mockResolveRuntimeWithOverrides returns maxRetries: 2
309
+ // No --maxRetries CLI flag
310
+ await handleRuntimeProbe({
311
+ runtime: 'pi-ai',
312
+ provider: 'test-provider',
313
+ model: 'test-model',
314
+ apiKeyEnv: 'TEST_API_KEY',
315
+ workspace: '/tmp/ws',
316
+ json: true,
317
+ } as RuntimeProbeOptions);
318
+
319
+ expect(vi.mocked(probeRuntime)).toHaveBeenCalledWith(
320
+ expect.objectContaining({ maxRetries: 2 }),
321
+ );
322
+
323
+ delete process.env.TEST_API_KEY;
324
+ consoleSpy.mockRestore();
325
+ exitSpy.mockRestore();
326
+ });
327
+
328
+ it('PRI-393: CLI --maxRetries overrides .pd/config.yaml maxRetries', async () => {
329
+ process.env.TEST_API_KEY = 'test-value';
330
+ const { probeRuntime } = await import('@principles/core/runtime-v2');
331
+ vi.mocked(probeRuntime).mockResolvedValue({
332
+ runtimeKind: 'pi-ai',
333
+ provider: 'test-provider',
334
+ model: 'test-model',
335
+ health: { healthy: true, degraded: false, warnings: [], lastCheckedAt: '2026-06-14T00:00:00.000Z' },
336
+ capabilities: {},
337
+ });
338
+
339
+ const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
340
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => undefined) as () => never);
341
+
342
+ await handleRuntimeProbe({
343
+ runtime: 'pi-ai',
344
+ provider: 'test-provider',
345
+ model: 'test-model',
346
+ apiKeyEnv: 'TEST_API_KEY',
347
+ maxRetries: 5,
348
+ workspace: '/tmp/ws',
349
+ json: true,
350
+ } as RuntimeProbeOptions);
351
+
352
+ expect(vi.mocked(probeRuntime)).toHaveBeenCalledWith(
353
+ expect.objectContaining({ maxRetries: 5 }),
354
+ );
355
+
356
+ delete process.env.TEST_API_KEY;
357
+ consoleSpy.mockRestore();
358
+ exitSpy.mockRestore();
359
+ });
360
+
361
+ it('PRI-393: env var missing → process.exit(1) and does NOT call probeRuntime', async () => {
362
+ const { probeRuntime } = await import('@principles/core/runtime-v2');
363
+ vi.mocked(probeRuntime).mockClear();
364
+
365
+ // Ensure NONEXISTENT_VAR is NOT set
366
+ delete process.env.NONEXISTENT_VAR;
367
+
368
+ const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
369
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => undefined) as () => never);
370
+
371
+ await handleRuntimeProbe({
372
+ runtime: 'pi-ai',
373
+ provider: 'test-provider',
374
+ model: 'test-model',
375
+ apiKeyEnv: 'NONEXISTENT_VAR',
376
+ json: true,
377
+ } as RuntimeProbeOptions);
378
+
379
+ expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('NONEXISTENT_VAR'));
380
+ expect(exitSpy).toHaveBeenCalledWith(1);
381
+ expect(vi.mocked(probeRuntime)).not.toHaveBeenCalled();
382
+
383
+ consoleErrorSpy.mockRestore();
384
+ exitSpy.mockRestore();
385
+ });
263
386
  });