@principles/pd-cli 1.82.0 → 1.84.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 (65) hide show
  1. package/dist/commands/diagnose.d.ts.map +1 -1
  2. package/dist/commands/diagnose.js +5 -0
  3. package/dist/commands/diagnose.js.map +1 -1
  4. package/dist/commands/pain-retry.d.ts.map +1 -1
  5. package/dist/commands/pain-retry.js +5 -0
  6. package/dist/commands/pain-retry.js.map +1 -1
  7. package/dist/commands/runtime-internalization-run-once.d.ts.map +1 -1
  8. package/dist/commands/runtime-internalization-run-once.js +5 -1
  9. package/dist/commands/runtime-internalization-run-once.js.map +1 -1
  10. package/dist/commands/runtime-uat.d.ts +1 -0
  11. package/dist/commands/runtime-uat.d.ts.map +1 -1
  12. package/dist/commands/runtime-uat.guard.test.d.ts +2 -0
  13. package/dist/commands/runtime-uat.guard.test.d.ts.map +1 -0
  14. package/dist/commands/runtime-uat.guard.test.js +155 -0
  15. package/dist/commands/runtime-uat.guard.test.js.map +1 -0
  16. package/dist/commands/runtime-uat.js +29 -3
  17. package/dist/commands/runtime-uat.js.map +1 -1
  18. package/dist/config-reader.d.ts +25 -0
  19. package/dist/config-reader.d.ts.map +1 -0
  20. package/dist/config-reader.js +109 -0
  21. package/dist/config-reader.js.map +1 -0
  22. package/dist/index.js +2 -0
  23. package/dist/index.js.map +1 -1
  24. package/dist/utils/production-workspace-guard.d.ts +77 -0
  25. package/dist/utils/production-workspace-guard.d.ts.map +1 -0
  26. package/dist/utils/production-workspace-guard.js +170 -0
  27. package/dist/utils/production-workspace-guard.js.map +1 -0
  28. package/dist/utils/production-workspace-guard.test.d.ts +2 -0
  29. package/dist/utils/production-workspace-guard.test.d.ts.map +1 -0
  30. package/dist/utils/production-workspace-guard.test.js +95 -0
  31. package/dist/utils/production-workspace-guard.test.js.map +1 -0
  32. package/package.json +1 -1
  33. package/src/commands/diagnose.ts +8 -1
  34. package/src/commands/pain-retry.ts +8 -1
  35. package/src/commands/runtime-internalization-run-once.ts +6 -2
  36. package/src/commands/runtime-uat.guard.test.ts +177 -0
  37. package/src/commands/runtime-uat.ts +42 -4
  38. package/src/config-reader.ts +122 -0
  39. package/src/index.ts +2 -0
  40. package/src/utils/production-workspace-guard.test.ts +108 -0
  41. package/src/utils/production-workspace-guard.ts +219 -0
  42. package/tests/commands/candidate-audit-repair.test.ts +1 -0
  43. package/tests/commands/candidate-intake.test.ts +1 -0
  44. package/tests/commands/candidate-internalization-backfill.test.ts +1 -0
  45. package/tests/commands/candidate-internalize.test.ts +1 -0
  46. package/tests/commands/candidate-route.test.ts +1 -0
  47. package/tests/commands/diagnose.test.ts +5 -0
  48. package/tests/commands/health.test.ts +1 -0
  49. package/tests/commands/pain-record.test.ts +1 -0
  50. package/tests/commands/pain-retry.test.ts +5 -0
  51. package/tests/commands/runtime-activation.test.ts +1 -0
  52. package/tests/commands/runtime-canary.test.ts +1 -0
  53. package/tests/commands/runtime-diagnostics-export.test.ts +1 -0
  54. package/tests/commands/runtime-health-snapshot.test.ts +1 -0
  55. package/tests/commands/runtime-internalization-enqueue-successors.test.ts +1 -0
  56. package/tests/commands/runtime-internalization-integrity-repair.test.ts +1 -0
  57. package/tests/commands/runtime-internalization-integrity.test.ts +1 -0
  58. package/tests/commands/runtime-internalization-queue.test.ts +1 -0
  59. package/tests/commands/runtime-internalization-run-once.test.ts +5 -0
  60. package/tests/commands/runtime-internalization-wake-once.test.ts +1 -0
  61. package/tests/commands/runtime-pruning.test.ts +1 -0
  62. package/tests/commands/runtime-recovery.test.ts +1 -0
  63. package/tests/commands/runtime.test.ts +1 -0
  64. package/tests/commands/trace.test.ts +1 -0
  65. package/tests/config-reader.test.ts +142 -0
@@ -43,6 +43,7 @@ vi.mock('@principles/core/runtime-v2', () => ({
43
43
  auditCandidateLedgerConsistency: mockAuditConsistency,
44
44
  buildGfiWorkspaceSnapshot: mockBuildGfiSnapshot,
45
45
  classifyGfiWorkspaceHealth: mockClassifyGfiHealth,
46
+ resolveOutputLanguage: vi.fn().mockReturnValue({ outputLanguage: 'zh-CN' }),
46
47
  }));
47
48
 
48
49
  vi.mock('../../src/services/feature-flag-loader.js', () => ({
@@ -36,6 +36,7 @@ vi.mock('@principles/core/runtime-v2', () => ({
36
36
  }),
37
37
  auditCandidateLedgerConsistency: mockAuditConsistency,
38
38
  buildGfiWorkspaceSnapshot: mockBuildGfiSnapshot,
39
+ resolveOutputLanguage: vi.fn().mockReturnValue({ outputLanguage: 'zh-CN' }),
39
40
  }));
40
41
 
41
42
  vi.mock('../../src/commands/runtime-canary.js', () => ({
@@ -20,6 +20,7 @@ vi.mock('@principles/core/runtime-v2', () => ({
20
20
  OperatorHealthReadModel: vi.fn().mockImplementation(function () {
21
21
  return { getSnapshot: mockSnapshotFn, close: mockCloseFn };
22
22
  }),
23
+ resolveOutputLanguage: vi.fn().mockReturnValue({ outputLanguage: 'zh-CN' }),
23
24
  }));
24
25
 
25
26
  import { handleRuntimeHealthSnapshot } from '../../src/commands/runtime-health-snapshot.js';
@@ -54,6 +54,7 @@ vi.mock('@principles/core/runtime-v2', () => ({
54
54
  return null;
55
55
  }
56
56
  }),
57
+ resolveOutputLanguage: vi.fn().mockReturnValue({ outputLanguage: 'zh-CN' }),
57
58
  }));
58
59
 
59
60
  import { handleRuntimeInternalizationEnqueueSuccessors } from '../../src/commands/runtime-internalization-enqueue-successors.js';
@@ -10,6 +10,7 @@ vi.mock('@principles/core/runtime-v2', () => ({
10
10
  InternalizationIntegrityRemediation: vi.fn().mockImplementation(function () {
11
11
  return { repair: mockRepair };
12
12
  }),
13
+ resolveOutputLanguage: vi.fn().mockReturnValue({ outputLanguage: 'zh-CN' }),
13
14
  }));
14
15
 
15
16
  import { Command } from 'commander';
@@ -10,6 +10,7 @@ vi.mock('@principles/core/runtime-v2', () => ({
10
10
  InternalizationChainIntegrityReadModel: vi.fn().mockImplementation(function () {
11
11
  return { check: mockCheck };
12
12
  }),
13
+ resolveOutputLanguage: vi.fn().mockReturnValue({ outputLanguage: 'zh-CN' }),
13
14
  }));
14
15
 
15
16
  import { handleRuntimeInternalizationIntegrity } from '../../src/commands/runtime-internalization-integrity.js';
@@ -21,6 +21,7 @@ vi.mock('@principles/core/runtime-v2', () => ({
21
21
  readModel: { getSnapshot: mockGetSnapshot, close: mockClose },
22
22
  close: mockClose,
23
23
  }),
24
+ resolveOutputLanguage: vi.fn().mockReturnValue({ outputLanguage: 'zh-CN' }),
24
25
  }));
25
26
 
26
27
  vi.mock('../../src/services/feature-flag-loader.js', () => ({
@@ -122,6 +122,11 @@ vi.mock('@principles/core/runtime-v2', () => ({
122
122
  }),
123
123
  isRuntimeConfigError: vi.fn().mockReturnValue(false),
124
124
  validateRuntimeConfig: vi.fn(),
125
+ resolveOutputLanguage: vi.fn().mockReturnValue({ outputLanguage: 'zh-CN' }),
126
+ }));
127
+
128
+ vi.mock('../../src/config-reader.js', () => ({
129
+ readOutputLanguageFromWorkspace: vi.fn().mockReturnValue({ outputLanguage: 'zh-CN' }),
125
130
  }));
126
131
 
127
132
  import { handleRuntimeInternalizationRunOnce } from '../../src/commands/runtime-internalization-run-once.js';
@@ -21,6 +21,7 @@ vi.mock('@principles/core/runtime-v2', () => ({
21
21
  InternalizationOrchestrator: vi.fn().mockImplementation(function () {
22
22
  return { wakeOnce: mockWakeOnce };
23
23
  }),
24
+ resolveOutputLanguage: vi.fn().mockReturnValue({ outputLanguage: 'zh-CN' }),
24
25
  }));
25
26
 
26
27
  import { handleRuntimeInternalizationWakeOnce } from '../../src/commands/runtime-internalization-wake-once.js';
@@ -87,6 +87,7 @@ vi.mock('@principles/core/runtime-v2', () => ({
87
87
  listPruningReviews: mockListPruningReviews,
88
88
  buildMaskedPrincipleSet: mockBuildMaskedPrincipleSet,
89
89
  removeOrphanReferencesFromLedger: mockRemoveOrphanReferencesFromLedger,
90
+ resolveOutputLanguage: vi.fn().mockReturnValue({ outputLanguage: 'zh-CN' }),
90
91
  }));
91
92
 
92
93
  import { handlePruningReport, handlePruningExplain, handlePruningReview, handlePruningRollback, handlePruningOrphans } from '../../src/commands/runtime-pruning.js';
@@ -28,6 +28,7 @@ vi.mock('@principles/core/runtime-v2', () => ({
28
28
  warnings: input.warnings ?? [],
29
29
  })),
30
30
  remediationAction: vi.fn((input) => input),
31
+ resolveOutputLanguage: vi.fn().mockReturnValue({ outputLanguage: 'zh-CN' }),
31
32
  }));
32
33
 
33
34
  import { handleRuntimeRecoverySweep } from '../../src/commands/runtime-recovery.js';
@@ -32,6 +32,7 @@ vi.mock('@principles/core/runtime-v2', () => ({
32
32
  agentId: 'main',
33
33
  }),
34
34
  isRuntimeConfigError: vi.fn().mockReturnValue(false),
35
+ resolveOutputLanguage: vi.fn().mockReturnValue({ outputLanguage: 'zh-CN' }),
35
36
  PDRuntimeError: class PDRuntimeError extends Error {
36
37
  constructor(public category: string, message: string) {
37
38
  super(message);
@@ -14,6 +14,7 @@ vi.mock('@principles/core/runtime-v2', () => ({
14
14
  PainChainReadModel: vi.fn().mockImplementation(function () {
15
15
  return { traceByPainId: mockTraceByPainId, close: mockPainChainClose };
16
16
  }),
17
+ resolveOutputLanguage: vi.fn().mockReturnValue({ outputLanguage: 'zh-CN' }),
17
18
  }));
18
19
 
19
20
  vi.mock('../../src/resolve-workspace.js', () => ({
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Tests for config-reader — readOutputLanguageFromWorkspace (PRI-336).
3
+ *
4
+ * Validates:
5
+ * - No config file → legitimate default, no warning
6
+ * - No principles section → legitimate default, no warning
7
+ * - No outputLanguage key → legitimate default, no warning
8
+ * - Read error → degraded with read_error reason + nextAction (ERR-002/009)
9
+ * - YAML parse error → degraded with yaml_parse_error reason + nextAction
10
+ * - Invalid config root → degraded with invalid_config_root reason + nextAction
11
+ * - Invalid principles structure → degraded with invalid_principles_structure reason + nextAction
12
+ * - Valid outputLanguage → resolved value
13
+ * - Invalid outputLanguage value → degraded with invalid value warning
14
+ */
15
+
16
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
17
+ import { readOutputLanguageFromWorkspace } from '../../src/config-reader.js';
18
+
19
+ // Mock fs and yaml
20
+ vi.mock('fs', () => ({
21
+ existsSync: vi.fn(),
22
+ readFileSync: vi.fn(),
23
+ }));
24
+
25
+ vi.mock('js-yaml', () => ({
26
+ default: {
27
+ load: vi.fn(),
28
+ JSON_SCHEMA: 'JSON_SCHEMA',
29
+ },
30
+ }));
31
+
32
+ import * as fs from 'fs';
33
+ import yaml from 'js-yaml';
34
+
35
+ const mockExistsSync = vi.mocked(fs.existsSync);
36
+ const mockReadFileSync = vi.mocked(fs.readFileSync);
37
+ const mockYamlLoad = vi.mocked(yaml.load);
38
+
39
+ beforeEach(() => {
40
+ vi.clearAllMocks();
41
+ });
42
+
43
+ afterEach(() => {
44
+ vi.restoreAllMocks();
45
+ });
46
+
47
+ describe('readOutputLanguageFromWorkspace', () => {
48
+ it('returns default with no warning when config file does not exist', () => {
49
+ mockExistsSync.mockReturnValue(false);
50
+ const result = readOutputLanguageFromWorkspace('/workspace');
51
+ expect(result.outputLanguage).toBe('zh-CN');
52
+ expect(result.degradationWarning).toBeUndefined();
53
+ });
54
+
55
+ it('returns default with no warning when principles section is missing', () => {
56
+ mockExistsSync.mockReturnValue(true);
57
+ mockReadFileSync.mockReturnValue('version: 1\n');
58
+ mockYamlLoad.mockReturnValue({ version: 1 });
59
+ const result = readOutputLanguageFromWorkspace('/workspace');
60
+ expect(result.outputLanguage).toBe('zh-CN');
61
+ expect(result.degradationWarning).toBeUndefined();
62
+ });
63
+
64
+ it('returns default with no warning when outputLanguage key is missing', () => {
65
+ mockExistsSync.mockReturnValue(true);
66
+ mockReadFileSync.mockReturnValue('version: 1\nprinciples: {}\n');
67
+ mockYamlLoad.mockReturnValue({ version: 1, principles: {} });
68
+ const result = readOutputLanguageFromWorkspace('/workspace');
69
+ expect(result.outputLanguage).toBe('zh-CN');
70
+ expect(result.degradationWarning).toBeUndefined();
71
+ });
72
+
73
+ it('returns valid outputLanguage when configured', () => {
74
+ mockExistsSync.mockReturnValue(true);
75
+ mockReadFileSync.mockReturnValue('version: 1\nprinciples:\n outputLanguage: en\n');
76
+ mockYamlLoad.mockReturnValue({ version: 1, principles: { outputLanguage: 'en' } });
77
+ const result = readOutputLanguageFromWorkspace('/workspace');
78
+ expect(result.outputLanguage).toBe('en');
79
+ expect(result.degradationWarning).toBeUndefined();
80
+ });
81
+
82
+ it('returns degraded with read_error when readFileSync throws', () => {
83
+ mockExistsSync.mockReturnValue(true);
84
+ mockReadFileSync.mockImplementation(() => { throw new Error('EACCES: permission denied'); });
85
+ const result = readOutputLanguageFromWorkspace('/workspace');
86
+ expect(result.outputLanguage).toBe('zh-CN');
87
+ expect(result.degradationWarning).toContain('Failed to read .pd/config.yaml');
88
+ expect(result.degradationWarning).toContain('nextAction');
89
+ expect(result.degradationWarning).toContain('Check file permissions');
90
+ });
91
+
92
+ it('returns degraded with yaml_parse_error when yaml.load throws', () => {
93
+ mockExistsSync.mockReturnValue(true);
94
+ mockReadFileSync.mockReturnValue('invalid: yaml: [broken');
95
+ mockYamlLoad.mockImplementation(() => { throw new Error('YAML syntax error'); });
96
+ const result = readOutputLanguageFromWorkspace('/workspace');
97
+ expect(result.outputLanguage).toBe('zh-CN');
98
+ expect(result.degradationWarning).toContain('Failed to parse .pd/config.yaml');
99
+ expect(result.degradationWarning).toContain('nextAction');
100
+ expect(result.degradationWarning).toContain('Fix YAML syntax');
101
+ });
102
+
103
+ it('returns degraded with invalid_config_root when parsed YAML is not an object', () => {
104
+ mockExistsSync.mockReturnValue(true);
105
+ mockReadFileSync.mockReturnValue('"just a string"');
106
+ mockYamlLoad.mockReturnValue('just a string');
107
+ const result = readOutputLanguageFromWorkspace('/workspace');
108
+ expect(result.outputLanguage).toBe('zh-CN');
109
+ expect(result.degradationWarning).toContain('root is not an object');
110
+ expect(result.degradationWarning).toContain('nextAction');
111
+ });
112
+
113
+ it('returns degraded with invalid_config_root when parsed YAML is an array', () => {
114
+ mockExistsSync.mockReturnValue(true);
115
+ mockReadFileSync.mockReturnValue('- item1\n- item2\n');
116
+ mockYamlLoad.mockReturnValue(['item1', 'item2']);
117
+ const result = readOutputLanguageFromWorkspace('/workspace');
118
+ expect(result.outputLanguage).toBe('zh-CN');
119
+ expect(result.degradationWarning).toContain('root is not an object');
120
+ });
121
+
122
+ it('returns degraded with invalid_principles_structure when principles is not an object', () => {
123
+ mockExistsSync.mockReturnValue(true);
124
+ mockReadFileSync.mockReturnValue('version: 1\nprinciples: "not an object"\n');
125
+ mockYamlLoad.mockReturnValue({ version: 1, principles: 'not an object' });
126
+ const result = readOutputLanguageFromWorkspace('/workspace');
127
+ expect(result.outputLanguage).toBe('zh-CN');
128
+ expect(result.degradationWarning).toContain('principles field is not an object');
129
+ expect(result.degradationWarning).toContain('nextAction');
130
+ });
131
+
132
+ it('returns degraded with invalid value warning when outputLanguage is invalid', () => {
133
+ mockExistsSync.mockReturnValue(true);
134
+ mockReadFileSync.mockReturnValue('version: 1\nprinciples:\n outputLanguage: fr\n');
135
+ mockYamlLoad.mockReturnValue({ version: 1, principles: { outputLanguage: 'fr' } });
136
+ const result = readOutputLanguageFromWorkspace('/workspace');
137
+ expect(result.outputLanguage).toBe('zh-CN');
138
+ expect(result.degradationWarning).toContain('invalid');
139
+ expect(result.degradationWarning).toContain('fr');
140
+ expect(result.degradationWarning).toContain('nextAction');
141
+ });
142
+ });