indusagi 0.12.19 → 0.12.21
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/README.md +16 -36
- package/dist/agent/agent-loop.d.ts +3 -9
- package/dist/agent/agent-loop.d.ts.map +1 -1
- package/dist/agent/agent-loop.js +19 -58
- package/dist/agent/agent-loop.js.map +1 -1
- package/dist/agent/agent.d.ts +9 -10
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/agent.js +182 -129
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/error-handler.d.ts.map +1 -1
- package/dist/agent/error-handler.js.map +1 -1
- package/dist/agent/event-bus.d.ts.map +1 -1
- package/dist/agent/event-bus.js +1 -3
- package/dist/agent/event-bus.js.map +1 -1
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +0 -6
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/messages.d.ts +1 -1
- package/dist/agent/messages.d.ts.map +1 -1
- package/dist/agent/proxy.d.ts +1 -14
- package/dist/agent/proxy.d.ts.map +1 -1
- package/dist/agent/proxy.js +67 -148
- package/dist/agent/proxy.js.map +1 -1
- package/dist/agent/session-manager.d.ts +10 -10
- package/dist/agent/session-manager.d.ts.map +1 -1
- package/dist/agent/session-manager.js +20 -16
- package/dist/agent/session-manager.js.map +1 -1
- package/dist/agent/state-manager.d.ts +1 -1
- package/dist/agent/state-manager.d.ts.map +1 -1
- package/dist/agent/state-manager.js +1 -0
- package/dist/agent/state-manager.js.map +1 -1
- package/dist/agent/telemetry.d.ts.map +1 -1
- package/dist/agent/telemetry.js +1 -3
- package/dist/agent/telemetry.js.map +1 -1
- package/dist/agent/tools/bash.d.ts.map +1 -1
- package/dist/agent/tools/bash.js +143 -118
- package/dist/agent/tools/bash.js.map +1 -1
- package/dist/agent/tools/edit-diff.d.ts +1 -1
- package/dist/agent/tools/edit-diff.d.ts.map +1 -1
- package/dist/agent/tools/edit-diff.js +189 -175
- package/dist/agent/tools/edit-diff.js.map +1 -1
- package/dist/agent/tools/edit.d.ts.map +1 -1
- package/dist/agent/tools/edit.js +137 -121
- package/dist/agent/tools/edit.js.map +1 -1
- package/dist/agent/tools/find.d.ts.map +1 -1
- package/dist/agent/tools/find.js +100 -65
- package/dist/agent/tools/find.js.map +1 -1
- package/dist/agent/tools/grep.d.ts.map +1 -1
- package/dist/agent/tools/grep.js +126 -97
- package/dist/agent/tools/grep.js.map +1 -1
- package/dist/agent/tools/index.d.ts +53 -40
- package/dist/agent/tools/index.d.ts.map +1 -1
- package/dist/agent/tools/index.js +19 -12
- package/dist/agent/tools/index.js.map +1 -1
- package/dist/agent/tools/ls.d.ts +2 -1
- package/dist/agent/tools/ls.d.ts.map +1 -1
- package/dist/agent/tools/ls.js +145 -94
- package/dist/agent/tools/ls.js.map +1 -1
- package/dist/agent/tools/path-utils.d.ts.map +1 -1
- package/dist/agent/tools/path-utils.js +48 -29
- package/dist/agent/tools/path-utils.js.map +1 -1
- package/dist/agent/tools/process-controller.d.ts +15 -0
- package/dist/agent/tools/process-controller.d.ts.map +1 -0
- package/dist/agent/tools/process-controller.js +39 -0
- package/dist/agent/tools/process-controller.js.map +1 -0
- package/dist/agent/tools/process-manager.d.ts +60 -0
- package/dist/agent/tools/process-manager.d.ts.map +1 -0
- package/dist/agent/tools/process-manager.js +485 -0
- package/dist/agent/tools/process-manager.js.map +1 -0
- package/dist/agent/tools/process-types.d.ts +74 -0
- package/dist/agent/tools/process-types.d.ts.map +1 -0
- package/dist/agent/tools/process-types.js +7 -0
- package/dist/agent/tools/process-types.js.map +1 -0
- package/dist/agent/tools/process.d.ts +38 -0
- package/dist/agent/tools/process.d.ts.map +1 -0
- package/dist/agent/tools/process.js +360 -0
- package/dist/agent/tools/process.js.map +1 -0
- package/dist/agent/tools/read.d.ts.map +1 -1
- package/dist/agent/tools/read.js +157 -135
- package/dist/agent/tools/read.js.map +1 -1
- package/dist/agent/tools/registry.js +2 -4
- package/dist/agent/tools/registry.js.map +1 -1
- package/dist/agent/tools/teams/activity-tracker.d.ts +66 -0
- package/dist/agent/tools/teams/activity-tracker.d.ts.map +1 -0
- package/dist/agent/tools/teams/activity-tracker.js +480 -0
- package/dist/agent/tools/teams/activity-tracker.js.map +1 -0
- package/dist/agent/tools/teams/cleanup.d.ts +51 -0
- package/dist/agent/tools/teams/cleanup.d.ts.map +1 -0
- package/dist/agent/tools/teams/cleanup.js +219 -0
- package/dist/agent/tools/teams/cleanup.js.map +1 -0
- package/dist/agent/tools/teams/fs-lock.d.ts +12 -0
- package/dist/agent/tools/teams/fs-lock.d.ts.map +1 -0
- package/dist/agent/tools/teams/fs-lock.js +74 -0
- package/dist/agent/tools/teams/fs-lock.js.map +1 -0
- package/dist/agent/tools/teams/index.d.ts +12 -0
- package/dist/agent/tools/teams/index.d.ts.map +1 -0
- package/dist/agent/tools/teams/index.js +12 -0
- package/dist/agent/tools/teams/index.js.map +1 -0
- package/dist/agent/tools/teams/mailbox.d.ts +21 -0
- package/dist/agent/tools/teams/mailbox.d.ts.map +1 -0
- package/dist/agent/tools/teams/mailbox.js +106 -0
- package/dist/agent/tools/teams/mailbox.js.map +1 -0
- package/dist/agent/tools/teams/model-policy.d.ts +23 -0
- package/dist/agent/tools/teams/model-policy.d.ts.map +1 -0
- package/dist/agent/tools/teams/model-policy.js +113 -0
- package/dist/agent/tools/teams/model-policy.js.map +1 -0
- package/dist/agent/tools/teams/names.d.ts +28 -0
- package/dist/agent/tools/teams/names.d.ts.map +1 -0
- package/dist/agent/tools/teams/names.js +109 -0
- package/dist/agent/tools/teams/names.js.map +1 -0
- package/dist/agent/tools/teams/protocol.d.ts +75 -0
- package/dist/agent/tools/teams/protocol.d.ts.map +1 -0
- package/dist/agent/tools/teams/protocol.js +205 -0
- package/dist/agent/tools/teams/protocol.js.map +1 -0
- package/dist/agent/tools/teams/task-store.d.ts +89 -0
- package/dist/agent/tools/teams/task-store.d.ts.map +1 -0
- package/dist/agent/tools/teams/task-store.js +445 -0
- package/dist/agent/tools/teams/task-store.js.map +1 -0
- package/dist/agent/tools/teams/team-attach-claim.d.ts +36 -0
- package/dist/agent/tools/teams/team-attach-claim.d.ts.map +1 -0
- package/dist/agent/tools/teams/team-attach-claim.js +144 -0
- package/dist/agent/tools/teams/team-attach-claim.js.map +1 -0
- package/dist/agent/tools/teams/team-config.d.ts +55 -0
- package/dist/agent/tools/teams/team-config.d.ts.map +1 -0
- package/dist/agent/tools/teams/team-config.js +252 -0
- package/dist/agent/tools/teams/team-config.js.map +1 -0
- package/dist/agent/tools/teams/worktree.d.ts +40 -0
- package/dist/agent/tools/teams/worktree.d.ts.map +1 -0
- package/dist/agent/tools/teams/worktree.js +213 -0
- package/dist/agent/tools/teams/worktree.js.map +1 -0
- package/dist/agent/tools/todo-store.js +2 -1
- package/dist/agent/tools/todo-store.js.map +1 -1
- package/dist/agent/tools/todo.d.ts +2 -2
- package/dist/agent/tools/todo.js +2 -2
- package/dist/agent/tools/truncate.d.ts.map +1 -1
- package/dist/agent/tools/truncate.js +150 -134
- package/dist/agent/tools/truncate.js.map +1 -1
- package/dist/agent/tools/utils/hook-runner.d.ts +9 -10
- package/dist/agent/tools/utils/hook-runner.d.ts.map +1 -1
- package/dist/agent/tools/utils/hook-runner.js +18 -16
- package/dist/agent/tools/utils/hook-runner.js.map +1 -1
- package/dist/agent/tools/utils/image-resize.d.ts +1 -14
- package/dist/agent/tools/utils/image-resize.d.ts.map +1 -1
- package/dist/agent/tools/utils/image-resize.js +80 -34
- package/dist/agent/tools/utils/image-resize.js.map +1 -1
- package/dist/agent/tools/utils/mime.d.ts +0 -8
- package/dist/agent/tools/utils/mime.d.ts.map +1 -1
- package/dist/agent/tools/utils/mime.js +43 -32
- package/dist/agent/tools/utils/mime.js.map +1 -1
- package/dist/agent/tools/utils/shell.d.ts +1 -23
- package/dist/agent/tools/utils/shell.d.ts.map +1 -1
- package/dist/agent/tools/utils/shell.js +43 -86
- package/dist/agent/tools/utils/shell.js.map +1 -1
- package/dist/agent/tools/write.d.ts.map +1 -1
- package/dist/agent/tools/write.js +105 -62
- package/dist/agent/tools/write.js.map +1 -1
- package/dist/agent/types.d.ts +69 -64
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js +38 -23
- package/dist/agent/types.js.map +1 -1
- package/dist/agent.d.ts +4 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +4 -0
- package/dist/agent.js.map +1 -1
- package/dist/ai/api-registry.d.ts.map +1 -1
- package/dist/ai/api-registry.js +3 -4
- package/dist/ai/api-registry.js.map +1 -1
- package/dist/ai/cli.js +62 -82
- package/dist/ai/cli.js.map +1 -1
- package/dist/ai/env-api-keys.d.ts.map +1 -1
- package/dist/ai/env-api-keys.js +78 -81
- package/dist/ai/env-api-keys.js.map +1 -1
- package/dist/ai/index.d.ts +6 -0
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +6 -0
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/models.d.ts +7 -17
- package/dist/ai/models.d.ts.map +1 -1
- package/dist/ai/models.generated.d.ts +19 -0
- package/dist/ai/models.generated.d.ts.map +1 -1
- package/dist/ai/models.generated.js +14 -2
- package/dist/ai/models.generated.js.map +1 -1
- package/dist/ai/models.js +17 -11
- package/dist/ai/models.js.map +1 -1
- package/dist/ai/providers/amazon-bedrock.d.ts.map +1 -1
- package/dist/ai/providers/amazon-bedrock.js +319 -248
- package/dist/ai/providers/amazon-bedrock.js.map +1 -1
- package/dist/ai/providers/anthropic.d.ts.map +1 -1
- package/dist/ai/providers/anthropic.js +378 -324
- package/dist/ai/providers/anthropic.js.map +1 -1
- package/dist/ai/providers/azure-openai-responses.d.ts.map +1 -1
- package/dist/ai/providers/azure-openai-responses.js +164 -123
- package/dist/ai/providers/azure-openai-responses.js.map +1 -1
- package/dist/ai/providers/google-shared.d.ts +0 -18
- package/dist/ai/providers/google-shared.d.ts.map +1 -1
- package/dist/ai/providers/google-shared.js +224 -225
- package/dist/ai/providers/google-shared.js.map +1 -1
- package/dist/ai/providers/google-vertex.d.ts.map +1 -1
- package/dist/ai/providers/google-vertex.js +244 -226
- package/dist/ai/providers/google-vertex.js.map +1 -1
- package/dist/ai/providers/google.d.ts +3 -0
- package/dist/ai/providers/google.d.ts.map +1 -1
- package/dist/ai/providers/google.js +232 -210
- package/dist/ai/providers/google.js.map +1 -1
- package/dist/ai/providers/kimi.js +1 -0
- package/dist/ai/providers/kimi.js.map +1 -1
- package/dist/ai/providers/mock.d.ts +10 -0
- package/dist/ai/providers/mock.d.ts.map +1 -0
- package/dist/ai/providers/mock.js +64 -0
- package/dist/ai/providers/mock.js.map +1 -0
- package/dist/ai/providers/openai-codex-responses.d.ts.map +1 -1
- package/dist/ai/providers/openai-codex-responses.js +178 -133
- package/dist/ai/providers/openai-codex-responses.js.map +1 -1
- package/dist/ai/providers/openai-completions.d.ts.map +1 -1
- package/dist/ai/providers/openai-completions.js +468 -387
- package/dist/ai/providers/openai-completions.js.map +1 -1
- package/dist/ai/providers/openai-responses-shared.d.ts.map +1 -1
- package/dist/ai/providers/openai-responses-shared.js +187 -166
- package/dist/ai/providers/openai-responses-shared.js.map +1 -1
- package/dist/ai/providers/openai-responses.d.ts.map +1 -1
- package/dist/ai/providers/openai-responses.js +108 -85
- package/dist/ai/providers/openai-responses.js.map +1 -1
- package/dist/ai/providers/openai-scaffold.d.ts +4 -0
- package/dist/ai/providers/openai-scaffold.d.ts.map +1 -0
- package/dist/ai/providers/openai-scaffold.js +33 -0
- package/dist/ai/providers/openai-scaffold.js.map +1 -0
- package/dist/ai/providers/register-builtins.d.ts.map +1 -1
- package/dist/ai/providers/register-builtins.js +109 -42
- package/dist/ai/providers/register-builtins.js.map +1 -1
- package/dist/ai/providers/simple-options.js +2 -0
- package/dist/ai/providers/simple-options.js.map +1 -1
- package/dist/ai/providers/transform-messages.js +3 -9
- package/dist/ai/providers/transform-messages.js.map +1 -1
- package/dist/ai/stream.d.ts +4 -14
- package/dist/ai/stream.d.ts.map +1 -1
- package/dist/ai/stream.js +0 -36
- package/dist/ai/stream.js.map +1 -1
- package/dist/ai/types.d.ts +22 -3
- package/dist/ai/types.d.ts.map +1 -1
- package/dist/ai/types.js +154 -77
- package/dist/ai/types.js.map +1 -1
- package/dist/ai/utils/base-stream-handler.js +1 -0
- package/dist/ai/utils/base-stream-handler.js.map +1 -1
- package/dist/ai/utils/event-stream.d.ts +2 -0
- package/dist/ai/utils/event-stream.d.ts.map +1 -1
- package/dist/ai/utils/event-stream.js +22 -5
- package/dist/ai/utils/event-stream.js.map +1 -1
- package/dist/ai/utils/json-parse.d.ts +3 -0
- package/dist/ai/utils/json-parse.d.ts.map +1 -1
- package/dist/ai/utils/json-parse.js +8 -5
- package/dist/ai/utils/json-parse.js.map +1 -1
- package/dist/ai/utils/oauth/anthropic.d.ts.map +1 -1
- package/dist/ai/utils/oauth/anthropic.js +110 -65
- package/dist/ai/utils/oauth/anthropic.js.map +1 -1
- package/dist/ai/utils/oauth/github-copilot.d.ts +8 -16
- package/dist/ai/utils/oauth/github-copilot.d.ts.map +1 -1
- package/dist/ai/utils/oauth/github-copilot.js +218 -227
- package/dist/ai/utils/oauth/github-copilot.js.map +1 -1
- package/dist/ai/utils/oauth/openai-codex.d.ts +4 -2
- package/dist/ai/utils/oauth/openai-codex.d.ts.map +1 -1
- package/dist/ai/utils/oauth/openai-codex.js +221 -236
- package/dist/ai/utils/oauth/openai-codex.js.map +1 -1
- package/dist/ai/utils/oauth/pkce.d.ts +6 -5
- package/dist/ai/utils/oauth/pkce.d.ts.map +1 -1
- package/dist/ai/utils/oauth/pkce.js +24 -21
- package/dist/ai/utils/oauth/pkce.js.map +1 -1
- package/dist/ai/utils/oauth/types.d.ts +31 -12
- package/dist/ai/utils/oauth/types.d.ts.map +1 -1
- package/dist/ai/utils/oauth/types.js +10 -1
- package/dist/ai/utils/oauth/types.js.map +1 -1
- package/dist/ai/utils/overflow.d.ts.map +1 -1
- package/dist/ai/utils/overflow.js +49 -21
- package/dist/ai/utils/overflow.js.map +1 -1
- package/dist/ai/utils/provider-adapter.js +9 -0
- package/dist/ai/utils/provider-adapter.js.map +1 -1
- package/dist/ai/utils/provider-client-builder.js +1 -1
- package/dist/ai/utils/provider-client-builder.js.map +1 -1
- package/dist/ai/utils/provider-errors.js +2 -0
- package/dist/ai/utils/provider-errors.js.map +1 -1
- package/dist/ai/utils/sanitize-unicode.d.ts +0 -20
- package/dist/ai/utils/sanitize-unicode.d.ts.map +1 -1
- package/dist/ai/utils/sanitize-unicode.js +35 -17
- package/dist/ai/utils/sanitize-unicode.js.map +1 -1
- package/dist/ai/utils/stream-event-helper.js +3 -0
- package/dist/ai/utils/stream-event-helper.js.map +1 -1
- package/dist/ai/utils/stream-handler-types.js +5 -0
- package/dist/ai/utils/stream-handler-types.js.map +1 -1
- package/dist/ai/utils/streaming-state-manager.js +4 -2
- package/dist/ai/utils/streaming-state-manager.js.map +1 -1
- package/dist/ai/utils/typebox-helpers.d.ts +6 -4
- package/dist/ai/utils/typebox-helpers.d.ts.map +1 -1
- package/dist/ai/utils/typebox-helpers.js +25 -7
- package/dist/ai/utils/typebox-helpers.js.map +1 -1
- package/dist/ai/utils/validation.d.ts.map +1 -1
- package/dist/ai/utils/validation.js +67 -34
- package/dist/ai/utils/validation.js.map +1 -1
- package/dist/ai.d.ts +4 -0
- package/dist/ai.d.ts.map +1 -1
- package/dist/ai.js +4 -0
- package/dist/ai.js.map +1 -1
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +3 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/client-pool.js +3 -2
- package/dist/mcp/client-pool.js.map +1 -1
- package/dist/mcp/client.js +19 -6
- package/dist/mcp/client.js.map +1 -1
- package/dist/mcp/config.d.ts +6 -6
- package/dist/mcp/config.js +17 -17
- package/dist/mcp/config.js.map +1 -1
- package/dist/mcp/errors.js +8 -0
- package/dist/mcp/errors.js.map +1 -1
- package/dist/mcp/index.d.ts +5 -5
- package/dist/mcp/index.js +5 -5
- package/dist/mcp/schema-converter.d.ts +1 -1
- package/dist/mcp/schema-converter.js +1 -1
- package/dist/mcp/server.d.ts +4 -4
- package/dist/mcp/server.js +12 -7
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tool-factory.d.ts +2 -2
- package/dist/mcp/tool-factory.js +2 -2
- package/dist/mcp.d.ts +0 -4
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +0 -4
- package/dist/mcp.js.map +1 -1
- package/dist/observability.d.ts +2 -0
- package/dist/observability.d.ts.map +1 -0
- package/dist/observability.js +2 -0
- package/dist/observability.js.map +1 -0
- package/dist/tui/autocomplete.d.ts +14 -18
- package/dist/tui/autocomplete.d.ts.map +1 -1
- package/dist/tui/autocomplete.js +290 -402
- package/dist/tui/autocomplete.js.map +1 -1
- package/dist/tui/components/box.d.ts +1 -6
- package/dist/tui/components/box.d.ts.map +1 -1
- package/dist/tui/components/box.js +98 -67
- package/dist/tui/components/box.js.map +1 -1
- package/dist/tui/components/cancellable-loader.d.ts +6 -3
- package/dist/tui/components/cancellable-loader.d.ts.map +1 -1
- package/dist/tui/components/cancellable-loader.js +8 -9
- package/dist/tui/components/cancellable-loader.js.map +1 -1
- package/dist/tui/components/editor.d.ts +18 -0
- package/dist/tui/components/editor.d.ts.map +1 -1
- package/dist/tui/components/editor.js +356 -354
- package/dist/tui/components/editor.js.map +1 -1
- package/dist/tui/components/image.d.ts +2 -0
- package/dist/tui/components/image.d.ts.map +1 -1
- package/dist/tui/components/image.js +79 -37
- package/dist/tui/components/image.js.map +1 -1
- package/dist/tui/components/input.d.ts +4 -8
- package/dist/tui/components/input.d.ts.map +1 -1
- package/dist/tui/components/input.js +236 -232
- package/dist/tui/components/input.js.map +1 -1
- package/dist/tui/components/loader.d.ts +5 -5
- package/dist/tui/components/loader.d.ts.map +1 -1
- package/dist/tui/components/loader.js +22 -19
- package/dist/tui/components/loader.js.map +1 -1
- package/dist/tui/components/markdown.d.ts +2 -32
- package/dist/tui/components/markdown.d.ts.map +1 -1
- package/dist/tui/components/markdown.js +338 -357
- package/dist/tui/components/markdown.js.map +1 -1
- package/dist/tui/components/select-list.d.ts +1 -0
- package/dist/tui/components/select-list.d.ts.map +1 -1
- package/dist/tui/components/select-list.js +83 -82
- package/dist/tui/components/select-list.js.map +1 -1
- package/dist/tui/components/settings-list.d.ts +10 -10
- package/dist/tui/components/settings-list.d.ts.map +1 -1
- package/dist/tui/components/settings-list.js +48 -40
- package/dist/tui/components/settings-list.js.map +1 -1
- package/dist/tui/components/spacer.d.ts +1 -0
- package/dist/tui/components/spacer.d.ts.map +1 -1
- package/dist/tui/components/spacer.js +20 -5
- package/dist/tui/components/spacer.js.map +1 -1
- package/dist/tui/components/text.d.ts.map +1 -1
- package/dist/tui/components/text.js +47 -20
- package/dist/tui/components/text.js.map +1 -1
- package/dist/tui/components/truncated-text.d.ts +8 -4
- package/dist/tui/components/truncated-text.d.ts.map +1 -1
- package/dist/tui/components/truncated-text.js +15 -12
- package/dist/tui/components/truncated-text.js.map +1 -1
- package/dist/tui/editor-component.d.ts +87 -23
- package/dist/tui/editor-component.d.ts.map +1 -1
- package/dist/tui/fuzzy.d.ts.map +1 -1
- package/dist/tui/fuzzy.js +101 -50
- package/dist/tui/fuzzy.js.map +1 -1
- package/dist/tui/keybindings.d.ts +3 -3
- package/dist/tui/keybindings.d.ts.map +1 -1
- package/dist/tui/keybindings.js +137 -111
- package/dist/tui/keybindings.js.map +1 -1
- package/dist/tui/keys.d.ts +46 -43
- package/dist/tui/keys.d.ts.map +1 -1
- package/dist/tui/keys.js +493 -411
- package/dist/tui/keys.js.map +1 -1
- package/dist/tui/stdin-buffer.d.ts.map +1 -1
- package/dist/tui/stdin-buffer.js +162 -159
- package/dist/tui/stdin-buffer.js.map +1 -1
- package/dist/tui/terminal-image.d.ts +10 -5
- package/dist/tui/terminal-image.d.ts.map +1 -1
- package/dist/tui/terminal-image.js +53 -51
- package/dist/tui/terminal-image.js.map +1 -1
- package/dist/tui/terminal.d.ts +4 -27
- package/dist/tui/terminal.d.ts.map +1 -1
- package/dist/tui/terminal.js +123 -121
- package/dist/tui/terminal.js.map +1 -1
- package/dist/tui/tui.d.ts +14 -1
- package/dist/tui/tui.d.ts.map +1 -1
- package/dist/tui/tui.js +185 -145
- package/dist/tui/tui.js.map +1 -1
- package/dist/tui/utils.d.ts.map +1 -1
- package/dist/tui/utils.js +235 -216
- package/dist/tui/utils.js.map +1 -1
- package/dist/tui.d.ts +4 -0
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +4 -0
- package/dist/tui.js.map +1 -1
- package/package.json +23 -43
- package/LICENSE.md +0 -22
- package/dist/agent/tools/task-types.d.ts +0 -74
- package/dist/agent/tools/task-types.d.ts.map +0 -1
- package/dist/agent/tools/task-types.js +0 -8
- package/dist/agent/tools/task-types.js.map +0 -1
- package/dist/agent/tools/task.d.ts +0 -84
- package/dist/agent/tools/task.d.ts.map +0 -1
- package/dist/agent/tools/task.js +0 -184
- package/dist/agent/tools/task.js.map +0 -1
- package/dist/memory/embedder/base.d.ts +0 -41
- package/dist/memory/embedder/base.d.ts.map +0 -1
- package/dist/memory/embedder/base.js +0 -10
- package/dist/memory/embedder/base.js.map +0 -1
- package/dist/memory/embedder/index.d.ts +0 -8
- package/dist/memory/embedder/index.d.ts.map +0 -1
- package/dist/memory/embedder/index.js +0 -6
- package/dist/memory/embedder/index.js.map +0 -1
- package/dist/memory/embedder/openai.d.ts +0 -35
- package/dist/memory/embedder/openai.d.ts.map +0 -1
- package/dist/memory/embedder/openai.js +0 -103
- package/dist/memory/embedder/openai.js.map +0 -1
- package/dist/memory/index.d.ts +0 -33
- package/dist/memory/index.d.ts.map +0 -1
- package/dist/memory/index.js +0 -31
- package/dist/memory/index.js.map +0 -1
- package/dist/memory/memory.d.ts +0 -126
- package/dist/memory/memory.d.ts.map +0 -1
- package/dist/memory/memory.js +0 -280
- package/dist/memory/memory.js.map +0 -1
- package/dist/memory/processors/base.d.ts +0 -42
- package/dist/memory/processors/base.d.ts.map +0 -1
- package/dist/memory/processors/base.js +0 -6
- package/dist/memory/processors/base.js.map +0 -1
- package/dist/memory/processors/index.d.ts +0 -16
- package/dist/memory/processors/index.d.ts.map +0 -1
- package/dist/memory/processors/index.js +0 -18
- package/dist/memory/processors/index.js.map +0 -1
- package/dist/memory/processors/message-history.d.ts +0 -35
- package/dist/memory/processors/message-history.d.ts.map +0 -1
- package/dist/memory/processors/message-history.js +0 -51
- package/dist/memory/processors/message-history.js.map +0 -1
- package/dist/memory/processors/observational-memory/index.d.ts +0 -82
- package/dist/memory/processors/observational-memory/index.d.ts.map +0 -1
- package/dist/memory/processors/observational-memory/index.js +0 -234
- package/dist/memory/processors/observational-memory/index.js.map +0 -1
- package/dist/memory/processors/observational-memory/observer-agent.d.ts +0 -64
- package/dist/memory/processors/observational-memory/observer-agent.d.ts.map +0 -1
- package/dist/memory/processors/observational-memory/observer-agent.js +0 -362
- package/dist/memory/processors/observational-memory/observer-agent.js.map +0 -1
- package/dist/memory/processors/observational-memory/reflector-agent.d.ts +0 -38
- package/dist/memory/processors/observational-memory/reflector-agent.d.ts.map +0 -1
- package/dist/memory/processors/observational-memory/reflector-agent.js +0 -213
- package/dist/memory/processors/observational-memory/reflector-agent.js.map +0 -1
- package/dist/memory/processors/observational-memory/token-counter.d.ts +0 -35
- package/dist/memory/processors/observational-memory/token-counter.d.ts.map +0 -1
- package/dist/memory/processors/observational-memory/token-counter.js +0 -90
- package/dist/memory/processors/observational-memory/token-counter.js.map +0 -1
- package/dist/memory/processors/semantic-recall.d.ts +0 -55
- package/dist/memory/processors/semantic-recall.d.ts.map +0 -1
- package/dist/memory/processors/semantic-recall.js +0 -143
- package/dist/memory/processors/semantic-recall.js.map +0 -1
- package/dist/memory/processors/working-memory.d.ts +0 -41
- package/dist/memory/processors/working-memory.d.ts.map +0 -1
- package/dist/memory/processors/working-memory.js +0 -82
- package/dist/memory/processors/working-memory.js.map +0 -1
- package/dist/memory/storage/base.d.ts +0 -288
- package/dist/memory/storage/base.d.ts.map +0 -1
- package/dist/memory/storage/base.js +0 -211
- package/dist/memory/storage/base.js.map +0 -1
- package/dist/memory/storage/index.d.ts +0 -9
- package/dist/memory/storage/index.d.ts.map +0 -1
- package/dist/memory/storage/index.js +0 -7
- package/dist/memory/storage/index.js.map +0 -1
- package/dist/memory/storage/inmemory.d.ts +0 -93
- package/dist/memory/storage/inmemory.d.ts.map +0 -1
- package/dist/memory/storage/inmemory.js +0 -646
- package/dist/memory/storage/inmemory.js.map +0 -1
- package/dist/memory/tools/working-memory.d.ts +0 -100
- package/dist/memory/tools/working-memory.d.ts.map +0 -1
- package/dist/memory/tools/working-memory.js +0 -237
- package/dist/memory/tools/working-memory.js.map +0 -1
- package/dist/memory/types.d.ts +0 -386
- package/dist/memory/types.d.ts.map +0 -1
- package/dist/memory/types.js +0 -58
- package/dist/memory/types.js.map +0 -1
- package/dist/memory/vector/base.d.ts +0 -145
- package/dist/memory/vector/base.d.ts.map +0 -1
- package/dist/memory/vector/base.js +0 -83
- package/dist/memory/vector/base.js.map +0 -1
- package/dist/memory/vector/index.d.ts +0 -8
- package/dist/memory/vector/index.d.ts.map +0 -1
- package/dist/memory/vector/index.js +0 -7
- package/dist/memory/vector/index.js.map +0 -1
- package/dist/memory/vector/inmemory.d.ts +0 -47
- package/dist/memory/vector/inmemory.d.ts.map +0 -1
- package/dist/memory/vector/inmemory.js +0 -234
- package/dist/memory/vector/inmemory.js.map +0 -1
package/dist/tui/autocomplete.js
CHANGED
|
@@ -16,480 +16,368 @@ function walkDirectoryWithFd(baseDir, fdPath, query, maxResults) {
|
|
|
16
16
|
"d",
|
|
17
17
|
"--full-path",
|
|
18
18
|
];
|
|
19
|
-
|
|
20
|
-
if (query) {
|
|
19
|
+
if (query)
|
|
21
20
|
args.push(query);
|
|
22
|
-
}
|
|
23
21
|
const result = spawnSync(fdPath, args, {
|
|
24
22
|
encoding: "utf-8",
|
|
25
23
|
stdio: ["pipe", "pipe", "pipe"],
|
|
26
24
|
maxBuffer: 10 * 1024 * 1024,
|
|
27
25
|
});
|
|
28
|
-
if (result.status !== 0 || !result.stdout)
|
|
26
|
+
if (result.status !== 0 || !result.stdout)
|
|
29
27
|
return [];
|
|
28
|
+
return result.stdout
|
|
29
|
+
.trim()
|
|
30
|
+
.split("\n")
|
|
31
|
+
.filter(Boolean)
|
|
32
|
+
.map((line) => ({ path: line, isDirectory: line.endsWith("/") }));
|
|
33
|
+
}
|
|
34
|
+
class SuggestionCache {
|
|
35
|
+
store = new Map();
|
|
36
|
+
getOrLoad(key, loader) {
|
|
37
|
+
const cached = this.store.get(key);
|
|
38
|
+
if (cached)
|
|
39
|
+
return cached;
|
|
40
|
+
const loaded = loader();
|
|
41
|
+
this.evictIfNeeded();
|
|
42
|
+
this.store.set(key, loaded);
|
|
43
|
+
return loaded;
|
|
30
44
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
clear() {
|
|
46
|
+
this.store.clear();
|
|
47
|
+
}
|
|
48
|
+
evictIfNeeded() {
|
|
49
|
+
if (this.store.size <= 200)
|
|
50
|
+
return;
|
|
51
|
+
const oldest = this.store.keys().next().value;
|
|
52
|
+
if (oldest)
|
|
53
|
+
this.store.delete(oldest);
|
|
40
54
|
}
|
|
41
|
-
return results;
|
|
42
55
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
constructor(commands
|
|
46
|
-
this.suggestionCache = new Map();
|
|
56
|
+
class CommandAutocompleteEngine {
|
|
57
|
+
commands;
|
|
58
|
+
constructor(commands) {
|
|
47
59
|
this.commands = commands;
|
|
48
|
-
this.basePath = basePath;
|
|
49
|
-
this.fdPath = fdPath;
|
|
50
60
|
}
|
|
51
|
-
getSuggestions(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const prefix = atMatch[1] ?? "@"; // The @... part
|
|
58
|
-
const query = prefix.slice(1); // Remove the @
|
|
59
|
-
const suggestions = this.getCachedSuggestions(`fuzzy:${query}`, () => this.getFuzzyFileSuggestions(query));
|
|
60
|
-
if (suggestions.length === 0)
|
|
61
|
-
return null;
|
|
62
|
-
return {
|
|
63
|
-
items: suggestions,
|
|
64
|
-
prefix: prefix,
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
// Check for slash commands
|
|
68
|
-
if (textBeforeCursor.startsWith("/")) {
|
|
69
|
-
const spaceIndex = textBeforeCursor.indexOf(" ");
|
|
70
|
-
if (spaceIndex === -1) {
|
|
71
|
-
// No space yet - complete command names with fuzzy matching
|
|
72
|
-
const prefix = textBeforeCursor.slice(1); // Remove the "/"
|
|
73
|
-
const commandItems = this.commands.map((cmd) => ({
|
|
74
|
-
name: "name" in cmd ? cmd.name : cmd.value,
|
|
75
|
-
label: "name" in cmd ? cmd.name : cmd.label,
|
|
76
|
-
description: cmd.description,
|
|
77
|
-
}));
|
|
78
|
-
const filtered = fuzzyFilter(commandItems, prefix, (item) => item.name).map((item) => ({
|
|
79
|
-
value: item.name,
|
|
80
|
-
label: item.label,
|
|
81
|
-
...(item.description && { description: item.description }),
|
|
82
|
-
}));
|
|
83
|
-
if (filtered.length === 0)
|
|
84
|
-
return null;
|
|
85
|
-
return {
|
|
86
|
-
items: filtered,
|
|
87
|
-
prefix: textBeforeCursor,
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
// Space found - complete command arguments
|
|
92
|
-
const commandName = textBeforeCursor.slice(1, spaceIndex); // Command without "/"
|
|
93
|
-
const argumentText = textBeforeCursor.slice(spaceIndex + 1); // Text after space
|
|
94
|
-
const command = this.commands.find((cmd) => {
|
|
95
|
-
const name = "name" in cmd ? cmd.name : cmd.value;
|
|
96
|
-
return name === commandName;
|
|
97
|
-
});
|
|
98
|
-
if (!command || !("getArgumentCompletions" in command) || !command.getArgumentCompletions) {
|
|
99
|
-
return null; // No argument completion for this command
|
|
100
|
-
}
|
|
101
|
-
const argumentSuggestions = command.getArgumentCompletions(argumentText);
|
|
102
|
-
if (!argumentSuggestions || argumentSuggestions.length === 0) {
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
return {
|
|
106
|
-
items: argumentSuggestions,
|
|
107
|
-
prefix: argumentText,
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
// Check for file paths - triggered by Tab or if we detect a path pattern
|
|
112
|
-
const pathMatch = this.extractPathPrefix(textBeforeCursor, false);
|
|
113
|
-
if (pathMatch !== null) {
|
|
114
|
-
const suggestions = this.getCachedSuggestions(`path:${pathMatch}`, () => this.getFileSuggestions(pathMatch));
|
|
115
|
-
if (suggestions.length === 0)
|
|
116
|
-
return null;
|
|
117
|
-
// Check if we have an exact match that is a directory
|
|
118
|
-
// In that case, we might want to return suggestions for the directory content instead
|
|
119
|
-
// But only if the prefix ends with /
|
|
120
|
-
if (suggestions.length === 1 && suggestions[0]?.value === pathMatch && !pathMatch.endsWith("/")) {
|
|
121
|
-
// Exact match found (e.g. user typed "src" and "src/" is the only match)
|
|
122
|
-
// We still return it so user can select it and add /
|
|
123
|
-
return {
|
|
124
|
-
items: suggestions,
|
|
125
|
-
prefix: pathMatch,
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
return {
|
|
129
|
-
items: suggestions,
|
|
130
|
-
prefix: pathMatch,
|
|
131
|
-
};
|
|
61
|
+
getSuggestions(textBeforeCursor) {
|
|
62
|
+
if (!textBeforeCursor.startsWith("/"))
|
|
63
|
+
return null;
|
|
64
|
+
const spaceIndex = textBeforeCursor.indexOf(" ");
|
|
65
|
+
if (spaceIndex === -1) {
|
|
66
|
+
return this.completeCommandName(textBeforeCursor);
|
|
132
67
|
}
|
|
133
|
-
return
|
|
68
|
+
return this.completeCommandArgument(textBeforeCursor, spaceIndex);
|
|
134
69
|
}
|
|
135
|
-
|
|
136
|
-
const
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
cursorCol: beforePrefix.length + item.value.length + 2, // +2 for "/" and space
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
// Check if we're completing a file attachment (prefix starts with "@")
|
|
154
|
-
if (prefix.startsWith("@")) {
|
|
155
|
-
// This is a file attachment completion
|
|
156
|
-
// Don't add space after directories so user can continue autocompleting
|
|
157
|
-
const isDirectory = item.value.endsWith("/");
|
|
158
|
-
const suffix = isDirectory ? "" : " ";
|
|
159
|
-
const newLine = `${beforePrefix + item.value}${suffix}${afterCursor}`;
|
|
160
|
-
const newLines = [...lines];
|
|
161
|
-
newLines[cursorLine] = newLine;
|
|
162
|
-
return {
|
|
163
|
-
lines: newLines,
|
|
164
|
-
cursorLine,
|
|
165
|
-
cursorCol: beforePrefix.length + item.value.length + suffix.length,
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
// Check if we're in a slash command context (beforePrefix contains "/command ")
|
|
169
|
-
const textBeforeCursor = currentLine.slice(0, cursorCol);
|
|
170
|
-
if (textBeforeCursor.includes("/") && textBeforeCursor.includes(" ")) {
|
|
171
|
-
// This is likely a command argument completion
|
|
172
|
-
const newLine = beforePrefix + item.value + afterCursor;
|
|
173
|
-
const newLines = [...lines];
|
|
174
|
-
newLines[cursorLine] = newLine;
|
|
175
|
-
return {
|
|
176
|
-
lines: newLines,
|
|
177
|
-
cursorLine,
|
|
178
|
-
cursorCol: beforePrefix.length + item.value.length,
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
// For file paths, complete the path
|
|
182
|
-
const newLine = beforePrefix + item.value + afterCursor;
|
|
183
|
-
const newLines = [...lines];
|
|
184
|
-
newLines[cursorLine] = newLine;
|
|
185
|
-
return {
|
|
186
|
-
lines: newLines,
|
|
187
|
-
cursorLine,
|
|
188
|
-
cursorCol: beforePrefix.length + item.value.length,
|
|
189
|
-
};
|
|
70
|
+
completeCommandName(textBeforeCursor) {
|
|
71
|
+
const prefix = textBeforeCursor.slice(1);
|
|
72
|
+
const commandItems = this.commands.map((cmd) => ({
|
|
73
|
+
name: "name" in cmd ? cmd.name : cmd.value,
|
|
74
|
+
label: "name" in cmd ? cmd.name : cmd.label,
|
|
75
|
+
description: cmd.description,
|
|
76
|
+
}));
|
|
77
|
+
const items = fuzzyFilter(commandItems, prefix, (item) => item.name).map((item) => ({
|
|
78
|
+
value: item.name,
|
|
79
|
+
label: item.label,
|
|
80
|
+
...(item.description && { description: item.description }),
|
|
81
|
+
}));
|
|
82
|
+
if (items.length === 0)
|
|
83
|
+
return null;
|
|
84
|
+
return { items, prefix: textBeforeCursor };
|
|
190
85
|
}
|
|
191
|
-
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
86
|
+
completeCommandArgument(textBeforeCursor, spaceIndex) {
|
|
87
|
+
const commandName = textBeforeCursor.slice(1, spaceIndex);
|
|
88
|
+
const argumentPrefix = textBeforeCursor.slice(spaceIndex + 1);
|
|
89
|
+
const command = this.commands.find((cmd) => {
|
|
90
|
+
const name = "name" in cmd ? cmd.name : cmd.value;
|
|
91
|
+
return name === commandName;
|
|
92
|
+
});
|
|
93
|
+
if (!command || !("getArgumentCompletions" in command) || !command.getArgumentCompletions) {
|
|
94
|
+
return null;
|
|
200
95
|
}
|
|
201
|
-
|
|
202
|
-
|
|
96
|
+
const items = command.getArgumentCompletions(argumentPrefix);
|
|
97
|
+
if (!items || items.length === 0)
|
|
98
|
+
return null;
|
|
99
|
+
return { items, prefix: argumentPrefix };
|
|
203
100
|
}
|
|
204
|
-
|
|
205
|
-
|
|
101
|
+
}
|
|
102
|
+
class AttachmentAutocompleteEngine {
|
|
103
|
+
getAttachmentPrefix(textBeforeCursor) {
|
|
104
|
+
const match = textBeforeCursor.match(/(?:^|[\s])(@[^\s]*)$/);
|
|
105
|
+
return match?.[1] ?? null;
|
|
106
|
+
}
|
|
107
|
+
toQuery(prefix) {
|
|
108
|
+
return prefix.slice(1);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
class PathAutocompleteEngine {
|
|
112
|
+
basePath;
|
|
113
|
+
fdPath;
|
|
114
|
+
constructor(basePath, fdPath) {
|
|
115
|
+
this.basePath = basePath;
|
|
116
|
+
this.fdPath = fdPath;
|
|
206
117
|
}
|
|
207
|
-
// Extract a path-like prefix from the text before cursor
|
|
208
118
|
extractPathPrefix(text, forceExtract = false) {
|
|
209
|
-
// Check for @ file attachment syntax first
|
|
210
119
|
const atMatch = text.match(/@([^\s]*)$/);
|
|
211
|
-
if (atMatch)
|
|
212
|
-
return atMatch[0];
|
|
213
|
-
}
|
|
214
|
-
// Simple approach: find the last whitespace/delimiter and extract the word after it
|
|
215
|
-
// This avoids catastrophic backtracking from nested quantifiers
|
|
120
|
+
if (atMatch)
|
|
121
|
+
return atMatch[0];
|
|
216
122
|
const lastDelimiterIndex = Math.max(text.lastIndexOf(" "), text.lastIndexOf("\t"), text.lastIndexOf('"'), text.lastIndexOf("'"), text.lastIndexOf("="));
|
|
217
123
|
const pathPrefix = lastDelimiterIndex === -1 ? text : text.slice(lastDelimiterIndex + 1);
|
|
218
|
-
|
|
219
|
-
if (forceExtract) {
|
|
124
|
+
if (forceExtract)
|
|
220
125
|
return pathPrefix;
|
|
221
|
-
|
|
222
|
-
// For natural triggers, return if it looks like a path, ends with /, starts with ~/, .
|
|
223
|
-
// Only return empty string if the text looks like it's starting a path context
|
|
224
|
-
if (pathPrefix.includes("/") || pathPrefix.startsWith(".") || pathPrefix.startsWith("~/")) {
|
|
126
|
+
if (pathPrefix.includes("/") || pathPrefix.startsWith(".") || pathPrefix.startsWith("~/"))
|
|
225
127
|
return pathPrefix;
|
|
226
|
-
|
|
227
|
-
// Return empty string only if we're at the beginning of the line or after a space
|
|
228
|
-
// (not after quotes or other delimiters that don't suggest file paths)
|
|
229
|
-
if (pathPrefix === "" && (text === "" || text.endsWith(" "))) {
|
|
128
|
+
if (pathPrefix === "" && (text === "" || text.endsWith(" ")))
|
|
230
129
|
return pathPrefix;
|
|
231
|
-
}
|
|
232
130
|
return null;
|
|
233
131
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
if (path.startsWith("~/")) {
|
|
237
|
-
const expandedPath = join(homedir(), path.slice(2));
|
|
238
|
-
// Preserve trailing slash if original path had one
|
|
239
|
-
return path.endsWith("/") && !expandedPath.endsWith("/") ? `${expandedPath}/` : expandedPath;
|
|
240
|
-
}
|
|
241
|
-
else if (path === "~") {
|
|
242
|
-
return homedir();
|
|
243
|
-
}
|
|
244
|
-
return path;
|
|
132
|
+
shouldTriggerForTab(textBeforeCursor) {
|
|
133
|
+
return !(textBeforeCursor.trim().startsWith("/") && !textBeforeCursor.trim().includes(" "));
|
|
245
134
|
}
|
|
246
|
-
// Get file/directory suggestions for a given path prefix
|
|
247
135
|
getFileSuggestions(prefix) {
|
|
248
136
|
try {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
let expandedPrefix = prefix;
|
|
252
|
-
let isAtPrefix = false;
|
|
253
|
-
// Handle @ file attachment prefix
|
|
254
|
-
if (prefix.startsWith("@")) {
|
|
255
|
-
isAtPrefix = true;
|
|
256
|
-
expandedPrefix = prefix.slice(1); // Remove the @
|
|
257
|
-
}
|
|
258
|
-
// Handle home directory expansion
|
|
259
|
-
if (expandedPrefix.startsWith("~")) {
|
|
260
|
-
expandedPrefix = this.expandHomePath(expandedPrefix);
|
|
261
|
-
}
|
|
262
|
-
if (expandedPrefix === "" ||
|
|
263
|
-
expandedPrefix === "./" ||
|
|
264
|
-
expandedPrefix === "../" ||
|
|
265
|
-
expandedPrefix === "~" ||
|
|
266
|
-
expandedPrefix === "~/" ||
|
|
267
|
-
expandedPrefix === "/" ||
|
|
268
|
-
prefix === "@") {
|
|
269
|
-
// Complete from specified position
|
|
270
|
-
if (prefix.startsWith("~") || expandedPrefix === "/") {
|
|
271
|
-
searchDir = expandedPrefix;
|
|
272
|
-
}
|
|
273
|
-
else {
|
|
274
|
-
searchDir = join(this.basePath, expandedPrefix);
|
|
275
|
-
}
|
|
276
|
-
searchPrefix = "";
|
|
277
|
-
}
|
|
278
|
-
else if (expandedPrefix.endsWith("/")) {
|
|
279
|
-
// If prefix ends with /, show contents of that directory
|
|
280
|
-
if (prefix.startsWith("~") || expandedPrefix.startsWith("/")) {
|
|
281
|
-
searchDir = expandedPrefix;
|
|
282
|
-
}
|
|
283
|
-
else {
|
|
284
|
-
searchDir = join(this.basePath, expandedPrefix);
|
|
285
|
-
}
|
|
286
|
-
searchPrefix = "";
|
|
287
|
-
}
|
|
288
|
-
else {
|
|
289
|
-
// Split into directory and file prefix
|
|
290
|
-
const dir = dirname(expandedPrefix);
|
|
291
|
-
const file = basename(expandedPrefix);
|
|
292
|
-
if (prefix.startsWith("~") || expandedPrefix.startsWith("/")) {
|
|
293
|
-
searchDir = dir;
|
|
294
|
-
}
|
|
295
|
-
else {
|
|
296
|
-
searchDir = join(this.basePath, dir);
|
|
297
|
-
}
|
|
298
|
-
searchPrefix = file;
|
|
299
|
-
}
|
|
300
|
-
const entries = readdirSync(searchDir, { withFileTypes: true });
|
|
137
|
+
const plan = this.resolveSearchPlan(prefix);
|
|
138
|
+
const entries = readdirSync(plan.searchDir, { withFileTypes: true });
|
|
301
139
|
const suggestions = [];
|
|
302
140
|
for (const entry of entries) {
|
|
303
|
-
if (!entry.name.toLowerCase().startsWith(searchPrefix.toLowerCase()))
|
|
141
|
+
if (!entry.name.toLowerCase().startsWith(plan.searchPrefix.toLowerCase()))
|
|
304
142
|
continue;
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
let isDirectory = entry.isDirectory();
|
|
308
|
-
if (!isDirectory && entry.isSymbolicLink()) {
|
|
309
|
-
try {
|
|
310
|
-
const fullPath = join(searchDir, entry.name);
|
|
311
|
-
isDirectory = statSync(fullPath).isDirectory();
|
|
312
|
-
}
|
|
313
|
-
catch {
|
|
314
|
-
// Broken symlink or permission error - treat as file
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
let relativePath;
|
|
318
|
-
const name = entry.name;
|
|
319
|
-
// Handle @ prefix path construction
|
|
320
|
-
if (isAtPrefix) {
|
|
321
|
-
const pathWithoutAt = expandedPrefix;
|
|
322
|
-
if (pathWithoutAt.endsWith("/")) {
|
|
323
|
-
relativePath = `@${pathWithoutAt}${name}`;
|
|
324
|
-
}
|
|
325
|
-
else if (pathWithoutAt.includes("/")) {
|
|
326
|
-
if (pathWithoutAt.startsWith("~/")) {
|
|
327
|
-
const homeRelativeDir = pathWithoutAt.slice(2); // Remove ~/
|
|
328
|
-
const dir = dirname(homeRelativeDir);
|
|
329
|
-
relativePath = `@~/${dir === "." ? name : join(dir, name)}`;
|
|
330
|
-
}
|
|
331
|
-
else {
|
|
332
|
-
relativePath = `@${join(dirname(pathWithoutAt), name)}`;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
else {
|
|
336
|
-
if (pathWithoutAt.startsWith("~")) {
|
|
337
|
-
relativePath = `@~/${name}`;
|
|
338
|
-
}
|
|
339
|
-
else {
|
|
340
|
-
relativePath = `@${name}`;
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
else if (prefix.endsWith("/")) {
|
|
345
|
-
// If prefix ends with /, append entry to the prefix
|
|
346
|
-
relativePath = prefix + name;
|
|
347
|
-
}
|
|
348
|
-
else if (prefix.includes("/")) {
|
|
349
|
-
// Preserve ~/ format for home directory paths
|
|
350
|
-
if (prefix.startsWith("~/")) {
|
|
351
|
-
const homeRelativeDir = prefix.slice(2); // Remove ~/
|
|
352
|
-
const dir = dirname(homeRelativeDir);
|
|
353
|
-
relativePath = `~/${dir === "." ? name : join(dir, name)}`;
|
|
354
|
-
}
|
|
355
|
-
else if (prefix.startsWith("/")) {
|
|
356
|
-
// Absolute path - construct properly
|
|
357
|
-
const dir = dirname(prefix);
|
|
358
|
-
if (dir === "/") {
|
|
359
|
-
relativePath = `/${name}`;
|
|
360
|
-
}
|
|
361
|
-
else {
|
|
362
|
-
relativePath = `${dir}/${name}`;
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
else {
|
|
366
|
-
relativePath = join(dirname(prefix), name);
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
else {
|
|
370
|
-
// For standalone entries, preserve ~/ if original prefix was ~/
|
|
371
|
-
if (prefix.startsWith("~")) {
|
|
372
|
-
relativePath = `~/${name}`;
|
|
373
|
-
}
|
|
374
|
-
else {
|
|
375
|
-
relativePath = name;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
143
|
+
const isDirectory = this.resolveDirectoryFlag(plan.searchDir, entry.name, entry.isDirectory(), entry.isSymbolicLink());
|
|
144
|
+
const relativePath = this.toRelativePath(prefix, plan.expandedPrefix, entry.name, plan.isAtPrefix);
|
|
378
145
|
suggestions.push({
|
|
379
146
|
value: isDirectory ? `${relativePath}/` : relativePath,
|
|
380
|
-
label: name + (isDirectory ? "/" : ""),
|
|
147
|
+
label: entry.name + (isDirectory ? "/" : ""),
|
|
381
148
|
});
|
|
382
149
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
const
|
|
386
|
-
|
|
387
|
-
if (aIsDir && !bIsDir)
|
|
150
|
+
return suggestions.sort((a, b) => {
|
|
151
|
+
const aDir = a.value.endsWith("/");
|
|
152
|
+
const bDir = b.value.endsWith("/");
|
|
153
|
+
if (aDir && !bDir)
|
|
388
154
|
return -1;
|
|
389
|
-
if (!
|
|
155
|
+
if (!aDir && bDir)
|
|
390
156
|
return 1;
|
|
391
157
|
return a.label.localeCompare(b.label);
|
|
392
158
|
});
|
|
393
|
-
return suggestions;
|
|
394
159
|
}
|
|
395
|
-
catch
|
|
396
|
-
// Directory doesn't exist or not accessible
|
|
160
|
+
catch {
|
|
397
161
|
return [];
|
|
398
162
|
}
|
|
399
163
|
}
|
|
400
|
-
// Score an entry against the query (higher = better match)
|
|
401
|
-
// isDirectory adds bonus to prioritize folders
|
|
402
|
-
scoreEntry(filePath, query, isDirectory) {
|
|
403
|
-
const fileName = basename(filePath);
|
|
404
|
-
const lowerFileName = fileName.toLowerCase();
|
|
405
|
-
const lowerQuery = query.toLowerCase();
|
|
406
|
-
let score = 0;
|
|
407
|
-
// Exact filename match (highest)
|
|
408
|
-
if (lowerFileName === lowerQuery)
|
|
409
|
-
score = 100;
|
|
410
|
-
// Filename starts with query
|
|
411
|
-
else if (lowerFileName.startsWith(lowerQuery))
|
|
412
|
-
score = 80;
|
|
413
|
-
// Substring match in filename
|
|
414
|
-
else if (lowerFileName.includes(lowerQuery))
|
|
415
|
-
score = 50;
|
|
416
|
-
// Substring match in full path
|
|
417
|
-
else if (filePath.toLowerCase().includes(lowerQuery))
|
|
418
|
-
score = 30;
|
|
419
|
-
// Directories get a bonus to appear first
|
|
420
|
-
if (isDirectory && score > 0)
|
|
421
|
-
score += 10;
|
|
422
|
-
return score;
|
|
423
|
-
}
|
|
424
|
-
// Fuzzy file search using fd (fast, respects .gitignore)
|
|
425
164
|
getFuzzyFileSuggestions(query) {
|
|
426
|
-
if (!this.fdPath)
|
|
427
|
-
// fd not available, return empty results
|
|
165
|
+
if (!this.fdPath)
|
|
428
166
|
return [];
|
|
429
|
-
}
|
|
430
167
|
try {
|
|
431
168
|
const entries = walkDirectoryWithFd(this.basePath, this.fdPath, query, 100);
|
|
432
|
-
|
|
433
|
-
const scoredEntries = entries
|
|
169
|
+
const scored = entries
|
|
434
170
|
.map((entry) => ({
|
|
435
171
|
...entry,
|
|
436
172
|
score: query ? this.scoreEntry(entry.path, query, entry.isDirectory) : 1,
|
|
437
173
|
}))
|
|
438
|
-
.filter((entry) => entry.score > 0)
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
for (const { path: entryPath, isDirectory } of topEntries) {
|
|
445
|
-
// fd already includes trailing / for directories
|
|
446
|
-
const pathWithoutSlash = isDirectory ? entryPath.slice(0, -1) : entryPath;
|
|
447
|
-
const entryName = basename(pathWithoutSlash);
|
|
448
|
-
suggestions.push({
|
|
174
|
+
.filter((entry) => entry.score > 0)
|
|
175
|
+
.sort((a, b) => b.score - a.score)
|
|
176
|
+
.slice(0, 20);
|
|
177
|
+
return scored.map(({ path: entryPath, isDirectory }) => {
|
|
178
|
+
const normalizedPath = isDirectory ? entryPath.slice(0, -1) : entryPath;
|
|
179
|
+
return {
|
|
449
180
|
value: `@${entryPath}`,
|
|
450
|
-
label:
|
|
451
|
-
description:
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
return suggestions;
|
|
181
|
+
label: basename(normalizedPath) + (isDirectory ? "/" : ""),
|
|
182
|
+
description: normalizedPath,
|
|
183
|
+
};
|
|
184
|
+
});
|
|
455
185
|
}
|
|
456
186
|
catch {
|
|
457
187
|
return [];
|
|
458
188
|
}
|
|
459
189
|
}
|
|
190
|
+
resolveSearchPlan(prefix) {
|
|
191
|
+
const isAtPrefix = prefix.startsWith("@");
|
|
192
|
+
let expandedPrefix = isAtPrefix ? prefix.slice(1) : prefix;
|
|
193
|
+
if (expandedPrefix.startsWith("~"))
|
|
194
|
+
expandedPrefix = this.expandHomePath(expandedPrefix);
|
|
195
|
+
const rootLike = expandedPrefix === "" ||
|
|
196
|
+
expandedPrefix === "./" ||
|
|
197
|
+
expandedPrefix === "../" ||
|
|
198
|
+
expandedPrefix === "~" ||
|
|
199
|
+
expandedPrefix === "~/" ||
|
|
200
|
+
expandedPrefix === "/" ||
|
|
201
|
+
prefix === "@";
|
|
202
|
+
if (rootLike) {
|
|
203
|
+
const searchDir = prefix.startsWith("~") || expandedPrefix === "/" ? expandedPrefix : join(this.basePath, expandedPrefix);
|
|
204
|
+
return { searchDir, searchPrefix: "", expandedPrefix, isAtPrefix };
|
|
205
|
+
}
|
|
206
|
+
if (expandedPrefix.endsWith("/")) {
|
|
207
|
+
const searchDir = prefix.startsWith("~") || expandedPrefix.startsWith("/")
|
|
208
|
+
? expandedPrefix
|
|
209
|
+
: join(this.basePath, expandedPrefix);
|
|
210
|
+
return { searchDir, searchPrefix: "", expandedPrefix, isAtPrefix };
|
|
211
|
+
}
|
|
212
|
+
const dir = dirname(expandedPrefix);
|
|
213
|
+
const file = basename(expandedPrefix);
|
|
214
|
+
const searchDir = prefix.startsWith("~") || expandedPrefix.startsWith("/") ? dir : join(this.basePath, dir);
|
|
215
|
+
return { searchDir, searchPrefix: file, expandedPrefix, isAtPrefix };
|
|
216
|
+
}
|
|
217
|
+
toRelativePath(prefix, expandedPrefix, name, isAtPrefix) {
|
|
218
|
+
if (isAtPrefix)
|
|
219
|
+
return this.buildAtPath(expandedPrefix, name);
|
|
220
|
+
if (prefix.endsWith("/"))
|
|
221
|
+
return prefix + name;
|
|
222
|
+
if (prefix.includes("/")) {
|
|
223
|
+
if (prefix.startsWith("~/")) {
|
|
224
|
+
const homeRelativeDir = prefix.slice(2);
|
|
225
|
+
const dir = dirname(homeRelativeDir);
|
|
226
|
+
return `~/${dir === "." ? name : join(dir, name)}`;
|
|
227
|
+
}
|
|
228
|
+
if (prefix.startsWith("/")) {
|
|
229
|
+
const dir = dirname(prefix);
|
|
230
|
+
return dir === "/" ? `/${name}` : `${dir}/${name}`;
|
|
231
|
+
}
|
|
232
|
+
return join(dirname(prefix), name);
|
|
233
|
+
}
|
|
234
|
+
return prefix.startsWith("~") ? `~/${name}` : name;
|
|
235
|
+
}
|
|
236
|
+
buildAtPath(pathWithoutAt, name) {
|
|
237
|
+
if (pathWithoutAt.endsWith("/")) {
|
|
238
|
+
return `@${pathWithoutAt}${name}`;
|
|
239
|
+
}
|
|
240
|
+
if (pathWithoutAt.includes("/")) {
|
|
241
|
+
if (pathWithoutAt.startsWith("~/")) {
|
|
242
|
+
const homeRelativeDir = pathWithoutAt.slice(2);
|
|
243
|
+
const dir = dirname(homeRelativeDir);
|
|
244
|
+
return `@~/${dir === "." ? name : join(dir, name)}`;
|
|
245
|
+
}
|
|
246
|
+
return `@${join(dirname(pathWithoutAt), name)}`;
|
|
247
|
+
}
|
|
248
|
+
return pathWithoutAt.startsWith("~") ? `@~/${name}` : `@${name}`;
|
|
249
|
+
}
|
|
250
|
+
resolveDirectoryFlag(searchDir, name, isDirectory, isSymlink) {
|
|
251
|
+
if (isDirectory || !isSymlink)
|
|
252
|
+
return isDirectory;
|
|
253
|
+
try {
|
|
254
|
+
return statSync(join(searchDir, name)).isDirectory();
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
expandHomePath(pathValue) {
|
|
261
|
+
if (pathValue.startsWith("~/")) {
|
|
262
|
+
const expanded = join(homedir(), pathValue.slice(2));
|
|
263
|
+
return pathValue.endsWith("/") && !expanded.endsWith("/") ? `${expanded}/` : expanded;
|
|
264
|
+
}
|
|
265
|
+
if (pathValue === "~")
|
|
266
|
+
return homedir();
|
|
267
|
+
return pathValue;
|
|
268
|
+
}
|
|
269
|
+
scoreEntry(filePath, query, isDirectory) {
|
|
270
|
+
const fileName = basename(filePath).toLowerCase();
|
|
271
|
+
const queryLower = query.toLowerCase();
|
|
272
|
+
let score = 0;
|
|
273
|
+
if (fileName === queryLower)
|
|
274
|
+
score = 100;
|
|
275
|
+
else if (fileName.startsWith(queryLower))
|
|
276
|
+
score = 80;
|
|
277
|
+
else if (fileName.includes(queryLower))
|
|
278
|
+
score = 50;
|
|
279
|
+
else if (filePath.toLowerCase().includes(queryLower))
|
|
280
|
+
score = 30;
|
|
281
|
+
if (isDirectory && score > 0)
|
|
282
|
+
score += 10;
|
|
283
|
+
return score;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
class CompletionApplyStrategy {
|
|
287
|
+
apply(lines, cursorLine, cursorCol, item, prefix) {
|
|
288
|
+
const currentLine = lines[cursorLine] || "";
|
|
289
|
+
const beforePrefix = currentLine.slice(0, cursorCol - prefix.length);
|
|
290
|
+
const afterCursor = currentLine.slice(cursorCol);
|
|
291
|
+
if (this.isCommandName(prefix, beforePrefix)) {
|
|
292
|
+
return this.replaceWithSuffix(lines, cursorLine, `${beforePrefix}/${item.value} ${afterCursor}`, beforePrefix.length + item.value.length + 2);
|
|
293
|
+
}
|
|
294
|
+
if (prefix.startsWith("@")) {
|
|
295
|
+
const isDirectory = item.value.endsWith("/");
|
|
296
|
+
const suffix = isDirectory ? "" : " ";
|
|
297
|
+
return this.replaceWithSuffix(lines, cursorLine, `${beforePrefix + item.value}${suffix}${afterCursor}`, beforePrefix.length + item.value.length + suffix.length);
|
|
298
|
+
}
|
|
299
|
+
const textBeforeCursor = currentLine.slice(0, cursorCol);
|
|
300
|
+
const replacement = beforePrefix + item.value + afterCursor;
|
|
301
|
+
const nextCursor = beforePrefix.length + item.value.length;
|
|
302
|
+
if (textBeforeCursor.includes("/") && textBeforeCursor.includes(" ")) {
|
|
303
|
+
return this.replaceWithSuffix(lines, cursorLine, replacement, nextCursor);
|
|
304
|
+
}
|
|
305
|
+
return this.replaceWithSuffix(lines, cursorLine, replacement, nextCursor);
|
|
306
|
+
}
|
|
307
|
+
isCommandName(prefix, beforePrefix) {
|
|
308
|
+
return prefix.startsWith("/") && beforePrefix.trim() === "" && !prefix.slice(1).includes("/");
|
|
309
|
+
}
|
|
310
|
+
replaceWithSuffix(lines, cursorLine, line, cursorCol) {
|
|
311
|
+
const newLines = [...lines];
|
|
312
|
+
newLines[cursorLine] = line;
|
|
313
|
+
return { lines: newLines, cursorLine, cursorCol };
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
// Combined provider that handles both slash commands and file paths
|
|
317
|
+
export class CombinedAutocompleteProvider {
|
|
318
|
+
basePath;
|
|
319
|
+
fdPath;
|
|
320
|
+
cache = new SuggestionCache();
|
|
321
|
+
commandEngine;
|
|
322
|
+
attachmentEngine = new AttachmentAutocompleteEngine();
|
|
323
|
+
pathEngine;
|
|
324
|
+
applyStrategy = new CompletionApplyStrategy();
|
|
325
|
+
constructor(commands = [], basePath = process.cwd(), fdPath = null) {
|
|
326
|
+
this.basePath = basePath;
|
|
327
|
+
this.fdPath = fdPath;
|
|
328
|
+
this.commandEngine = new CommandAutocompleteEngine(commands);
|
|
329
|
+
this.pathEngine = new PathAutocompleteEngine(this.basePath, this.fdPath);
|
|
330
|
+
}
|
|
331
|
+
getSuggestions(lines, cursorLine, cursorCol) {
|
|
332
|
+
const currentLine = lines[cursorLine] || "";
|
|
333
|
+
const textBeforeCursor = currentLine.slice(0, cursorCol);
|
|
334
|
+
const attachmentPrefix = this.attachmentEngine.getAttachmentPrefix(textBeforeCursor);
|
|
335
|
+
if (attachmentPrefix) {
|
|
336
|
+
const query = this.attachmentEngine.toQuery(attachmentPrefix);
|
|
337
|
+
const items = this.cache.getOrLoad(`fuzzy:${query}`, () => this.pathEngine.getFuzzyFileSuggestions(query));
|
|
338
|
+
if (items.length > 0)
|
|
339
|
+
return { items, prefix: attachmentPrefix };
|
|
340
|
+
}
|
|
341
|
+
const commandSuggestions = this.commandEngine.getSuggestions(textBeforeCursor);
|
|
342
|
+
if (commandSuggestions)
|
|
343
|
+
return commandSuggestions;
|
|
344
|
+
const pathPrefix = this.pathEngine.extractPathPrefix(textBeforeCursor, false);
|
|
345
|
+
if (pathPrefix === null)
|
|
346
|
+
return null;
|
|
347
|
+
const items = this.cache.getOrLoad(`path:${pathPrefix}`, () => this.pathEngine.getFileSuggestions(pathPrefix));
|
|
348
|
+
if (items.length === 0)
|
|
349
|
+
return null;
|
|
350
|
+
return { items, prefix: pathPrefix };
|
|
351
|
+
}
|
|
352
|
+
applyCompletion(lines, cursorLine, cursorCol, item, prefix) {
|
|
353
|
+
return this.applyStrategy.apply(lines, cursorLine, cursorCol, item, prefix);
|
|
354
|
+
}
|
|
355
|
+
clearCache() {
|
|
356
|
+
this.cache.clear();
|
|
357
|
+
}
|
|
460
358
|
// Force file completion (called on Tab key) - always returns suggestions
|
|
461
359
|
getForceFileSuggestions(lines, cursorLine, cursorCol) {
|
|
462
360
|
const currentLine = lines[cursorLine] || "";
|
|
463
361
|
const textBeforeCursor = currentLine.slice(0, cursorCol);
|
|
464
|
-
|
|
465
|
-
if (textBeforeCursor.trim().startsWith("/") && !textBeforeCursor.trim().includes(" ")) {
|
|
362
|
+
if (!this.pathEngine.shouldTriggerForTab(textBeforeCursor))
|
|
466
363
|
return null;
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
return {
|
|
475
|
-
items: suggestions,
|
|
476
|
-
prefix: pathMatch,
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
|
-
return null;
|
|
364
|
+
const pathPrefix = this.pathEngine.extractPathPrefix(textBeforeCursor, true);
|
|
365
|
+
if (pathPrefix === null)
|
|
366
|
+
return null;
|
|
367
|
+
const items = this.cache.getOrLoad(`path:${pathPrefix}`, () => this.pathEngine.getFileSuggestions(pathPrefix));
|
|
368
|
+
if (items.length === 0)
|
|
369
|
+
return null;
|
|
370
|
+
return { items, prefix: pathPrefix };
|
|
480
371
|
}
|
|
481
372
|
// Check if we should trigger file completion (called on Tab key)
|
|
482
373
|
shouldTriggerFileCompletion(lines, cursorLine, cursorCol) {
|
|
483
374
|
const currentLine = lines[cursorLine] || "";
|
|
484
375
|
const textBeforeCursor = currentLine.slice(0, cursorCol);
|
|
485
|
-
|
|
486
|
-
if (textBeforeCursor.trim().startsWith("/") && !textBeforeCursor.trim().includes(" ")) {
|
|
487
|
-
return false;
|
|
488
|
-
}
|
|
489
|
-
return true;
|
|
376
|
+
return this.pathEngine.shouldTriggerForTab(textBeforeCursor);
|
|
490
377
|
}
|
|
491
378
|
}
|
|
492
379
|
export class AsyncAutocompleteChain {
|
|
380
|
+
providers;
|
|
493
381
|
constructor(providers) {
|
|
494
382
|
this.providers = providers;
|
|
495
383
|
}
|