@osovv/vv-opencode 1.1.6 → 1.2.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.
Files changed (121) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +59 -2
  3. package/dist/commands/completion.js +1 -1
  4. package/dist/commands/completion.js.map +1 -1
  5. package/dist/commands/init.js +1 -1
  6. package/dist/commands/init.js.map +1 -1
  7. package/dist/commands/install.js +7 -2
  8. package/dist/commands/install.js.map +1 -1
  9. package/dist/commands/patch-provider.d.ts +4 -4
  10. package/dist/commands/patch-provider.js +7 -6
  11. package/dist/commands/patch-provider.js.map +1 -1
  12. package/dist/commands/plugin-list.js +1 -1
  13. package/dist/commands/plugin-list.js.map +1 -1
  14. package/dist/commands/plugin-toggle.js +1 -1
  15. package/dist/commands/plugin-toggle.js.map +1 -1
  16. package/dist/commands/preset.js +1 -0
  17. package/dist/commands/preset.js.map +1 -1
  18. package/dist/commands/role.js +1 -1
  19. package/dist/commands/role.js.map +1 -1
  20. package/dist/commands/sync.js +7 -2
  21. package/dist/commands/sync.js.map +1 -1
  22. package/dist/commands/upgrade.js +1 -1
  23. package/dist/commands/upgrade.js.map +1 -1
  24. package/dist/index.d.ts +1 -0
  25. package/dist/index.js +7 -5
  26. package/dist/index.js.map +1 -1
  27. package/dist/lib/agent-models.js +1 -1
  28. package/dist/lib/agent-models.js.map +1 -1
  29. package/dist/lib/managed-agents.js +1 -1
  30. package/dist/lib/managed-agents.js.map +1 -1
  31. package/dist/lib/managed-skills.js +1 -1
  32. package/dist/lib/managed-skills.js.map +1 -1
  33. package/dist/lib/model-roles.js +1 -1
  34. package/dist/lib/model-roles.js.map +1 -1
  35. package/dist/lib/opencode.js +22 -7
  36. package/dist/lib/opencode.js.map +1 -1
  37. package/dist/lib/orchestration.js +4 -2
  38. package/dist/lib/orchestration.js.map +1 -1
  39. package/dist/lib/plugin-toggle-config.d.ts +1 -1
  40. package/dist/lib/plugin-toggle-config.js +4 -2
  41. package/dist/lib/plugin-toggle-config.js.map +1 -1
  42. package/dist/lib/vvoc-config.d.ts +93 -0
  43. package/dist/lib/vvoc-config.js +87 -2
  44. package/dist/lib/vvoc-config.js.map +1 -1
  45. package/dist/lib/vvoc-preset-registry.js +1 -1
  46. package/dist/lib/vvoc-preset-registry.js.map +1 -1
  47. package/dist/plugins/guardian/index.js +44 -6
  48. package/dist/plugins/guardian/index.js.map +1 -1
  49. package/dist/plugins/hashline-edit/edit-text-normalization.js +6 -5
  50. package/dist/plugins/hashline-edit/edit-text-normalization.js.map +1 -1
  51. package/dist/plugins/hashline-edit/index.js +16 -7
  52. package/dist/plugins/hashline-edit/index.js.map +1 -1
  53. package/dist/plugins/hashline-edit/tool-description.d.ts +1 -1
  54. package/dist/plugins/hashline-edit/tool-description.js +3 -2
  55. package/dist/plugins/hashline-edit/tool-description.js.map +1 -1
  56. package/dist/plugins/secrets-redaction/config.d.ts +6 -1
  57. package/dist/plugins/secrets-redaction/config.js +29 -4
  58. package/dist/plugins/secrets-redaction/config.js.map +1 -1
  59. package/dist/plugins/secrets-redaction/engine.js +10 -4
  60. package/dist/plugins/secrets-redaction/engine.js.map +1 -1
  61. package/dist/plugins/secrets-redaction/index.js +14 -21
  62. package/dist/plugins/secrets-redaction/index.js.map +1 -1
  63. package/dist/plugins/secrets-redaction/patterns.js +3 -3
  64. package/dist/plugins/secrets-redaction/patterns.js.map +1 -1
  65. package/dist/plugins/secrets-redaction/session.js +0 -1
  66. package/dist/plugins/secrets-redaction/session.js.map +1 -1
  67. package/dist/plugins/web-tools/config.d.ts +43 -0
  68. package/dist/plugins/web-tools/config.js +134 -0
  69. package/dist/plugins/web-tools/config.js.map +1 -0
  70. package/dist/plugins/web-tools/fetch-service.d.ts +14 -0
  71. package/dist/plugins/web-tools/fetch-service.js +166 -0
  72. package/dist/plugins/web-tools/fetch-service.js.map +1 -0
  73. package/dist/plugins/web-tools/html-markdown.d.ts +13 -0
  74. package/dist/plugins/web-tools/html-markdown.js +82 -0
  75. package/dist/plugins/web-tools/html-markdown.js.map +1 -0
  76. package/dist/plugins/web-tools/http.d.ts +34 -0
  77. package/dist/plugins/web-tools/http.js +154 -0
  78. package/dist/plugins/web-tools/http.js.map +1 -0
  79. package/dist/plugins/web-tools/index.d.ts +18 -0
  80. package/dist/plugins/web-tools/index.js +93 -0
  81. package/dist/plugins/web-tools/index.js.map +1 -0
  82. package/dist/plugins/web-tools/media-loader.d.ts +26 -0
  83. package/dist/plugins/web-tools/media-loader.js +178 -0
  84. package/dist/plugins/web-tools/media-loader.js.map +1 -0
  85. package/dist/plugins/web-tools/providers/brave.d.ts +3 -0
  86. package/dist/plugins/web-tools/providers/brave.js +101 -0
  87. package/dist/plugins/web-tools/providers/brave.js.map +1 -0
  88. package/dist/plugins/web-tools/providers/exa.d.ts +28 -0
  89. package/dist/plugins/web-tools/providers/exa.js +138 -0
  90. package/dist/plugins/web-tools/providers/exa.js.map +1 -0
  91. package/dist/plugins/web-tools/providers/native-fetch.d.ts +21 -0
  92. package/dist/plugins/web-tools/providers/native-fetch.js +112 -0
  93. package/dist/plugins/web-tools/providers/native-fetch.js.map +1 -0
  94. package/dist/plugins/web-tools/providers/spider.d.ts +25 -0
  95. package/dist/plugins/web-tools/providers/spider.js +104 -0
  96. package/dist/plugins/web-tools/providers/spider.js.map +1 -0
  97. package/dist/plugins/web-tools/providers/zai.d.ts +33 -0
  98. package/dist/plugins/web-tools/providers/zai.js +181 -0
  99. package/dist/plugins/web-tools/providers/zai.js.map +1 -0
  100. package/dist/plugins/web-tools/search-service.d.ts +18 -0
  101. package/dist/plugins/web-tools/search-service.js +110 -0
  102. package/dist/plugins/web-tools/search-service.js.map +1 -0
  103. package/dist/plugins/workflow/index.js +24 -5
  104. package/dist/plugins/workflow/index.js.map +1 -1
  105. package/dist/plugins/workflow/persistence.js +1 -1
  106. package/dist/plugins/workflow/persistence.js.map +1 -1
  107. package/dist/plugins/workflow/state.d.ts +14 -0
  108. package/dist/plugins/workflow/state.js +44 -1
  109. package/dist/plugins/workflow/state.js.map +1 -1
  110. package/dist/plugins/workflow/tooling.js +1 -1
  111. package/dist/plugins/workflow/tooling.js.map +1 -1
  112. package/dist/tui/context/analyze.js +11 -3
  113. package/dist/tui/context/analyze.js.map +1 -1
  114. package/dist/tui/context/collect.js +1 -1
  115. package/dist/tui/context/collect.js.map +1 -1
  116. package/dist/tui/context/plugin.js +3 -2
  117. package/dist/tui/context/plugin.js.map +1 -1
  118. package/dist/tui.js +1 -1
  119. package/package.json +15 -8
  120. package/schemas/vvoc/v3.json +43 -1
  121. package/templates/skills/vv-execute/SKILL.md +17 -12
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-markdown.js","sourceRoot":"","sources":["../../../src/plugins/web-tools/html-markdown.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,iBAAiB;AACjB,wBAAwB;AACxB,2FAA2F;AAC3F,8HAA8H;AAC9H,qCAAqC;AACrC,qDAAqD;AACrD,kBAAkB;AAClB,sBAAsB;AACtB,sBAAsB;AACtB,EAAE;AACF,mBAAmB;AACnB,kFAAkF;AAClF,oEAAoE;AACpE,iBAAiB;AACjB,EAAE;AACF,uBAAuB;AACvB,8GAA8G;AAC9G,qBAAqB;AAErB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,eAAe,MAAM,UAAU,CAAC;AAEvC,uBAAuB;AACvB,IAAI,cAA2C,CAAC;AAEhD,SAAS,WAAW;IAClB,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,cAAc,GAAG,IAAI,eAAe,CAAC;YACnC,YAAY,EAAE,KAAK;YACnB,cAAc,EAAE,QAAQ;YACxB,gBAAgB,EAAE,GAAG;SACtB,CAAC,CAAC;QACH,cAAc,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,cAAc,CAAC;AACxB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAChC,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,WAAW,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;AAC7C,CAAC;AACD,qBAAqB;AAErB,mBAAmB;AACnB;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAChC,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB;QACE,SAAS,CAAC,IAAI;YACZ,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC1C,SAAS,IAAI,CAAC,CAAC;YACjB,CAAC;QACH,CAAC;QACD,MAAM,CAAC,IAAI;YACT,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;gBACpB,IAAI,IAAI,IAAI,CAAC;YACf,CAAC;QACH,CAAC;QACD,UAAU,CAAC,IAAI;YACb,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC1C,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;KACF,EACD,EAAE,cAAc,EAAE,IAAI,EAAE,CACzB,CAAC;IACF,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnB,MAAM,CAAC,GAAG,EAAE,CAAC;IACb,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AAC1C,CAAC;AACD,iBAAiB"}
@@ -0,0 +1,34 @@
1
+ export type WebHttpErrorCode = "NETWORK_ERROR" | "TIMEOUT" | "ABORTED" | "OVERSIZED" | "HTTP_ERROR";
2
+ /** Transport-level failure. status is set only for HTTP_ERROR. Messages never include credentials. */
3
+ export declare class WebHttpError extends Error {
4
+ readonly code: WebHttpErrorCode;
5
+ readonly status?: number;
6
+ constructor(code: WebHttpErrorCode, message: string, status?: number);
7
+ }
8
+ export type BoundedHttpRequest = {
9
+ url: string;
10
+ method?: "GET" | "POST";
11
+ headers?: Record<string, string>;
12
+ body?: string;
13
+ /** Wall-clock timeout in milliseconds. */
14
+ timeoutMs: number;
15
+ /** Hard response body cap in bytes. */
16
+ maxBytes: number;
17
+ /** Optional caller abort signal; combined with the internal timeout controller. */
18
+ abort?: AbortSignal;
19
+ };
20
+ export type BoundedHttpResponse = {
21
+ status: number;
22
+ headers: Headers;
23
+ bytes: Uint8Array;
24
+ finalUrl: string;
25
+ };
26
+ /** Minimal fetch-compatible callable; avoids Bun-specific fetch properties for injectable mocks. */
27
+ export type FetchLike = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
28
+ /** Default cap for textual responses (5 MiB). */
29
+ export declare const DEFAULT_TEXT_MAX_BYTES: number;
30
+ /** Default cap for media responses (20 MiB). */
31
+ export declare const DEFAULT_MEDIA_MAX_BYTES: number;
32
+ /** Default request timeout (30 seconds). */
33
+ export declare const DEFAULT_REQUEST_TIMEOUT_MS = 30000;
34
+ export declare function requestBounded(request: BoundedHttpRequest, fetchImpl?: FetchLike): Promise<BoundedHttpResponse>;
@@ -0,0 +1,154 @@
1
+ // FILE: src/plugins/web-tools/http.ts
2
+ // VERSION: 1.0.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Provide shared bounded HTTP execution for the web tools providers and media loader.
5
+ // SCOPE: Timeout enforcement, caller abort propagation, a hard response-size cap, redirect following, and a transport error taxonomy.
6
+ // DEPENDS: [none]
7
+ // LINKS: [M-WEB-HTTP, M-WEB-EXA, M-WEB-BRAVE, M-WEB-NATIVE-FETCH, M-WEB-SPIDER, M-WEB-MEDIA-LOADER]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // WebHttpErrorCode - Transport error codes.
14
+ // WebHttpError - Transport-level error carrying a code and optional HTTP status.
15
+ // BoundedHttpRequest - Request input with timeout, size cap, and optional caller abort.
16
+ // BoundedHttpResponse - Response with status, headers, bytes, and final URL.
17
+ // FetchLike - Minimal fetch-compatible callable for injectable mocks.
18
+ // DEFAULT_TEXT_MAX_BYTES - Default cap for textual responses.
19
+ // DEFAULT_MEDIA_MAX_BYTES - Default cap for media responses.
20
+ // DEFAULT_REQUEST_TIMEOUT_MS - Default request timeout.
21
+ // requestBounded - Execute one bounded HTTP request.
22
+ // END_MODULE_MAP
23
+ //
24
+ // START_CHANGE_SUMMARY
25
+ // LAST_CHANGE: [v1.0.0 - Initial bounded HTTP transport and error taxonomy for the unified web tools.]
26
+ // END_CHANGE_SUMMARY
27
+ /** Transport-level failure. status is set only for HTTP_ERROR. Messages never include credentials. */
28
+ export class WebHttpError extends Error {
29
+ code;
30
+ status;
31
+ constructor(code, message, status) {
32
+ super(message);
33
+ this.name = "WebHttpError";
34
+ this.code = code;
35
+ this.status = status;
36
+ }
37
+ }
38
+ /** Default cap for textual responses (5 MiB). */
39
+ export const DEFAULT_TEXT_MAX_BYTES = 5 * 1024 * 1024;
40
+ /** Default cap for media responses (20 MiB). */
41
+ export const DEFAULT_MEDIA_MAX_BYTES = 20 * 1024 * 1024;
42
+ /** Default request timeout (30 seconds). */
43
+ export const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
44
+ // START_BLOCK_HELPERS
45
+ function safeMessage(error) {
46
+ return error instanceof Error ? error.message : String(error);
47
+ }
48
+ function mapTransportError(error, controller, timedOut, timeoutMs) {
49
+ if (controller.signal.aborted) {
50
+ if (timedOut) {
51
+ return new WebHttpError("TIMEOUT", `request timed out after ${timeoutMs}ms`);
52
+ }
53
+ return new WebHttpError("ABORTED", "request aborted by caller");
54
+ }
55
+ return new WebHttpError("NETWORK_ERROR", `network error: ${safeMessage(error)}`);
56
+ }
57
+ async function readBodyWithCap(response, maxBytes, controller) {
58
+ const body = response.body;
59
+ if (!body) {
60
+ return new Uint8Array(0);
61
+ }
62
+ const reader = body.getReader();
63
+ const chunks = [];
64
+ let total = 0;
65
+ try {
66
+ for (;;) {
67
+ const { done, value } = await reader.read();
68
+ if (done)
69
+ break;
70
+ if (!value)
71
+ continue;
72
+ total += value.byteLength;
73
+ if (total > maxBytes) {
74
+ controller.abort();
75
+ throw new WebHttpError("OVERSIZED", `response body exceeded ${maxBytes} bytes`);
76
+ }
77
+ chunks.push(value);
78
+ }
79
+ }
80
+ finally {
81
+ reader.releaseLock();
82
+ }
83
+ const out = new Uint8Array(total);
84
+ let offset = 0;
85
+ for (const chunk of chunks) {
86
+ out.set(chunk, offset);
87
+ offset += chunk.byteLength;
88
+ }
89
+ return out;
90
+ }
91
+ // END_BLOCK_HELPERS
92
+ // START_CONTRACT: requestBounded
93
+ // PURPOSE: Execute one bounded HTTP request.
94
+ // INPUTS: { request: BoundedHttpRequest; fetchImpl: injectable fetch implementation for tests }
95
+ // OUTPUTS: { BoundedHttpResponse - status, headers, bytes, and finalUrl }
96
+ // SIDE_EFFECTS: performs network I/O through fetchImpl; rejects with WebHttpError on failure
97
+ // LINKS: M-WEB-EXA, M-WEB-BRAVE, M-WEB-NATIVE-FETCH, M-WEB-SPIDER, M-WEB-MEDIA-LOADER
98
+ // END_CONTRACT: requestBounded
99
+ export async function requestBounded(request, fetchImpl = fetch) {
100
+ const controller = new AbortController();
101
+ let timedOut = false;
102
+ const timeout = setTimeout(() => {
103
+ timedOut = true;
104
+ controller.abort();
105
+ }, request.timeoutMs);
106
+ const onCallerAbort = () => controller.abort();
107
+ if (request.abort) {
108
+ if (request.abort.aborted) {
109
+ controller.abort();
110
+ }
111
+ else {
112
+ request.abort.addEventListener("abort", onCallerAbort, { once: true });
113
+ }
114
+ }
115
+ try {
116
+ let response;
117
+ try {
118
+ response = await fetchImpl(request.url, {
119
+ method: request.method ?? "GET",
120
+ headers: request.headers,
121
+ body: request.body,
122
+ signal: controller.signal,
123
+ redirect: "follow",
124
+ });
125
+ }
126
+ catch (error) {
127
+ throw mapTransportError(error, controller, timedOut, request.timeoutMs);
128
+ }
129
+ if (!response.ok) {
130
+ throw new WebHttpError("HTTP_ERROR", `HTTP ${response.status} for ${request.url}`, response.status);
131
+ }
132
+ let bytes;
133
+ try {
134
+ bytes = await readBodyWithCap(response, request.maxBytes, controller);
135
+ }
136
+ catch (error) {
137
+ if (error instanceof WebHttpError) {
138
+ throw error;
139
+ }
140
+ throw mapTransportError(error, controller, timedOut, request.timeoutMs);
141
+ }
142
+ return {
143
+ status: response.status,
144
+ headers: response.headers,
145
+ bytes,
146
+ finalUrl: response.url || request.url,
147
+ };
148
+ }
149
+ finally {
150
+ clearTimeout(timeout);
151
+ request.abort?.removeEventListener("abort", onCallerAbort);
152
+ }
153
+ }
154
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/plugins/web-tools/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { type Config, type Plugin } from "@opencode-ai/plugin";
2
+ /** Built-in permission ids suppressed at runtime while web-tools is enabled. */
3
+ export declare const SUPPRESSED_BUILTIN_PERMISSIONS: readonly ["webfetch", "websearch"];
4
+ /**
5
+ * Hide the built-in web tools by denying their permission keys in the merged runtime config.
6
+ * Skips any key the user configured explicitly so explicit user policy always wins.
7
+ * Mutates only the in-memory config object; no files are written.
8
+ */
9
+ export declare function applyBuiltinSuppression(config: Config): void;
10
+ /**
11
+ * WebToolsPlugin entry.
12
+ * Disabled toggle: returns empty hooks and injects nothing.
13
+ * Enabled: returns a config hook applying suppression and a tool map with exactly
14
+ * web_search and web_fetch. Startup logs include provider names and credential sources
15
+ * and never credential values; a git-tracked project config with an apiKey logs a warning
16
+ * naming the file without the value.
17
+ */
18
+ export declare const WebToolsPlugin: Plugin;
@@ -0,0 +1,93 @@
1
+ // FILE: src/plugins/web-tools/index.ts
2
+ // VERSION: 1.0.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Register the canonical web_search and web_fetch tools and suppress OpenCode built-ins at runtime while the web-tools plugin is enabled.
5
+ // SCOPE: Startup vvoc snapshot use, plugin toggle handling, runtime permission suppression, tool registration, and credential-safe diagnostics.
6
+ // DEPENDS: [@opencode-ai/plugin, src/lib/config-layers.ts, src/lib/plugin-toggle-config.ts, src/plugins/web-tools/config.ts, src/plugins/web-tools/search-service.ts, src/plugins/web-tools/fetch-service.ts]
7
+ // LINKS: [M-PLUGIN-WEB-TOOLS, M-WEB-CONFIG, M-WEB-SEARCH-SERVICE, M-WEB-FETCH-SERVICE]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // SUPPRESSED_BUILTIN_PERMISSIONS - Built-in permission ids hidden while the plugin is enabled.
14
+ // applyBuiltinSuppression - Add runtime-only deny rules unless the user configured a key explicitly.
15
+ // WebToolsPlugin - Public plugin entry registering web_search and web_fetch.
16
+ // END_MODULE_MAP
17
+ //
18
+ // START_CHANGE_SUMMARY
19
+ // LAST_CHANGE: [C-ZAI-DIRECT-WEB-PROVIDERS - Added credential-safe direct Z.AI region diagnostics while preserving the canonical tool surface.]
20
+ // LAST_CHANGE: [v1.0.0 - Initial WebToolsPlugin with runtime built-in suppression and credential-safe startup diagnostics.]
21
+ // END_CHANGE_SUMMARY
22
+ import { loadVvocConfig } from "../../lib/config-layers.js";
23
+ import { isVvocPluginEnabled } from "../../lib/plugin-toggle-config.js";
24
+ import { resolveWebRuntimeConfig, warnIfSecretBearingProjectConfigTracked } from "./config.js";
25
+ import { createWebFetchTool } from "./fetch-service.js";
26
+ import { createWebSearchTool } from "./search-service.js";
27
+ /** Built-in permission ids suppressed at runtime while web-tools is enabled. */
28
+ export const SUPPRESSED_BUILTIN_PERMISSIONS = ["webfetch", "websearch"];
29
+ /**
30
+ * Hide the built-in web tools by denying their permission keys in the merged runtime config.
31
+ * Skips any key the user configured explicitly so explicit user policy always wins.
32
+ * Mutates only the in-memory config object; no files are written.
33
+ */
34
+ export function applyBuiltinSuppression(config) {
35
+ config.permission ??= {};
36
+ const permission = config.permission;
37
+ for (const key of SUPPRESSED_BUILTIN_PERMISSIONS) {
38
+ if (permission[key] === undefined) {
39
+ permission[key] = "deny";
40
+ }
41
+ }
42
+ }
43
+ /**
44
+ * WebToolsPlugin entry.
45
+ * Disabled toggle: returns empty hooks and injects nothing.
46
+ * Enabled: returns a config hook applying suppression and a tool map with exactly
47
+ * web_search and web_fetch. Startup logs include provider names and credential sources
48
+ * and never credential values; a git-tracked project config with an apiKey logs a warning
49
+ * naming the file without the value.
50
+ */
51
+ export const WebToolsPlugin = async ({ client, directory }) => {
52
+ const vvoc = await loadVvocConfig({ cwd: directory });
53
+ if (!isVvocPluginEnabled(vvoc.config, "web-tools")) {
54
+ return {};
55
+ }
56
+ const resolved = resolveWebRuntimeConfig(vvoc);
57
+ await client.app.log({
58
+ body: {
59
+ service: "web-tools",
60
+ level: "info",
61
+ message: "web tools configuration loaded",
62
+ extra: {
63
+ searchProvider: resolved.search.provider,
64
+ ...(resolved.search.provider === "zai" ? { searchRegion: resolved.search.region } : {}),
65
+ searchCredentialSource: resolved.search.credential?.source ?? "missing",
66
+ fetchProvider: resolved.fetch.provider,
67
+ ...(resolved.fetch.provider === "zai" ? { fetchRegion: resolved.fetch.region } : {}),
68
+ fetchCredentialSource: resolved.fetch.provider === "native"
69
+ ? "not-required"
70
+ : (resolved.fetch.credential?.source ?? "missing"),
71
+ },
72
+ },
73
+ });
74
+ for (const warning of resolved.warnings) {
75
+ await client.app.log({
76
+ body: { service: "web-tools", level: "warn", message: warning },
77
+ });
78
+ }
79
+ const trackedConfigWarning = warnIfSecretBearingProjectConfigTracked(vvoc);
80
+ if (trackedConfigWarning) {
81
+ await client.app.log({
82
+ body: { service: "web-tools", level: "warn", message: trackedConfigWarning },
83
+ });
84
+ }
85
+ return {
86
+ config: async (config) => applyBuiltinSuppression(config),
87
+ tool: {
88
+ web_search: createWebSearchTool(resolved.search),
89
+ web_fetch: createWebFetchTool(resolved.fetch),
90
+ },
91
+ };
92
+ };
93
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/web-tools/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { ToolAttachment } from "@opencode-ai/plugin";
2
+ import { type FetchLike } from "./http.js";
3
+ export declare const SUPPORTED_MEDIA_MIME_TYPES: readonly ["image/jpeg", "image/png", "image/gif", "image/webp", "application/pdf"];
4
+ export type SupportedMediaMimeType = (typeof SUPPORTED_MEDIA_MIME_TYPES)[number];
5
+ /** Unsupported-media failure. The message names the detected or declared MIME type and never includes the payload. */
6
+ export declare class WebMediaError extends Error {
7
+ readonly code: "UNSUPPORTED";
8
+ readonly mime?: string;
9
+ constructor(message: string, mime?: string);
10
+ }
11
+ /**
12
+ * Sniff the media MIME type from leading bytes.
13
+ * Returns undefined when the signature matches no supported format.
14
+ */
15
+ export declare function sniffMediaMimeType(bytes: Uint8Array): SupportedMediaMimeType | undefined;
16
+ export declare function mediaAttachmentFromBytes(bytes: Uint8Array, source: {
17
+ url: string;
18
+ declaredContentType?: string;
19
+ maxBytes?: number;
20
+ }): ToolAttachment;
21
+ export declare function loadMediaAttachment(input: {
22
+ url: string;
23
+ abort?: AbortSignal;
24
+ timeoutMs?: number;
25
+ maxBytes?: number;
26
+ }, fetchImpl?: FetchLike): Promise<ToolAttachment>;
@@ -0,0 +1,178 @@
1
+ // FILE: src/plugins/web-tools/media-loader.ts
2
+ // VERSION: 1.0.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Load supported images and PDFs as base64 file attachments for the web tools fetch path.
5
+ // SCOPE: MIME and magic-byte identification, base64 data-URL attachment construction, filename derivation, and rejection of unsupported or oversized payloads.
6
+ // DEPENDS: [src/plugins/web-tools/http.ts, @opencode-ai/plugin]
7
+ // LINKS: [M-WEB-MEDIA-LOADER, M-WEB-HTTP, M-WEB-NATIVE-FETCH, M-WEB-SPIDER]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // SUPPORTED_MEDIA_MIME_TYPES - Tuple of supported media MIME types.
14
+ // SupportedMediaMimeType - Supported media MIME type union.
15
+ // WebMediaError - Unsupported-media error carrying the detected or declared MIME type.
16
+ // sniffMediaMimeType - Detect a supported MIME type from leading bytes.
17
+ // mediaAttachmentFromBytes - Build a base64 data-URL attachment from already-fetched bytes.
18
+ // loadMediaAttachment - Fetch a URL and return it as an attachment when supported.
19
+ // END_MODULE_MAP
20
+ //
21
+ // START_CHANGE_SUMMARY
22
+ // LAST_CHANGE: [v1.0.0 - Initial direct media attachment loader for the unified web tools.]
23
+ // END_CHANGE_SUMMARY
24
+ import { DEFAULT_MEDIA_MAX_BYTES, DEFAULT_REQUEST_TIMEOUT_MS, requestBounded, WebHttpError, } from "./http.js";
25
+ export const SUPPORTED_MEDIA_MIME_TYPES = [
26
+ "image/jpeg",
27
+ "image/png",
28
+ "image/gif",
29
+ "image/webp",
30
+ "application/pdf",
31
+ ];
32
+ /** Unsupported-media failure. The message names the detected or declared MIME type and never includes the payload. */
33
+ export class WebMediaError extends Error {
34
+ code;
35
+ mime;
36
+ constructor(message, mime) {
37
+ super(message);
38
+ this.name = "WebMediaError";
39
+ this.code = "UNSUPPORTED";
40
+ this.mime = mime;
41
+ }
42
+ }
43
+ const EXTENSION_BY_MIME = {
44
+ "image/jpeg": ".jpg",
45
+ "image/png": ".png",
46
+ "image/gif": ".gif",
47
+ "image/webp": ".webp",
48
+ "application/pdf": ".pdf",
49
+ };
50
+ // START_BLOCK_SNIFF
51
+ /**
52
+ * Sniff the media MIME type from leading bytes.
53
+ * Returns undefined when the signature matches no supported format.
54
+ */
55
+ export function sniffMediaMimeType(bytes) {
56
+ if (bytes.length >= 3 && bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) {
57
+ return "image/jpeg";
58
+ }
59
+ if (bytes.length >= 4 &&
60
+ bytes[0] === 0x89 &&
61
+ bytes[1] === 0x50 &&
62
+ bytes[2] === 0x4e &&
63
+ bytes[3] === 0x47) {
64
+ return "image/png";
65
+ }
66
+ if (bytes.length >= 4 &&
67
+ bytes[0] === 0x47 &&
68
+ bytes[1] === 0x49 &&
69
+ bytes[2] === 0x46 &&
70
+ bytes[3] === 0x38) {
71
+ return "image/gif";
72
+ }
73
+ if (bytes.length >= 12 &&
74
+ bytes[0] === 0x52 &&
75
+ bytes[1] === 0x49 &&
76
+ bytes[2] === 0x46 &&
77
+ bytes[3] === 0x46 &&
78
+ bytes[8] === 0x57 &&
79
+ bytes[9] === 0x45 &&
80
+ bytes[10] === 0x42 &&
81
+ bytes[11] === 0x50) {
82
+ return "image/webp";
83
+ }
84
+ if (bytes.length >= 4 &&
85
+ bytes[0] === 0x25 &&
86
+ bytes[1] === 0x50 &&
87
+ bytes[2] === 0x44 &&
88
+ bytes[3] === 0x46) {
89
+ return "application/pdf";
90
+ }
91
+ return undefined;
92
+ }
93
+ // END_BLOCK_SNIFF
94
+ // START_BLOCK_HELPERS
95
+ function normalizeDeclaredContentType(declared) {
96
+ if (!declared) {
97
+ return undefined;
98
+ }
99
+ const mime = declared.split(";")[0]?.trim().toLowerCase();
100
+ return mime || undefined;
101
+ }
102
+ function filenameFromUrl(url, mime) {
103
+ const extension = EXTENSION_BY_MIME[mime];
104
+ try {
105
+ const base = new URL(url).pathname.split("/").pop() ?? "";
106
+ if (base && base.includes(".")) {
107
+ return base;
108
+ }
109
+ if (base) {
110
+ return `${base}${extension}`;
111
+ }
112
+ return `resource${extension}`;
113
+ }
114
+ catch {
115
+ return `resource${extension}`;
116
+ }
117
+ }
118
+ function resolveMimeType(bytes, declaredContentType) {
119
+ const sniffed = sniffMediaMimeType(bytes);
120
+ if (sniffed) {
121
+ return sniffed;
122
+ }
123
+ const declared = normalizeDeclaredContentType(declaredContentType);
124
+ if (declared && SUPPORTED_MEDIA_MIME_TYPES.includes(declared)) {
125
+ return declared;
126
+ }
127
+ return undefined;
128
+ }
129
+ // END_BLOCK_HELPERS
130
+ // START_CONTRACT: mediaAttachmentFromBytes
131
+ // PURPOSE: Build a base64 data-URL file attachment from already-fetched bytes.
132
+ // INPUTS: { bytes: payload; source: url, declaredContentType, optional maxBytes }
133
+ // OUTPUTS: { ToolAttachment - type file, mime, data URL, filename }
134
+ // SIDE_EFFECTS: none; performs no network I/O
135
+ // LINKS: M-WEB-NATIVE-FETCH, M-WEB-SPIDER
136
+ // END_CONTRACT: mediaAttachmentFromBytes
137
+ export function mediaAttachmentFromBytes(bytes, source) {
138
+ const maxBytes = source.maxBytes ?? DEFAULT_MEDIA_MAX_BYTES;
139
+ if (bytes.byteLength > maxBytes) {
140
+ throw new WebHttpError("OVERSIZED", `media payload exceeded ${maxBytes} bytes`);
141
+ }
142
+ const mime = resolveMimeType(bytes, source.declaredContentType);
143
+ if (!mime) {
144
+ const detail = sniffMediaMimeType(bytes) ??
145
+ normalizeDeclaredContentType(source.declaredContentType) ??
146
+ "unknown";
147
+ throw new WebMediaError(`unsupported media type: ${detail}`, detail === "unknown" ? undefined : detail);
148
+ }
149
+ const base64 = Buffer.from(bytes).toString("base64");
150
+ return {
151
+ type: "file",
152
+ mime,
153
+ url: `data:${mime};base64,${base64}`,
154
+ filename: filenameFromUrl(source.url, mime),
155
+ };
156
+ }
157
+ // START_CONTRACT: loadMediaAttachment
158
+ // PURPOSE: Fetch a URL through the bounded transport and return it as an attachment when supported.
159
+ // INPUTS: { input: url, optional abort, timeoutMs, maxBytes; fetchImpl: injectable fetch }
160
+ // OUTPUTS: { ToolAttachment }
161
+ // SIDE_EFFECTS: performs network I/O through fetchImpl
162
+ // LINKS: M-WEB-HTTP
163
+ // END_CONTRACT: loadMediaAttachment
164
+ export async function loadMediaAttachment(input, fetchImpl) {
165
+ const maxBytes = input.maxBytes ?? DEFAULT_MEDIA_MAX_BYTES;
166
+ const response = await requestBounded({
167
+ url: input.url,
168
+ timeoutMs: input.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,
169
+ maxBytes,
170
+ abort: input.abort,
171
+ }, fetchImpl);
172
+ return mediaAttachmentFromBytes(response.bytes, {
173
+ url: response.finalUrl,
174
+ declaredContentType: response.headers.get("content-type") ?? undefined,
175
+ maxBytes,
176
+ });
177
+ }
178
+ //# sourceMappingURL=media-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-loader.js","sourceRoot":"","sources":["../../../src/plugins/web-tools/media-loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type FetchLike } from "../http.js";
2
+ import { type WebSearchInput, type WebSearchResult } from "./exa.js";
3
+ export declare function searchBrave(input: WebSearchInput, fetchImpl?: FetchLike): Promise<WebSearchResult[]>;
@@ -0,0 +1,101 @@
1
+ // FILE: src/plugins/web-tools/providers/brave.ts
2
+ // VERSION: 1.0.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Call the Brave Web Search endpoint directly and normalize web results for the web_search tool.
5
+ // SCOPE: Brave request construction with X-Subscription-Token auth, count and freshness mapping, moderate safe search, and web result normalization.
6
+ // DEPENDS: [src/plugins/web-tools/http.ts, src/plugins/web-tools/providers/exa.ts]
7
+ // LINKS: [M-WEB-BRAVE, M-WEB-HTTP, M-WEB-SEARCH-SERVICE]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // searchBrave - Execute one Brave Web Search.
14
+ // END_MODULE_MAP
15
+ //
16
+ // START_CHANGE_SUMMARY
17
+ // LAST_CHANGE: [v1.0.0 - Initial Brave Web Search adapter.]
18
+ // END_CHANGE_SUMMARY
19
+ import { DEFAULT_TEXT_MAX_BYTES, requestBounded, } from "../http.js";
20
+ import { mapHttpErrorToProviderError, WebProviderError, } from "./exa.js";
21
+ const BRAVE_SEARCH_URL = "https://api.search.brave.com/res/v1/web/search";
22
+ const BRAVE_FRESHNESS = { day: "pd", week: "pw", month: "pm", year: "py" };
23
+ // START_BLOCK_HELPERS
24
+ function isPlainObject(value) {
25
+ return typeof value === "object" && value !== null && !Array.isArray(value);
26
+ }
27
+ function normalizeBraveResult(item) {
28
+ if (!isPlainObject(item)) {
29
+ return undefined;
30
+ }
31
+ const url = typeof item.url === "string" ? item.url : undefined;
32
+ if (!url) {
33
+ return undefined;
34
+ }
35
+ const title = typeof item.title === "string" && item.title.length > 0 ? item.title : url;
36
+ const snippet = typeof item.description === "string" && item.description.length > 0
37
+ ? item.description
38
+ : undefined;
39
+ const publishedAt = typeof item.page_age === "string" ? item.page_age : undefined;
40
+ return {
41
+ title,
42
+ url,
43
+ ...(snippet ? { snippet } : {}),
44
+ ...(publishedAt ? { publishedAt } : {}),
45
+ };
46
+ }
47
+ function parseBraveResults(bytes) {
48
+ let parsed;
49
+ try {
50
+ parsed = JSON.parse(new TextDecoder().decode(bytes));
51
+ }
52
+ catch {
53
+ throw new WebProviderError("brave", "BAD_RESPONSE", "malformed JSON response from brave");
54
+ }
55
+ const web = isPlainObject(parsed) ? parsed.web : undefined;
56
+ const results = isPlainObject(web) && Array.isArray(web.results) ? web.results : undefined;
57
+ if (!results) {
58
+ throw new WebProviderError("brave", "BAD_RESPONSE", "unexpected brave response envelope");
59
+ }
60
+ return results
61
+ .map(normalizeBraveResult)
62
+ .filter((result) => result !== undefined);
63
+ }
64
+ // END_BLOCK_HELPERS
65
+ // START_CONTRACT: searchBrave
66
+ // PURPOSE: GET the Brave Web Search endpoint with X-Subscription-Token auth and normalize web.results.
67
+ // INPUTS: { input: WebSearchInput; fetchImpl: injectable fetch }
68
+ // OUTPUTS: { WebSearchResult[] - ranked results, empty array when none }
69
+ // SIDE_EFFECTS: performs network I/O through fetchImpl; never logs the credential
70
+ // LINKS: M-WEB-SEARCH-SERVICE
71
+ // END_CONTRACT: searchBrave
72
+ export async function searchBrave(input, fetchImpl) {
73
+ const params = new URLSearchParams();
74
+ params.set("q", input.query);
75
+ params.set("count", String(input.count));
76
+ params.set("safesearch", "moderate");
77
+ if (input.freshness) {
78
+ params.set("freshness", BRAVE_FRESHNESS[input.freshness]);
79
+ }
80
+ const url = `${BRAVE_SEARCH_URL}?${params.toString()}`;
81
+ let response;
82
+ try {
83
+ response = await requestBounded({
84
+ url,
85
+ method: "GET",
86
+ headers: {
87
+ "X-Subscription-Token": input.credential.value,
88
+ accept: "application/json",
89
+ },
90
+ timeoutMs: input.timeoutMs,
91
+ maxBytes: DEFAULT_TEXT_MAX_BYTES,
92
+ abort: input.abort,
93
+ }, fetchImpl);
94
+ }
95
+ catch (error) {
96
+ mapHttpErrorToProviderError(error, "brave");
97
+ throw error;
98
+ }
99
+ return parseBraveResults(response.bytes);
100
+ }
101
+ //# sourceMappingURL=brave.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brave.js","sourceRoot":"","sources":["../../../../src/plugins/web-tools/providers/brave.ts"],"names":[],"mappings":"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"}