@renxqoo/renx-code 0.0.9 → 0.0.12
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 +31 -143
- package/bin/renx.cjs +79 -42
- package/bin/renx.exe +0 -0
- package/package.json +10 -28
- package/src/App.tsx +0 -297
- package/src/agent/runtime/event-format.ts +0 -258
- package/src/agent/runtime/model-types.ts +0 -13
- package/src/agent/runtime/runtime.context-usage.test.ts +0 -192
- package/src/agent/runtime/runtime.error-handling.test.ts +0 -235
- package/src/agent/runtime/runtime.simple.test.ts +0 -16
- package/src/agent/runtime/runtime.test.ts +0 -296
- package/src/agent/runtime/runtime.ts +0 -875
- package/src/agent/runtime/runtime.usage-forwarding.test.ts +0 -228
- package/src/agent/runtime/source-modules.test.ts +0 -38
- package/src/agent/runtime/source-modules.ts +0 -370
- package/src/agent/runtime/tool-call-buffer.test.ts +0 -65
- package/src/agent/runtime/tool-call-buffer.ts +0 -60
- package/src/agent/runtime/tool-confirmation.test.ts +0 -56
- package/src/agent/runtime/tool-confirmation.ts +0 -15
- package/src/agent/runtime/types.ts +0 -99
- package/src/commands/slash-commands.test.ts +0 -216
- package/src/commands/slash-commands.ts +0 -64
- package/src/components/chat/assistant-reply.test.tsx +0 -47
- package/src/components/chat/assistant-reply.tsx +0 -136
- package/src/components/chat/assistant-segment.test.ts +0 -99
- package/src/components/chat/assistant-segment.tsx +0 -125
- package/src/components/chat/assistant-tool-group.tsx +0 -900
- package/src/components/chat/code-block.test.tsx +0 -206
- package/src/components/chat/code-block.tsx +0 -313
- package/src/components/chat/prompt-card.tsx +0 -81
- package/src/components/chat/segment-groups.test.ts +0 -52
- package/src/components/chat/segment-groups.ts +0 -106
- package/src/components/chat/turn-item.tsx +0 -39
- package/src/components/conversation-panel.tsx +0 -43
- package/src/components/file-mention-menu.tsx +0 -77
- package/src/components/file-picker-dialog.tsx +0 -206
- package/src/components/footer-hints.tsx +0 -75
- package/src/components/model-picker-dialog.tsx +0 -248
- package/src/components/prompt.tsx +0 -233
- package/src/components/slash-command-menu.tsx +0 -65
- package/src/components/tool-confirm-dialog-content.test.ts +0 -103
- package/src/components/tool-confirm-dialog-content.ts +0 -186
- package/src/components/tool-confirm-dialog.tsx +0 -187
- package/src/components/tool-display-config.ts +0 -119
- package/src/context-usage-regressions.test.ts +0 -26
- package/src/files/attachment-capabilities.test.ts +0 -30
- package/src/files/attachment-capabilities.ts +0 -50
- package/src/files/attachment-content.ts +0 -153
- package/src/files/file-mention-query.test.ts +0 -34
- package/src/files/file-mention-query.ts +0 -32
- package/src/files/prompt-display.ts +0 -13
- package/src/files/types.ts +0 -5
- package/src/files/workspace-files.ts +0 -61
- package/src/hooks/agent-event-handlers.test.ts +0 -207
- package/src/hooks/agent-event-handlers.ts +0 -196
- package/src/hooks/chat-local-replies.fixed.test.ts +0 -119
- package/src/hooks/chat-local-replies.test.ts +0 -153
- package/src/hooks/chat-local-replies.ts +0 -63
- package/src/hooks/turn-updater.test.ts +0 -70
- package/src/hooks/turn-updater.ts +0 -166
- package/src/hooks/use-agent-chat.context.test.ts +0 -10
- package/src/hooks/use-agent-chat.status.test.ts +0 -14
- package/src/hooks/use-agent-chat.test.ts +0 -80
- package/src/hooks/use-agent-chat.ts +0 -621
- package/src/hooks/use-file-mention-menu.ts +0 -196
- package/src/hooks/use-file-picker.ts +0 -185
- package/src/hooks/use-model-picker.ts +0 -196
- package/src/hooks/use-slash-command-menu.ts +0 -154
- package/src/index.tsx +0 -55
- package/src/runtime/clipboard.test.ts +0 -43
- package/src/runtime/clipboard.ts +0 -89
- package/src/runtime/exit.test.ts +0 -177
- package/src/runtime/exit.ts +0 -98
- package/src/runtime/runtime-support.test.ts +0 -31
- package/src/runtime/terminal-theme.test.ts +0 -55
- package/src/runtime/terminal-theme.ts +0 -196
- package/src/types/chat.ts +0 -32
- package/src/types/message-content.ts +0 -48
- package/src/ui/open-code-theme.ts +0 -176
- package/src/ui/opencode-markdown.ts +0 -211
- package/src/ui/theme.simple.test.ts +0 -52
- package/src/ui/theme.test.ts +0 -151
- package/src/ui/theme.ts +0 -152
- package/src/utils/time.test.ts +0 -144
- package/src/utils/time.ts +0 -7
- package/tsconfig.json +0 -30
- package/vendor/agent-root/src/agent/ENTERPRISE_ACCEPTANCE_CHECKLIST.md +0 -95
- package/vendor/agent-root/src/agent/ENTERPRISE_REALTIME.html +0 -1345
- package/vendor/agent-root/src/agent/ENTERPRISE_REALTIME.md +0 -1353
- package/vendor/agent-root/src/agent/ERROR_CONTRACT.md +0 -60
- package/vendor/agent-root/src/agent/TEST_COVERAGE_ANALYSIS.md +0 -278
- package/vendor/agent-root/src/agent/__test__/error-contract.test.ts +0 -72
- package/vendor/agent-root/src/agent/__test__/types.test.ts +0 -137
- package/vendor/agent-root/src/agent/agent/__test__/abort-runtime.test.ts +0 -83
- package/vendor/agent-root/src/agent/agent/__test__/callback-safety.test.ts +0 -34
- package/vendor/agent-root/src/agent/agent/__test__/compaction.test.ts +0 -323
- package/vendor/agent-root/src/agent/agent/__test__/concurrency.test.ts +0 -290
- package/vendor/agent-root/src/agent/agent/__test__/error-normalizer.test.ts +0 -377
- package/vendor/agent-root/src/agent/agent/__test__/error.test.ts +0 -212
- package/vendor/agent-root/src/agent/agent/__test__/fault-injection.test.ts +0 -295
- package/vendor/agent-root/src/agent/agent/__test__/index.test.ts +0 -3607
- package/vendor/agent-root/src/agent/agent/__test__/logger.test.ts +0 -35
- package/vendor/agent-root/src/agent/agent/__test__/message-utils.test.ts +0 -517
- package/vendor/agent-root/src/agent/agent/__test__/telemetry.test.ts +0 -97
- package/vendor/agent-root/src/agent/agent/__test__/timeout-budget.test.ts +0 -479
- package/vendor/agent-root/src/agent/agent/__test__/tool-call-merge.test.ts +0 -80
- package/vendor/agent-root/src/agent/agent/__test__/tool-execution-ledger.test.ts +0 -76
- package/vendor/agent-root/src/agent/agent/__test__/write-buffer.test.ts +0 -173
- package/vendor/agent-root/src/agent/agent/__test__/write-file-session.test.ts +0 -109
- package/vendor/agent-root/src/agent/agent/abort-runtime.ts +0 -71
- package/vendor/agent-root/src/agent/agent/callback-safety.ts +0 -33
- package/vendor/agent-root/src/agent/agent/compaction.ts +0 -291
- package/vendor/agent-root/src/agent/agent/concurrency.ts +0 -103
- package/vendor/agent-root/src/agent/agent/error-normalizer.ts +0 -190
- package/vendor/agent-root/src/agent/agent/error.ts +0 -198
- package/vendor/agent-root/src/agent/agent/index.ts +0 -1772
- package/vendor/agent-root/src/agent/agent/logger.ts +0 -65
- package/vendor/agent-root/src/agent/agent/message-utils.ts +0 -101
- package/vendor/agent-root/src/agent/agent/stream-events.ts +0 -61
- package/vendor/agent-root/src/agent/agent/telemetry.ts +0 -123
- package/vendor/agent-root/src/agent/agent/timeout-budget.ts +0 -227
- package/vendor/agent-root/src/agent/agent/tool-call-merge.ts +0 -111
- package/vendor/agent-root/src/agent/agent/tool-execution-ledger.ts +0 -164
- package/vendor/agent-root/src/agent/agent/write-buffer.ts +0 -188
- package/vendor/agent-root/src/agent/agent/write-file-session.ts +0 -238
- package/vendor/agent-root/src/agent/app/__test__/agent-app-service.test.ts +0 -1053
- package/vendor/agent-root/src/agent/app/__test__/minimal-agent-application.test.ts +0 -158
- package/vendor/agent-root/src/agent/app/__test__/sqlite-agent-app-store.test.ts +0 -437
- package/vendor/agent-root/src/agent/app/agent-app-service.ts +0 -748
- package/vendor/agent-root/src/agent/app/contracts.ts +0 -109
- package/vendor/agent-root/src/agent/app/index.ts +0 -5
- package/vendor/agent-root/src/agent/app/minimal-agent-application.ts +0 -151
- package/vendor/agent-root/src/agent/app/ports.ts +0 -72
- package/vendor/agent-root/src/agent/app/sqlite-agent-app-store.ts +0 -1182
- package/vendor/agent-root/src/agent/app/sqlite-client.ts +0 -177
- package/vendor/agent-root/src/agent/docs/cli-app-layer/00-README.md +0 -36
- package/vendor/agent-root/src/agent/docs/cli-app-layer/01-scope-and-goals.md +0 -33
- package/vendor/agent-root/src/agent/docs/cli-app-layer/02-architecture-overview.md +0 -40
- package/vendor/agent-root/src/agent/docs/cli-app-layer/03-domain-model-and-contracts.md +0 -91
- package/vendor/agent-root/src/agent/docs/cli-app-layer/04-ports-and-interfaces.md +0 -116
- package/vendor/agent-root/src/agent/docs/cli-app-layer/05-run-orchestration-and-state-machine.md +0 -52
- package/vendor/agent-root/src/agent/docs/cli-app-layer/06-cli-commands-and-ux.md +0 -53
- package/vendor/agent-root/src/agent/docs/cli-app-layer/07-storage-design-local.md +0 -52
- package/vendor/agent-root/src/agent/docs/cli-app-layer/08-error-and-observability.md +0 -40
- package/vendor/agent-root/src/agent/docs/cli-app-layer/09-security-and-policy-boundary.md +0 -19
- package/vendor/agent-root/src/agent/docs/cli-app-layer/10-test-plan-and-acceptance.md +0 -28
- package/vendor/agent-root/src/agent/docs/cli-app-layer/11-implementation-phases.md +0 -26
- package/vendor/agent-root/src/agent/docs/cli-app-layer/12-open-questions-and-risks.md +0 -30
- package/vendor/agent-root/src/agent/docs/cli-app-layer/13-sqlite-schema-fields-and-rationale.md +0 -567
- package/vendor/agent-root/src/agent/docs/cli-app-layer/14-project-flow-mermaid.md +0 -583
- package/vendor/agent-root/src/agent/docs/cli-app-layer/15-openclaw-style-project-blueprint.md +0 -972
- package/vendor/agent-root/src/agent/error-contract.ts +0 -154
- package/vendor/agent-root/src/agent/prompts/system.ts +0 -246
- package/vendor/agent-root/src/agent/prompts/system1.ts +0 -208
- package/vendor/agent-root/src/agent/storage/__test__/file-history-store.test.ts +0 -98
- package/vendor/agent-root/src/agent/storage/file-history-store.ts +0 -313
- package/vendor/agent-root/src/agent/storage/file-storage-config.ts +0 -94
- package/vendor/agent-root/src/agent/storage/file-system.ts +0 -31
- package/vendor/agent-root/src/agent/storage/file-write-service.ts +0 -21
- package/vendor/agent-root/src/agent/tool/__test__/base-tool.test.ts +0 -413
- package/vendor/agent-root/src/agent/tool/__test__/bash-policy.test.ts +0 -356
- package/vendor/agent-root/src/agent/tool/__test__/bash.mocked-coverage.test.ts +0 -375
- package/vendor/agent-root/src/agent/tool/__test__/bash.test.ts +0 -372
- package/vendor/agent-root/src/agent/tool/__test__/error.test.ts +0 -108
- package/vendor/agent-root/src/agent/tool/__test__/file-edit-tool.test.ts +0 -258
- package/vendor/agent-root/src/agent/tool/__test__/file-history-tools.test.ts +0 -121
- package/vendor/agent-root/src/agent/tool/__test__/file-read-tool.test.ts +0 -210
- package/vendor/agent-root/src/agent/tool/__test__/glob.test.ts +0 -139
- package/vendor/agent-root/src/agent/tool/__test__/grep.mocked-coverage.test.ts +0 -456
- package/vendor/agent-root/src/agent/tool/__test__/grep.test.ts +0 -192
- package/vendor/agent-root/src/agent/tool/__test__/lsp.test.ts +0 -300
- package/vendor/agent-root/src/agent/tool/__test__/outside-workspace-confirmation.test.ts +0 -214
- package/vendor/agent-root/src/agent/tool/__test__/path-security.test.ts +0 -336
- package/vendor/agent-root/src/agent/tool/__test__/skill-loader.test.ts +0 -494
- package/vendor/agent-root/src/agent/tool/__test__/skill-parser.test.ts +0 -543
- package/vendor/agent-root/src/agent/tool/__test__/skill-tool.test.ts +0 -172
- package/vendor/agent-root/src/agent/tool/__test__/task-concurrency-and-version.test.ts +0 -116
- package/vendor/agent-root/src/agent/tool/__test__/task-create-get-list-update.test.ts +0 -267
- package/vendor/agent-root/src/agent/tool/__test__/task-create.test.ts +0 -519
- package/vendor/agent-root/src/agent/tool/__test__/task-errors.test.ts +0 -225
- package/vendor/agent-root/src/agent/tool/__test__/task-output-blocking.test.ts +0 -223
- package/vendor/agent-root/src/agent/tool/__test__/task-output.test.ts +0 -184
- package/vendor/agent-root/src/agent/tool/__test__/task-parent-abort.test.ts +0 -287
- package/vendor/agent-root/src/agent/tool/__test__/task-real-runner-adapter.test.ts +0 -190
- package/vendor/agent-root/src/agent/tool/__test__/task-run-lifecycle.test.ts +0 -352
- package/vendor/agent-root/src/agent/tool/__test__/task-store-runner-branches.test.ts +0 -395
- package/vendor/agent-root/src/agent/tool/__test__/task-store.test.ts +0 -391
- package/vendor/agent-root/src/agent/tool/__test__/task-subagent-config-integration.test.ts +0 -176
- package/vendor/agent-root/src/agent/tool/__test__/task-subagent-config.test.ts +0 -68
- package/vendor/agent-root/src/agent/tool/__test__/task-tools-core-edges.test.ts +0 -630
- package/vendor/agent-root/src/agent/tool/__test__/task-tools-runtime-edges.test.ts +0 -732
- package/vendor/agent-root/src/agent/tool/__test__/task-types.test.ts +0 -494
- package/vendor/agent-root/src/agent/tool/__test__/task-utils-branches.test.ts +0 -175
- package/vendor/agent-root/src/agent/tool/__test__/tool-manager.test.ts +0 -505
- package/vendor/agent-root/src/agent/tool/__test__/types.test.ts +0 -55
- package/vendor/agent-root/src/agent/tool/__test__/web-fetch.test.ts +0 -244
- package/vendor/agent-root/src/agent/tool/__test__/web-search.test.ts +0 -290
- package/vendor/agent-root/src/agent/tool/__test__/write-file.test.ts +0 -368
- package/vendor/agent-root/src/agent/tool/base-tool.ts +0 -345
- package/vendor/agent-root/src/agent/tool/bash-policy.ts +0 -636
- package/vendor/agent-root/src/agent/tool/bash.ts +0 -688
- package/vendor/agent-root/src/agent/tool/error.ts +0 -131
- package/vendor/agent-root/src/agent/tool/file-edit-tool.ts +0 -264
- package/vendor/agent-root/src/agent/tool/file-history-list.ts +0 -103
- package/vendor/agent-root/src/agent/tool/file-history-restore.ts +0 -149
- package/vendor/agent-root/src/agent/tool/file-read-tool.ts +0 -211
- package/vendor/agent-root/src/agent/tool/glob.ts +0 -171
- package/vendor/agent-root/src/agent/tool/grep.ts +0 -496
- package/vendor/agent-root/src/agent/tool/lsp.ts +0 -481
- package/vendor/agent-root/src/agent/tool/path-security.ts +0 -117
- package/vendor/agent-root/src/agent/tool/search/common.ts +0 -153
- package/vendor/agent-root/src/agent/tool/skill/index.ts +0 -13
- package/vendor/agent-root/src/agent/tool/skill/loader.ts +0 -229
- package/vendor/agent-root/src/agent/tool/skill/parser.ts +0 -124
- package/vendor/agent-root/src/agent/tool/skill/types.ts +0 -27
- package/vendor/agent-root/src/agent/tool/skill-tool.ts +0 -143
- package/vendor/agent-root/src/agent/tool/task-create.ts +0 -186
- package/vendor/agent-root/src/agent/tool/task-errors.ts +0 -42
- package/vendor/agent-root/src/agent/tool/task-get.ts +0 -116
- package/vendor/agent-root/src/agent/tool/task-graph.ts +0 -78
- package/vendor/agent-root/src/agent/tool/task-list.ts +0 -141
- package/vendor/agent-root/src/agent/tool/task-mock-runner-adapter.ts +0 -232
- package/vendor/agent-root/src/agent/tool/task-output.ts +0 -223
- package/vendor/agent-root/src/agent/tool/task-parent-abort.ts +0 -115
- package/vendor/agent-root/src/agent/tool/task-real-runner-adapter.ts +0 -336
- package/vendor/agent-root/src/agent/tool/task-runner-adapter.ts +0 -55
- package/vendor/agent-root/src/agent/tool/task-stop.ts +0 -187
- package/vendor/agent-root/src/agent/tool/task-store.ts +0 -217
- package/vendor/agent-root/src/agent/tool/task-subagent-config.ts +0 -149
- package/vendor/agent-root/src/agent/tool/task-types.ts +0 -264
- package/vendor/agent-root/src/agent/tool/task-update.ts +0 -315
- package/vendor/agent-root/src/agent/tool/task.ts +0 -209
- package/vendor/agent-root/src/agent/tool/tool-manager.ts +0 -361
- package/vendor/agent-root/src/agent/tool/tool-prompts.ts +0 -242
- package/vendor/agent-root/src/agent/tool/types.ts +0 -116
- package/vendor/agent-root/src/agent/tool/web-fetch.ts +0 -227
- package/vendor/agent-root/src/agent/tool/web-search.ts +0 -208
- package/vendor/agent-root/src/agent/tool/write-file.ts +0 -497
- package/vendor/agent-root/src/agent/types.ts +0 -232
- package/vendor/agent-root/src/agent/utils/__tests__/index.test.ts +0 -18
- package/vendor/agent-root/src/agent/utils/__tests__/message-utils.test.ts +0 -610
- package/vendor/agent-root/src/agent/utils/__tests__/message.test.ts +0 -223
- package/vendor/agent-root/src/agent/utils/__tests__/token.test.ts +0 -42
- package/vendor/agent-root/src/agent/utils/index.ts +0 -16
- package/vendor/agent-root/src/agent/utils/message.ts +0 -171
- package/vendor/agent-root/src/agent/utils/token.ts +0 -28
- package/vendor/agent-root/src/config/__tests__/load-config-to-env.test.ts +0 -238
- package/vendor/agent-root/src/config/__tests__/loader.test.ts +0 -361
- package/vendor/agent-root/src/config/__tests__/runtime.test.ts +0 -88
- package/vendor/agent-root/src/config/index.ts +0 -55
- package/vendor/agent-root/src/config/loader.ts +0 -494
- package/vendor/agent-root/src/config/paths.ts +0 -30
- package/vendor/agent-root/src/config/runtime.ts +0 -163
- package/vendor/agent-root/src/config/types.ts +0 -96
- package/vendor/agent-root/src/logger/index.ts +0 -57
- package/vendor/agent-root/src/logger/logger.ts +0 -819
- package/vendor/agent-root/src/logger/types.ts +0 -150
- package/vendor/agent-root/src/providers/__tests__/errors.test.ts +0 -441
- package/vendor/agent-root/src/providers/__tests__/index.test.ts +0 -16
- package/vendor/agent-root/src/providers/__tests__/openai-compatible.options.test.ts +0 -318
- package/vendor/agent-root/src/providers/__tests__/openai-compatible.test.ts +0 -600
- package/vendor/agent-root/src/providers/__tests__/registry.test.ts +0 -523
- package/vendor/agent-root/src/providers/__tests__/responses-adapter.test.ts +0 -298
- package/vendor/agent-root/src/providers/adapters/__tests__/anthropic.test.ts +0 -354
- package/vendor/agent-root/src/providers/adapters/__tests__/kimi.test.ts +0 -58
- package/vendor/agent-root/src/providers/adapters/__tests__/standard.test.ts +0 -261
- package/vendor/agent-root/src/providers/adapters/anthropic.ts +0 -572
- package/vendor/agent-root/src/providers/adapters/base.ts +0 -131
- package/vendor/agent-root/src/providers/adapters/kimi.ts +0 -48
- package/vendor/agent-root/src/providers/adapters/responses.ts +0 -732
- package/vendor/agent-root/src/providers/adapters/standard.ts +0 -120
- package/vendor/agent-root/src/providers/http/__tests__/client.timeout.test.ts +0 -313
- package/vendor/agent-root/src/providers/http/client.ts +0 -289
- package/vendor/agent-root/src/providers/http/stream-parser.ts +0 -109
- package/vendor/agent-root/src/providers/index.ts +0 -76
- package/vendor/agent-root/src/providers/kimi-headers.ts +0 -177
- package/vendor/agent-root/src/providers/openai-compatible.ts +0 -387
- package/vendor/agent-root/src/providers/registry/model-config.ts +0 -477
- package/vendor/agent-root/src/providers/registry/provider-factory.ts +0 -127
- package/vendor/agent-root/src/providers/registry.ts +0 -135
- package/vendor/agent-root/src/providers/types/api.ts +0 -284
- package/vendor/agent-root/src/providers/types/config.ts +0 -58
- package/vendor/agent-root/src/providers/types/errors.ts +0 -323
- package/vendor/agent-root/src/providers/types/index.ts +0 -72
- package/vendor/agent-root/src/providers/types/provider.ts +0 -45
- package/vendor/agent-root/src/providers/types/registry.ts +0 -68
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs/promises';
|
|
2
|
-
import type { Dirent } from 'node:fs';
|
|
3
|
-
import * as path from 'node:path';
|
|
4
|
-
import { minimatch } from 'minimatch';
|
|
5
|
-
import {
|
|
6
|
-
ensurePathWithinAllowed,
|
|
7
|
-
normalizeAllowedDirectories,
|
|
8
|
-
resolveRequestedPath,
|
|
9
|
-
} from '../path-security';
|
|
10
|
-
|
|
11
|
-
export const DEFAULT_IGNORE_GLOBS = [
|
|
12
|
-
'**/node_modules/**',
|
|
13
|
-
'**/.git/**',
|
|
14
|
-
'**/dist/**',
|
|
15
|
-
'**/build/**',
|
|
16
|
-
'**/.next/**',
|
|
17
|
-
'**/.nuxt/**',
|
|
18
|
-
'**/coverage/**',
|
|
19
|
-
'**/*.min.js',
|
|
20
|
-
'**/*.min.css',
|
|
21
|
-
];
|
|
22
|
-
|
|
23
|
-
export interface SearchPathOptions {
|
|
24
|
-
requestedPath?: string;
|
|
25
|
-
allowedDirectories?: string[];
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface SearchPathResolved {
|
|
29
|
-
rootPath: string;
|
|
30
|
-
allowedDirectories: string[];
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface TraverseFile {
|
|
34
|
-
absolutePath: string;
|
|
35
|
-
relativePath: string;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export async function resolveSearchRoot(options: SearchPathOptions): Promise<SearchPathResolved> {
|
|
39
|
-
const allowedDirectories = normalizeAllowedDirectories(options.allowedDirectories);
|
|
40
|
-
const requestedPath = options.requestedPath?.trim().length
|
|
41
|
-
? options.requestedPath
|
|
42
|
-
: process.cwd();
|
|
43
|
-
const absolute = resolveRequestedPath(requestedPath);
|
|
44
|
-
const validated = ensurePathWithinAllowed(
|
|
45
|
-
absolute,
|
|
46
|
-
allowedDirectories,
|
|
47
|
-
'SEARCH_PATH_NOT_ALLOWED'
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
let stats: Awaited<ReturnType<typeof fs.stat>>;
|
|
51
|
-
try {
|
|
52
|
-
stats = await fs.stat(validated);
|
|
53
|
-
} catch (error) {
|
|
54
|
-
const nodeError = error as NodeJS.ErrnoException;
|
|
55
|
-
if (nodeError.code === 'ENOENT') {
|
|
56
|
-
throw new Error(`SEARCH_PATH_NOT_FOUND: ${validated}`);
|
|
57
|
-
}
|
|
58
|
-
if (nodeError.code === 'EACCES' || nodeError.code === 'EPERM') {
|
|
59
|
-
throw new Error(`SEARCH_PATH_NO_PERMISSION: ${validated}`);
|
|
60
|
-
}
|
|
61
|
-
throw error;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (!stats.isDirectory()) {
|
|
65
|
-
throw new Error(`SEARCH_PATH_NOT_DIRECTORY: ${validated}`);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return {
|
|
69
|
-
rootPath: validated,
|
|
70
|
-
allowedDirectories,
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export async function collectFilesByGlob(options: {
|
|
75
|
-
rootPath: string;
|
|
76
|
-
pattern: string;
|
|
77
|
-
includeHidden: boolean;
|
|
78
|
-
ignorePatterns: string[];
|
|
79
|
-
maxResults: number;
|
|
80
|
-
}): Promise<{ files: TraverseFile[]; truncated: boolean }> {
|
|
81
|
-
const files: TraverseFile[] = [];
|
|
82
|
-
const queue = [options.rootPath];
|
|
83
|
-
const visited = new Set<string>();
|
|
84
|
-
let truncated = false;
|
|
85
|
-
|
|
86
|
-
while (queue.length > 0) {
|
|
87
|
-
const current = queue.shift();
|
|
88
|
-
if (!current) {
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
let realCurrent: string;
|
|
93
|
-
try {
|
|
94
|
-
realCurrent = await fs.realpath(current);
|
|
95
|
-
} catch {
|
|
96
|
-
continue;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (visited.has(realCurrent)) {
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
102
|
-
visited.add(realCurrent);
|
|
103
|
-
|
|
104
|
-
let entries: Dirent[];
|
|
105
|
-
try {
|
|
106
|
-
entries = await fs.readdir(current, { withFileTypes: true });
|
|
107
|
-
} catch {
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
entries.sort((left, right) => left.name.localeCompare(right.name));
|
|
112
|
-
|
|
113
|
-
for (const entry of entries) {
|
|
114
|
-
if (!options.includeHidden && entry.name.startsWith('.')) {
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const absolutePath = path.join(current, entry.name);
|
|
119
|
-
const relativePath = path.relative(options.rootPath, absolutePath).split(path.sep).join('/');
|
|
120
|
-
if (!relativePath || relativePath === '.') {
|
|
121
|
-
continue;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const ignored = options.ignorePatterns.some((pattern) =>
|
|
125
|
-
minimatch(relativePath, pattern, { dot: options.includeHidden })
|
|
126
|
-
);
|
|
127
|
-
if (ignored) {
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (entry.isDirectory()) {
|
|
132
|
-
queue.push(absolutePath);
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (!entry.isFile()) {
|
|
137
|
-
continue;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (!minimatch(relativePath, options.pattern, { dot: options.includeHidden })) {
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
files.push({ absolutePath, relativePath });
|
|
145
|
-
if (files.length >= options.maxResults) {
|
|
146
|
-
truncated = true;
|
|
147
|
-
return { files, truncated };
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return { files, truncated };
|
|
153
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export type { Skill, SkillFrontmatter, SkillLoaderOptions, SkillMetadata } from './types';
|
|
2
|
-
|
|
3
|
-
export {
|
|
4
|
-
parseFrontmatter,
|
|
5
|
-
stripFrontmatter,
|
|
6
|
-
extractFileRefs,
|
|
7
|
-
extractShellCommands,
|
|
8
|
-
deriveDescriptionFromMarkdown,
|
|
9
|
-
formatSkillForContext,
|
|
10
|
-
isValidSkillName,
|
|
11
|
-
} from './parser';
|
|
12
|
-
|
|
13
|
-
export { SkillLoader, getSkillLoader, initializeSkillLoader, resetSkillLoader } from './loader';
|
|
@@ -1,229 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs/promises';
|
|
2
|
-
import type { Dirent } from 'node:fs';
|
|
3
|
-
import * as os from 'node:os';
|
|
4
|
-
import * as path from 'node:path';
|
|
5
|
-
import {
|
|
6
|
-
deriveDescriptionFromMarkdown,
|
|
7
|
-
extractFileRefs,
|
|
8
|
-
extractShellCommands,
|
|
9
|
-
isValidSkillName,
|
|
10
|
-
parseFrontmatter,
|
|
11
|
-
stripFrontmatter,
|
|
12
|
-
} from './parser';
|
|
13
|
-
import type { Skill, SkillLoaderOptions, SkillMetadata } from './types';
|
|
14
|
-
|
|
15
|
-
const SKILL_FILE_NAME = 'SKILL.md';
|
|
16
|
-
|
|
17
|
-
function getDefaultSkillRoots(workingDir: string): string[] {
|
|
18
|
-
const roots: string[] = [];
|
|
19
|
-
const codexHome = process.env.CODEX_HOME?.trim();
|
|
20
|
-
if (codexHome) {
|
|
21
|
-
roots.push(path.join(codexHome, 'skills'));
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
roots.push(path.join(workingDir, '.agents', 'skills'));
|
|
25
|
-
roots.push(path.join(os.homedir(), '.agents', 'skills'));
|
|
26
|
-
roots.push(path.join(os.homedir(), '.codex', 'skills'));
|
|
27
|
-
|
|
28
|
-
return Array.from(new Set(roots.map((dir) => path.resolve(dir))));
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function toLoaderKey(options?: SkillLoaderOptions): string {
|
|
32
|
-
const roots = options?.skillRoots?.map((root) => path.resolve(root)).sort() || [];
|
|
33
|
-
const workingDir = path.resolve(options?.workingDir || process.cwd());
|
|
34
|
-
return JSON.stringify({ roots, workingDir });
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export class SkillLoader {
|
|
38
|
-
private readonly roots: string[];
|
|
39
|
-
private readonly metadataMap = new Map<string, SkillMetadata>();
|
|
40
|
-
private readonly skillCache = new Map<string, Skill>();
|
|
41
|
-
private initialized = false;
|
|
42
|
-
|
|
43
|
-
constructor(options: SkillLoaderOptions = {}) {
|
|
44
|
-
const workingDir = options.workingDir ?? process.cwd();
|
|
45
|
-
this.roots = options.skillRoots?.length
|
|
46
|
-
? options.skillRoots.map((dir) => path.resolve(dir))
|
|
47
|
-
: getDefaultSkillRoots(workingDir);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async initialize(): Promise<void> {
|
|
51
|
-
if (this.initialized) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
this.metadataMap.clear();
|
|
56
|
-
const skillFiles = await this.discoverSkillFiles();
|
|
57
|
-
|
|
58
|
-
for (const skillFilePath of skillFiles) {
|
|
59
|
-
const metadata = await this.loadMetadata(skillFilePath);
|
|
60
|
-
if (!metadata) {
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
if (!this.metadataMap.has(metadata.name)) {
|
|
64
|
-
this.metadataMap.set(metadata.name, metadata);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
this.initialized = true;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
getAllMetadata(): SkillMetadata[] {
|
|
72
|
-
return Array.from(this.metadataMap.values()).sort((left, right) =>
|
|
73
|
-
left.name.localeCompare(right.name)
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
hasSkill(name: string): boolean {
|
|
78
|
-
return this.metadataMap.has(name);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
async loadSkill(name: string): Promise<Skill | null> {
|
|
82
|
-
const cached = this.skillCache.get(name);
|
|
83
|
-
if (cached) {
|
|
84
|
-
return cached;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const metadata = this.metadataMap.get(name);
|
|
88
|
-
if (!metadata) {
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
let rawContent: string;
|
|
93
|
-
try {
|
|
94
|
-
rawContent = await fs.readFile(metadata.skillFilePath, 'utf-8');
|
|
95
|
-
} catch {
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const content = stripFrontmatter(rawContent).trim();
|
|
100
|
-
const skill: Skill = {
|
|
101
|
-
metadata,
|
|
102
|
-
content,
|
|
103
|
-
fileRefs: extractFileRefs(content),
|
|
104
|
-
shellCommands: extractShellCommands(content),
|
|
105
|
-
loadedAt: Date.now(),
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
this.skillCache.set(name, skill);
|
|
109
|
-
return skill;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
private async discoverSkillFiles(): Promise<string[]> {
|
|
113
|
-
const files: string[] = [];
|
|
114
|
-
for (const root of this.roots) {
|
|
115
|
-
const discovered = await this.walkSkillFiles(root);
|
|
116
|
-
files.push(...discovered);
|
|
117
|
-
}
|
|
118
|
-
return files;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
private async walkSkillFiles(rootDirectory: string): Promise<string[]> {
|
|
122
|
-
let stats: Awaited<ReturnType<typeof fs.stat>>;
|
|
123
|
-
try {
|
|
124
|
-
stats = await fs.stat(rootDirectory);
|
|
125
|
-
} catch {
|
|
126
|
-
return [];
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (!stats.isDirectory()) {
|
|
130
|
-
return [];
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const queue = [rootDirectory];
|
|
134
|
-
const skillFiles: string[] = [];
|
|
135
|
-
const visited = new Set<string>();
|
|
136
|
-
|
|
137
|
-
while (queue.length > 0) {
|
|
138
|
-
const current = queue.shift();
|
|
139
|
-
if (!current) {
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
let realCurrent: string;
|
|
144
|
-
try {
|
|
145
|
-
realCurrent = await fs.realpath(current);
|
|
146
|
-
} catch {
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (visited.has(realCurrent)) {
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
visited.add(realCurrent);
|
|
154
|
-
|
|
155
|
-
let entries: Dirent[];
|
|
156
|
-
try {
|
|
157
|
-
entries = await fs.readdir(current, { withFileTypes: true });
|
|
158
|
-
} catch {
|
|
159
|
-
continue;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
for (const entry of entries) {
|
|
163
|
-
const entryPath = path.join(current, entry.name);
|
|
164
|
-
if (entry.isFile() && entry.name === SKILL_FILE_NAME) {
|
|
165
|
-
skillFiles.push(entryPath);
|
|
166
|
-
continue;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (entry.isDirectory()) {
|
|
170
|
-
queue.push(entryPath);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return skillFiles;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
private async loadMetadata(skillFilePath: string): Promise<SkillMetadata | null> {
|
|
179
|
-
let content: string;
|
|
180
|
-
try {
|
|
181
|
-
content = await fs.readFile(skillFilePath, 'utf-8');
|
|
182
|
-
} catch {
|
|
183
|
-
return null;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const frontmatter = parseFrontmatter(content);
|
|
187
|
-
const skillDirectory = path.dirname(skillFilePath);
|
|
188
|
-
const fallbackName = path.basename(skillDirectory).toLowerCase();
|
|
189
|
-
const name = (frontmatter?.name || fallbackName).trim();
|
|
190
|
-
if (!isValidSkillName(name)) {
|
|
191
|
-
return null;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const description = (frontmatter?.description || deriveDescriptionFromMarkdown(content)).trim();
|
|
195
|
-
if (!description) {
|
|
196
|
-
return null;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
return {
|
|
200
|
-
name,
|
|
201
|
-
description,
|
|
202
|
-
path: skillDirectory,
|
|
203
|
-
skillFilePath,
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
let globalLoader: SkillLoader | null = null;
|
|
209
|
-
let globalLoaderKey: string | null = null;
|
|
210
|
-
|
|
211
|
-
export function getSkillLoader(options?: SkillLoaderOptions): SkillLoader {
|
|
212
|
-
const nextKey = toLoaderKey(options);
|
|
213
|
-
if (!globalLoader || globalLoaderKey !== nextKey) {
|
|
214
|
-
globalLoader = new SkillLoader(options);
|
|
215
|
-
globalLoaderKey = nextKey;
|
|
216
|
-
}
|
|
217
|
-
return globalLoader;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
export async function initializeSkillLoader(options?: SkillLoaderOptions): Promise<SkillLoader> {
|
|
221
|
-
const loader = getSkillLoader(options);
|
|
222
|
-
await loader.initialize();
|
|
223
|
-
return loader;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
export function resetSkillLoader(): void {
|
|
227
|
-
globalLoader = null;
|
|
228
|
-
globalLoaderKey = null;
|
|
229
|
-
}
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import type { SkillFrontmatter } from './types';
|
|
2
|
-
|
|
3
|
-
const FRONTMATTER_REGEX = /^---\s*\n([\s\S]*?)\n---/;
|
|
4
|
-
const FILE_REF_REGEX = /(?<![`\w])@(\.{0,2}[/\\]?[^\s`,.*!?()]+(?:\.[^\s`,.*!?()]+)+)/g;
|
|
5
|
-
const SHELL_COMMAND_REGEX = /!`([^`]+)`/g;
|
|
6
|
-
|
|
7
|
-
export function parseFrontmatter(content: string): SkillFrontmatter | null {
|
|
8
|
-
const matched = content.match(FRONTMATTER_REGEX);
|
|
9
|
-
if (!matched) {
|
|
10
|
-
return null;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const frontmatter: Partial<SkillFrontmatter> = {};
|
|
14
|
-
for (const line of matched[1].split('\n')) {
|
|
15
|
-
const colonIndex = line.indexOf(':');
|
|
16
|
-
if (colonIndex < 0) {
|
|
17
|
-
continue;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const key = line.slice(0, colonIndex).trim();
|
|
21
|
-
let value = line.slice(colonIndex + 1).trim();
|
|
22
|
-
if (
|
|
23
|
-
(value.startsWith('"') && value.endsWith('"')) ||
|
|
24
|
-
(value.startsWith("'") && value.endsWith("'"))
|
|
25
|
-
) {
|
|
26
|
-
value = value.slice(1, -1);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (key === 'name') {
|
|
30
|
-
frontmatter.name = value;
|
|
31
|
-
}
|
|
32
|
-
if (key === 'description') {
|
|
33
|
-
frontmatter.description = value;
|
|
34
|
-
}
|
|
35
|
-
if (key === 'license') {
|
|
36
|
-
frontmatter.license = value;
|
|
37
|
-
}
|
|
38
|
-
if (key === 'version') {
|
|
39
|
-
frontmatter.version = value;
|
|
40
|
-
}
|
|
41
|
-
if (key === 'author') {
|
|
42
|
-
frontmatter.author = value;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (!frontmatter.name || !frontmatter.description) {
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return frontmatter as SkillFrontmatter;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function stripFrontmatter(content: string): string {
|
|
54
|
-
const matched = content.match(/^---\s*\n[\s\S]*?\n---\s*\n?/);
|
|
55
|
-
if (!matched) {
|
|
56
|
-
return content;
|
|
57
|
-
}
|
|
58
|
-
return content.slice(matched[0].length);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function extractFileRefs(content: string): string[] {
|
|
62
|
-
const matches = Array.from(content.matchAll(FILE_REF_REGEX), (match) => match[1]);
|
|
63
|
-
return Array.from(new Set(matches));
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export function extractShellCommands(content: string): string[] {
|
|
67
|
-
const matches = Array.from(content.matchAll(SHELL_COMMAND_REGEX), (match) => match[1]);
|
|
68
|
-
return Array.from(new Set(matches));
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function deriveDescriptionFromMarkdown(content: string): string {
|
|
72
|
-
const stripped = stripFrontmatter(content);
|
|
73
|
-
const lines = stripped
|
|
74
|
-
.split('\n')
|
|
75
|
-
.map((line) => line.trim())
|
|
76
|
-
.filter((line) => line.length > 0);
|
|
77
|
-
|
|
78
|
-
for (const line of lines) {
|
|
79
|
-
if (line.startsWith('#')) {
|
|
80
|
-
continue;
|
|
81
|
-
}
|
|
82
|
-
return line.length > 180 ? `${line.slice(0, 177)}...` : line;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return 'No description provided';
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function formatSkillForContext(skill: {
|
|
89
|
-
metadata: { name: string; description: string; path: string };
|
|
90
|
-
content: string;
|
|
91
|
-
fileRefs: string[];
|
|
92
|
-
shellCommands: string[];
|
|
93
|
-
}): string {
|
|
94
|
-
const lines: string[] = [
|
|
95
|
-
`## Skill: ${skill.metadata.name}`,
|
|
96
|
-
'',
|
|
97
|
-
`Description: ${skill.metadata.description}`,
|
|
98
|
-
`Base directory: ${skill.metadata.path}`,
|
|
99
|
-
];
|
|
100
|
-
|
|
101
|
-
if (skill.fileRefs.length > 0) {
|
|
102
|
-
lines.push('', 'Referenced files:');
|
|
103
|
-
for (const fileRef of skill.fileRefs) {
|
|
104
|
-
lines.push(`- ${fileRef}`);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (skill.shellCommands.length > 0) {
|
|
109
|
-
lines.push('', 'Shell commands:');
|
|
110
|
-
for (const shellCommand of skill.shellCommands) {
|
|
111
|
-
lines.push(`- !\`${shellCommand}\``);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
lines.push('', '---', '', skill.content);
|
|
116
|
-
return lines.join('\n');
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export function isValidSkillName(name: string): boolean {
|
|
120
|
-
if (name.length === 0 || name.length > 64) {
|
|
121
|
-
return false;
|
|
122
|
-
}
|
|
123
|
-
return /^[a-z0-9._]+(?:-[a-z0-9._]+)*$/.test(name);
|
|
124
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
export interface SkillMetadata {
|
|
2
|
-
readonly name: string;
|
|
3
|
-
readonly description: string;
|
|
4
|
-
readonly path: string;
|
|
5
|
-
readonly skillFilePath: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface Skill {
|
|
9
|
-
readonly metadata: SkillMetadata;
|
|
10
|
-
readonly content: string;
|
|
11
|
-
readonly fileRefs: string[];
|
|
12
|
-
readonly shellCommands: string[];
|
|
13
|
-
readonly loadedAt: number;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface SkillLoaderOptions {
|
|
17
|
-
skillRoots?: string[];
|
|
18
|
-
workingDir?: string;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface SkillFrontmatter {
|
|
22
|
-
name: string;
|
|
23
|
-
description: string;
|
|
24
|
-
license?: string;
|
|
25
|
-
version?: string;
|
|
26
|
-
author?: string;
|
|
27
|
-
}
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { BaseTool, type ToolResult } from './base-tool';
|
|
3
|
-
import { ToolExecutionError } from './error';
|
|
4
|
-
import { formatSkillForContext } from './skill/parser';
|
|
5
|
-
import { getSkillLoader, initializeSkillLoader } from './skill/loader';
|
|
6
|
-
import type { SkillLoaderOptions } from './skill/types';
|
|
7
|
-
import { SKILL_TOOL_BASE_DESCRIPTION } from './tool-prompts';
|
|
8
|
-
|
|
9
|
-
const schema = z
|
|
10
|
-
.object({
|
|
11
|
-
name: z.string().min(1).describe('Skill identifier from available skills list'),
|
|
12
|
-
})
|
|
13
|
-
.strict();
|
|
14
|
-
|
|
15
|
-
export interface SkillToolOptions {
|
|
16
|
-
includeSkillList?: boolean;
|
|
17
|
-
loaderOptions?: SkillLoaderOptions;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
interface SkillToolPayload {
|
|
21
|
-
name: string;
|
|
22
|
-
description: string;
|
|
23
|
-
baseDir: string;
|
|
24
|
-
content: string;
|
|
25
|
-
fileRefs: string[];
|
|
26
|
-
shellCommands: string[];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export class SkillTool extends BaseTool<typeof schema> {
|
|
30
|
-
name = 'skill';
|
|
31
|
-
parameters = schema;
|
|
32
|
-
|
|
33
|
-
private readonly includeSkillList: boolean;
|
|
34
|
-
private readonly loaderOptions?: SkillLoaderOptions;
|
|
35
|
-
private cachedDescription: string | null = null;
|
|
36
|
-
|
|
37
|
-
constructor(options: SkillToolOptions = {}) {
|
|
38
|
-
super();
|
|
39
|
-
this.includeSkillList = options.includeSkillList ?? true;
|
|
40
|
-
this.loaderOptions = options.loaderOptions;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
get description(): string {
|
|
44
|
-
if (!this.cachedDescription) {
|
|
45
|
-
this.cachedDescription = this.buildDescription();
|
|
46
|
-
}
|
|
47
|
-
return this.cachedDescription;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
refreshDescription(): void {
|
|
51
|
-
this.cachedDescription = null;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
override getConcurrencyMode(): 'parallel-safe' {
|
|
55
|
-
return 'parallel-safe';
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
override getConcurrencyLockKey(args: z.infer<typeof schema>): string {
|
|
59
|
-
return `skill:${args.name}`;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async execute(args: z.infer<typeof schema>): Promise<ToolResult> {
|
|
63
|
-
try {
|
|
64
|
-
await initializeSkillLoader(this.loaderOptions);
|
|
65
|
-
const loader = getSkillLoader(this.loaderOptions);
|
|
66
|
-
|
|
67
|
-
if (!loader.hasSkill(args.name)) {
|
|
68
|
-
const availableSkills = loader.getAllMetadata().map((item) => item.name);
|
|
69
|
-
const suggestion =
|
|
70
|
-
availableSkills.length > 0
|
|
71
|
-
? `Available skills: ${availableSkills.join(', ')}`
|
|
72
|
-
: 'No skills are currently available.';
|
|
73
|
-
const message = `SKILL_NOT_FOUND: Skill "${args.name}" not found. ${suggestion}`;
|
|
74
|
-
|
|
75
|
-
return {
|
|
76
|
-
success: false,
|
|
77
|
-
output: message,
|
|
78
|
-
error: new ToolExecutionError(message),
|
|
79
|
-
metadata: {
|
|
80
|
-
error: 'SKILL_NOT_FOUND',
|
|
81
|
-
suggestion,
|
|
82
|
-
requested_name: args.name,
|
|
83
|
-
},
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const skill = await loader.loadSkill(args.name);
|
|
88
|
-
if (!skill) {
|
|
89
|
-
const message = `SKILL_LOAD_FAILED: Failed to load skill "${args.name}"`;
|
|
90
|
-
return {
|
|
91
|
-
success: false,
|
|
92
|
-
output: message,
|
|
93
|
-
error: new ToolExecutionError(message),
|
|
94
|
-
metadata: {
|
|
95
|
-
error: 'SKILL_LOAD_FAILED',
|
|
96
|
-
requested_name: args.name,
|
|
97
|
-
},
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const payload: SkillToolPayload = {
|
|
102
|
-
name: skill.metadata.name,
|
|
103
|
-
description: skill.metadata.description,
|
|
104
|
-
baseDir: skill.metadata.path,
|
|
105
|
-
content: skill.content,
|
|
106
|
-
fileRefs: skill.fileRefs,
|
|
107
|
-
shellCommands: skill.shellCommands,
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
return {
|
|
111
|
-
success: true,
|
|
112
|
-
output: formatSkillForContext(skill),
|
|
113
|
-
metadata: payload as unknown as Record<string, unknown>,
|
|
114
|
-
};
|
|
115
|
-
} catch (error) {
|
|
116
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
117
|
-
return {
|
|
118
|
-
success: false,
|
|
119
|
-
output: message,
|
|
120
|
-
error: new ToolExecutionError(message),
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
private buildDescription(): string {
|
|
126
|
-
const base = `${SKILL_TOOL_BASE_DESCRIPTION}\n\n`;
|
|
127
|
-
|
|
128
|
-
if (!this.includeSkillList) {
|
|
129
|
-
return base;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const loader = getSkillLoader(this.loaderOptions);
|
|
133
|
-
const skills = loader.getAllMetadata();
|
|
134
|
-
if (skills.length === 0) {
|
|
135
|
-
return `${base}No skills are currently available.`;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const lines = skills.map((skill) => `- ${skill.name}: ${skill.description}`);
|
|
139
|
-
return `${base}Available skills:\n${lines.join('\n')}`;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export default SkillTool;
|