@posthog/wizard 2.2.0 → 2.4.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/src/lib/__tests__/agent-interface.test.js +22 -0
- package/dist/src/lib/__tests__/agent-interface.test.js.map +1 -1
- package/dist/src/lib/agent-interface.d.ts +20 -2
- package/dist/src/lib/agent-interface.js +97 -14
- package/dist/src/lib/agent-interface.js.map +1 -1
- package/dist/src/lib/agent-runner.js +21 -9
- package/dist/src/lib/agent-runner.js.map +1 -1
- package/dist/src/lib/api.d.ts +4 -4
- package/dist/src/lib/constants.d.ts +1 -1
- package/dist/src/lib/health-checks/__tests__/health-checks.test.js +11 -4
- package/dist/src/lib/health-checks/__tests__/health-checks.test.js.map +1 -1
- package/dist/src/lib/health-checks/endpoints.d.ts +1 -0
- package/dist/src/lib/health-checks/endpoints.js +3 -1
- package/dist/src/lib/health-checks/endpoints.js.map +1 -1
- package/dist/src/lib/health-checks/index.d.ts +1 -1
- package/dist/src/lib/health-checks/index.js +2 -1
- package/dist/src/lib/health-checks/index.js.map +1 -1
- package/dist/src/lib/health-checks/readiness.js +12 -3
- package/dist/src/lib/health-checks/readiness.js.map +1 -1
- package/dist/src/lib/health-checks/types.d.ts +1 -0
- package/dist/src/lib/health-checks/types.js.map +1 -1
- package/dist/src/lib/version.d.ts +1 -1
- package/dist/src/lib/version.js +1 -1
- package/dist/src/lib/version.js.map +1 -1
- package/dist/src/lib/wizard-session.d.ts +2 -0
- package/dist/src/lib/wizard-session.js +1 -0
- package/dist/src/lib/wizard-session.js.map +1 -1
- package/dist/src/lib/wizard-tools.d.ts +22 -0
- package/dist/src/lib/wizard-tools.js +71 -39
- package/dist/src/lib/wizard-tools.js.map +1 -1
- package/dist/src/steps/add-mcp-server-to-clients/clients/zed.d.ts +6 -6
- package/dist/src/ui/logging-ui.d.ts +3 -1
- package/dist/src/ui/logging-ui.js +6 -6
- package/dist/src/ui/logging-ui.js.map +1 -1
- package/dist/src/ui/tui/ink-ui.d.ts +3 -1
- package/dist/src/ui/tui/ink-ui.js +5 -2
- package/dist/src/ui/tui/ink-ui.js.map +1 -1
- package/dist/src/ui/tui/playground/demos/HealthCheckDemo.js +1 -0
- package/dist/src/ui/tui/playground/demos/HealthCheckDemo.js.map +1 -1
- package/dist/src/ui/tui/router.d.ts +3 -1
- package/dist/src/ui/tui/router.js +2 -0
- package/dist/src/ui/tui/router.js.map +1 -1
- package/dist/src/ui/tui/screen-registry.js +4 -0
- package/dist/src/ui/tui/screen-registry.js.map +1 -1
- package/dist/src/ui/tui/screens/AuthErrorScreen.d.ts +7 -0
- package/dist/src/ui/tui/screens/AuthErrorScreen.js +16 -0
- package/dist/src/ui/tui/screens/AuthErrorScreen.js.map +1 -0
- package/dist/src/ui/tui/screens/ManagedSettingsScreen.d.ts +13 -0
- package/dist/src/ui/tui/screens/ManagedSettingsScreen.js +32 -0
- package/dist/src/ui/tui/screens/ManagedSettingsScreen.js.map +1 -0
- package/dist/src/ui/tui/screens/SettingsOverrideScreen.d.ts +0 -4
- package/dist/src/ui/tui/screens/SettingsOverrideScreen.js +13 -7
- package/dist/src/ui/tui/screens/SettingsOverrideScreen.js.map +1 -1
- package/dist/src/ui/tui/screens/health/HealthCheckScreen.js +50 -5
- package/dist/src/ui/tui/screens/health/HealthCheckScreen.js.map +1 -1
- package/dist/src/ui/tui/store.d.ts +4 -1
- package/dist/src/ui/tui/store.js +16 -3
- package/dist/src/ui/tui/store.js.map +1 -1
- package/dist/src/ui/wizard-ui.d.ts +4 -2
- package/dist/src/ui/wizard-ui.js.map +1 -1
- package/dist/src/utils/__tests__/semver.test.js +45 -3
- package/dist/src/utils/__tests__/semver.test.js.map +1 -1
- package/dist/src/utils/semver.js +25 -0
- package/dist/src/utils/semver.js.map +1 -1
- package/package.json +1 -1
|
@@ -263,5 +263,27 @@ describe('createStopHook', () => {
|
|
|
263
263
|
const extra = hook(hookInput); // still allow
|
|
264
264
|
expect(extra).toEqual({});
|
|
265
265
|
});
|
|
266
|
+
it('allows stop immediately on API error (401)', () => {
|
|
267
|
+
const collectedText = [
|
|
268
|
+
'Failed to authenticate. API Error: 401 {"detail":"Authentication required"}',
|
|
269
|
+
];
|
|
270
|
+
const hook = (0, agent_interface_1.createStopHook)([wizard_session_1.AdditionalFeature.LLM], collectedText);
|
|
271
|
+
const result = hook(hookInput);
|
|
272
|
+
expect(result).toEqual({});
|
|
273
|
+
});
|
|
274
|
+
it('allows stop immediately on generic API error', () => {
|
|
275
|
+
const collectedText = ['API Error: 500 Internal Server Error'];
|
|
276
|
+
const hook = (0, agent_interface_1.createStopHook)([wizard_session_1.AdditionalFeature.LLM], collectedText);
|
|
277
|
+
const result = hook(hookInput);
|
|
278
|
+
expect(result).toEqual({});
|
|
279
|
+
});
|
|
280
|
+
it('proceeds normally when collectedText has no API error', () => {
|
|
281
|
+
const collectedText = ['Some normal agent output'];
|
|
282
|
+
const hook = (0, agent_interface_1.createStopHook)([], collectedText);
|
|
283
|
+
// First call → remark prompt (normal behavior)
|
|
284
|
+
const first = hook(hookInput);
|
|
285
|
+
expect(first).toHaveProperty('decision', 'block');
|
|
286
|
+
expect(first.reason).toContain('WIZARD-REMARK');
|
|
287
|
+
});
|
|
266
288
|
});
|
|
267
289
|
//# sourceMappingURL=agent-interface.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-interface.test.js","sourceRoot":"","sources":["../../../../src/lib/__tests__/agent-interface.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { runAgent, createStopHook } from '../agent-interface';\nimport type { WizardOptions } from '../../utils/types';\nimport type { SpinnerHandle } from '../../ui';\nimport {\n AdditionalFeature,\n ADDITIONAL_FEATURE_PROMPTS,\n} from '../wizard-session';\n\n// Mock dependencies\njest.mock('../../utils/analytics');\njest.mock('../../utils/debug');\n\n// Mock the SDK module\nconst mockQuery = jest.fn();\njest.mock('@anthropic-ai/claude-agent-sdk', () => ({\n query: (...args: unknown[]) => mockQuery(...args),\n}));\n\n// Mock the UI layer\nconst mockUIInstance = {\n log: {\n step: jest.fn(),\n success: jest.fn(),\n error: jest.fn(),\n warn: jest.fn(),\n info: jest.fn(),\n },\n spinner: jest.fn(),\n select: jest.fn(),\n confirm: jest.fn(),\n text: jest.fn(),\n intro: jest.fn(),\n outro: jest.fn(),\n cancel: jest.fn(),\n note: jest.fn(),\n isCancel: jest.fn(),\n setDetectedFramework: jest.fn(),\n setCredentials: jest.fn(),\n pushStatus: jest.fn(),\n setLoginUrl: jest.fn(),\n showBlockingOutage: jest.fn(),\n setReadinessWarnings: jest.fn(),\n showSettingsOverride: jest.fn(),\n startRun: jest.fn(),\n syncTodos: jest.fn(),\n groupMultiselect: jest.fn(),\n multiselect: jest.fn(),\n};\njest.mock('../../ui', () => ({\n getUI: () => mockUIInstance,\n}));\n\ndescribe('runAgent', () => {\n let mockSpinner: {\n start: jest.Mock;\n stop: jest.Mock;\n message: jest.Mock;\n };\n\n const defaultOptions: WizardOptions = {\n debug: false,\n installDir: '/test/dir',\n forceInstall: false,\n default: false,\n signup: false,\n localMcp: false,\n ci: false,\n menu: false,\n benchmark: false,\n yaraReport: false,\n };\n\n const defaultAgentConfig = {\n workingDirectory: '/test/dir',\n mcpServers: {},\n model: 'claude-opus-4-5-20251101',\n };\n\n beforeEach(() => {\n jest.clearAllMocks();\n\n mockSpinner = {\n start: jest.fn(),\n stop: jest.fn(),\n message: jest.fn(),\n };\n\n mockUIInstance.spinner.mockReturnValue(mockSpinner);\n // Reset log mocks\n Object.values(mockUIInstance.log).forEach((fn) => fn.mockReset());\n });\n\n describe('race condition handling', () => {\n it('should return success when agent completes successfully then SDK cleanup fails', async () => {\n // This simulates the race condition:\n // 1. Agent completes with success result\n // 2. signalDone() is called, completing the prompt generator\n // 3. SDK tries to send cleanup command while streaming is active\n // 4. SDK throws an error\n // The fix should recognize we already got a success and return success anyway\n\n function* mockGeneratorWithCleanupError() {\n yield {\n type: 'system',\n subtype: 'init',\n model: 'claude-opus-4-5-20251101',\n tools: [],\n mcp_servers: [],\n };\n\n yield {\n type: 'result',\n subtype: 'success',\n is_error: false,\n result: 'Agent completed successfully',\n };\n\n // Simulate the SDK cleanup error that occurs after success\n throw new Error('only prompt commands are supported in streaming mode');\n }\n\n mockQuery.mockReturnValue(mockGeneratorWithCleanupError());\n\n const result = await runAgent(\n defaultAgentConfig,\n 'test prompt',\n defaultOptions,\n mockSpinner as unknown as SpinnerHandle,\n {\n successMessage: 'Test success',\n errorMessage: 'Test error',\n },\n );\n\n // Should return success (empty object), not throw\n expect(result).toEqual({});\n expect(mockSpinner.stop).toHaveBeenCalledWith('Test success');\n });\n\n it('should still throw when no success result was received before error', async () => {\n // If we never got a success result, errors should propagate normally\n\n function* mockGeneratorWithOnlyError() {\n yield {\n type: 'system',\n subtype: 'init',\n model: 'claude-opus-4-5-20251101',\n tools: [],\n mcp_servers: [],\n };\n\n // No success result, just an error\n throw new Error('Actual SDK error');\n }\n\n mockQuery.mockReturnValue(mockGeneratorWithOnlyError());\n\n await expect(\n runAgent(\n defaultAgentConfig,\n 'test prompt',\n defaultOptions,\n mockSpinner as unknown as SpinnerHandle,\n {\n successMessage: 'Test success',\n errorMessage: 'Test error',\n },\n ),\n ).rejects.toThrow('Actual SDK error');\n\n expect(mockSpinner.stop).toHaveBeenCalledWith('Test error');\n });\n\n it('should not treat error results as success', async () => {\n // A result with is_error: true should not count as success\n // Even if subtype is 'success', the is_error flag takes precedence\n\n function* mockGeneratorWithErrorResult() {\n yield {\n type: 'system',\n subtype: 'init',\n model: 'claude-opus-4-5-20251101',\n tools: [],\n mcp_servers: [],\n };\n\n yield {\n type: 'result',\n subtype: 'success', // subtype can be success but is_error true\n is_error: true,\n result: 'API Error: 500 Internal Server Error',\n };\n\n throw new Error('Process exited with code 1');\n }\n\n mockQuery.mockReturnValue(mockGeneratorWithErrorResult());\n\n const result = await runAgent(\n defaultAgentConfig,\n 'test prompt',\n defaultOptions,\n mockSpinner as unknown as SpinnerHandle,\n {\n successMessage: 'Test success',\n errorMessage: 'Test error',\n },\n );\n\n // Should return API error, not success\n expect(result.error).toBe('WIZARD_API_ERROR');\n expect(result.message).toContain('API Error');\n });\n\n it('should suppress user-facing errors when SDK yields error result after success', async () => {\n // This test models actual SDK behavior where the SDK emits TWO result messages:\n // 1. SDK yields success result (num_turns: 105, is_error: false)\n // 2. SDK yields a SECOND result with is_error: true containing\n // accumulated cleanup/telemetry errors\n // 3. The errors should be logged to file but NOT shown to the user\n //\n // This differs from the thrown exception test above - here the SDK YIELDS\n // an error result message instead of THROWING an exception.\n\n function* mockGeneratorWithYieldedErrorAfterSuccess() {\n yield {\n type: 'system',\n subtype: 'init',\n model: 'claude-opus-4-5-20251101',\n tools: [],\n mcp_servers: [],\n };\n\n // First result: success (this is the real completion)\n yield {\n type: 'result',\n subtype: 'success',\n is_error: false,\n num_turns: 105,\n result: '[WIZARD-REMARK] Integration completed successfully',\n session_id: '2ce14bda-6d86-4220-b5bb-ab24f7004290',\n total_cost_usd: 5.83,\n };\n\n // Second result: error (SDK cleanup noise - yielded, not thrown)\n yield {\n type: 'result',\n subtype: 'error_during_execution',\n is_error: true,\n num_turns: 0,\n session_id: '2ce14bda-6d86-4220-b5bb-ab24f7004290',\n total_cost_usd: 0,\n errors: [\n 'only prompt commands are supported in streaming mode',\n 'Error: 1P event logging: 14 events failed to export',\n 'Error: 1P event logging: 13 events failed to export',\n 'Error: Failed to export 14 events',\n ],\n };\n }\n\n mockQuery.mockReturnValue(mockGeneratorWithYieldedErrorAfterSuccess());\n\n const result = await runAgent(\n defaultAgentConfig,\n 'test prompt',\n defaultOptions,\n mockSpinner as unknown as SpinnerHandle,\n {\n successMessage: 'Test success',\n errorMessage: 'Test error',\n },\n );\n\n // Should return success (empty object), not error\n expect(result).toEqual({});\n expect(mockSpinner.stop).toHaveBeenCalledWith('Test success');\n\n // ui.log.error should NOT have been called (errors suppressed for user)\n expect(mockUIInstance.log.error).not.toHaveBeenCalled();\n });\n });\n});\n\ndescribe('createStopHook', () => {\n const hookInput = { stop_hook_active: false };\n\n it('empty queue: first call blocks for remark, second allows stop', () => {\n const hook = createStopHook([]);\n\n // First call → remark prompt\n const first = hook(hookInput);\n expect(first).toHaveProperty('decision', 'block');\n expect((first as { reason: string }).reason).toContain('WIZARD-REMARK');\n\n // Second call → allow stop\n const second = hook(hookInput);\n expect(second).toEqual({});\n });\n\n it('single feature: feature prompt, then remark, then allow stop', () => {\n const hook = createStopHook([AdditionalFeature.LLM]);\n\n // First call → LLM feature prompt\n const first = hook(hookInput);\n expect(first).toHaveProperty('decision', 'block');\n expect((first as { reason: string }).reason).toBe(\n ADDITIONAL_FEATURE_PROMPTS[AdditionalFeature.LLM],\n );\n\n // Second call → remark prompt\n const second = hook(hookInput);\n expect(second).toHaveProperty('decision', 'block');\n expect((second as { reason: string }).reason).toContain('WIZARD-REMARK');\n\n // Third call → allow stop\n const third = hook(hookInput);\n expect(third).toEqual({});\n });\n\n it('multiple queue entries: drains all, then remark, then allow stop', () => {\n // Queue the same feature twice to exercise multi-item draining\n const hook = createStopHook([AdditionalFeature.LLM, AdditionalFeature.LLM]);\n\n // First call → LLM prompt\n const first = hook(hookInput);\n expect(first).toHaveProperty('decision', 'block');\n expect((first as { reason: string }).reason).toBe(\n ADDITIONAL_FEATURE_PROMPTS[AdditionalFeature.LLM],\n );\n\n // Second call → LLM prompt again\n const second = hook(hookInput);\n expect(second).toHaveProperty('decision', 'block');\n expect((second as { reason: string }).reason).toBe(\n ADDITIONAL_FEATURE_PROMPTS[AdditionalFeature.LLM],\n );\n\n // Third call → remark prompt\n const third = hook(hookInput);\n expect(third).toHaveProperty('decision', 'block');\n expect((third as { reason: string }).reason).toContain('WIZARD-REMARK');\n\n // Fourth call → allow stop\n const fourth = hook(hookInput);\n expect(fourth).toEqual({});\n });\n\n it('allow stop is idempotent after all phases complete', () => {\n const hook = createStopHook([]);\n\n hook(hookInput); // remark\n hook(hookInput); // allow\n const extra = hook(hookInput); // still allow\n expect(extra).toEqual({});\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"agent-interface.test.js","sourceRoot":"","sources":["../../../../src/lib/__tests__/agent-interface.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { runAgent, createStopHook } from '../agent-interface';\nimport type { WizardOptions } from '../../utils/types';\nimport type { SpinnerHandle } from '../../ui';\nimport {\n AdditionalFeature,\n ADDITIONAL_FEATURE_PROMPTS,\n} from '../wizard-session';\n\n// Mock dependencies\njest.mock('../../utils/analytics');\njest.mock('../../utils/debug');\n\n// Mock the SDK module\nconst mockQuery = jest.fn();\njest.mock('@anthropic-ai/claude-agent-sdk', () => ({\n query: (...args: unknown[]) => mockQuery(...args),\n}));\n\n// Mock the UI layer\nconst mockUIInstance = {\n log: {\n step: jest.fn(),\n success: jest.fn(),\n error: jest.fn(),\n warn: jest.fn(),\n info: jest.fn(),\n },\n spinner: jest.fn(),\n select: jest.fn(),\n confirm: jest.fn(),\n text: jest.fn(),\n intro: jest.fn(),\n outro: jest.fn(),\n cancel: jest.fn(),\n note: jest.fn(),\n isCancel: jest.fn(),\n setDetectedFramework: jest.fn(),\n setCredentials: jest.fn(),\n pushStatus: jest.fn(),\n setLoginUrl: jest.fn(),\n showBlockingOutage: jest.fn(),\n setReadinessWarnings: jest.fn(),\n showSettingsOverride: jest.fn(),\n startRun: jest.fn(),\n syncTodos: jest.fn(),\n groupMultiselect: jest.fn(),\n multiselect: jest.fn(),\n};\njest.mock('../../ui', () => ({\n getUI: () => mockUIInstance,\n}));\n\ndescribe('runAgent', () => {\n let mockSpinner: {\n start: jest.Mock;\n stop: jest.Mock;\n message: jest.Mock;\n };\n\n const defaultOptions: WizardOptions = {\n debug: false,\n installDir: '/test/dir',\n forceInstall: false,\n default: false,\n signup: false,\n localMcp: false,\n ci: false,\n menu: false,\n benchmark: false,\n yaraReport: false,\n };\n\n const defaultAgentConfig = {\n workingDirectory: '/test/dir',\n mcpServers: {},\n model: 'claude-opus-4-5-20251101',\n };\n\n beforeEach(() => {\n jest.clearAllMocks();\n\n mockSpinner = {\n start: jest.fn(),\n stop: jest.fn(),\n message: jest.fn(),\n };\n\n mockUIInstance.spinner.mockReturnValue(mockSpinner);\n // Reset log mocks\n Object.values(mockUIInstance.log).forEach((fn) => fn.mockReset());\n });\n\n describe('race condition handling', () => {\n it('should return success when agent completes successfully then SDK cleanup fails', async () => {\n // This simulates the race condition:\n // 1. Agent completes with success result\n // 2. signalDone() is called, completing the prompt generator\n // 3. SDK tries to send cleanup command while streaming is active\n // 4. SDK throws an error\n // The fix should recognize we already got a success and return success anyway\n\n function* mockGeneratorWithCleanupError() {\n yield {\n type: 'system',\n subtype: 'init',\n model: 'claude-opus-4-5-20251101',\n tools: [],\n mcp_servers: [],\n };\n\n yield {\n type: 'result',\n subtype: 'success',\n is_error: false,\n result: 'Agent completed successfully',\n };\n\n // Simulate the SDK cleanup error that occurs after success\n throw new Error('only prompt commands are supported in streaming mode');\n }\n\n mockQuery.mockReturnValue(mockGeneratorWithCleanupError());\n\n const result = await runAgent(\n defaultAgentConfig,\n 'test prompt',\n defaultOptions,\n mockSpinner as unknown as SpinnerHandle,\n {\n successMessage: 'Test success',\n errorMessage: 'Test error',\n },\n );\n\n // Should return success (empty object), not throw\n expect(result).toEqual({});\n expect(mockSpinner.stop).toHaveBeenCalledWith('Test success');\n });\n\n it('should still throw when no success result was received before error', async () => {\n // If we never got a success result, errors should propagate normally\n\n function* mockGeneratorWithOnlyError() {\n yield {\n type: 'system',\n subtype: 'init',\n model: 'claude-opus-4-5-20251101',\n tools: [],\n mcp_servers: [],\n };\n\n // No success result, just an error\n throw new Error('Actual SDK error');\n }\n\n mockQuery.mockReturnValue(mockGeneratorWithOnlyError());\n\n await expect(\n runAgent(\n defaultAgentConfig,\n 'test prompt',\n defaultOptions,\n mockSpinner as unknown as SpinnerHandle,\n {\n successMessage: 'Test success',\n errorMessage: 'Test error',\n },\n ),\n ).rejects.toThrow('Actual SDK error');\n\n expect(mockSpinner.stop).toHaveBeenCalledWith('Test error');\n });\n\n it('should not treat error results as success', async () => {\n // A result with is_error: true should not count as success\n // Even if subtype is 'success', the is_error flag takes precedence\n\n function* mockGeneratorWithErrorResult() {\n yield {\n type: 'system',\n subtype: 'init',\n model: 'claude-opus-4-5-20251101',\n tools: [],\n mcp_servers: [],\n };\n\n yield {\n type: 'result',\n subtype: 'success', // subtype can be success but is_error true\n is_error: true,\n result: 'API Error: 500 Internal Server Error',\n };\n\n throw new Error('Process exited with code 1');\n }\n\n mockQuery.mockReturnValue(mockGeneratorWithErrorResult());\n\n const result = await runAgent(\n defaultAgentConfig,\n 'test prompt',\n defaultOptions,\n mockSpinner as unknown as SpinnerHandle,\n {\n successMessage: 'Test success',\n errorMessage: 'Test error',\n },\n );\n\n // Should return API error, not success\n expect(result.error).toBe('WIZARD_API_ERROR');\n expect(result.message).toContain('API Error');\n });\n\n it('should suppress user-facing errors when SDK yields error result after success', async () => {\n // This test models actual SDK behavior where the SDK emits TWO result messages:\n // 1. SDK yields success result (num_turns: 105, is_error: false)\n // 2. SDK yields a SECOND result with is_error: true containing\n // accumulated cleanup/telemetry errors\n // 3. The errors should be logged to file but NOT shown to the user\n //\n // This differs from the thrown exception test above - here the SDK YIELDS\n // an error result message instead of THROWING an exception.\n\n function* mockGeneratorWithYieldedErrorAfterSuccess() {\n yield {\n type: 'system',\n subtype: 'init',\n model: 'claude-opus-4-5-20251101',\n tools: [],\n mcp_servers: [],\n };\n\n // First result: success (this is the real completion)\n yield {\n type: 'result',\n subtype: 'success',\n is_error: false,\n num_turns: 105,\n result: '[WIZARD-REMARK] Integration completed successfully',\n session_id: '2ce14bda-6d86-4220-b5bb-ab24f7004290',\n total_cost_usd: 5.83,\n };\n\n // Second result: error (SDK cleanup noise - yielded, not thrown)\n yield {\n type: 'result',\n subtype: 'error_during_execution',\n is_error: true,\n num_turns: 0,\n session_id: '2ce14bda-6d86-4220-b5bb-ab24f7004290',\n total_cost_usd: 0,\n errors: [\n 'only prompt commands are supported in streaming mode',\n 'Error: 1P event logging: 14 events failed to export',\n 'Error: 1P event logging: 13 events failed to export',\n 'Error: Failed to export 14 events',\n ],\n };\n }\n\n mockQuery.mockReturnValue(mockGeneratorWithYieldedErrorAfterSuccess());\n\n const result = await runAgent(\n defaultAgentConfig,\n 'test prompt',\n defaultOptions,\n mockSpinner as unknown as SpinnerHandle,\n {\n successMessage: 'Test success',\n errorMessage: 'Test error',\n },\n );\n\n // Should return success (empty object), not error\n expect(result).toEqual({});\n expect(mockSpinner.stop).toHaveBeenCalledWith('Test success');\n\n // ui.log.error should NOT have been called (errors suppressed for user)\n expect(mockUIInstance.log.error).not.toHaveBeenCalled();\n });\n });\n});\n\ndescribe('createStopHook', () => {\n const hookInput = { stop_hook_active: false };\n\n it('empty queue: first call blocks for remark, second allows stop', () => {\n const hook = createStopHook([]);\n\n // First call → remark prompt\n const first = hook(hookInput);\n expect(first).toHaveProperty('decision', 'block');\n expect((first as { reason: string }).reason).toContain('WIZARD-REMARK');\n\n // Second call → allow stop\n const second = hook(hookInput);\n expect(second).toEqual({});\n });\n\n it('single feature: feature prompt, then remark, then allow stop', () => {\n const hook = createStopHook([AdditionalFeature.LLM]);\n\n // First call → LLM feature prompt\n const first = hook(hookInput);\n expect(first).toHaveProperty('decision', 'block');\n expect((first as { reason: string }).reason).toBe(\n ADDITIONAL_FEATURE_PROMPTS[AdditionalFeature.LLM],\n );\n\n // Second call → remark prompt\n const second = hook(hookInput);\n expect(second).toHaveProperty('decision', 'block');\n expect((second as { reason: string }).reason).toContain('WIZARD-REMARK');\n\n // Third call → allow stop\n const third = hook(hookInput);\n expect(third).toEqual({});\n });\n\n it('multiple queue entries: drains all, then remark, then allow stop', () => {\n // Queue the same feature twice to exercise multi-item draining\n const hook = createStopHook([AdditionalFeature.LLM, AdditionalFeature.LLM]);\n\n // First call → LLM prompt\n const first = hook(hookInput);\n expect(first).toHaveProperty('decision', 'block');\n expect((first as { reason: string }).reason).toBe(\n ADDITIONAL_FEATURE_PROMPTS[AdditionalFeature.LLM],\n );\n\n // Second call → LLM prompt again\n const second = hook(hookInput);\n expect(second).toHaveProperty('decision', 'block');\n expect((second as { reason: string }).reason).toBe(\n ADDITIONAL_FEATURE_PROMPTS[AdditionalFeature.LLM],\n );\n\n // Third call → remark prompt\n const third = hook(hookInput);\n expect(third).toHaveProperty('decision', 'block');\n expect((third as { reason: string }).reason).toContain('WIZARD-REMARK');\n\n // Fourth call → allow stop\n const fourth = hook(hookInput);\n expect(fourth).toEqual({});\n });\n\n it('allow stop is idempotent after all phases complete', () => {\n const hook = createStopHook([]);\n\n hook(hookInput); // remark\n hook(hookInput); // allow\n const extra = hook(hookInput); // still allow\n expect(extra).toEqual({});\n });\n\n it('allows stop immediately on API error (401)', () => {\n const collectedText = [\n 'Failed to authenticate. API Error: 401 {\"detail\":\"Authentication required\"}',\n ];\n const hook = createStopHook([AdditionalFeature.LLM], collectedText);\n\n const result = hook(hookInput);\n expect(result).toEqual({});\n });\n\n it('allows stop immediately on generic API error', () => {\n const collectedText = ['API Error: 500 Internal Server Error'];\n const hook = createStopHook([AdditionalFeature.LLM], collectedText);\n\n const result = hook(hookInput);\n expect(result).toEqual({});\n });\n\n it('proceeds normally when collectedText has no API error', () => {\n const collectedText = ['Some normal agent output'];\n const hook = createStopHook([], collectedText);\n\n // First call → remark prompt (normal behavior)\n const first = hook(hookInput);\n expect(first).toHaveProperty('decision', 'block');\n expect((first as { reason: string }).reason).toContain('WIZARD-REMARK');\n });\n});\n"]}
|
|
@@ -36,12 +36,30 @@ export declare enum AgentErrorType {
|
|
|
36
36
|
/** YARA scanner detected a security violation */
|
|
37
37
|
YARA_VIOLATION = "WIZARD_YARA_VIOLATION"
|
|
38
38
|
}
|
|
39
|
+
/** Where a settings conflict was found. */
|
|
40
|
+
export type SettingsConflictSource = 'project' | 'managed';
|
|
41
|
+
/** A single settings conflict detected during startup. */
|
|
42
|
+
export interface SettingsConflict {
|
|
43
|
+
/** Where the conflict was found. */
|
|
44
|
+
source: SettingsConflictSource;
|
|
45
|
+
/** The blocking keys found (e.g. 'ANTHROPIC_BASE_URL', 'apiKeyHelper'). */
|
|
46
|
+
keys: string[];
|
|
47
|
+
/** Whether the wizard can back up / remove this file. Managed settings are read-only. */
|
|
48
|
+
writable: boolean;
|
|
49
|
+
}
|
|
39
50
|
/**
|
|
40
51
|
* Check if .claude/settings.json in the project directory contains env
|
|
41
|
-
* overrides
|
|
52
|
+
* overrides or apiKeyHelper that block the Wizard from accessing the PostHog LLM Gateway.
|
|
42
53
|
* Returns the list of matched key names, or an empty array if none found.
|
|
54
|
+
*
|
|
55
|
+
* @deprecated Use {@link checkAllSettingsConflicts} for comprehensive detection.
|
|
43
56
|
*/
|
|
44
57
|
export declare function checkClaudeSettingsOverrides(workingDirectory: string): string[];
|
|
58
|
+
/**
|
|
59
|
+
* Check project and org-managed settings for blocking keys that conflict
|
|
60
|
+
* with the wizard's proxy auth.
|
|
61
|
+
*/
|
|
62
|
+
export declare function checkAllSettingsConflicts(workingDirectory: string): SettingsConflict[];
|
|
45
63
|
/**
|
|
46
64
|
* Copy .claude/settings.json to .wizard-backup (overwriting if it exists),
|
|
47
65
|
* then remove the original so the SDK doesn't load the blocking overrides.
|
|
@@ -83,7 +101,7 @@ export type StopHookResult = Record<string, never> | {
|
|
|
83
101
|
* Phase 2 — collect remark (once): block with remark prompt
|
|
84
102
|
* Phase 3 — allow stop: return {}
|
|
85
103
|
*/
|
|
86
|
-
export declare function createStopHook(featureQueue: readonly AdditionalFeature[]): (input: {
|
|
104
|
+
export declare function createStopHook(featureQueue: readonly AdditionalFeature[], collectedText?: string[]): (input: {
|
|
87
105
|
stop_hook_active: boolean;
|
|
88
106
|
}) => StopHookResult;
|
|
89
107
|
/**
|
|
@@ -42,6 +42,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
42
42
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
43
|
exports.isSkillInstallCommand = exports.AgentErrorType = exports.AgentSignals = void 0;
|
|
44
44
|
exports.checkClaudeSettingsOverrides = checkClaudeSettingsOverrides;
|
|
45
|
+
exports.checkAllSettingsConflicts = checkAllSettingsConflicts;
|
|
45
46
|
exports.backupAndFixClaudeSettings = backupAndFixClaudeSettings;
|
|
46
47
|
exports.restoreClaudeSettings = restoreClaudeSettings;
|
|
47
48
|
exports.createStopHook = createStopHook;
|
|
@@ -109,11 +110,41 @@ var AgentErrorType;
|
|
|
109
110
|
/** YARA scanner detected a security violation */
|
|
110
111
|
AgentErrorType["YARA_VIOLATION"] = "WIZARD_YARA_VIOLATION";
|
|
111
112
|
})(AgentErrorType || (exports.AgentErrorType = AgentErrorType = {}));
|
|
112
|
-
const BLOCKING_ENV_KEYS = [
|
|
113
|
+
const BLOCKING_ENV_KEYS = [
|
|
114
|
+
'ANTHROPIC_API_KEY',
|
|
115
|
+
'ANTHROPIC_BASE_URL',
|
|
116
|
+
'ANTHROPIC_AUTH_TOKEN',
|
|
117
|
+
];
|
|
118
|
+
const BLOCKING_SETTINGS_KEYS = ['apiKeyHelper'];
|
|
119
|
+
/**
|
|
120
|
+
* Check a single settings file for blocking env keys and top-level settings keys.
|
|
121
|
+
* Returns matched key names, or an empty array if none found.
|
|
122
|
+
*/
|
|
123
|
+
function checkSettingsFile(filePath) {
|
|
124
|
+
try {
|
|
125
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
126
|
+
const parsed = JSON.parse(raw);
|
|
127
|
+
const matched = [];
|
|
128
|
+
// Check env block for blocking env keys
|
|
129
|
+
const envBlock = parsed?.env;
|
|
130
|
+
if (envBlock && typeof envBlock === 'object') {
|
|
131
|
+
matched.push(...BLOCKING_ENV_KEYS.filter((key) => key in envBlock));
|
|
132
|
+
}
|
|
133
|
+
// Check top-level settings keys
|
|
134
|
+
matched.push(...BLOCKING_SETTINGS_KEYS.filter((key) => key in parsed && parsed[key] !== '' && parsed[key] != null));
|
|
135
|
+
return matched;
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// File doesn't exist or isn't valid JSON — skip
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
}
|
|
113
142
|
/**
|
|
114
143
|
* Check if .claude/settings.json in the project directory contains env
|
|
115
|
-
* overrides
|
|
144
|
+
* overrides or apiKeyHelper that block the Wizard from accessing the PostHog LLM Gateway.
|
|
116
145
|
* Returns the list of matched key names, or an empty array if none found.
|
|
146
|
+
*
|
|
147
|
+
* @deprecated Use {@link checkAllSettingsConflicts} for comprehensive detection.
|
|
117
148
|
*/
|
|
118
149
|
function checkClaudeSettingsOverrides(workingDirectory) {
|
|
119
150
|
const candidates = [
|
|
@@ -121,19 +152,48 @@ function checkClaudeSettingsOverrides(workingDirectory) {
|
|
|
121
152
|
path_1.default.join(workingDirectory, '.claude', 'settings'),
|
|
122
153
|
];
|
|
123
154
|
for (const filePath of candidates) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
155
|
+
const matched = checkSettingsFile(filePath);
|
|
156
|
+
if (matched.length > 0)
|
|
157
|
+
return matched;
|
|
158
|
+
}
|
|
159
|
+
return [];
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Managed settings path on macOS.
|
|
163
|
+
* IT/MDM-deployed settings — readable by all users, writable only by root.
|
|
164
|
+
*/
|
|
165
|
+
const MANAGED_SETTINGS_PATH = '/Library/Application Support/ClaudeCode/managed-settings.json';
|
|
166
|
+
/**
|
|
167
|
+
* Check project and org-managed settings for blocking keys that conflict
|
|
168
|
+
* with the wizard's proxy auth.
|
|
169
|
+
*/
|
|
170
|
+
function checkAllSettingsConflicts(workingDirectory) {
|
|
171
|
+
const conflicts = [];
|
|
172
|
+
const sources = [
|
|
173
|
+
{
|
|
174
|
+
source: 'managed',
|
|
175
|
+
paths: [MANAGED_SETTINGS_PATH],
|
|
176
|
+
writable: false,
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
source: 'project',
|
|
180
|
+
paths: [
|
|
181
|
+
path_1.default.join(workingDirectory, '.claude', 'settings.json'),
|
|
182
|
+
path_1.default.join(workingDirectory, '.claude', 'settings'),
|
|
183
|
+
],
|
|
184
|
+
writable: true,
|
|
185
|
+
},
|
|
186
|
+
];
|
|
187
|
+
for (const { source, paths, writable } of sources) {
|
|
188
|
+
for (const filePath of paths) {
|
|
189
|
+
const keys = checkSettingsFile(filePath);
|
|
190
|
+
if (keys.length > 0) {
|
|
191
|
+
conflicts.push({ source, keys, writable });
|
|
192
|
+
break; // Only one conflict per source (settings.json vs settings fallback)
|
|
130
193
|
}
|
|
131
194
|
}
|
|
132
|
-
catch {
|
|
133
|
-
// File doesn't exist or isn't valid JSON — skip
|
|
134
|
-
}
|
|
135
195
|
}
|
|
136
|
-
return
|
|
196
|
+
return conflicts;
|
|
137
197
|
}
|
|
138
198
|
/**
|
|
139
199
|
* Copy .claude/settings.json to .wizard-backup (overwriting if it exists),
|
|
@@ -189,7 +249,7 @@ function restoreClaudeSettings(workingDirectory) {
|
|
|
189
249
|
* Phase 2 — collect remark (once): block with remark prompt
|
|
190
250
|
* Phase 3 — allow stop: return {}
|
|
191
251
|
*/
|
|
192
|
-
function createStopHook(featureQueue) {
|
|
252
|
+
function createStopHook(featureQueue, collectedText) {
|
|
193
253
|
let featureIndex = 0;
|
|
194
254
|
let remarkRequested = false;
|
|
195
255
|
return (input) => {
|
|
@@ -199,6 +259,15 @@ function createStopHook(featureQueue) {
|
|
|
199
259
|
remarkRequested,
|
|
200
260
|
queueLength: featureQueue.length,
|
|
201
261
|
});
|
|
262
|
+
// On API errors, allow stop immediately — blocking with remark/feature
|
|
263
|
+
// prompts would just fail again. The auth error screen is shown separately.
|
|
264
|
+
if (collectedText) {
|
|
265
|
+
const text = collectedText.join('\n');
|
|
266
|
+
if (text.includes('API Error:')) {
|
|
267
|
+
(0, debug_1.logToFile)('Stop hook: API error detected, allowing immediate stop');
|
|
268
|
+
return {};
|
|
269
|
+
}
|
|
270
|
+
}
|
|
202
271
|
// Phase 1: drain feature queue
|
|
203
272
|
if (featureIndex < featureQueue.length) {
|
|
204
273
|
const feature = featureQueue[featureIndex++];
|
|
@@ -674,7 +743,9 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
674
743
|
PostToolUse: (0, yara_hooks_1.createPostToolUseYaraHooks)(),
|
|
675
744
|
Stop: [
|
|
676
745
|
{
|
|
677
|
-
hooks: [
|
|
746
|
+
hooks: [
|
|
747
|
+
createStopHook(config?.additionalFeatureQueue ?? [], collectedText),
|
|
748
|
+
],
|
|
678
749
|
timeout: 30,
|
|
679
750
|
},
|
|
680
751
|
],
|
|
@@ -722,6 +793,18 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
722
793
|
// Pass receivedSuccessResult so handleSDKMessage can suppress user-facing error
|
|
723
794
|
// output for post-success cleanup errors while still logging them to file
|
|
724
795
|
handleSDKMessage(message, options, spinner, collectedText, receivedSuccessResult);
|
|
796
|
+
// 401: show auth error screen and exit immediately
|
|
797
|
+
if (message.type === 'assistant' &&
|
|
798
|
+
collectedText.join('\n').includes('API Error: 401')) {
|
|
799
|
+
signalDone();
|
|
800
|
+
spinner.stop('Authentication failed');
|
|
801
|
+
(0, debug_1.logToFile)('Agent error: 401, showing auth error screen');
|
|
802
|
+
(0, ui_1.getUI)().showAuthError();
|
|
803
|
+
await (0, wizard_abort_1.wizardAbort)({
|
|
804
|
+
message: 'Authentication failed (401)',
|
|
805
|
+
error: new wizard_abort_1.WizardError('Authentication failed'),
|
|
806
|
+
});
|
|
807
|
+
}
|
|
725
808
|
try {
|
|
726
809
|
middleware?.onMessage(message);
|
|
727
810
|
}
|