@qvac/harness 0.3.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +700 -126
- package/README.md +156 -0
- package/dist/harness.bundle +71 -103
- package/dist/prebuilds-manifest.json +0 -8
- package/dist-lib/index.d.ts +42 -40
- package/dist-lib/index.js +307 -117
- package/dist-lib/lib/audio-transcode-bare.d.ts +2 -2
- package/dist-lib/lib/audio-transcode-bare.js +28 -18
- package/dist-lib/lib/audio-transcode-node.d.ts +2 -2
- package/dist-lib/lib/capabilities/audio-resample.d.ts +7 -6
- package/dist-lib/lib/capabilities/audio-resample.js +30 -18
- package/dist-lib/lib/capabilities/completion.d.ts +20 -19
- package/dist-lib/lib/capabilities/completion.js +194 -135
- package/dist-lib/lib/capabilities/download.d.ts +6 -6
- package/dist-lib/lib/capabilities/download.js +15 -8
- package/dist-lib/lib/capabilities/embed.js +2 -1
- package/dist-lib/lib/capabilities/enhance.d.ts +6 -1
- package/dist-lib/lib/capabilities/enhance.js +7 -4
- package/dist-lib/lib/capabilities/invoke.js +7 -4
- package/dist-lib/lib/capabilities/kv-cache.js +2 -1
- package/dist-lib/lib/capabilities/preview-model-source.d.ts +69 -0
- package/dist-lib/lib/capabilities/preview-model-source.js +439 -0
- package/dist-lib/lib/capabilities/speech-text.js +5 -4
- package/dist-lib/lib/capabilities/tool-selection.js +10 -9
- package/dist-lib/lib/capabilities/tool-turns.js +30 -16
- package/dist-lib/lib/capabilities/usage-breakdown.js +2 -1
- package/dist-lib/lib/capabilities/voice.d.ts +5 -1
- package/dist-lib/lib/capabilities/voice.js +22 -12
- package/dist-lib/lib/connect.d.ts +15 -37
- package/dist-lib/lib/connect.js +161 -112
- package/dist-lib/lib/context-window.js +25 -21
- package/dist-lib/lib/contract-types.d.ts +26 -20
- package/dist-lib/lib/diagram-repair.d.ts +4 -4
- package/dist-lib/lib/diagram-repair.js +6 -3
- package/dist-lib/lib/docx/index.d.ts +3 -2
- package/dist-lib/lib/{error-fields.d.ts → guards.d.ts} +1 -0
- package/dist-lib/lib/{error-fields.js → guards.js} +3 -0
- package/dist-lib/lib/hardware/capability-probe.js +20 -10
- package/dist-lib/lib/hardware/gpu-classify.js +6 -3
- package/dist-lib/lib/hardware/gpu-probe-addon.js +8 -4
- package/dist-lib/lib/hardware/gpu-probe.js +4 -2
- package/dist-lib/lib/hardware/gpu-stats.native.cjs +8 -9
- package/dist-lib/lib/hardware/parsers.js +8 -4
- package/dist-lib/lib/helpers/buffer-burst.js +4 -2
- package/dist-lib/lib/helpers/control-tokens.js +4 -2
- package/dist-lib/lib/helpers/join-guard.d.ts +2 -2
- package/dist-lib/lib/helpers/join-guard.js +4 -2
- package/dist-lib/lib/helpers/load-stall.js +4 -2
- package/dist-lib/lib/helpers/markup-stream-filter.d.ts +2 -2
- package/dist-lib/lib/helpers/markup-stream-filter.js +6 -3
- package/dist-lib/lib/helpers/race-abort.js +2 -1
- package/dist-lib/lib/helpers/race-timeout.d.ts +5 -0
- package/dist-lib/lib/helpers/race-timeout.js +14 -0
- package/dist-lib/lib/helpers/run-outcome.d.ts +6 -8
- package/dist-lib/lib/helpers/run-outcome.js +36 -20
- package/dist-lib/lib/helpers/spawn-path.js +6 -3
- package/dist-lib/lib/helpers/text-coalescer.js +6 -3
- package/dist-lib/lib/helpers/thinking.js +38 -45
- package/dist-lib/lib/helpers/tool-call-markup.d.ts +9 -7
- package/dist-lib/lib/helpers/tool-call-markup.js +36 -20
- package/dist-lib/lib/helpers/tool-intent.d.ts +3 -2
- package/dist-lib/lib/helpers/tool-intent.js +4 -2
- package/dist-lib/lib/helpers/tool-label.js +18 -9
- package/dist-lib/lib/hooks/built-in/arg-repair.js +23 -13
- package/dist-lib/lib/hooks/built-in/egress.js +2 -1
- package/dist-lib/lib/hooks/built-in/skill-catalog.js +2 -1
- package/dist-lib/lib/hooks/pipeline.d.ts +5 -4
- package/dist-lib/lib/hooks/pipeline.js +6 -3
- package/dist-lib/lib/hooks/run.js +12 -8
- package/dist-lib/lib/model-download-progress.js +10 -8
- package/dist-lib/lib/models/context.d.ts +1 -1
- package/dist-lib/lib/models/context.js +5 -1
- package/dist-lib/lib/models/custom-model-cache.d.ts +13 -0
- package/dist-lib/lib/models/custom-model-cache.js +70 -0
- package/dist-lib/lib/models/gguf-header.d.ts +31 -0
- package/dist-lib/lib/models/gguf-header.js +230 -0
- package/dist-lib/lib/models/idle-unload.d.ts +14 -0
- package/dist-lib/lib/models/idle-unload.js +51 -0
- package/dist-lib/lib/models/kv-cache.d.ts +3 -2
- package/dist-lib/lib/models/kv-cache.js +4 -3
- package/dist-lib/lib/models/llm-presets.d.ts +2 -2
- package/dist-lib/lib/models/llm-presets.js +4 -2
- package/dist-lib/lib/models/model-catalog-constants.js +3 -2
- package/dist-lib/lib/models/model-catalog.d.ts +19 -21
- package/dist-lib/lib/models/model-catalog.js +66 -33
- package/dist-lib/lib/models/model-delete.d.ts +4 -1
- package/dist-lib/lib/models/model-delete.js +30 -15
- package/dist-lib/lib/models/model-handle.js +2 -1
- package/dist-lib/lib/models/model-list.d.ts +14 -3
- package/dist-lib/lib/models/model-list.js +33 -6
- package/dist-lib/lib/models/model-pool.d.ts +44 -10
- package/dist-lib/lib/models/model-pool.js +47 -42
- package/dist-lib/lib/models/model-source.js +11 -6
- package/dist-lib/lib/models/music-catalog.d.ts +2 -2
- package/dist-lib/lib/models/nmt-catalog.d.ts +4 -3
- package/dist-lib/lib/models/nmt-catalog.js +10 -5
- package/dist-lib/lib/models/opencl-cache.d.ts +6 -1
- package/dist-lib/lib/models/opencl-cache.js +5 -3
- package/dist-lib/lib/models/sdk-faults.d.ts +11 -8
- package/dist-lib/lib/models/sdk-faults.js +9 -6
- package/dist-lib/lib/models/shards.d.ts +11 -0
- package/dist-lib/lib/models/shards.js +15 -0
- package/dist-lib/lib/models/tool-dialect.js +10 -5
- package/dist-lib/lib/no-redirect-fetch-bare.d.ts +3 -3
- package/dist-lib/lib/no-redirect-fetch-bare.js +1 -1
- package/dist-lib/lib/no-redirect-fetch-impl.js +6 -3
- package/dist-lib/lib/no-redirect-fetch-node.d.ts +1 -1
- package/dist-lib/lib/no-redirect-fetch-node.js +9 -9
- package/dist-lib/lib/office/index.d.ts +3 -2
- package/dist-lib/lib/office/python.d.ts +3 -2
- package/dist-lib/lib/office/python.js +2 -1
- package/dist-lib/lib/prompt.d.ts +5 -4
- package/dist-lib/lib/prompt.js +8 -4
- package/dist-lib/lib/queue.js +10 -5
- package/dist-lib/lib/resolution-detector.js +21 -11
- package/dist-lib/lib/rpc-session.js +2 -1
- package/dist-lib/lib/sdk-loader.js +2 -1
- package/dist-lib/lib/sdk-storage.js +4 -2
- package/dist-lib/lib/serve.js +128 -68
- package/dist-lib/lib/spawn.js +7 -4
- package/dist-lib/lib/tmp-path.d.ts +7 -6
- package/dist-lib/lib/tool-call-display.d.ts +2 -2
- package/dist-lib/lib/tools/create-documents.js +18 -10
- package/dist-lib/lib/tools/edit-documents.js +23 -13
- package/dist-lib/lib/tools/edit-image.d.ts +2 -2
- package/dist-lib/lib/tools/edit-image.js +60 -36
- package/dist-lib/lib/tools/exec/adapters/adapter.d.ts +10 -10
- package/dist-lib/lib/tools/exec/adapters/python/attachments.d.ts +17 -11
- package/dist-lib/lib/tools/exec/adapters/python/attachments.js +53 -40
- package/dist-lib/lib/tools/exec/adapters/python/create-effect.d.ts +2 -2
- package/dist-lib/lib/tools/exec/adapters/python/create-effect.js +60 -32
- package/dist-lib/lib/tools/exec/adapters/python/guarded-fetch.d.ts +33 -22
- package/dist-lib/lib/tools/exec/adapters/python/guarded-fetch.js +58 -29
- package/dist-lib/lib/tools/exec/adapters/python/interrupt-timer.d.ts +2 -2
- package/dist-lib/lib/tools/exec/adapters/python/loader.js +23 -12
- package/dist-lib/lib/tools/exec/adapters/python/memfs.d.ts +13 -11
- package/dist-lib/lib/tools/exec/adapters/python/memfs.js +10 -5
- package/dist-lib/lib/tools/exec/adapters/python/net-shim.js +3 -1
- package/dist-lib/lib/tools/exec/adapters/python/output-policy.d.ts +6 -4
- package/dist-lib/lib/tools/exec/adapters/python/output-policy.js +20 -10
- package/dist-lib/lib/tools/exec/adapters/python/pyodide.d.ts +2 -2
- package/dist-lib/lib/tools/exec/adapters/python/pyodide.js +14 -7
- package/dist-lib/lib/tools/exec/adapters/python/python-adapter.d.ts +41 -34
- package/dist-lib/lib/tools/exec/adapters/python/python-adapter.js +316 -166
- package/dist-lib/lib/tools/exec/adapters/python/run-session.d.ts +9 -8
- package/dist-lib/lib/tools/exec/adapters/python/run-session.js +56 -28
- package/dist-lib/lib/tools/exec/adapters/python/wheels.d.ts +8 -10
- package/dist-lib/lib/tools/exec/adapters/python/wheels.js +22 -11
- package/dist-lib/lib/tools/exec/adapters/python/worker/client.d.ts +3 -2
- package/dist-lib/lib/tools/exec/adapters/python/worker/client.js +41 -26
- package/dist-lib/lib/tools/exec/adapters/python/worker/entry.js +27 -18
- package/dist-lib/lib/tools/exec/adapters/python/worker/protocol.d.ts +2 -2
- package/dist-lib/lib/tools/exec/adapters/python/worker/protocol.js +14 -13
- package/dist-lib/lib/tools/exec/adapters/python/worker/spawn-node.d.ts +4 -4
- package/dist-lib/lib/tools/exec/adapters/python/worker/spawn-node.js +10 -5
- package/dist-lib/lib/tools/exec/adapters/shell/shell-adapter.d.ts +4 -4
- package/dist-lib/lib/tools/exec/adapters/shell/shell-adapter.js +2 -1
- package/dist-lib/lib/tools/exec/obsidian/cli-process.d.ts +6 -1
- package/dist-lib/lib/tools/exec/obsidian/cli-process.js +8 -5
- package/dist-lib/lib/tools/exec/obsidian/cli.d.ts +6 -6
- package/dist-lib/lib/tools/exec/obsidian/cli.js +4 -4
- package/dist-lib/lib/tools/exec/obsidian/command.d.ts +3 -2
- package/dist-lib/lib/tools/exec/obsidian/command.js +6 -3
- package/dist-lib/lib/tools/exec/obsidian/output.js +2 -1
- package/dist-lib/lib/tools/exec/obsidian/route.d.ts +4 -6
- package/dist-lib/lib/tools/exec/obsidian/route.js +17 -11
- package/dist-lib/lib/tools/exec/obsidian/safe-path.js +2 -1
- package/dist-lib/lib/tools/exec/obsidian/vault-create.js +15 -7
- package/dist-lib/lib/tools/exec/obsidian/vault-paths.d.ts +2 -2
- package/dist-lib/lib/tools/exec/obsidian/vault-paths.js +20 -10
- package/dist-lib/lib/tools/exec/obsidian/vault-read.js +20 -13
- package/dist-lib/lib/tools/exec/obsidian/vault-write.js +24 -12
- package/dist-lib/lib/tools/exec/runner.d.ts +14 -14
- package/dist-lib/lib/tools/exec/runner.js +5 -3
- package/dist-lib/lib/tools/exec/scope.js +52 -28
- package/dist-lib/lib/tools/exec/shell-argv.js +31 -18
- package/dist-lib/lib/tools/exec/shell-guidance.d.ts +6 -1
- package/dist-lib/lib/tools/exec/shell-guidance.js +35 -20
- package/dist-lib/lib/tools/exec/video-tools.js +2 -2
- package/dist-lib/lib/tools/exec.d.ts +6 -8
- package/dist-lib/lib/tools/exec.js +113 -54
- package/dist-lib/lib/tools/file-glob.d.ts +4 -5
- package/dist-lib/lib/tools/file-glob.js +16 -11
- package/dist-lib/lib/tools/fs/glob.js +13 -18
- package/dist-lib/lib/tools/fs/remote-protocol.d.ts +10 -10
- package/dist-lib/lib/tools/fs/remote.d.ts +3 -2
- package/dist-lib/lib/tools/fs/remote.js +13 -7
- package/dist-lib/lib/tools/fs/scope.d.ts +8 -3
- package/dist-lib/lib/tools/fs/scope.js +20 -12
- package/dist-lib/lib/tools/fs/walk.js +6 -3
- package/dist-lib/lib/tools/fs/write.d.ts +3 -2
- package/dist-lib/lib/tools/generate-image.d.ts +11 -9
- package/dist-lib/lib/tools/generate-image.js +73 -37
- package/dist-lib/lib/tools/generate-music.d.ts +22 -11
- package/dist-lib/lib/tools/generate-music.js +79 -48
- package/dist-lib/lib/tools/grep.js +66 -41
- package/dist-lib/lib/tools/http-request/encode-fields.js +18 -9
- package/dist-lib/lib/tools/http-request/{utils.js → request.js} +20 -11
- package/dist-lib/lib/tools/http-request/truncate-response.js +57 -46
- package/dist-lib/lib/tools/http-request.d.ts +1 -1
- package/dist-lib/lib/tools/http-request.js +33 -18
- package/dist-lib/lib/tools/mcp/protocol.d.ts +53 -0
- package/dist-lib/lib/tools/mcp/{utils.js → protocol.js} +45 -23
- package/dist-lib/lib/tools/mcp-call.d.ts +1 -1
- package/dist-lib/lib/tools/mcp-call.js +37 -16
- package/dist-lib/lib/tools/operations/builders.js +10 -6
- package/dist-lib/lib/tools/operations/compile.js +20 -10
- package/dist-lib/lib/tools/operations/decoders.js +12 -6
- package/dist-lib/lib/tools/operations/gmail-message.js +3 -2
- package/dist-lib/lib/tools/outbound-guard.d.ts +4 -3
- package/dist-lib/lib/tools/outbound-guard.js +14 -8
- package/dist-lib/lib/tools/private-ip.js +8 -7
- package/dist-lib/lib/tools/rag-search.js +14 -7
- package/dist-lib/lib/tools/read-files.js +23 -20
- package/dist-lib/lib/tools/skill.js +19 -10
- package/dist-lib/lib/tools/skills/auth-resolver.d.ts +11 -18
- package/dist-lib/lib/tools/skills/auth-resolver.js +30 -18
- package/dist-lib/lib/tools/skills/bin-check.d.ts +3 -2
- package/dist-lib/lib/tools/skills/bin-check.js +10 -3
- package/dist-lib/lib/tools/skills/bundled-dir.js +20 -10
- package/dist-lib/lib/tools/skills/bundled-hash.d.ts +3 -2
- package/dist-lib/lib/tools/skills/bundled-hash.js +6 -1
- package/dist-lib/lib/tools/skills/catalog.d.ts +3 -2
- package/dist-lib/lib/tools/skills/catalog.js +33 -28
- package/dist-lib/lib/tools/skills/cli-argv.d.ts +3 -2
- package/dist-lib/lib/tools/skills/cli-argv.js +55 -52
- package/dist-lib/lib/tools/skills/cli-schema-check.js +21 -10
- package/dist-lib/lib/tools/skills/cli-schema-load.js +28 -20
- package/dist-lib/lib/tools/skills/cli-schema-types.d.ts +6 -6
- package/dist-lib/lib/tools/skills/cli-schema.js +2 -1
- package/dist-lib/lib/tools/skills/credential-check.d.ts +6 -3
- package/dist-lib/lib/tools/skills/credential-check.js +24 -12
- package/dist-lib/lib/tools/skills/credential-grants.js +1 -6
- package/dist-lib/lib/tools/skills/credential-health.d.ts +5 -1
- package/dist-lib/lib/tools/skills/credential-health.js +5 -3
- package/dist-lib/lib/tools/skills/frontmatter-parser.js +10 -5
- package/dist-lib/lib/tools/skills/manifest-parse.js +84 -64
- package/dist-lib/lib/tools/skills/mention.js +7 -6
- package/dist-lib/lib/tools/skills/obsidian-readiness.d.ts +2 -2
- package/dist-lib/lib/tools/skills/obsidian-readiness.js +11 -3
- package/dist-lib/lib/tools/skills/overlay-crud.d.ts +6 -4
- package/dist-lib/lib/tools/skills/overlay-crud.js +12 -6
- package/dist-lib/lib/tools/skills/overlay-dir.js +4 -2
- package/dist-lib/lib/tools/skills/overlay-watch.d.ts +3 -2
- package/dist-lib/lib/tools/skills/overlay-watch.js +8 -4
- package/dist-lib/lib/tools/skills/setup-routes.js +1 -3
- package/dist-lib/lib/tools/skills/skill-settings.js +4 -1
- package/dist-lib/lib/tools/skills/skill-state.d.ts +6 -11
- package/dist-lib/lib/tools/skills/skill-state.js +48 -29
- package/dist-lib/lib/tools/skills/tool-grants.js +6 -3
- package/dist-lib/lib/tools/toolsets.js +2 -1
- package/dist-lib/lib/tools/translate.d.ts +4 -5
- package/dist-lib/lib/tools/translate.js +31 -14
- package/dist-lib/lib/tools/url-guard.js +2 -1
- package/dist-lib/lib/tools/weather-lookup/place.js +8 -4
- package/dist-lib/lib/tools/weather-lookup/report.d.ts +7 -1
- package/dist-lib/lib/tools/weather-lookup/report.js +46 -9
- package/dist-lib/lib/tools/weather-lookup.js +18 -12
- package/dist-lib/lib/tools/web-fetch.js +47 -24
- package/dist-lib/lib/tools/web-search.js +8 -3
- package/dist-lib/lib/validating-lookup.d.ts +4 -4
- package/dist-lib/lib/wav-encode.d.ts +1 -1
- package/dist-lib/lib/wav-encode.js +11 -10
- package/dist-lib/lib/web-fetch/embedded-state.js +24 -12
- package/dist-lib/lib/web-fetch/extract.js +4 -2
- package/dist-lib/lib/web-fetch/images.js +8 -4
- package/dist-lib/lib/web-fetch/video.d.ts +2 -2
- package/dist-lib/lib/web-fetch/video.js +8 -4
- package/dist-lib/lib/web-search/engine-registry.d.ts +2 -2
- package/dist-lib/lib/web-search/engines/aol.js +1 -1
- package/dist-lib/lib/web-search/engines/bing.js +1 -1
- package/dist-lib/lib/web-search/engines/brave.js +4 -1
- package/dist-lib/lib/web-search/engines/duckduckgo.js +3 -2
- package/dist-lib/lib/web-search/engines/google.js +7 -3
- package/dist-lib/lib/web-search/engines/wikipedia.js +5 -4
- package/dist-lib/lib/web-search/engines/yahoo.js +1 -1
- package/dist-lib/lib/web-search/fetch-html.d.ts +5 -4
- package/dist-lib/lib/web-search/fetch-html.js +13 -7
- package/dist-lib/lib/web-search/orchestrator.d.ts +9 -5
- package/dist-lib/lib/web-search/orchestrator.js +3 -3
- package/dist-lib/lib/wire.d.ts +3 -2
- package/dist-lib/lib/wire.js +23 -15
- package/dist-lib/schema/baseline.js +10 -5
- package/dist-lib/schema/build.js +2 -1
- package/dist-lib/schema/harness.d.ts +15 -2
- package/dist-lib/schema/harness.js +55 -2
- package/dist-lib/schema/release-tags.d.ts +3 -2
- package/dist-lib/schema/release-tags.js +6 -3
- package/dist-lib/spec/bind.js +6 -0
- package/dist-lib/spec/calls.js +2 -0
- package/dist-lib/spec/hrpc/hrpc.json +26 -0
- package/dist-lib/spec/hrpc/index.js +27 -3
- package/dist-lib/spec/hrpc/messages.js +207 -8
- package/dist-lib/spec/hyperschema/index.js +207 -8
- package/dist-lib/spec/hyperschema/schema.json +165 -1
- package/dist-lib/spec/hyperschema/types.d.ts +42 -1
- package/package.json +13 -14
- package/worker/harness-sidecar.mjs +16 -22
- package/worker/stow-entry.mjs +7 -4
- package/dist-lib/lib/tools/mcp/utils.d.ts +0 -47
- /package/dist-lib/lib/tools/http-request/{utils.d.ts → request.d.ts} +0 -0
|
@@ -32,8 +32,9 @@ function operationTool(owningSkill, operation, transportTool) {
|
|
|
32
32
|
async execute(args, ctx) {
|
|
33
33
|
const skillContext = { ...ctx, skills: [owningSkill] };
|
|
34
34
|
const built = builder.build(args);
|
|
35
|
-
if ('error' in built)
|
|
35
|
+
if ('error' in built) {
|
|
36
36
|
return { error: `${operation.tool}: ${built.error}` };
|
|
37
|
+
}
|
|
37
38
|
if (read && (built.request.body !== undefined || built.request.encode !== undefined)) {
|
|
38
39
|
return { error: `${operation.tool}: a read operation cannot send a body` };
|
|
39
40
|
}
|
|
@@ -42,8 +43,9 @@ function operationTool(owningSkill, operation, transportTool) {
|
|
|
42
43
|
return transportTool.execute({ url: request.url, method: request.method, params: built.request.params }, skillContext);
|
|
43
44
|
}
|
|
44
45
|
const url = fillTemplate(request.url, args, request.urlDefaults);
|
|
45
|
-
if ('error' in url)
|
|
46
|
+
if ('error' in url) {
|
|
46
47
|
return { error: `${operation.tool}: ${url.error}` };
|
|
48
|
+
}
|
|
47
49
|
const { response } = operation;
|
|
48
50
|
const result = await transportTool.execute({
|
|
49
51
|
url: url.value,
|
|
@@ -59,20 +61,24 @@ function operationTool(owningSkill, operation, transportTool) {
|
|
|
59
61
|
const JsonResult = z.looseObject({ status: z.number().optional(), body: z.string() });
|
|
60
62
|
function capBody(result) {
|
|
61
63
|
const parsed = JsonResult.safeParse(result);
|
|
62
|
-
if (!parsed.success)
|
|
64
|
+
if (!parsed.success) {
|
|
63
65
|
return result;
|
|
66
|
+
}
|
|
64
67
|
return { ...parsed.data, body: truncateResponseBody(parsed.data.body) };
|
|
65
68
|
}
|
|
66
69
|
function shapeResponse(result, response) {
|
|
67
70
|
const parsed = JsonResult.safeParse(result);
|
|
68
|
-
if (!parsed.success)
|
|
71
|
+
if (!parsed.success) {
|
|
69
72
|
return result;
|
|
73
|
+
}
|
|
70
74
|
const { status } = parsed.data;
|
|
71
|
-
if (status !== undefined && status >= 400)
|
|
75
|
+
if (status !== undefined && status >= 400) {
|
|
72
76
|
return result;
|
|
77
|
+
}
|
|
73
78
|
const body = jsonObject(parsed.data.body);
|
|
74
|
-
if (!body)
|
|
79
|
+
if (!body) {
|
|
75
80
|
return result;
|
|
81
|
+
}
|
|
76
82
|
const shaped = 'pick' in response ? pick(body, response.pick) : DECODERS[response.decode].decode(body);
|
|
77
83
|
return { ...parsed.data, body: JSON.stringify(shaped) };
|
|
78
84
|
}
|
|
@@ -87,9 +93,11 @@ function jsonObject(body) {
|
|
|
87
93
|
}
|
|
88
94
|
function pick(body, keys) {
|
|
89
95
|
const picked = {};
|
|
90
|
-
for (const key of keys)
|
|
91
|
-
if (key in body)
|
|
96
|
+
for (const key of keys) {
|
|
97
|
+
if (key in body) {
|
|
92
98
|
picked[key] = body[key];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
93
101
|
return picked;
|
|
94
102
|
}
|
|
95
103
|
const PLACEHOLDER = /\{(\w+)\}/g;
|
|
@@ -97,12 +105,14 @@ function fillTemplate(template, args, defaults) {
|
|
|
97
105
|
const missing = [];
|
|
98
106
|
const value = template.replace(PLACEHOLDER, (_match, name) => {
|
|
99
107
|
const filled = args[name] ?? defaults?.[name];
|
|
100
|
-
if (filled === undefined)
|
|
108
|
+
if (filled === undefined) {
|
|
101
109
|
missing.push(name);
|
|
110
|
+
}
|
|
102
111
|
return encodeURIComponent(String(filled));
|
|
103
112
|
});
|
|
104
|
-
if (missing.length)
|
|
113
|
+
if (missing.length) {
|
|
105
114
|
return { error: `missing required argument ${missing.join(', ')}` };
|
|
115
|
+
}
|
|
106
116
|
return { value };
|
|
107
117
|
}
|
|
108
118
|
function hostOf(url) {
|
|
@@ -23,8 +23,9 @@ const MessageSchema = z.object({
|
|
|
23
23
|
const gmailMessage = {
|
|
24
24
|
decode(body) {
|
|
25
25
|
const parsed = MessageSchema.safeParse(body);
|
|
26
|
-
if (!parsed.success)
|
|
26
|
+
if (!parsed.success) {
|
|
27
27
|
return body;
|
|
28
|
+
}
|
|
28
29
|
const { id, threadId, labelIds, snippet, payload } = parsed.data;
|
|
29
30
|
return {
|
|
30
31
|
id,
|
|
@@ -40,27 +41,32 @@ function keptHeaders(part) {
|
|
|
40
41
|
const kept = {};
|
|
41
42
|
for (const header of part.headers ?? []) {
|
|
42
43
|
const name = KEPT_HEADERS.find((known) => known.toLowerCase() === header.name.toLowerCase());
|
|
43
|
-
if (name && !(name in kept))
|
|
44
|
+
if (name && !(name in kept)) {
|
|
44
45
|
kept[name] = header.value;
|
|
46
|
+
}
|
|
45
47
|
}
|
|
46
48
|
return kept;
|
|
47
49
|
}
|
|
48
50
|
function textOf(part) {
|
|
49
51
|
const plain = leaves(part, 'text/plain');
|
|
50
|
-
if (plain.length)
|
|
52
|
+
if (plain.length) {
|
|
51
53
|
return plain.join('\n\n');
|
|
54
|
+
}
|
|
52
55
|
const html = leaves(part, 'text/html')
|
|
53
56
|
.map((leaf) => extractPageText(leaf).text)
|
|
54
57
|
.filter((text) => text.length > 0);
|
|
55
|
-
if (html.length)
|
|
58
|
+
if (html.length) {
|
|
56
59
|
return html.join('\n\n');
|
|
60
|
+
}
|
|
57
61
|
return undefined;
|
|
58
62
|
}
|
|
59
63
|
function leaves(part, mimeType) {
|
|
60
|
-
if (part.parts?.length)
|
|
64
|
+
if (part.parts?.length) {
|
|
61
65
|
return part.parts.flatMap((child) => leaves(child, mimeType));
|
|
62
|
-
|
|
66
|
+
}
|
|
67
|
+
if (part.mimeType?.toLowerCase() !== mimeType || part.filename || !part.body?.data) {
|
|
63
68
|
return [];
|
|
69
|
+
}
|
|
64
70
|
const text = decodeData(part.body.data);
|
|
65
71
|
return text ? [text] : [];
|
|
66
72
|
}
|
|
@@ -14,7 +14,7 @@ export const GmailEnvelopeSchema = z
|
|
|
14
14
|
inReplyTo: z.string().optional(),
|
|
15
15
|
references: z.string().optional()
|
|
16
16
|
})
|
|
17
|
-
.refine((value) =>
|
|
17
|
+
.refine((value) => !!value.text?.length || !!value.html?.length);
|
|
18
18
|
export function buildGmailMessage(envelope) {
|
|
19
19
|
return [...headerLines(envelope), ...bodyLines(envelope)].join('\r\n');
|
|
20
20
|
}
|
|
@@ -31,8 +31,9 @@ function joinAddresses(value) {
|
|
|
31
31
|
}
|
|
32
32
|
function encodeHeaderValue(value) {
|
|
33
33
|
const sanitized = stripNewlines(value);
|
|
34
|
-
if (/^[\x20-\x7e]*$/.test(sanitized))
|
|
34
|
+
if (/^[\x20-\x7e]*$/.test(sanitized)) {
|
|
35
35
|
return sanitized;
|
|
36
|
+
}
|
|
36
37
|
return `=?UTF-8?B?${b4a.toString(b4a.from(sanitized, 'utf8'), 'base64')}?=`;
|
|
37
38
|
}
|
|
38
39
|
function headerLines(envelope) {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
export declare const REFUSAL = "Refusing to send:";
|
|
2
2
|
export type TrustedOrigin = 'user' | 'tool-result' | 'skill';
|
|
3
|
-
export
|
|
3
|
+
export interface TrustedSource {
|
|
4
4
|
origin: TrustedOrigin;
|
|
5
5
|
text: string;
|
|
6
|
-
}
|
|
6
|
+
}
|
|
7
7
|
export interface GuardOptions {
|
|
8
|
+
readonly sources: readonly TrustedSource[];
|
|
8
9
|
externalWrite?: boolean;
|
|
9
10
|
}
|
|
10
|
-
export declare function guardToolCall(toolName: string, args: Record<string, unknown>, sources
|
|
11
|
+
export declare function guardToolCall(toolName: string, args: Record<string, unknown>, { sources, externalWrite }: GuardOptions): string | null;
|
|
@@ -9,20 +9,22 @@ const OUTBOUND_TOOLS = new Set(['http_request', 'mcp_call']);
|
|
|
9
9
|
const MCP_READ_METHOD = /^(tools\/list|resources\/\w+|(get|list|search|read|find|fetch)[_.-])/i;
|
|
10
10
|
const HINT_LIMIT = 5;
|
|
11
11
|
export const REFUSAL = 'Refusing to send:';
|
|
12
|
-
export function guardToolCall(toolName, args, sources,
|
|
12
|
+
export function guardToolCall(toolName, args, { sources, externalWrite = false }) {
|
|
13
13
|
if (!externalWrite && !isOutbound(toolName, args))
|
|
14
14
|
return null;
|
|
15
15
|
const addresses = unique(scanPayload(args));
|
|
16
|
-
if (!addresses.length)
|
|
16
|
+
if (!addresses.length) {
|
|
17
17
|
return null;
|
|
18
|
+
}
|
|
18
19
|
const reserved = addresses.find((value) => isReserved(key(value)));
|
|
19
20
|
if (reserved) {
|
|
20
21
|
return `${REFUSAL} ${mask(reserved)} is a reserved documentation domain (RFC 2606) that cannot receive mail — a placeholder copied from an example, not a real address. Ask the user for the actual address.`;
|
|
21
22
|
}
|
|
22
23
|
const trusted = addressesIn(sources, (origin) => origin !== 'skill');
|
|
23
24
|
const unverified = addresses.filter((value) => !grounded(value, trusted).ok);
|
|
24
|
-
if (!unverified.length)
|
|
25
|
+
if (!unverified.length) {
|
|
25
26
|
return null;
|
|
27
|
+
}
|
|
26
28
|
if (alreadyRefusedThisTurn(sources)) {
|
|
27
29
|
return `${REFUSAL} ${masked(unverified)} still cannot be verified, and an earlier call in this turn was already refused for the same reason. Stop calling this tool. Reply to the user in plain text and ask them for the address.`;
|
|
28
30
|
}
|
|
@@ -32,8 +34,9 @@ export function guardToolCall(toolName, args, sources, { externalWrite = false }
|
|
|
32
34
|
return `${REFUSAL} ${masked(placeholders)} appears only in the skill's own documentation — an example placeholder, not a real address. Ask the user for the actual address.`;
|
|
33
35
|
}
|
|
34
36
|
const spoofed = unverified.filter((value) => lookalikeOf(value, trusted) !== undefined);
|
|
35
|
-
if (spoofed.length)
|
|
37
|
+
if (spoofed.length) {
|
|
36
38
|
return drawnLike(spoofed, trusted);
|
|
39
|
+
}
|
|
37
40
|
return invented(unverified, trusted);
|
|
38
41
|
}
|
|
39
42
|
function lookalikeOf(value, trusted) {
|
|
@@ -53,8 +56,9 @@ function invented(unverified, trusted) {
|
|
|
53
56
|
function alreadyRefusedThisTurn(sources) {
|
|
54
57
|
let turnStart = 0;
|
|
55
58
|
for (const [index, source] of sources.entries()) {
|
|
56
|
-
if (source.origin === 'user')
|
|
59
|
+
if (source.origin === 'user') {
|
|
57
60
|
turnStart = index + 1;
|
|
61
|
+
}
|
|
58
62
|
}
|
|
59
63
|
return sources
|
|
60
64
|
.slice(turnStart)
|
|
@@ -63,9 +67,10 @@ function alreadyRefusedThisTurn(sources) {
|
|
|
63
67
|
function isOutbound(toolName, args) {
|
|
64
68
|
if (!OUTBOUND_TOOLS.has(toolName))
|
|
65
69
|
return false;
|
|
66
|
-
const method = typeof args
|
|
67
|
-
if (toolName !== 'http_request')
|
|
70
|
+
const method = typeof args.method === 'string' ? args.method : undefined;
|
|
71
|
+
if (toolName !== 'http_request') {
|
|
68
72
|
return !MCP_READ_METHOD.test(method ?? '');
|
|
73
|
+
}
|
|
69
74
|
return !READ_METHODS.has((method ?? 'GET').toUpperCase());
|
|
70
75
|
}
|
|
71
76
|
const IDENTIFIER_HEADER = /^\s*(message-id|in-reply-to|references)\s*:/i;
|
|
@@ -107,8 +112,9 @@ function addressesIn(sources, accept) {
|
|
|
107
112
|
function unique(values) {
|
|
108
113
|
const seen = new Map();
|
|
109
114
|
for (const value of values) {
|
|
110
|
-
if (!seen.has(key(value)))
|
|
115
|
+
if (!seen.has(key(value))) {
|
|
111
116
|
seen.set(key(value), value.trim());
|
|
117
|
+
}
|
|
112
118
|
}
|
|
113
119
|
return [...seen.values()];
|
|
114
120
|
}
|
|
@@ -41,13 +41,14 @@ export function isPrivateOrBlockedIPv6(address) {
|
|
|
41
41
|
if (isAllZeroBytes(bytes, 0, 12)) {
|
|
42
42
|
return isPrivateIPv4(embeddedIPv4);
|
|
43
43
|
}
|
|
44
|
-
|
|
44
|
+
const [first = 0, second = 0] = bytes;
|
|
45
|
+
if ((first & 0xfe) === 0xfc) {
|
|
45
46
|
return true;
|
|
46
47
|
}
|
|
47
|
-
if (
|
|
48
|
+
if (first === 0xfe && ((second & 0xc0) === 0x80 || (second & 0xc0) === 0xc0)) {
|
|
48
49
|
return true;
|
|
49
50
|
}
|
|
50
|
-
return
|
|
51
|
+
return first === 0xff;
|
|
51
52
|
}
|
|
52
53
|
function parseIPv6ToBytes(lower) {
|
|
53
54
|
const zoneless = lower.split('%')[0] ?? '';
|
|
@@ -67,8 +68,7 @@ function parseIPv6ToBytes(lower) {
|
|
|
67
68
|
}
|
|
68
69
|
const groups = [...headGroups, ...Array(zeroFill).fill('0'), ...tailGroups];
|
|
69
70
|
const bytes = new Uint8Array(16);
|
|
70
|
-
for (
|
|
71
|
-
const group = groups[i];
|
|
71
|
+
for (const [i, group] of groups.entries()) {
|
|
72
72
|
if (!/^[0-9a-f]{1,4}$/.test(group)) {
|
|
73
73
|
return null;
|
|
74
74
|
}
|
|
@@ -94,8 +94,9 @@ function expandEmbeddedIPv4(groups) {
|
|
|
94
94
|
if (octets.some((n) => n > 255)) {
|
|
95
95
|
return null;
|
|
96
96
|
}
|
|
97
|
-
const
|
|
98
|
-
const
|
|
97
|
+
const [a = 0, b = 0, c = 0, d = 0] = octets;
|
|
98
|
+
const hi = ((a << 8) | b).toString(16);
|
|
99
|
+
const lo = ((c << 8) | d).toString(16);
|
|
99
100
|
return [...groups.slice(0, -1), hi, lo];
|
|
100
101
|
}
|
|
101
102
|
function isAllZeroBytes(bytes, start, end) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { errorMessage } from '../guards.js';
|
|
1
2
|
import { RAG_CITATION_LINE } from '../prompt.js';
|
|
2
3
|
const DEFAULT_LIMIT = 5;
|
|
3
4
|
const MAX_LIMIT = 20;
|
|
@@ -31,24 +32,29 @@ export function createRagSearchTool() {
|
|
|
31
32
|
if (typeof query !== 'string' || query.trim().length === 0) {
|
|
32
33
|
return { error: 'query must be a non-empty string' };
|
|
33
34
|
}
|
|
34
|
-
if (!ctx?.ragSearch)
|
|
35
|
+
if (!ctx?.ragSearch) {
|
|
35
36
|
return { content: NOT_AVAILABLE };
|
|
37
|
+
}
|
|
36
38
|
let result;
|
|
37
39
|
try {
|
|
38
40
|
result = await ctx.ragSearch({ query, limit: limitFrom(args.limit) });
|
|
39
41
|
}
|
|
40
42
|
catch (err) {
|
|
41
|
-
return { error: `rag_search failed: ${
|
|
43
|
+
return { error: `rag_search failed: ${errorMessage(err)}` };
|
|
42
44
|
}
|
|
43
|
-
if (!result.enabled)
|
|
45
|
+
if (!result.enabled) {
|
|
44
46
|
return { content: NOT_AVAILABLE };
|
|
45
|
-
|
|
47
|
+
}
|
|
48
|
+
if (result.errorMessage) {
|
|
46
49
|
return { error: `rag_search failed: ${result.errorMessage}` };
|
|
50
|
+
}
|
|
47
51
|
if (result.hits.length === 0) {
|
|
48
|
-
if (!result.hasKnowledge)
|
|
52
|
+
if (!result.hasKnowledge) {
|
|
49
53
|
return { content: NO_DOCUMENTS };
|
|
50
|
-
|
|
54
|
+
}
|
|
55
|
+
if (result.indexEmpty || result.pendingReferenced) {
|
|
51
56
|
return { content: STILL_SYNCING };
|
|
57
|
+
}
|
|
52
58
|
return { content: NO_RELEVANT };
|
|
53
59
|
}
|
|
54
60
|
return { content: formatHits(result.hits) };
|
|
@@ -77,8 +83,9 @@ function parseMetadata(raw) {
|
|
|
77
83
|
return {};
|
|
78
84
|
try {
|
|
79
85
|
const parsed = JSON.parse(raw);
|
|
80
|
-
if (typeof parsed !== 'object' || parsed === null)
|
|
86
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
81
87
|
return {};
|
|
88
|
+
}
|
|
82
89
|
return {
|
|
83
90
|
title: 'title' in parsed && typeof parsed.title === 'string' ? parsed.title : undefined,
|
|
84
91
|
chunkIndex: 'chunkIndex' in parsed &&
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { errorMessage, isRecord } from '../guards.js';
|
|
1
2
|
import { readLines } from './fs/read.js';
|
|
2
3
|
import { isDriveReadTruncated } from './fs/remote.js';
|
|
3
4
|
import { canonicalDenyRoots, defaultRealpath, resolveKey } from './fs/scope.js';
|
|
@@ -7,8 +8,9 @@ function lineIndex(value) {
|
|
|
7
8
|
if (value === undefined || value === null)
|
|
8
9
|
return undefined;
|
|
9
10
|
const n = Number(value);
|
|
10
|
-
if (!Number.isInteger(n) || n < 1)
|
|
11
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
11
12
|
return null;
|
|
13
|
+
}
|
|
12
14
|
return n;
|
|
13
15
|
}
|
|
14
16
|
function fileRequests(raw) {
|
|
@@ -16,22 +18,19 @@ function fileRequests(raw) {
|
|
|
16
18
|
return null;
|
|
17
19
|
const files = [];
|
|
18
20
|
for (const entry of raw) {
|
|
19
|
-
|
|
20
|
-
if (typeof record?.path !== 'string' || !record.path.trim())
|
|
21
|
+
if (!isRecord(entry) || typeof entry.path !== 'string' || !entry.path.trim()) {
|
|
21
22
|
return null;
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
|
|
23
|
+
}
|
|
24
|
+
const startLine = lineIndex(entry.startLine);
|
|
25
|
+
const endLine = lineIndex(entry.endLine);
|
|
26
|
+
if (startLine === null || endLine === null) {
|
|
25
27
|
return null;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
...(startLine !== undefined ? { startLine } : {}),
|
|
29
|
-
...(endLine !== undefined ? { endLine } : {})
|
|
30
|
-
});
|
|
28
|
+
}
|
|
29
|
+
files.push({ path: entry.path, startLine, endLine });
|
|
31
30
|
}
|
|
32
31
|
return files;
|
|
33
32
|
}
|
|
34
|
-
async function slice(drive, key, request, maxChars) {
|
|
33
|
+
async function slice(drive, key, { request, maxChars }) {
|
|
35
34
|
const first = request.startLine ?? 1;
|
|
36
35
|
const last = request.endLine ?? Infinity;
|
|
37
36
|
const kept = [];
|
|
@@ -46,13 +45,15 @@ async function slice(drive, key, request, maxChars) {
|
|
|
46
45
|
break;
|
|
47
46
|
kept.push(line);
|
|
48
47
|
length += line.length + (kept.length > 1 ? 1 : 0);
|
|
49
|
-
if (length > maxChars)
|
|
48
|
+
if (length > maxChars) {
|
|
50
49
|
break;
|
|
50
|
+
}
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
catch (err) {
|
|
54
|
-
if (!isDriveReadTruncated(err))
|
|
54
|
+
if (!isDriveReadTruncated(err)) {
|
|
55
55
|
throw err;
|
|
56
|
+
}
|
|
56
57
|
capped = true;
|
|
57
58
|
}
|
|
58
59
|
const text = kept.join('\n');
|
|
@@ -107,8 +108,9 @@ export function createReadFilesTool({ realpath = defaultRealpath, deniedRoots }
|
|
|
107
108
|
},
|
|
108
109
|
resource(args) {
|
|
109
110
|
const files = fileRequests(args.files);
|
|
110
|
-
if (!files)
|
|
111
|
+
if (!files) {
|
|
111
112
|
return null;
|
|
113
|
+
}
|
|
112
114
|
const label = files
|
|
113
115
|
.map((f) => f.path)
|
|
114
116
|
.slice(0, 3)
|
|
@@ -121,14 +123,15 @@ export function createReadFilesTool({ realpath = defaultRealpath, deniedRoots }
|
|
|
121
123
|
async execute(rawArgs, ctx) {
|
|
122
124
|
const roots = ctx?.fsRoots ?? [];
|
|
123
125
|
const requests = fileRequests(rawArgs.files);
|
|
124
|
-
if (!requests)
|
|
126
|
+
if (!requests) {
|
|
125
127
|
return { error: 'files must be a non-empty array of { path }' };
|
|
128
|
+
}
|
|
126
129
|
const maxChars = rawArgs.maxChars ? Number(rawArgs.maxChars) : DEFAULT_READ_CHARS;
|
|
127
130
|
const files = [];
|
|
128
131
|
const failed = [];
|
|
129
132
|
const deny = await canonicalDenyRoots(deniedRoots, realpath);
|
|
130
133
|
for (const request of requests) {
|
|
131
|
-
const resolved = await resolveKey(request.path, roots, realpath, deny);
|
|
134
|
+
const resolved = await resolveKey(request.path, roots, { realpath, deny });
|
|
132
135
|
if ('error' in resolved) {
|
|
133
136
|
failed.push({ path: request.path, error: resolved.error });
|
|
134
137
|
continue;
|
|
@@ -140,14 +143,14 @@ export function createReadFilesTool({ realpath = defaultRealpath, deniedRoots }
|
|
|
140
143
|
}
|
|
141
144
|
files.push({
|
|
142
145
|
path: request.path,
|
|
143
|
-
...(await slice(resolved.root.drive, resolved.key, request, maxChars))
|
|
146
|
+
...(await slice(resolved.root.drive, resolved.key, { request, maxChars }))
|
|
144
147
|
});
|
|
145
148
|
}
|
|
146
149
|
catch (err) {
|
|
147
|
-
failed.push({ path: request.path, error: err
|
|
150
|
+
failed.push({ path: request.path, error: errorMessage(err) });
|
|
148
151
|
}
|
|
149
152
|
}
|
|
150
|
-
return { files,
|
|
153
|
+
return { files, failed: failed.length ? failed : undefined };
|
|
151
154
|
}
|
|
152
155
|
};
|
|
153
156
|
}
|
|
@@ -40,8 +40,9 @@ function toolNote(tools) {
|
|
|
40
40
|
const grants = [];
|
|
41
41
|
for (const entry of tools) {
|
|
42
42
|
const { name } = parseToolGrant(entry);
|
|
43
|
-
if (!grants.includes(name))
|
|
43
|
+
if (!grants.includes(name)) {
|
|
44
44
|
grants.push(name);
|
|
45
|
+
}
|
|
45
46
|
}
|
|
46
47
|
return [
|
|
47
48
|
`You can now call: ${grants.join(', ')}.`,
|
|
@@ -49,17 +50,21 @@ function toolNote(tools) {
|
|
|
49
50
|
'anything, open another app, or run code themselves.'
|
|
50
51
|
].join(' ');
|
|
51
52
|
}
|
|
53
|
+
async function addSkillFiles(files, drive, name) {
|
|
54
|
+
for await (const entry of drive.list(`/${name}`)) {
|
|
55
|
+
const rel = String(entry.key).slice(name.length + 2);
|
|
56
|
+
if (rel && rel !== 'SKILL.md') {
|
|
57
|
+
files.add(rel);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
52
61
|
async function listSkillFiles(drives, name) {
|
|
53
62
|
const files = new Set();
|
|
54
63
|
for (const drive of drives) {
|
|
55
64
|
if (!drive)
|
|
56
65
|
continue;
|
|
57
66
|
try {
|
|
58
|
-
|
|
59
|
-
const rel = String(entry.key).slice(name.length + 2);
|
|
60
|
-
if (rel && rel !== 'SKILL.md')
|
|
61
|
-
files.add(rel);
|
|
62
|
-
}
|
|
67
|
+
await addSkillFiles(files, drive, name);
|
|
63
68
|
}
|
|
64
69
|
catch {
|
|
65
70
|
}
|
|
@@ -75,23 +80,26 @@ async function vaultModeNote(name, credentialStore, ctx) {
|
|
|
75
80
|
return null;
|
|
76
81
|
const record = credentialRecord(await credentialStore(OBSIDIAN_VAULT_PATH_CREDENTIAL_KEY, { ...ctx, skills: [name] }));
|
|
77
82
|
const token = record?.token?.trim();
|
|
78
|
-
if (!token || !isObsidianVaultPath(token))
|
|
83
|
+
if (!token || !isObsidianVaultPath(token)) {
|
|
79
84
|
return null;
|
|
85
|
+
}
|
|
80
86
|
return OBSIDIAN_VAULT_MODE_NOTE;
|
|
81
87
|
}
|
|
82
88
|
export function createSkillTool({ skillsDir, overlayDir = resolveSkillsOverlayDir(), read, credentialStore } = {}) {
|
|
83
89
|
const baseDrive = skillsDir ? new Localdrive(skillsDir) : null;
|
|
84
90
|
const overlayDrive = overlayDir ? new Localdrive(overlayDir) : null;
|
|
85
91
|
async function resolveSkill(name, file) {
|
|
86
|
-
if (read)
|
|
92
|
+
if (read) {
|
|
87
93
|
return { raw: await read(name, file), root: skillsDir };
|
|
94
|
+
}
|
|
88
95
|
for (const [drive, root] of [
|
|
89
96
|
[overlayDrive, overlayDir],
|
|
90
97
|
[baseDrive, skillsDir]
|
|
91
98
|
]) {
|
|
92
99
|
const buf = drive ? await drive.get(`/${name}/${file}`) : null;
|
|
93
|
-
if (buf)
|
|
100
|
+
if (buf) {
|
|
94
101
|
return { raw: b4a.toString(buf, 'utf8'), root: root ?? undefined };
|
|
102
|
+
}
|
|
95
103
|
}
|
|
96
104
|
throw new Error(`ENOENT: ${name}/${file}`);
|
|
97
105
|
}
|
|
@@ -154,8 +162,9 @@ export function createSkillTool({ skillsDir, overlayDir = resolveSkillsOverlayDi
|
|
|
154
162
|
return await load(file);
|
|
155
163
|
}
|
|
156
164
|
catch {
|
|
157
|
-
if (file === MAIN_FILE)
|
|
165
|
+
if (file === MAIN_FILE) {
|
|
158
166
|
return { error: `skill not found: ${name}` };
|
|
167
|
+
}
|
|
159
168
|
const available = await listSkillFiles([overlayDrive, baseDrive], name);
|
|
160
169
|
const near = nearestFile(file, available);
|
|
161
170
|
if (near !== null) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AbortSignal as BareAbortSignal } from 'bare-abort-controller';
|
|
2
2
|
import type { ToolExecuteContext } from '../../capabilities/completion.ts';
|
|
3
|
-
import { type ParseResult } from '../http-request/
|
|
3
|
+
import { type ParseResult } from '../http-request/request.ts';
|
|
4
4
|
export interface HttpRequestAuth {
|
|
5
5
|
type: 'bearer';
|
|
6
6
|
tokenCredentialKey: string;
|
|
@@ -17,28 +17,21 @@ export type CredentialAllowList = Record<string, string | string[]>;
|
|
|
17
17
|
export declare function urlAllowed(url: URL, patterns: readonly string[]): boolean;
|
|
18
18
|
export declare function isCredentialUrlAllowed(target: string, patterns: readonly string[]): boolean;
|
|
19
19
|
export type CredentialAllowListFn = (ctx?: ToolExecuteContext) => CredentialAllowList;
|
|
20
|
-
export
|
|
20
|
+
export interface ResolvedCredential {
|
|
21
21
|
readonly token: string;
|
|
22
22
|
readonly key: string;
|
|
23
|
-
}
|
|
23
|
+
}
|
|
24
|
+
export interface AuthError {
|
|
24
25
|
readonly error: string;
|
|
25
|
-
}
|
|
26
|
+
}
|
|
27
|
+
export type AuthOutcome = ResolvedCredential | AuthError;
|
|
26
28
|
export declare function parseAuth(v: unknown): ParseResult<HttpRequestAuth>;
|
|
27
29
|
export declare function resolveAuth(auth: HttpRequestAuth, url: URL, credentialStore: CredentialStoreFn | undefined, credentialAllowList: CredentialAllowList | undefined, ctx: ToolExecuteContext | undefined): Promise<AuthOutcome>;
|
|
28
|
-
export declare function resolveAutoAuth(url: URL, credentialStore: CredentialStoreFn | undefined, credentialAllowList: CredentialAllowList | undefined, ctx: ToolExecuteContext | undefined): Promise<
|
|
29
|
-
|
|
30
|
-
key: string;
|
|
31
|
-
} | {
|
|
32
|
-
error: string;
|
|
33
|
-
} | null>;
|
|
34
|
-
export type BearerOutcome = {
|
|
30
|
+
export declare function resolveAutoAuth(url: URL, credentialStore: CredentialStoreFn | undefined, credentialAllowList: CredentialAllowList | undefined, ctx: ToolExecuteContext | undefined): Promise<AuthOutcome | null>;
|
|
31
|
+
export interface BearerHeader {
|
|
35
32
|
readonly header: string | null;
|
|
36
33
|
readonly credentialKey?: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
};
|
|
34
|
+
}
|
|
35
|
+
export type BearerOutcome = BearerHeader | AuthError;
|
|
40
36
|
export declare function resolveBearerHeader(auth: HttpRequestAuth | undefined, url: URL, credentialStore: CredentialStoreFn | undefined, credentialAllowList: CredentialAllowList | undefined, ctx: ToolExecuteContext | undefined, signal: BareAbortSignal): Promise<BearerOutcome>;
|
|
41
|
-
export declare function resolveRedirectBearerHeader(auth: HttpRequestAuth | undefined, url: URL, credentialStore: CredentialStoreFn | undefined, credentialAllowList: CredentialAllowList | undefined, ctx: ToolExecuteContext | undefined, signal: BareAbortSignal): Promise<
|
|
42
|
-
readonly header: string | null;
|
|
43
|
-
readonly credentialKey?: string;
|
|
44
|
-
}>;
|
|
37
|
+
export declare function resolveRedirectBearerHeader(auth: HttpRequestAuth | undefined, url: URL, credentialStore: CredentialStoreFn | undefined, credentialAllowList: CredentialAllowList | undefined, ctx: ToolExecuteContext | undefined, signal: BareAbortSignal): Promise<BearerHeader>;
|