@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,28 @@
1
+ import type { WebProviderCredential } from "../config.js";
2
+ import { type FetchLike } from "../http.js";
3
+ export type WebProviderName = "exa" | "brave" | "spider" | "native" | "zai";
4
+ export type WebProviderErrorCode = "AUTH_FAILED" | "RATE_LIMITED" | "PROVIDER_ERROR" | "BAD_RESPONSE" | "MISSING_CREDENTIAL" | "UNSUPPORTED" | "CONVERSION_FAILED";
5
+ /** Provider-facing search or scrape error. Messages name the provider and never include the credential. */
6
+ export declare class WebProviderError extends Error {
7
+ readonly provider: WebProviderName;
8
+ readonly code: WebProviderErrorCode;
9
+ readonly status?: number;
10
+ constructor(provider: WebProviderName, code: WebProviderErrorCode, message: string, status?: number);
11
+ }
12
+ export type WebSearchResult = {
13
+ title: string;
14
+ url: string;
15
+ snippet?: string;
16
+ publishedAt?: string;
17
+ };
18
+ export type WebSearchInput = {
19
+ query: string;
20
+ count: number;
21
+ freshness?: "day" | "week" | "month" | "year";
22
+ credential: WebProviderCredential;
23
+ abort: AbortSignal;
24
+ timeoutMs: number;
25
+ };
26
+ /** Map a bounded-transport HTTP error to a provider error; re-throw timeout, abort, oversized, and network errors unchanged. */
27
+ export declare function mapHttpErrorToProviderError(error: unknown, provider: WebProviderName): never;
28
+ export declare function searchExa(input: WebSearchInput, fetchImpl?: FetchLike): Promise<WebSearchResult[]>;
@@ -0,0 +1,138 @@
1
+ // FILE: src/plugins/web-tools/providers/exa.ts
2
+ // VERSION: 1.0.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Call the official Exa Search API directly and normalize ranked results for the web_search tool.
5
+ // SCOPE: Exa request construction with x-api-key auth, count and freshness mapping, result normalization, and provider error mapping. Also owns the shared provider search types and WebProviderError used by sibling adapters.
6
+ // DEPENDS: [src/plugins/web-tools/http.ts, src/plugins/web-tools/config.ts]
7
+ // LINKS: [M-WEB-EXA, M-WEB-HTTP, M-WEB-SEARCH-SERVICE]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // WebProviderName - Provider identifiers for error attribution.
14
+ // WebProviderErrorCode - Provider-facing error codes.
15
+ // WebProviderError - Provider error carrying provider, code, and optional status.
16
+ // WebSearchResult - Normalized ranked search result.
17
+ // WebSearchInput - Provider-neutral search input.
18
+ // mapHttpErrorToProviderError - Map bounded HTTP status failures into credential-safe provider errors.
19
+ // searchExa - Execute one Exa search.
20
+ // END_MODULE_MAP
21
+ //
22
+ // START_CHANGE_SUMMARY
23
+ // LAST_CHANGE: [C-ZAI-DIRECT-WEB-PROVIDERS - Extended shared provider error attribution with the direct zai adapter.]
24
+ // LAST_CHANGE: [v1.0.0 - Initial Exa Search API adapter and shared provider search contracts.]
25
+ // END_CHANGE_SUMMARY
26
+ import { DEFAULT_TEXT_MAX_BYTES, requestBounded, WebHttpError, } from "../http.js";
27
+ /** Provider-facing search or scrape error. Messages name the provider and never include the credential. */
28
+ export class WebProviderError extends Error {
29
+ provider;
30
+ code;
31
+ status;
32
+ constructor(provider, code, message, status) {
33
+ super(message);
34
+ this.name = "WebProviderError";
35
+ this.provider = provider;
36
+ this.code = code;
37
+ this.status = status;
38
+ }
39
+ }
40
+ const EXA_SEARCH_URL = "https://api.exa.ai/search";
41
+ const FRESHNESS_DAYS = { day: 1, week: 7, month: 31, year: 365 };
42
+ // START_BLOCK_HELPERS
43
+ function isPlainObject(value) {
44
+ return typeof value === "object" && value !== null && !Array.isArray(value);
45
+ }
46
+ function freshnessToDate(freshness) {
47
+ const ms = Date.now() - FRESHNESS_DAYS[freshness] * 24 * 60 * 60 * 1000;
48
+ return new Date(ms).toISOString();
49
+ }
50
+ /** Map a bounded-transport HTTP error to a provider error; re-throw timeout, abort, oversized, and network errors unchanged. */
51
+ export function mapHttpErrorToProviderError(error, provider) {
52
+ if (error instanceof WebHttpError && error.code === "HTTP_ERROR") {
53
+ const status = error.status ?? 0;
54
+ if (status === 401 || status === 403) {
55
+ throw new WebProviderError(provider, "AUTH_FAILED", `${provider} authentication failed`, status);
56
+ }
57
+ if (status === 429) {
58
+ throw new WebProviderError(provider, "RATE_LIMITED", `${provider} rate limit exceeded`, status);
59
+ }
60
+ throw new WebProviderError(provider, "PROVIDER_ERROR", `${provider} server error HTTP ${status}`, status);
61
+ }
62
+ throw error;
63
+ }
64
+ function normalizeExaResult(item) {
65
+ if (!isPlainObject(item)) {
66
+ return undefined;
67
+ }
68
+ const url = typeof item.url === "string" ? item.url : undefined;
69
+ if (!url) {
70
+ return undefined;
71
+ }
72
+ const title = typeof item.title === "string" && item.title.length > 0 ? item.title : url;
73
+ const highlights = Array.isArray(item.highlights)
74
+ ? item.highlights.filter((entry) => typeof entry === "string")
75
+ : [];
76
+ const snippet = highlights[0];
77
+ const publishedAt = typeof item.publishedDate === "string" ? item.publishedDate : undefined;
78
+ return {
79
+ title,
80
+ url,
81
+ ...(snippet ? { snippet } : {}),
82
+ ...(publishedAt ? { publishedAt } : {}),
83
+ };
84
+ }
85
+ function parseExaResults(bytes) {
86
+ let parsed;
87
+ try {
88
+ parsed = JSON.parse(new TextDecoder().decode(bytes));
89
+ }
90
+ catch {
91
+ throw new WebProviderError("exa", "BAD_RESPONSE", "malformed JSON response from exa");
92
+ }
93
+ if (!isPlainObject(parsed) || !Array.isArray(parsed.results)) {
94
+ throw new WebProviderError("exa", "BAD_RESPONSE", "unexpected exa response envelope");
95
+ }
96
+ return parsed.results
97
+ .map(normalizeExaResult)
98
+ .filter((result) => result !== undefined);
99
+ }
100
+ // END_BLOCK_HELPERS
101
+ // START_CONTRACT: searchExa
102
+ // PURPOSE: POST https://api.exa.ai/search with x-api-key auth and normalize results.
103
+ // INPUTS: { input: WebSearchInput; fetchImpl: injectable fetch }
104
+ // OUTPUTS: { WebSearchResult[] - ranked results, empty array when none }
105
+ // SIDE_EFFECTS: performs network I/O through fetchImpl; never logs the credential
106
+ // LINKS: M-WEB-SEARCH-SERVICE
107
+ // END_CONTRACT: searchExa
108
+ export async function searchExa(input, fetchImpl) {
109
+ const body = JSON.stringify({
110
+ query: input.query,
111
+ type: "auto",
112
+ numResults: input.count,
113
+ contents: { highlights: { query: input.query, numSentences: 3 } },
114
+ ...(input.freshness ? { startPublishedDate: freshnessToDate(input.freshness) } : {}),
115
+ });
116
+ let response;
117
+ try {
118
+ response = await requestBounded({
119
+ url: EXA_SEARCH_URL,
120
+ method: "POST",
121
+ headers: {
122
+ "x-api-key": input.credential.value,
123
+ "content-type": "application/json",
124
+ accept: "application/json",
125
+ },
126
+ body,
127
+ timeoutMs: input.timeoutMs,
128
+ maxBytes: DEFAULT_TEXT_MAX_BYTES,
129
+ abort: input.abort,
130
+ }, fetchImpl);
131
+ }
132
+ catch (error) {
133
+ mapHttpErrorToProviderError(error, "exa");
134
+ throw error;
135
+ }
136
+ return parseExaResults(response.bytes);
137
+ }
138
+ //# sourceMappingURL=exa.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exa.js","sourceRoot":"","sources":["../../../../src/plugins/web-tools/providers/exa.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { ToolAttachment } from "@opencode-ai/plugin";
2
+ import { type FetchLike } from "../http.js";
3
+ export type NativeFetchOutcome = {
4
+ kind: "text";
5
+ content: string;
6
+ contentType: string;
7
+ finalUrl: string;
8
+ status: number;
9
+ } | {
10
+ kind: "media";
11
+ attachment: ToolAttachment;
12
+ finalUrl: string;
13
+ status: number;
14
+ };
15
+ export declare function fetchNative(input: {
16
+ url: string;
17
+ format: "markdown" | "text" | "html";
18
+ abort: AbortSignal;
19
+ timeoutMs: number;
20
+ maxBytes?: number;
21
+ }, fetchImpl?: FetchLike): Promise<NativeFetchOutcome>;
@@ -0,0 +1,112 @@
1
+ // FILE: src/plugins/web-tools/providers/native-fetch.ts
2
+ // VERSION: 1.0.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Fetch HTTP and HTTPS resources directly and dispatch the body to media, HTML conversion, or plain text passthrough.
5
+ // SCOPE: Redirect following and size limits via the bounded transport, MIME and signature sniffing, local HTML conversion, and rejection of unsupported binaries.
6
+ // DEPENDS: [src/plugins/web-tools/http.ts, src/plugins/web-tools/html-markdown.ts, src/plugins/web-tools/media-loader.ts, src/plugins/web-tools/providers/exa.ts, @opencode-ai/plugin]
7
+ // LINKS: [M-WEB-NATIVE-FETCH, M-WEB-HTTP, M-WEB-HTML-MARKDOWN, M-WEB-MEDIA-LOADER]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // NativeFetchOutcome - Text or media outcome of a native fetch.
14
+ // fetchNative - Fetch one URL and dispatch its body by content.
15
+ // END_MODULE_MAP
16
+ //
17
+ // START_CHANGE_SUMMARY
18
+ // LAST_CHANGE: [v1.0.0 - Initial native fetch provider with local conversion.]
19
+ // END_CHANGE_SUMMARY
20
+ import { convertHtmlToMarkdown, convertHtmlToText } from "../html-markdown.js";
21
+ import { DEFAULT_MEDIA_MAX_BYTES, DEFAULT_TEXT_MAX_BYTES, requestBounded, WebHttpError, } from "../http.js";
22
+ import { mediaAttachmentFromBytes, sniffMediaMimeType, SUPPORTED_MEDIA_MIME_TYPES, } from "../media-loader.js";
23
+ import { WebProviderError } from "./exa.js";
24
+ const STRUCTURED_TEXT_TYPES = new Set([
25
+ "application/json",
26
+ "application/xml",
27
+ "text/xml",
28
+ "application/javascript",
29
+ "text/javascript",
30
+ ]);
31
+ // START_BLOCK_HELPERS
32
+ function normalizeContentType(declared) {
33
+ if (!declared) {
34
+ return undefined;
35
+ }
36
+ const mime = declared.split(";")[0]?.trim().toLowerCase();
37
+ return mime || undefined;
38
+ }
39
+ function isSupportedMediaMime(mime) {
40
+ return SUPPORTED_MEDIA_MIME_TYPES.includes(mime);
41
+ }
42
+ function isTextLike(mime) {
43
+ if (!mime) {
44
+ return true;
45
+ }
46
+ if (mime.startsWith("text/")) {
47
+ return true;
48
+ }
49
+ if (STRUCTURED_TEXT_TYPES.has(mime)) {
50
+ return true;
51
+ }
52
+ return mime.endsWith("+json") || mime.endsWith("+xml");
53
+ }
54
+ function looksLikeHtml(mime, text) {
55
+ if (mime === "text/html" || mime === "application/xhtml+xml") {
56
+ return true;
57
+ }
58
+ if (!mime || mime === "application/octet-stream") {
59
+ return /<\s*(html|body|div|p|h[1-6]|table)\b/i.test(text.slice(0, 2000));
60
+ }
61
+ return false;
62
+ }
63
+ // END_BLOCK_HELPERS
64
+ // START_CONTRACT: fetchNative
65
+ // PURPOSE: Fetch one URL through the bounded transport with redirects followed and dispatch the body by content.
66
+ // INPUTS: { input: url, format, abort, timeoutMs, optional maxBytes; fetchImpl: injectable fetch }
67
+ // OUTPUTS: { NativeFetchOutcome - text or media }
68
+ // SIDE_EFFECTS: performs network I/O through fetchImpl
69
+ // LINKS: M-WEB-FETCH-SERVICE
70
+ // END_CONTRACT: fetchNative
71
+ export async function fetchNative(input, fetchImpl) {
72
+ const downloadCap = input.maxBytes ?? DEFAULT_MEDIA_MAX_BYTES;
73
+ const response = await requestBounded({
74
+ url: input.url,
75
+ timeoutMs: input.timeoutMs,
76
+ maxBytes: downloadCap,
77
+ abort: input.abort,
78
+ }, fetchImpl);
79
+ const declared = normalizeContentType(response.headers.get("content-type") ?? undefined);
80
+ const sniffed = sniffMediaMimeType(response.bytes);
81
+ if (sniffed || (declared && isSupportedMediaMime(declared))) {
82
+ const attachment = mediaAttachmentFromBytes(response.bytes, {
83
+ url: response.finalUrl,
84
+ declaredContentType: declared,
85
+ maxBytes: downloadCap,
86
+ });
87
+ return { kind: "media", attachment, finalUrl: response.finalUrl, status: response.status };
88
+ }
89
+ if (isTextLike(declared)) {
90
+ const textCap = input.maxBytes ?? DEFAULT_TEXT_MAX_BYTES;
91
+ if (response.bytes.byteLength > textCap) {
92
+ throw new WebHttpError("OVERSIZED", `text response exceeded ${textCap} bytes`);
93
+ }
94
+ const text = new TextDecoder().decode(response.bytes);
95
+ const content = looksLikeHtml(declared, text)
96
+ ? input.format === "markdown"
97
+ ? convertHtmlToMarkdown(text)
98
+ : input.format === "text"
99
+ ? convertHtmlToText(text)
100
+ : text
101
+ : text;
102
+ return {
103
+ kind: "text",
104
+ content,
105
+ contentType: declared ?? "text/plain",
106
+ finalUrl: response.finalUrl,
107
+ status: response.status,
108
+ };
109
+ }
110
+ throw new WebProviderError("native", "UNSUPPORTED", `unsupported content type: ${declared ?? "unknown"}`);
111
+ }
112
+ //# sourceMappingURL=native-fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-fetch.js","sourceRoot":"","sources":["../../../../src/plugins/web-tools/providers/native-fetch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { ToolAttachment } from "@opencode-ai/plugin";
2
+ import type { WebProviderCredential } from "../config.js";
3
+ import { type FetchLike } from "../http.js";
4
+ export type SpiderOutcome = {
5
+ kind: "text";
6
+ content: string;
7
+ metadata: {
8
+ status?: number;
9
+ durationMs?: number;
10
+ };
11
+ } | {
12
+ kind: "media";
13
+ attachment: ToolAttachment;
14
+ metadata: {
15
+ status?: number;
16
+ durationMs?: number;
17
+ };
18
+ };
19
+ export declare function scrapeSpider(input: {
20
+ url: string;
21
+ format: "markdown" | "text" | "html";
22
+ credential: WebProviderCredential;
23
+ abort: AbortSignal;
24
+ timeoutMs: number;
25
+ }, fetchImpl?: FetchLike): Promise<SpiderOutcome>;
@@ -0,0 +1,104 @@
1
+ // FILE: src/plugins/web-tools/providers/spider.ts
2
+ // VERSION: 1.0.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Call the Spider.cloud Scrape API for one exact URL and serve binary targets through the shared direct media loader.
5
+ // SCOPE: Bearer auth, mapped return_format, array envelope validation, status and duration metadata, provider error mapping, and media-first dispatch.
6
+ // DEPENDS: [src/plugins/web-tools/http.ts, src/plugins/web-tools/config.ts, src/plugins/web-tools/media-loader.ts, src/plugins/web-tools/providers/exa.ts, @opencode-ai/plugin]
7
+ // LINKS: [M-WEB-SPIDER, M-WEB-HTTP, M-WEB-MEDIA-LOADER, M-WEB-FETCH-SERVICE]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // SpiderOutcome - Text or media outcome of a Spider scrape.
14
+ // scrapeSpider - Serve media targets directly, otherwise scrape one URL through Spider.
15
+ // END_MODULE_MAP
16
+ //
17
+ // START_CHANGE_SUMMARY
18
+ // LAST_CHANGE: [v1.0.0 - Initial Spider Scrape adapter.]
19
+ // END_CHANGE_SUMMARY
20
+ import { DEFAULT_TEXT_MAX_BYTES, requestBounded, } from "../http.js";
21
+ import { loadMediaAttachment, WebMediaError } from "../media-loader.js";
22
+ import { mapHttpErrorToProviderError, WebProviderError } from "./exa.js";
23
+ const SPIDER_SCRAPE_URL = "https://api.spider.cloud/scrape";
24
+ const SPIDER_RETURN_FORMAT = { markdown: "markdown", text: "text", html: "raw" };
25
+ // START_BLOCK_HELPERS
26
+ function isPlainObject(value) {
27
+ return typeof value === "object" && value !== null && !Array.isArray(value);
28
+ }
29
+ function parseSpiderResponse(bytes) {
30
+ let parsed;
31
+ try {
32
+ parsed = JSON.parse(new TextDecoder().decode(bytes));
33
+ }
34
+ catch {
35
+ throw new WebProviderError("spider", "BAD_RESPONSE", "malformed JSON response from spider");
36
+ }
37
+ if (!Array.isArray(parsed) || parsed.length === 0) {
38
+ throw new WebProviderError("spider", "BAD_RESPONSE", "unexpected spider response envelope");
39
+ }
40
+ const entry = parsed[0];
41
+ if (!isPlainObject(entry)) {
42
+ throw new WebProviderError("spider", "BAD_RESPONSE", "unexpected spider response envelope");
43
+ }
44
+ const status = typeof entry.status === "number" ? entry.status : undefined;
45
+ const duration = typeof entry.duration === "number" ? entry.duration : undefined;
46
+ const metadata = {
47
+ ...(status !== undefined ? { status } : {}),
48
+ ...(duration !== undefined ? { durationMs: duration } : {}),
49
+ };
50
+ if (entry.error) {
51
+ const detail = typeof entry.error === "string" ? entry.error : "scrape failed";
52
+ throw new WebProviderError("spider", "PROVIDER_ERROR", `spider error: ${detail}`, status);
53
+ }
54
+ const content = typeof entry.content === "string" ? entry.content : undefined;
55
+ if (content === undefined) {
56
+ throw new WebProviderError("spider", "BAD_RESPONSE", "spider response missing content");
57
+ }
58
+ return { kind: "text", content, metadata };
59
+ }
60
+ // END_BLOCK_HELPERS
61
+ // START_CONTRACT: scrapeSpider
62
+ // PURPOSE: Serve image and PDF targets through the shared media loader; scrape textual targets through Spider.
63
+ // INPUTS: { input: url, format, credential, abort, timeoutMs; fetchImpl: injectable fetch }
64
+ // OUTPUTS: { SpiderOutcome - text or media with provider metadata }
65
+ // SIDE_EFFECTS: performs network I/O through fetchImpl; never logs the credential
66
+ // LINKS: M-WEB-FETCH-SERVICE
67
+ // END_CONTRACT: scrapeSpider
68
+ export async function scrapeSpider(input, fetchImpl) {
69
+ try {
70
+ const attachment = await loadMediaAttachment({ url: input.url, abort: input.abort, timeoutMs: input.timeoutMs }, fetchImpl);
71
+ return { kind: "media", attachment, metadata: {} };
72
+ }
73
+ catch (error) {
74
+ if (!(error instanceof WebMediaError)) {
75
+ throw error;
76
+ }
77
+ }
78
+ const body = JSON.stringify({
79
+ url: input.url,
80
+ return_format: [SPIDER_RETURN_FORMAT[input.format]],
81
+ });
82
+ let response;
83
+ try {
84
+ response = await requestBounded({
85
+ url: SPIDER_SCRAPE_URL,
86
+ method: "POST",
87
+ headers: {
88
+ Authorization: `Bearer ${input.credential.value}`,
89
+ "content-type": "application/json",
90
+ accept: "application/json",
91
+ },
92
+ body,
93
+ timeoutMs: input.timeoutMs,
94
+ maxBytes: DEFAULT_TEXT_MAX_BYTES,
95
+ abort: input.abort,
96
+ }, fetchImpl);
97
+ }
98
+ catch (error) {
99
+ mapHttpErrorToProviderError(error, "spider");
100
+ throw error;
101
+ }
102
+ return parseSpiderResponse(response.bytes);
103
+ }
104
+ //# sourceMappingURL=spider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spider.js","sourceRoot":"","sources":["../../../../src/plugins/web-tools/providers/spider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { ToolAttachment } from "@opencode-ai/plugin";
2
+ import type { VvocWebRegion } from "../../../lib/vvoc-config.js";
3
+ import type { WebProviderCredential } from "../config.js";
4
+ import { type FetchLike } from "../http.js";
5
+ import { type WebSearchInput, type WebSearchResult } from "./exa.js";
6
+ type FetchFormat = "markdown" | "text" | "html";
7
+ export type ZaiReaderOutcome = {
8
+ kind: "text";
9
+ content: string;
10
+ metadata: {
11
+ status: number;
12
+ requestId?: string;
13
+ model?: string;
14
+ created?: number;
15
+ title?: string;
16
+ };
17
+ } | {
18
+ kind: "media";
19
+ attachment: ToolAttachment;
20
+ metadata: Record<string, never>;
21
+ };
22
+ export declare function searchZai(input: WebSearchInput & {
23
+ region: VvocWebRegion;
24
+ }, fetchImpl?: FetchLike): Promise<WebSearchResult[]>;
25
+ export declare function fetchZai(input: {
26
+ url: string;
27
+ format: FetchFormat;
28
+ region: VvocWebRegion;
29
+ credential: WebProviderCredential;
30
+ abort: AbortSignal;
31
+ timeoutMs: number;
32
+ }, fetchImpl?: FetchLike): Promise<ZaiReaderOutcome>;
33
+ export {};