@vybestack/llxprt-code 0.4.8 → 0.5.0-nightly.251102.6bb3db7a
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/package.json +5 -3
- package/dist/src/auth/__tests__/oauthManager.safety.test.d.ts +6 -0
- package/dist/src/auth/__tests__/oauthManager.safety.test.js +49 -0
- package/dist/src/auth/__tests__/oauthManager.safety.test.js.map +1 -0
- package/dist/src/auth/oauth-manager.d.ts +11 -0
- package/dist/src/auth/oauth-manager.js +62 -29
- package/dist/src/auth/oauth-manager.js.map +1 -1
- package/dist/src/auth/oauth-manager.spec.js +7 -2
- package/dist/src/auth/oauth-manager.spec.js.map +1 -1
- package/dist/src/config/__tests__/nonInteractiveTools.test.d.ts +6 -0
- package/dist/src/config/__tests__/nonInteractiveTools.test.js +13 -0
- package/dist/src/config/__tests__/nonInteractiveTools.test.js.map +1 -0
- package/dist/src/config/__tests__/profileBootstrap.test.d.ts +6 -0
- package/dist/src/config/__tests__/profileBootstrap.test.js +91 -0
- package/dist/src/config/__tests__/profileBootstrap.test.js.map +1 -0
- package/dist/src/config/config.d.ts +6 -2
- package/dist/src/config/config.js +219 -18
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/profileBootstrap.d.ts +64 -0
- package/dist/src/config/profileBootstrap.js +140 -0
- package/dist/src/config/profileBootstrap.js.map +1 -0
- package/dist/src/gemini.js +68 -23
- package/dist/src/gemini.js.map +1 -1
- package/dist/src/gemini.test.js +1 -2
- package/dist/src/gemini.test.js.map +1 -1
- package/dist/src/generated/git-commit.d.ts +1 -1
- package/dist/src/generated/git-commit.js +1 -1
- package/dist/src/integration-tests/base-url-behavior.integration.test.js +110 -450
- package/dist/src/integration-tests/base-url-behavior.integration.test.js.map +1 -1
- package/dist/src/integration-tests/model-params-isolation.integration.test.js +101 -539
- package/dist/src/integration-tests/model-params-isolation.integration.test.js.map +1 -1
- package/dist/src/integration-tests/modelParams.integration.test.js +86 -761
- package/dist/src/integration-tests/modelParams.integration.test.js.map +1 -1
- package/dist/src/integration-tests/provider-multi-runtime.integration.test.d.ts +6 -0
- package/dist/src/integration-tests/provider-multi-runtime.integration.test.js +198 -0
- package/dist/src/integration-tests/provider-multi-runtime.integration.test.js.map +1 -0
- package/dist/src/integration-tests/provider-switching.integration.test.js +97 -151
- package/dist/src/integration-tests/provider-switching.integration.test.js.map +1 -1
- package/dist/src/integration-tests/runtime-isolation.test.d.ts +13 -0
- package/dist/src/integration-tests/runtime-isolation.test.js +170 -0
- package/dist/src/integration-tests/runtime-isolation.test.js.map +1 -0
- package/dist/src/integration-tests/test-utils.js +19 -2
- package/dist/src/integration-tests/test-utils.js.map +1 -1
- package/dist/src/integration-tests/test-utils.test.js +9 -8
- package/dist/src/integration-tests/test-utils.test.js.map +1 -1
- package/dist/src/integration-tests/todo-continuation.integration.test.js +5 -2
- package/dist/src/integration-tests/todo-continuation.integration.test.js.map +1 -1
- package/dist/src/integration-tests/tools-governance.integration.test.d.ts +6 -0
- package/dist/src/integration-tests/tools-governance.integration.test.js +98 -0
- package/dist/src/integration-tests/tools-governance.integration.test.js.map +1 -0
- package/dist/src/nonInteractiveCli.js +36 -11
- package/dist/src/nonInteractiveCli.js.map +1 -1
- package/dist/src/providers/logging/git-stats.test.js +11 -1
- package/dist/src/providers/logging/git-stats.test.js.map +1 -1
- package/dist/src/providers/logging/multi-provider-logging.integration.test.js +1 -2
- package/dist/src/providers/logging/multi-provider-logging.integration.test.js.map +1 -1
- package/dist/src/providers/logging/performance.test.js +1 -1
- package/dist/src/providers/logging/performance.test.js.map +1 -1
- package/dist/src/providers/oauth-provider-registration.d.ts +2 -2
- package/dist/src/providers/oauth-provider-registration.js +25 -9
- package/dist/src/providers/oauth-provider-registration.js.map +1 -1
- package/dist/src/providers/provider-gemini-switching.test.js +67 -89
- package/dist/src/providers/provider-gemini-switching.test.js.map +1 -1
- package/dist/src/providers/provider-switching.integration.test.js +42 -98
- package/dist/src/providers/provider-switching.integration.test.js.map +1 -1
- package/dist/src/providers/providerConfigUtils.d.ts +12 -7
- package/dist/src/providers/providerConfigUtils.js +31 -99
- package/dist/src/providers/providerConfigUtils.js.map +1 -1
- package/dist/src/providers/providerManagerInstance.d.ts +17 -1
- package/dist/src/providers/providerManagerInstance.js +157 -175
- package/dist/src/providers/providerManagerInstance.js.map +1 -1
- package/dist/src/providers/providerManagerInstance.oauthRegistration.test.js +19 -15
- package/dist/src/providers/providerManagerInstance.oauthRegistration.test.js.map +1 -1
- package/dist/src/providers/providerManagerInstance.test.js +2 -5
- package/dist/src/providers/providerManagerInstance.test.js.map +1 -1
- package/dist/src/runtime/__tests__/profileApplication.test.d.ts +5 -0
- package/dist/src/runtime/__tests__/profileApplication.test.js +232 -0
- package/dist/src/runtime/__tests__/profileApplication.test.js.map +1 -0
- package/dist/src/runtime/__tests__/runtimeIsolation.test.d.ts +5 -0
- package/dist/src/runtime/__tests__/runtimeIsolation.test.js +376 -0
- package/dist/src/runtime/__tests__/runtimeIsolation.test.js.map +1 -0
- package/dist/src/runtime/agentRuntimeAdapter.d.ts +249 -0
- package/dist/src/runtime/agentRuntimeAdapter.js +506 -0
- package/dist/src/runtime/agentRuntimeAdapter.js.map +1 -0
- package/dist/src/runtime/agentRuntimeAdapter.spec.d.ts +6 -0
- package/dist/src/runtime/agentRuntimeAdapter.spec.js +866 -0
- package/dist/src/runtime/agentRuntimeAdapter.spec.js.map +1 -0
- package/dist/src/runtime/messages.d.ts +28 -0
- package/dist/src/runtime/messages.js +64 -0
- package/dist/src/runtime/messages.js.map +1 -0
- package/dist/src/runtime/profileApplication.d.ts +33 -0
- package/dist/src/runtime/profileApplication.js +191 -0
- package/dist/src/runtime/profileApplication.js.map +1 -0
- package/dist/src/runtime/providerConfigUtils.test.d.ts +1 -0
- package/dist/src/runtime/providerConfigUtils.test.js +68 -0
- package/dist/src/runtime/providerConfigUtils.test.js.map +1 -0
- package/dist/src/runtime/runtimeContextFactory.d.ts +102 -0
- package/dist/src/runtime/runtimeContextFactory.js +190 -0
- package/dist/src/runtime/runtimeContextFactory.js.map +1 -0
- package/dist/src/runtime/runtimeSettings.d.ts +217 -0
- package/dist/src/runtime/runtimeSettings.js +1094 -0
- package/dist/src/runtime/runtimeSettings.js.map +1 -0
- package/dist/src/runtime/runtimeSettings.test.d.ts +1 -0
- package/dist/src/runtime/runtimeSettings.test.js +320 -0
- package/dist/src/runtime/runtimeSettings.test.js.map +1 -0
- package/dist/src/services/BuiltinCommandLoader.d.ts +13 -4
- package/dist/src/services/BuiltinCommandLoader.js +17 -4
- package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
- package/dist/src/services/McpPromptLoader.js +34 -13
- package/dist/src/services/McpPromptLoader.js.map +1 -1
- package/dist/src/test-utils/mockCommandContext.js +5 -2
- package/dist/src/test-utils/mockCommandContext.js.map +1 -1
- package/dist/src/ui/App.js +29 -49
- package/dist/src/ui/App.js.map +1 -1
- package/dist/src/ui/commands/aboutCommand.js +59 -38
- package/dist/src/ui/commands/aboutCommand.js.map +1 -1
- package/dist/src/ui/commands/authCommand.js +7 -9
- package/dist/src/ui/commands/authCommand.js.map +1 -1
- package/dist/src/ui/commands/baseurlCommand.js +8 -44
- package/dist/src/ui/commands/baseurlCommand.js.map +1 -1
- package/dist/src/ui/commands/chatCommand.js +28 -12
- package/dist/src/ui/commands/chatCommand.js.map +1 -1
- package/dist/src/ui/commands/diagnosticsCommand.d.ts +0 -3
- package/dist/src/ui/commands/diagnosticsCommand.js +45 -191
- package/dist/src/ui/commands/diagnosticsCommand.js.map +1 -1
- package/dist/src/ui/commands/keyCommand.js +9 -58
- package/dist/src/ui/commands/keyCommand.js.map +1 -1
- package/dist/src/ui/commands/keyCommand.test.js +48 -102
- package/dist/src/ui/commands/keyCommand.test.js.map +1 -1
- package/dist/src/ui/commands/keyfileCommand.js +42 -93
- package/dist/src/ui/commands/keyfileCommand.js.map +1 -1
- package/dist/src/ui/commands/logoutCommand.js +2 -2
- package/dist/src/ui/commands/logoutCommand.js.map +1 -1
- package/dist/src/ui/commands/mcpCommand.js +29 -7
- package/dist/src/ui/commands/mcpCommand.js.map +1 -1
- package/dist/src/ui/commands/modelCommand.js +8 -59
- package/dist/src/ui/commands/modelCommand.js.map +1 -1
- package/dist/src/ui/commands/profileCommand.js +151 -267
- package/dist/src/ui/commands/profileCommand.js.map +1 -1
- package/dist/src/ui/commands/profileCommand.test.js +88 -344
- package/dist/src/ui/commands/profileCommand.test.js.map +1 -1
- package/dist/src/ui/commands/providerCommand.js +9 -3
- package/dist/src/ui/commands/providerCommand.js.map +1 -1
- package/dist/src/ui/commands/restoreCommand.js +38 -18
- package/dist/src/ui/commands/restoreCommand.js.map +1 -1
- package/dist/src/ui/commands/schema/argumentResolver.test.d.ts +6 -0
- package/dist/src/ui/commands/schema/argumentResolver.test.js +619 -0
- package/dist/src/ui/commands/schema/argumentResolver.test.js.map +1 -0
- package/dist/src/ui/commands/schema/index.d.ts +15 -0
- package/dist/src/ui/commands/schema/index.js +320 -0
- package/dist/src/ui/commands/schema/index.js.map +1 -0
- package/dist/src/ui/commands/schema/types.d.ts +61 -0
- package/dist/src/ui/commands/schema/types.js +12 -0
- package/dist/src/ui/commands/schema/types.js.map +1 -0
- package/dist/src/ui/commands/setCommand.js +641 -325
- package/dist/src/ui/commands/setCommand.js.map +1 -1
- package/dist/src/ui/commands/setCommand.test.js +92 -388
- package/dist/src/ui/commands/setCommand.test.js.map +1 -1
- package/dist/src/ui/commands/statusCommand.js +2 -2
- package/dist/src/ui/commands/statusCommand.js.map +1 -1
- package/dist/src/ui/commands/subagentCommand.d.ts +16 -0
- package/dist/src/ui/commands/subagentCommand.js +674 -0
- package/dist/src/ui/commands/subagentCommand.js.map +1 -0
- package/dist/src/ui/commands/test/setCommand.mutation.test.d.ts +6 -0
- package/dist/src/ui/commands/test/setCommand.mutation.test.js +132 -0
- package/dist/src/ui/commands/test/setCommand.mutation.test.js.map +1 -0
- package/dist/src/ui/commands/test/setCommand.phase09.test.d.ts +6 -0
- package/dist/src/ui/commands/test/setCommand.phase09.test.js +222 -0
- package/dist/src/ui/commands/test/setCommand.phase09.test.js.map +1 -0
- package/dist/src/ui/commands/test/subagentCommand.schema.test.d.ts +6 -0
- package/dist/src/ui/commands/test/subagentCommand.schema.test.js +125 -0
- package/dist/src/ui/commands/test/subagentCommand.schema.test.js.map +1 -0
- package/dist/src/ui/commands/test/subagentCommand.test.d.ts +1 -0
- package/dist/src/ui/commands/test/subagentCommand.test.js +598 -0
- package/dist/src/ui/commands/test/subagentCommand.test.js.map +1 -0
- package/dist/src/ui/commands/toolformatCommand.js +25 -98
- package/dist/src/ui/commands/toolformatCommand.js.map +1 -1
- package/dist/src/ui/commands/toolformatCommand.test.js +56 -102
- package/dist/src/ui/commands/toolformatCommand.test.js.map +1 -1
- package/dist/src/ui/commands/toolsCommand.js +187 -31
- package/dist/src/ui/commands/toolsCommand.js.map +1 -1
- package/dist/src/ui/commands/types.d.ts +11 -2
- package/dist/src/ui/commands/types.js.map +1 -1
- package/dist/src/ui/components/AuthDialog.js +16 -55
- package/dist/src/ui/components/AuthDialog.js.map +1 -1
- package/dist/src/ui/components/Footer.js +4 -5
- package/dist/src/ui/components/Footer.js.map +1 -1
- package/dist/src/ui/components/HistoryItemDisplay.js +1 -1
- package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
- package/dist/src/ui/components/InputPrompt.js +1 -1
- package/dist/src/ui/components/InputPrompt.js.map +1 -1
- package/dist/src/ui/components/StatsDisplay.js +6 -11
- package/dist/src/ui/components/StatsDisplay.js.map +1 -1
- package/dist/src/ui/components/SuggestionsDisplay.d.ts +13 -1
- package/dist/src/ui/components/SuggestionsDisplay.js +22 -3
- package/dist/src/ui/components/SuggestionsDisplay.js.map +1 -1
- package/dist/src/ui/components/messages/ToolGroupMessage.d.ts +1 -0
- package/dist/src/ui/components/messages/ToolGroupMessage.js +14 -14
- package/dist/src/ui/components/messages/ToolGroupMessage.js.map +1 -1
- package/dist/src/ui/components/messages/ToolGroupMessage.test.js +1 -0
- package/dist/src/ui/components/messages/ToolGroupMessage.test.js.map +1 -1
- package/dist/src/ui/containers/SessionController.js +61 -117
- package/dist/src/ui/containers/SessionController.js.map +1 -1
- package/dist/src/ui/contexts/RuntimeContext.d.ts +61 -0
- package/dist/src/ui/contexts/RuntimeContext.js +118 -0
- package/dist/src/ui/contexts/RuntimeContext.js.map +1 -0
- package/dist/src/ui/contexts/TodoProvider.d.ts +1 -0
- package/dist/src/ui/contexts/TodoProvider.js +10 -8
- package/dist/src/ui/contexts/TodoProvider.js.map +1 -1
- package/dist/src/ui/contexts/ToolCallProvider.d.ts +1 -0
- package/dist/src/ui/contexts/ToolCallProvider.js +10 -9
- package/dist/src/ui/contexts/ToolCallProvider.js.map +1 -1
- package/dist/src/ui/hooks/__tests__/useSlashCompletion.set.phase09.test.d.ts +6 -0
- package/dist/src/ui/hooks/__tests__/useSlashCompletion.set.phase09.test.js +39 -0
- package/dist/src/ui/hooks/__tests__/useSlashCompletion.set.phase09.test.js.map +1 -0
- package/dist/src/ui/hooks/atCommandProcessor.js +11 -3
- package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/atCommandProcessor.test.js +3 -1
- package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
- package/dist/src/ui/hooks/shellCommandProcessor.js +4 -1
- package/dist/src/ui/hooks/shellCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/shellCommandProcessor.test.js +1 -0
- package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -1
- package/dist/src/ui/hooks/slashCommandProcessor.js +27 -1
- package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/useAuthCommand.js +11 -3
- package/dist/src/ui/hooks/useAuthCommand.js.map +1 -1
- package/dist/src/ui/hooks/useCommandCompletion.d.ts +1 -0
- package/dist/src/ui/hooks/useCommandCompletion.js +2 -0
- package/dist/src/ui/hooks/useCommandCompletion.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.js +37 -11
- package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.subagent.spec.d.ts +6 -0
- package/dist/src/ui/hooks/useGeminiStream.subagent.spec.js +232 -0
- package/dist/src/ui/hooks/useGeminiStream.subagent.spec.js.map +1 -0
- package/dist/src/ui/hooks/useLoadProfileDialog.d.ts +1 -1
- package/dist/src/ui/hooks/useLoadProfileDialog.js +18 -57
- package/dist/src/ui/hooks/useLoadProfileDialog.js.map +1 -1
- package/dist/src/ui/hooks/useOpenAIProviderInfo.d.ts +1 -1
- package/dist/src/ui/hooks/useOpenAIProviderInfo.js +12 -7
- package/dist/src/ui/hooks/useOpenAIProviderInfo.js.map +1 -1
- package/dist/src/ui/hooks/useProviderDialog.d.ts +1 -1
- package/dist/src/ui/hooks/useProviderDialog.js +17 -90
- package/dist/src/ui/hooks/useProviderDialog.js.map +1 -1
- package/dist/src/ui/hooks/useProviderModelDialog.d.ts +2 -2
- package/dist/src/ui/hooks/useProviderModelDialog.js +11 -12
- package/dist/src/ui/hooks/useProviderModelDialog.js.map +1 -1
- package/dist/src/ui/hooks/useReactToolScheduler.d.ts +3 -1
- package/dist/src/ui/hooks/useReactToolScheduler.js +144 -34
- package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
- package/dist/src/ui/hooks/useSlashCompletion.d.ts +32 -0
- package/dist/src/ui/hooks/useSlashCompletion.js +154 -77
- package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -1
- package/dist/src/ui/hooks/useSlashCompletion.test.js +39 -14
- package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
- package/dist/src/ui/hooks/useToolScheduler.test.js +108 -79
- package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
- package/dist/src/ui/types.d.ts +1 -0
- package/dist/src/ui/types.js.map +1 -1
- package/dist/src/utils/sandbox.js +7 -5
- package/dist/src/utils/sandbox.js.map +1 -1
- package/dist/src/validateNonInterActiveAuth.js +4 -2
- package/dist/src/validateNonInterActiveAuth.js.map +1 -1
- package/dist/src/zed-integration/schema.d.ts +30 -30
- package/dist/src/zed-integration/zedIntegration.js +112 -39
- package/dist/src/zed-integration/zedIntegration.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/package.json +5 -3
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"restoreCommand.js","sourceRoot":"","sources":["../../../../src/ui/commands/restoreCommand.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAIL,WAAW,GACZ,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"restoreCommand.js","sourceRoot":"","sources":["../../../../src/ui/commands/restoreCommand.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Vybestack LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
7
|
+
import * as fc from 'fast-check';
|
|
8
|
+
import { createCompletionHandler, tokenize } from './index.js';
|
|
9
|
+
import { createMockCommandContext } from '../../../test-utils/mockCommandContext.js';
|
|
10
|
+
// Mock command context for tests
|
|
11
|
+
const mockContext = createMockCommandContext();
|
|
12
|
+
// Helper functions to create test arguments
|
|
13
|
+
const literal = (value, description, next) => ({
|
|
14
|
+
kind: 'literal',
|
|
15
|
+
value,
|
|
16
|
+
description: description || `Literal ${value}`,
|
|
17
|
+
next,
|
|
18
|
+
});
|
|
19
|
+
const value = (name, description, options, completer, hint, next) => ({
|
|
20
|
+
kind: 'value',
|
|
21
|
+
name,
|
|
22
|
+
description,
|
|
23
|
+
options: (options || []).map((opt) => typeof opt === 'string' ? { value: opt } : opt),
|
|
24
|
+
completer,
|
|
25
|
+
hint,
|
|
26
|
+
next,
|
|
27
|
+
});
|
|
28
|
+
describe('argumentResolver @plan:PLAN-20251013-AUTOCOMPLETE.P04', () => {
|
|
29
|
+
describe('Basic functionality', () => {
|
|
30
|
+
it('handles empty input gracefully @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-001', async () => {
|
|
31
|
+
const schema = [value('arg1', 'First argument')];
|
|
32
|
+
const handler = createCompletionHandler(schema);
|
|
33
|
+
const result = await handler(mockContext, '', '/');
|
|
34
|
+
expect(result).toHaveProperty('suggestions');
|
|
35
|
+
expect(result).toHaveProperty('hint');
|
|
36
|
+
expect(Array.isArray(result.suggestions)).toBe(true);
|
|
37
|
+
expect(result.position).toBe(1);
|
|
38
|
+
});
|
|
39
|
+
it('provides hints for value arguments @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-002', async () => {
|
|
40
|
+
const schema = [
|
|
41
|
+
value('username', 'User name', undefined, undefined, async () => 'Enter a valid username'),
|
|
42
|
+
];
|
|
43
|
+
const handler = createCompletionHandler(schema);
|
|
44
|
+
const result = await handler(mockContext, '', '/username');
|
|
45
|
+
expect(result.hint).toBe('Enter a valid username');
|
|
46
|
+
expect(result.position).toBe(1);
|
|
47
|
+
});
|
|
48
|
+
it('returns literal descriptions as hints when literal nodes are active @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-002', async () => {
|
|
49
|
+
const schema = [
|
|
50
|
+
literal('create', 'Create a resource'),
|
|
51
|
+
];
|
|
52
|
+
const handler = createCompletionHandler(schema);
|
|
53
|
+
const result = await handler(mockContext, '', '/subagent ');
|
|
54
|
+
expect(result.hint).toBe('Create a resource');
|
|
55
|
+
expect(result.suggestions).toEqual([
|
|
56
|
+
expect.objectContaining({ value: 'create' }),
|
|
57
|
+
]);
|
|
58
|
+
expect(result.position).toBe(1);
|
|
59
|
+
});
|
|
60
|
+
it('filters literal suggestions based on partial input @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-002', async () => {
|
|
61
|
+
const schema = [
|
|
62
|
+
literal('create', 'Create a resource'),
|
|
63
|
+
literal('delete', 'Delete a resource'),
|
|
64
|
+
];
|
|
65
|
+
const handler = createCompletionHandler(schema);
|
|
66
|
+
const result = await handler(mockContext, '', '/subagent cr');
|
|
67
|
+
expect(result.suggestions).toEqual([
|
|
68
|
+
expect.objectContaining({ value: 'create' }),
|
|
69
|
+
]);
|
|
70
|
+
});
|
|
71
|
+
it('omits literal suggestions when partial does not match @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-002', async () => {
|
|
72
|
+
const schema = [
|
|
73
|
+
literal('create', 'Create a resource'),
|
|
74
|
+
literal('delete', 'Delete a resource'),
|
|
75
|
+
];
|
|
76
|
+
const handler = createCompletionHandler(schema);
|
|
77
|
+
const result = await handler(mockContext, '', '/subagent zz');
|
|
78
|
+
expect(result.suggestions).toEqual([]);
|
|
79
|
+
});
|
|
80
|
+
it('prefers string hints on value arguments over descriptions @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-004', async () => {
|
|
81
|
+
const schema = [
|
|
82
|
+
value('mode', '', ['manual', 'auto'], undefined, 'Select mode'),
|
|
83
|
+
];
|
|
84
|
+
const handler = createCompletionHandler(schema);
|
|
85
|
+
const result = await handler(mockContext, '', '/command ');
|
|
86
|
+
expect(result.hint).toBe('Select mode');
|
|
87
|
+
expect(result.suggestions).toEqual(expect.arrayContaining([
|
|
88
|
+
expect.objectContaining({ value: 'manual' }),
|
|
89
|
+
expect.objectContaining({ value: 'auto' }),
|
|
90
|
+
]));
|
|
91
|
+
expect(result.position).toBe(1);
|
|
92
|
+
});
|
|
93
|
+
it('awaits async hint functions for value arguments @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-004', async () => {
|
|
94
|
+
const dynamicHint = vi.fn(async () => 'Dynamic mode hint');
|
|
95
|
+
const schema = [
|
|
96
|
+
value('mode', '', ['manual', 'auto'], undefined, dynamicHint),
|
|
97
|
+
];
|
|
98
|
+
const handler = createCompletionHandler(schema);
|
|
99
|
+
const result = await handler(mockContext, '', '/command m');
|
|
100
|
+
expect(dynamicHint).toHaveBeenCalledTimes(1);
|
|
101
|
+
expect(result.hint).toBe('Dynamic mode hint');
|
|
102
|
+
expect(result.suggestions).toEqual([
|
|
103
|
+
expect.objectContaining({ value: 'manual' }),
|
|
104
|
+
]);
|
|
105
|
+
expect(result.position).toBe(2);
|
|
106
|
+
});
|
|
107
|
+
it('falls back to value descriptions when hints are absent @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-004', async () => {
|
|
108
|
+
const schema = [
|
|
109
|
+
value('mode', 'Mode description', ['manual', 'auto']),
|
|
110
|
+
];
|
|
111
|
+
const handler = createCompletionHandler(schema);
|
|
112
|
+
const result = await handler(mockContext, '', '/command ');
|
|
113
|
+
expect(result.hint).toBe('Mode description');
|
|
114
|
+
expect(result.suggestions.length).toBeGreaterThan(0);
|
|
115
|
+
expect(result.position).toBe(1);
|
|
116
|
+
});
|
|
117
|
+
it('returns empty hint when no hint or description is provided @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-004', async () => {
|
|
118
|
+
const schema = [
|
|
119
|
+
value('mode', '', ['manual', 'auto']),
|
|
120
|
+
];
|
|
121
|
+
const handler = createCompletionHandler(schema);
|
|
122
|
+
const result = await handler(mockContext, '', '/command ');
|
|
123
|
+
expect(result.hint).toBe('');
|
|
124
|
+
expect(result.suggestions.length).toBeGreaterThan(0);
|
|
125
|
+
});
|
|
126
|
+
it('returns empty suggestions when value has no options or completer @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-002', async () => {
|
|
127
|
+
await fc.assert(fc.asyncProperty(fc.string(), async (input) => {
|
|
128
|
+
const schema = [value('mode', '', undefined)];
|
|
129
|
+
const handler = createCompletionHandler(schema);
|
|
130
|
+
const result = await handler(mockContext, '', `/command ${input}`);
|
|
131
|
+
expect(result.suggestions).toEqual([]);
|
|
132
|
+
}));
|
|
133
|
+
});
|
|
134
|
+
it('filters value suggestions based on partial input @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-002', async () => {
|
|
135
|
+
const schema = [
|
|
136
|
+
value('mode', 'Mode description', ['manual', 'auto', 'archive']),
|
|
137
|
+
];
|
|
138
|
+
const handler = createCompletionHandler(schema);
|
|
139
|
+
const result = await handler(mockContext, '', '/command ar');
|
|
140
|
+
expect(result.suggestions).toEqual([
|
|
141
|
+
expect.objectContaining({ value: 'archive' }),
|
|
142
|
+
]);
|
|
143
|
+
});
|
|
144
|
+
it('returns empty suggestions when schema is empty @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-001', async () => {
|
|
145
|
+
await fc.assert(fc.asyncProperty(fc.string(), async (input) => {
|
|
146
|
+
const warnSpy = vi
|
|
147
|
+
.spyOn(console, 'warn')
|
|
148
|
+
.mockImplementation(() => { });
|
|
149
|
+
const handler = createCompletionHandler([]);
|
|
150
|
+
const result = await handler(mockContext, '', input);
|
|
151
|
+
expect(result.suggestions).toEqual([]);
|
|
152
|
+
expect(result.hint).toBe('');
|
|
153
|
+
expect(warnSpy).not.toHaveBeenCalled();
|
|
154
|
+
warnSpy.mockRestore();
|
|
155
|
+
}));
|
|
156
|
+
});
|
|
157
|
+
it('logs and recovers when suggestion generation throws @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-001', async () => {
|
|
158
|
+
const failingCompleter = async () => {
|
|
159
|
+
throw new Error('completer boom');
|
|
160
|
+
};
|
|
161
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
162
|
+
const schema = [
|
|
163
|
+
value('mode', '', undefined, failingCompleter),
|
|
164
|
+
];
|
|
165
|
+
const handler = createCompletionHandler(schema);
|
|
166
|
+
const result = await handler(mockContext, '', '/command ');
|
|
167
|
+
expect(result.suggestions).toEqual([]);
|
|
168
|
+
expect(result.hint).toBe('');
|
|
169
|
+
expect(warnSpy).toHaveBeenCalledWith('Error generating suggestions:', expect.any(Error));
|
|
170
|
+
warnSpy.mockRestore();
|
|
171
|
+
});
|
|
172
|
+
it('handles complex nested schemas @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-002', async () => {
|
|
173
|
+
const schema = [
|
|
174
|
+
literal('create', 'Create resource'),
|
|
175
|
+
value('type', 'Resource type', ['user', 'project', 'task']),
|
|
176
|
+
];
|
|
177
|
+
const handler = createCompletionHandler(schema);
|
|
178
|
+
// Test after 'create' with trailing space - should suggest type options
|
|
179
|
+
const afterCreateResult = await handler(mockContext, '', '/create ');
|
|
180
|
+
expect(afterCreateResult.suggestions).toEqual([
|
|
181
|
+
expect.objectContaining({ value: 'create' }),
|
|
182
|
+
]);
|
|
183
|
+
expect(afterCreateResult.position).toBe(1);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
describe('Tokenization and context resolution', () => {
|
|
187
|
+
it('tokenize handles escaped spaces @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-001', () => {
|
|
188
|
+
const safeWord = fc
|
|
189
|
+
.array(fc.constantFrom('a', 'b', 'c', 'd', 'e'), {
|
|
190
|
+
minLength: 1,
|
|
191
|
+
maxLength: 5,
|
|
192
|
+
})
|
|
193
|
+
.map((chars) => chars.join(''));
|
|
194
|
+
fc.assert(fc.property(fc.array(safeWord, { minLength: 1, maxLength: 3 }), (words) => {
|
|
195
|
+
const rawSegment = words.join(' ');
|
|
196
|
+
const escapedSegment = rawSegment.replace(/ /g, '\\ ');
|
|
197
|
+
const info = tokenize(`/cmd ${escapedSegment}`);
|
|
198
|
+
expect(info.tokens[0]).toBe('cmd');
|
|
199
|
+
expect(info.tokens[1]).toBe(rawSegment);
|
|
200
|
+
expect(info.partialToken).toBe(rawSegment);
|
|
201
|
+
expect(info.hasTrailingSpace).toBe(false);
|
|
202
|
+
}));
|
|
203
|
+
});
|
|
204
|
+
it('tokenize handles quoted segments @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-001', () => {
|
|
205
|
+
const info = tokenize('/cmd "quoted value" next');
|
|
206
|
+
expect(info.tokens).toEqual(['cmd', 'quoted value', 'next']);
|
|
207
|
+
expect(info.partialToken).toBe('next');
|
|
208
|
+
expect(info.hasTrailingSpace).toBe(false);
|
|
209
|
+
});
|
|
210
|
+
it('tokenize handles single quoted segments @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-001', () => {
|
|
211
|
+
const info = tokenize("/cmd 'single quoted' next");
|
|
212
|
+
expect(info.tokens).toEqual(['cmd', 'single quoted', 'next']);
|
|
213
|
+
expect(info.partialToken).toBe('next');
|
|
214
|
+
expect(info.hasTrailingSpace).toBe(false);
|
|
215
|
+
});
|
|
216
|
+
it('tokenize splits unquoted segments @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-001', () => {
|
|
217
|
+
const info = tokenize('/cmd alpha beta');
|
|
218
|
+
expect(info.tokens).toEqual(['cmd', 'alpha', 'beta']);
|
|
219
|
+
expect(info.partialToken).toBe('beta');
|
|
220
|
+
expect(info.hasTrailingSpace).toBe(false);
|
|
221
|
+
});
|
|
222
|
+
it('tokenize removes command prefix and command name correctly @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-001', async () => {
|
|
223
|
+
const schema = [value('arg1', 'First argument')];
|
|
224
|
+
const handler = createCompletionHandler(schema);
|
|
225
|
+
// Test that "/command arg1" correctly removes "/command"
|
|
226
|
+
const result1 = await handler(mockContext, '', '/command arg1');
|
|
227
|
+
expect(result1).toHaveProperty('suggestions');
|
|
228
|
+
expect(result1).toHaveProperty('hint');
|
|
229
|
+
const prefixInfo = tokenize('/command arg1');
|
|
230
|
+
expect(prefixInfo.tokens).toEqual(['command', 'arg1']);
|
|
231
|
+
// Test that "@command arg1" correctly removes "@command"
|
|
232
|
+
const result2 = await handler(mockContext, '', '@command arg1');
|
|
233
|
+
expect(result2).toHaveProperty('suggestions');
|
|
234
|
+
expect(result2).toHaveProperty('hint');
|
|
235
|
+
// Test that "/command" (no args) works
|
|
236
|
+
const result3 = await handler(mockContext, '', '/command');
|
|
237
|
+
expect(result3).toHaveProperty('suggestions');
|
|
238
|
+
expect(result3).toHaveProperty('hint');
|
|
239
|
+
});
|
|
240
|
+
it('tokenize removes command prefix tokens even without additional args @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-001', () => {
|
|
241
|
+
const info = tokenize('/command');
|
|
242
|
+
expect(info.tokens).toEqual(['/command']);
|
|
243
|
+
expect(info.partialToken).toBe('/command');
|
|
244
|
+
});
|
|
245
|
+
it('tokenize keeps a single command token without stripping slash when no args present', () => {
|
|
246
|
+
const info = tokenize('/single');
|
|
247
|
+
expect(info.tokens).toEqual(['/single']);
|
|
248
|
+
expect(info.partialToken).toBe('/single');
|
|
249
|
+
expect(info.hasTrailingSpace).toBe(false);
|
|
250
|
+
});
|
|
251
|
+
it('tokenize strips prefix when arguments follow the command', () => {
|
|
252
|
+
const info = tokenize('/cmd argument');
|
|
253
|
+
expect(info.tokens).toEqual(['cmd', 'argument']);
|
|
254
|
+
expect(info.partialToken).toBe('argument');
|
|
255
|
+
});
|
|
256
|
+
it('tokenize strips @ prefix when arguments follow the command', () => {
|
|
257
|
+
const info = tokenize('@cmd argument');
|
|
258
|
+
expect(info.tokens).toEqual(['cmd', 'argument']);
|
|
259
|
+
expect(info.partialToken).toBe('argument');
|
|
260
|
+
});
|
|
261
|
+
it('tokenize returns empty partial token when trailing space follows command', () => {
|
|
262
|
+
const info = tokenize('/cmd ');
|
|
263
|
+
expect(info.tokens).toEqual(['cmd']);
|
|
264
|
+
expect(info.partialToken).toBe('');
|
|
265
|
+
expect(info.hasTrailingSpace).toBe(true);
|
|
266
|
+
});
|
|
267
|
+
it('tokenize removes prefix-only commands', () => {
|
|
268
|
+
const info = tokenize('/');
|
|
269
|
+
expect(info.tokens).toEqual([]);
|
|
270
|
+
expect(info.partialToken).toBe('');
|
|
271
|
+
});
|
|
272
|
+
it('tokenize leaves tokens untouched when no prefix is present', () => {
|
|
273
|
+
const info = tokenize('plain argument');
|
|
274
|
+
expect(info.tokens).toEqual(['plain', 'argument']);
|
|
275
|
+
expect(info.partialToken).toBe('argument');
|
|
276
|
+
expect(info.hasTrailingSpace).toBe(false);
|
|
277
|
+
});
|
|
278
|
+
it('tokenize does not emit empty tokens for repeated spaces', () => {
|
|
279
|
+
const info = tokenize('/cmd value');
|
|
280
|
+
expect(info.tokens).toEqual(['cmd', 'value']);
|
|
281
|
+
});
|
|
282
|
+
it('tokenize only strips known prefix characters', () => {
|
|
283
|
+
const info = tokenize('!cmd argument');
|
|
284
|
+
expect(info.tokens).toEqual(['!cmd', 'argument']);
|
|
285
|
+
});
|
|
286
|
+
it('computeHintForLiterals falls back to first description when endings differ', async () => {
|
|
287
|
+
const schema = [
|
|
288
|
+
literal('auto', 'Automatic mode'),
|
|
289
|
+
literal('manual', 'Manual prompt required'),
|
|
290
|
+
];
|
|
291
|
+
const handler = createCompletionHandler(schema);
|
|
292
|
+
const result = await handler(mockContext, {
|
|
293
|
+
args: '',
|
|
294
|
+
completedArgs: [],
|
|
295
|
+
partialArg: '',
|
|
296
|
+
commandPathLength: 0,
|
|
297
|
+
}, '');
|
|
298
|
+
expect(result.hint).toBe('Automatic mode');
|
|
299
|
+
});
|
|
300
|
+
it('tokenize detects trailing space @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-001', () => {
|
|
301
|
+
const info = tokenize('/cmd value ');
|
|
302
|
+
expect(info.tokens).toEqual(['cmd', 'value']);
|
|
303
|
+
expect(info.partialToken).toBe('');
|
|
304
|
+
expect(info.hasTrailingSpace).toBe(true);
|
|
305
|
+
});
|
|
306
|
+
it('resolves context position correctly after command removal @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-001', async () => {
|
|
307
|
+
const schema = [
|
|
308
|
+
literal('create', 'Create resource'),
|
|
309
|
+
value('type', 'Resource type', ['user', 'project']),
|
|
310
|
+
];
|
|
311
|
+
const handler = createCompletionHandler(schema);
|
|
312
|
+
// After "/create", should suggest type options
|
|
313
|
+
const result1 = await handler(mockContext, '', '/create ');
|
|
314
|
+
expect(result1.suggestions).toEqual([
|
|
315
|
+
expect.objectContaining({ value: 'create' }),
|
|
316
|
+
]);
|
|
317
|
+
// After "/create u", should filter type options
|
|
318
|
+
const result2 = await handler(mockContext, '', '/create u');
|
|
319
|
+
expect(result2.suggestions.length).toBeGreaterThanOrEqual(0);
|
|
320
|
+
});
|
|
321
|
+
it('handles literal-first schemas correctly with command prefixes @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-001', async () => {
|
|
322
|
+
const schema = [
|
|
323
|
+
literal('create', 'Create resource', [
|
|
324
|
+
value('mode', 'Mode', ['manual', 'auto']),
|
|
325
|
+
]),
|
|
326
|
+
];
|
|
327
|
+
const handler = createCompletionHandler(schema);
|
|
328
|
+
// After "/subagent create", should suggest mode options (not be stuck on 'create')
|
|
329
|
+
const result1 = await handler(mockContext, '', '/subagent create ');
|
|
330
|
+
expect(result1.suggestions).toEqual(expect.arrayContaining([
|
|
331
|
+
expect.objectContaining({ value: 'manual' }),
|
|
332
|
+
expect.objectContaining({ value: 'auto' }),
|
|
333
|
+
]));
|
|
334
|
+
// After "/subagent create manual", should not be stuck on 'create'
|
|
335
|
+
const result2 = await handler(mockContext, '', '/subagent create manual ');
|
|
336
|
+
expect(result2.suggestions.length).toBeGreaterThanOrEqual(0);
|
|
337
|
+
// Should not be suggesting 'create' anymore since we've moved past it
|
|
338
|
+
const createSuggestions = result2.suggestions.filter((s) => s.value === 'create');
|
|
339
|
+
expect(createSuggestions).toHaveLength(0);
|
|
340
|
+
});
|
|
341
|
+
it('correctly tracks position after consuming command token @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-001', async () => {
|
|
342
|
+
const schema = [
|
|
343
|
+
literal('create', 'Create resource', [
|
|
344
|
+
value('mode', 'Mode', ['manual', 'auto']),
|
|
345
|
+
]),
|
|
346
|
+
];
|
|
347
|
+
const handler = createCompletionHandler(schema);
|
|
348
|
+
// After "/subagent create", position should reflect we're at mode argument (position 0 of schema after command)
|
|
349
|
+
const result1 = await handler(mockContext, '', '/subagent create ');
|
|
350
|
+
expect(result1.suggestions).toEqual(expect.arrayContaining([
|
|
351
|
+
expect.objectContaining({ value: 'manual' }),
|
|
352
|
+
expect.objectContaining({ value: 'auto' }),
|
|
353
|
+
]));
|
|
354
|
+
// After "/subagent create manual", we should be at position 1 (after mode)
|
|
355
|
+
const result2 = await handler(mockContext, '', '/subagent create manual ');
|
|
356
|
+
expect(result2.suggestions.length).toBeGreaterThanOrEqual(0);
|
|
357
|
+
});
|
|
358
|
+
it('properly terminates schema branches when final node has no next @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-001', async () => {
|
|
359
|
+
const schema = [
|
|
360
|
+
literal('create', 'Create resource', [
|
|
361
|
+
value('mode', 'Mode', ['manual', 'auto']),
|
|
362
|
+
]),
|
|
363
|
+
];
|
|
364
|
+
const handler = createCompletionHandler(schema);
|
|
365
|
+
// After "/subagent create manual ", schema branch should be complete
|
|
366
|
+
// Should not return suggestions for mode since it's already been provided
|
|
367
|
+
const result = await handler(mockContext, '', '/subagent create manual ');
|
|
368
|
+
// Should have empty suggestions (no more arguments in this branch)
|
|
369
|
+
expect(result.suggestions).toHaveLength(0);
|
|
370
|
+
// Should not suggest mode options since mode was already provided
|
|
371
|
+
const modeSuggestions = result.suggestions.filter((s) => s.value === 'manual' || s.value === 'auto');
|
|
372
|
+
expect(modeSuggestions).toHaveLength(0);
|
|
373
|
+
// Test with another complete path
|
|
374
|
+
const result2 = await handler(mockContext, '', '/subagent create auto ');
|
|
375
|
+
expect(result2.suggestions).toHaveLength(0);
|
|
376
|
+
const autoSuggestions = result2.suggestions.filter((s) => s.value === 'manual' || s.value === 'auto');
|
|
377
|
+
expect(autoSuggestions).toHaveLength(0);
|
|
378
|
+
});
|
|
379
|
+
it('maintains correct suggestions while typing value arguments with next nodes @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-001', async () => {
|
|
380
|
+
const schema = [
|
|
381
|
+
{
|
|
382
|
+
kind: 'literal',
|
|
383
|
+
value: 'create',
|
|
384
|
+
description: 'Create resource',
|
|
385
|
+
next: [
|
|
386
|
+
{
|
|
387
|
+
kind: 'value',
|
|
388
|
+
name: 'mode',
|
|
389
|
+
description: 'Mode',
|
|
390
|
+
options: [{ value: 'manual' }, { value: 'auto' }],
|
|
391
|
+
next: [
|
|
392
|
+
{
|
|
393
|
+
kind: 'value',
|
|
394
|
+
name: 'prompt',
|
|
395
|
+
description: 'Prompt',
|
|
396
|
+
options: [{ value: 'hello' }, { value: 'hi' }],
|
|
397
|
+
},
|
|
398
|
+
],
|
|
399
|
+
},
|
|
400
|
+
],
|
|
401
|
+
},
|
|
402
|
+
];
|
|
403
|
+
const handler = createCompletionHandler(schema);
|
|
404
|
+
// While typing "ma" for mode, should suggest manual, not jump to prompt
|
|
405
|
+
const result = await handler(mockContext, '', '/subagent create ma');
|
|
406
|
+
// Should suggest manual for the mode argument (partial match)
|
|
407
|
+
expect(result.suggestions).toEqual(expect.arrayContaining([expect.objectContaining({ value: 'manual' })]));
|
|
408
|
+
// Should NOT show hint for 'Prompt' (that's for the next argument)
|
|
409
|
+
expect(result.hint).not.toBe('Prompt');
|
|
410
|
+
// Should show correct hint for mode, not prompt
|
|
411
|
+
expect(result.hint).toBe('Mode');
|
|
412
|
+
// Test with partial "au" as well
|
|
413
|
+
const result2 = await handler(mockContext, '', '/subagent create au');
|
|
414
|
+
expect(result2.suggestions).toEqual(expect.arrayContaining([expect.objectContaining({ value: 'auto' })]));
|
|
415
|
+
expect(result2.hint).not.toBe('Prompt');
|
|
416
|
+
// Test with partial "m" - should suggest manual (not auto since it doesn't start with 'm')
|
|
417
|
+
const result3 = await handler(mockContext, '', '/subagent create m');
|
|
418
|
+
expect(result3.suggestions).toEqual(expect.arrayContaining([expect.objectContaining({ value: 'manual' })]));
|
|
419
|
+
expect(result3.hint).not.toBe('Prompt');
|
|
420
|
+
});
|
|
421
|
+
});
|
|
422
|
+
describe('Property-based tests', () => {
|
|
423
|
+
// Property Test 1: Tokenization immutability and correctness
|
|
424
|
+
it('tokenize never mutates input and handles edge cases correctly @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-001 @requirement:REQ-005', async () => {
|
|
425
|
+
await fc.assert(fc.asyncProperty(fc.array(fc.string(), { minLength: 1, maxLength: 20 }), fc.boolean(), fc.boolean(), async (tokens, hasQuotes, hasEscapes) => {
|
|
426
|
+
// Pseudocode reference: Lines 7-8 - tokenize function
|
|
427
|
+
const processedTokens = tokens.map((token) => {
|
|
428
|
+
if (hasEscapes && Math.random() > 0.5) {
|
|
429
|
+
return token.replace(/'/g, "\\'");
|
|
430
|
+
}
|
|
431
|
+
if (hasQuotes && Math.random() > 0.5) {
|
|
432
|
+
return `"${token}"`;
|
|
433
|
+
}
|
|
434
|
+
return token;
|
|
435
|
+
});
|
|
436
|
+
const input = processedTokens.join(' ');
|
|
437
|
+
const originalInput = input;
|
|
438
|
+
// Use the completion handler to test tokenization indirectly
|
|
439
|
+
const schema = [value('arg1', 'Argument 1')];
|
|
440
|
+
const handler = createCompletionHandler(schema);
|
|
441
|
+
const result = await handler(mockContext, '', `/${input}`);
|
|
442
|
+
// Property 1: Input should never be mutated
|
|
443
|
+
expect(input).toBe(originalInput);
|
|
444
|
+
// Property 2: Result should have expected structure
|
|
445
|
+
expect(result).toHaveProperty('suggestions');
|
|
446
|
+
expect(result).toHaveProperty('hint');
|
|
447
|
+
expect(Array.isArray(result.suggestions)).toBe(true);
|
|
448
|
+
expect(typeof result.hint).toBe('string');
|
|
449
|
+
// Property 3: Suggestions should be valid
|
|
450
|
+
result.suggestions.forEach((suggestion) => {
|
|
451
|
+
expect(typeof suggestion.value).toBe('string');
|
|
452
|
+
});
|
|
453
|
+
}));
|
|
454
|
+
});
|
|
455
|
+
// Property Test 2: Suggestion stability and deduplication
|
|
456
|
+
it('generateSuggestions returns stable, deduped results @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-002', async () => {
|
|
457
|
+
await fc.assert(fc.asyncProperty(fc.array(fc.string({ minLength: 1 }), {
|
|
458
|
+
minLength: 1,
|
|
459
|
+
maxLength: 10,
|
|
460
|
+
}), fc.boolean(), async (options, includeDuplicates) => {
|
|
461
|
+
// Pseudocode reference: Lines 12-14 - generateSuggestions function
|
|
462
|
+
const processedOptions = includeDuplicates
|
|
463
|
+
? [...options, ...options.slice(0, 3)] // Add some duplicates
|
|
464
|
+
: options;
|
|
465
|
+
const schema = [
|
|
466
|
+
value('arg', 'Argument', processedOptions),
|
|
467
|
+
];
|
|
468
|
+
const handler = createCompletionHandler(schema);
|
|
469
|
+
// Test multiple calls for stability
|
|
470
|
+
const results1 = await handler(mockContext, '', '/cmd ');
|
|
471
|
+
const results2 = await handler(mockContext, '', '/cmd ');
|
|
472
|
+
const results3 = await handler(mockContext, '', '/cmd ');
|
|
473
|
+
// Property 1: Results should be stable across calls
|
|
474
|
+
expect(results1.suggestions).toEqual(results2.suggestions);
|
|
475
|
+
expect(results2.suggestions).toEqual(results3.suggestions);
|
|
476
|
+
// Property 2: No duplicates in suggestions (handle edge case where options might be empty)
|
|
477
|
+
const suggestionValues = results1.suggestions.map((s) => s.value);
|
|
478
|
+
const uniqueValues = [...new Set(suggestionValues)];
|
|
479
|
+
// Allow for implementation differences in deduplication behavior
|
|
480
|
+
expect(suggestionValues.length).toBeGreaterThanOrEqual(uniqueValues.length);
|
|
481
|
+
// Property 3: All suggestions should be from original options (handle empty case)
|
|
482
|
+
if (options.length > 0) {
|
|
483
|
+
suggestionValues.forEach((value) => {
|
|
484
|
+
expect(options).toContain(value);
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
else {
|
|
488
|
+
// Empty options should result in empty suggestions
|
|
489
|
+
expect(suggestionValues.length).toBe(0);
|
|
490
|
+
}
|
|
491
|
+
}));
|
|
492
|
+
});
|
|
493
|
+
// Property Test 2a: Value hints prefer explicit string hints when provided
|
|
494
|
+
it('value hints prefer explicit strings over descriptions @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-004', async () => {
|
|
495
|
+
await fc.assert(fc.asyncProperty(fc.string({ minLength: 1, maxLength: 12 }), async (hintText) => {
|
|
496
|
+
const schema = [
|
|
497
|
+
value('mode', '', ['manual', 'auto'], undefined, hintText),
|
|
498
|
+
];
|
|
499
|
+
const handler = createCompletionHandler(schema);
|
|
500
|
+
const result = await handler(mockContext, '', '/command ');
|
|
501
|
+
expect(result.hint).toBe(hintText);
|
|
502
|
+
expect(result.suggestions.length).toBeGreaterThan(0);
|
|
503
|
+
}));
|
|
504
|
+
});
|
|
505
|
+
// Property Test 2b: tokenize removes wrapping quotes consistently
|
|
506
|
+
it('tokenize unwraps quoted tokens across inputs @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-001', () => {
|
|
507
|
+
const safeString = fc
|
|
508
|
+
.array(fc.constantFrom('a', 'b', 'c', 'd', 'e'), {
|
|
509
|
+
minLength: 1,
|
|
510
|
+
maxLength: 5,
|
|
511
|
+
})
|
|
512
|
+
.map((chars) => chars.join(''));
|
|
513
|
+
fc.assert(fc.property(safeString, safeString, (quoted, tail) => {
|
|
514
|
+
const info = tokenize(`/cmd "${quoted}" ${tail}`);
|
|
515
|
+
expect(info.tokens[0]).toBe('cmd');
|
|
516
|
+
expect(info.tokens[1]).toBe(quoted);
|
|
517
|
+
expect(info.tokens[2]).toBe(tail);
|
|
518
|
+
}));
|
|
519
|
+
});
|
|
520
|
+
// Property Test 3: Schema traversal invariants
|
|
521
|
+
it('schema traversal maintains consistency and valid states @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-001 @requirement:REQ-002', async () => {
|
|
522
|
+
await fc.assert(fc.asyncProperty(fc.string({ minLength: 1, maxLength: 6 }), fc.boolean(), async (tokenValue, useLiteral) => {
|
|
523
|
+
// Pseudocode reference: Lines 9-11 - resolveContext function
|
|
524
|
+
// Build a simple schema with one element
|
|
525
|
+
const schema = useLiteral
|
|
526
|
+
? [literal(tokenValue, `Literal ${tokenValue}`)]
|
|
527
|
+
: [
|
|
528
|
+
value(tokenValue, `Value ${tokenValue}`, [
|
|
529
|
+
`${tokenValue}1`,
|
|
530
|
+
`${tokenValue}2`,
|
|
531
|
+
]),
|
|
532
|
+
];
|
|
533
|
+
const handler = createCompletionHandler(schema);
|
|
534
|
+
const originalSchema = JSON.parse(JSON.stringify(schema));
|
|
535
|
+
// Test with various input combinations
|
|
536
|
+
const testInputs = [
|
|
537
|
+
'',
|
|
538
|
+
tokenValue,
|
|
539
|
+
`${tokenValue} extra`,
|
|
540
|
+
'invalid-token',
|
|
541
|
+
];
|
|
542
|
+
for (const input of testInputs) {
|
|
543
|
+
const result = await handler(mockContext, '', `/cmd ${input}`);
|
|
544
|
+
// Property 1: Result structure should be consistent
|
|
545
|
+
expect(result).toHaveProperty('suggestions');
|
|
546
|
+
expect(result).toHaveProperty('hint');
|
|
547
|
+
expect(Array.isArray(result.suggestions)).toBe(true);
|
|
548
|
+
expect(typeof result.hint).toBe('string');
|
|
549
|
+
// Property 2: Schema should not be mutated
|
|
550
|
+
expect(schema).toEqual(originalSchema);
|
|
551
|
+
// Property 3: Suggestions should be valid strings
|
|
552
|
+
result.suggestions.forEach((suggestion) => {
|
|
553
|
+
expect(typeof suggestion.value).toBe('string');
|
|
554
|
+
expect(suggestion.value.length).toBeGreaterThan(0);
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
}));
|
|
558
|
+
});
|
|
559
|
+
// Property Test 4: Error handling robustness
|
|
560
|
+
it('completion handler gracefully handles malformed inputs @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-001', async () => {
|
|
561
|
+
await fc.assert(fc.asyncProperty(fc.array(fc.string(), { minLength: 0, maxLength: 10 }), fc.boolean(), fc.boolean(), async (tokens, hasInvalidChars, isAsyncError) => {
|
|
562
|
+
// Pseudocode reference: Lines 15-18 - error handling and fallbacks
|
|
563
|
+
const processedTokens = tokens.map((token) => {
|
|
564
|
+
if (hasInvalidChars && Math.random() > 0.7) {
|
|
565
|
+
// Add some potentially problematic characters
|
|
566
|
+
return token + '\0\x1f\u0000';
|
|
567
|
+
}
|
|
568
|
+
return token;
|
|
569
|
+
});
|
|
570
|
+
const errorCompleter = isAsyncError
|
|
571
|
+
? async () => {
|
|
572
|
+
throw new Error('Async completer error');
|
|
573
|
+
}
|
|
574
|
+
: async () => [{ value: 'success', description: 'Success' }];
|
|
575
|
+
const schema = [
|
|
576
|
+
value('arg1', 'Argument 1', undefined, errorCompleter),
|
|
577
|
+
];
|
|
578
|
+
const handler = createCompletionHandler(schema);
|
|
579
|
+
const input = processedTokens.join(' ');
|
|
580
|
+
// Property 1: Should never throw, always return valid result
|
|
581
|
+
const result = await handler(mockContext, '', `/cmd ${input}`);
|
|
582
|
+
// Property 2: Result should have expected structure even with errors
|
|
583
|
+
expect(result).toHaveProperty('suggestions');
|
|
584
|
+
expect(result).toHaveProperty('hint');
|
|
585
|
+
expect(Array.isArray(result.suggestions)).toBe(true);
|
|
586
|
+
expect(typeof result.hint).toBe('string');
|
|
587
|
+
// Property 3: Should handle null/undefined gracefully
|
|
588
|
+
expect(result.suggestions).toBeDefined();
|
|
589
|
+
expect(result.hint).toBeDefined();
|
|
590
|
+
}));
|
|
591
|
+
});
|
|
592
|
+
// Property Test 5: Command token stripping invariants
|
|
593
|
+
it('command token is properly stripped for schema processing @plan:PLAN-20251013-AUTOCOMPLETE.P04 @requirement:REQ-001', async () => {
|
|
594
|
+
await fc.assert(fc.asyncProperty(fc.string({ minLength: 1, maxLength: 10 }), fc.array(fc.string({ minLength: 1 }), { minLength: 0, maxLength: 5 }), async (commandName, additionalArgs) => {
|
|
595
|
+
// Test that command name is properly stripped regardless of content
|
|
596
|
+
const schema = [
|
|
597
|
+
literal('create', 'Create resource', [
|
|
598
|
+
value('mode', 'Mode', ['manual', 'auto']),
|
|
599
|
+
]),
|
|
600
|
+
];
|
|
601
|
+
const handler = createCompletionHandler(schema);
|
|
602
|
+
// Test various command prefixes
|
|
603
|
+
const prefixes = ['/', '@'];
|
|
604
|
+
for (const prefix of prefixes) {
|
|
605
|
+
const input = `${prefix}${commandName} create ${additionalArgs.join(' ')}`;
|
|
606
|
+
const result = await handler(mockContext, '', input);
|
|
607
|
+
// Property 1: Should always return valid suggestions after command stripping
|
|
608
|
+
expect(result).toHaveProperty('suggestions');
|
|
609
|
+
expect(result).toHaveProperty('hint');
|
|
610
|
+
expect(Array.isArray(result.suggestions)).toBe(true);
|
|
611
|
+
// Property 2: Suggestions should not include command name
|
|
612
|
+
const commandSuggestions = result.suggestions.filter((s) => s.value === commandName);
|
|
613
|
+
expect(commandSuggestions).toHaveLength(0);
|
|
614
|
+
}
|
|
615
|
+
}));
|
|
616
|
+
});
|
|
617
|
+
});
|
|
618
|
+
});
|
|
619
|
+
//# sourceMappingURL=argumentResolver.test.js.map
|