inferoa 0.1.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 (200) hide show
  1. package/LICENSE +176 -0
  2. package/README.md +154 -0
  3. package/dist/src/app.d.ts +16 -0
  4. package/dist/src/app.js +17 -0
  5. package/dist/src/app.js.map +1 -0
  6. package/dist/src/autoresearch/state.d.ts +106 -0
  7. package/dist/src/autoresearch/state.js +469 -0
  8. package/dist/src/autoresearch/state.js.map +1 -0
  9. package/dist/src/cli.d.ts +2 -0
  10. package/dist/src/cli.js +415 -0
  11. package/dist/src/cli.js.map +1 -0
  12. package/dist/src/code-intelligence/codegraph-engine.d.ts +55 -0
  13. package/dist/src/code-intelligence/codegraph-engine.js +593 -0
  14. package/dist/src/code-intelligence/codegraph-engine.js.map +1 -0
  15. package/dist/src/code-intelligence/hub.d.ts +37 -0
  16. package/dist/src/code-intelligence/hub.js +65 -0
  17. package/dist/src/code-intelligence/hub.js.map +1 -0
  18. package/dist/src/config/config.d.ts +12 -0
  19. package/dist/src/config/config.js +229 -0
  20. package/dist/src/config/config.js.map +1 -0
  21. package/dist/src/config/defaults.d.ts +2 -0
  22. package/dist/src/config/defaults.js +44 -0
  23. package/dist/src/config/defaults.js.map +1 -0
  24. package/dist/src/config/secret-vault.d.ts +3 -0
  25. package/dist/src/config/secret-vault.js +106 -0
  26. package/dist/src/config/secret-vault.js.map +1 -0
  27. package/dist/src/context/compressor.d.ts +33 -0
  28. package/dist/src/context/compressor.js +501 -0
  29. package/dist/src/context/compressor.js.map +1 -0
  30. package/dist/src/context/prompt.d.ts +26 -0
  31. package/dist/src/context/prompt.js +572 -0
  32. package/dist/src/context/prompt.js.map +1 -0
  33. package/dist/src/daemon/serve.d.ts +2 -0
  34. package/dist/src/daemon/serve.js +11 -0
  35. package/dist/src/daemon/serve.js.map +1 -0
  36. package/dist/src/daemon/supervisor.d.ts +33 -0
  37. package/dist/src/daemon/supervisor.js +252 -0
  38. package/dist/src/daemon/supervisor.js.map +1 -0
  39. package/dist/src/goals/state.d.ts +105 -0
  40. package/dist/src/goals/state.js +736 -0
  41. package/dist/src/goals/state.js.map +1 -0
  42. package/dist/src/model/endpoint-signals.d.ts +15 -0
  43. package/dist/src/model/endpoint-signals.js +186 -0
  44. package/dist/src/model/endpoint-signals.js.map +1 -0
  45. package/dist/src/model/gateway.d.ts +11 -0
  46. package/dist/src/model/gateway.js +455 -0
  47. package/dist/src/model/gateway.js.map +1 -0
  48. package/dist/src/plans/state.d.ts +28 -0
  49. package/dist/src/plans/state.js +123 -0
  50. package/dist/src/plans/state.js.map +1 -0
  51. package/dist/src/runtime.d.ts +92 -0
  52. package/dist/src/runtime.js +757 -0
  53. package/dist/src/runtime.js.map +1 -0
  54. package/dist/src/session/store.d.ts +84 -0
  55. package/dist/src/session/store.js +593 -0
  56. package/dist/src/session/store.js.map +1 -0
  57. package/dist/src/session/workspace.d.ts +2 -0
  58. package/dist/src/session/workspace.js +14 -0
  59. package/dist/src/session/workspace.js.map +1 -0
  60. package/dist/src/skills/registry.d.ts +24 -0
  61. package/dist/src/skills/registry.js +203 -0
  62. package/dist/src/skills/registry.js.map +1 -0
  63. package/dist/src/tools/autoresearch-tools.d.ts +6 -0
  64. package/dist/src/tools/autoresearch-tools.js +412 -0
  65. package/dist/src/tools/autoresearch-tools.js.map +1 -0
  66. package/dist/src/tools/clarify-tool.d.ts +3 -0
  67. package/dist/src/tools/clarify-tool.js +107 -0
  68. package/dist/src/tools/clarify-tool.js.map +1 -0
  69. package/dist/src/tools/code-intelligence.d.ts +15 -0
  70. package/dist/src/tools/code-intelligence.js +391 -0
  71. package/dist/src/tools/code-intelligence.js.map +1 -0
  72. package/dist/src/tools/context.d.ts +11 -0
  73. package/dist/src/tools/context.js +2 -0
  74. package/dist/src/tools/context.js.map +1 -0
  75. package/dist/src/tools/goal-tools.d.ts +3 -0
  76. package/dist/src/tools/goal-tools.js +279 -0
  77. package/dist/src/tools/goal-tools.js.map +1 -0
  78. package/dist/src/tools/omni-tools.d.ts +8 -0
  79. package/dist/src/tools/omni-tools.js +349 -0
  80. package/dist/src/tools/omni-tools.js.map +1 -0
  81. package/dist/src/tools/permissions.d.ts +11 -0
  82. package/dist/src/tools/permissions.js +74 -0
  83. package/dist/src/tools/permissions.js.map +1 -0
  84. package/dist/src/tools/plan-tools.d.ts +3 -0
  85. package/dist/src/tools/plan-tools.js +314 -0
  86. package/dist/src/tools/plan-tools.js.map +1 -0
  87. package/dist/src/tools/process-tools.d.ts +6 -0
  88. package/dist/src/tools/process-tools.js +199 -0
  89. package/dist/src/tools/process-tools.js.map +1 -0
  90. package/dist/src/tools/registry.d.ts +20 -0
  91. package/dist/src/tools/registry.js +187 -0
  92. package/dist/src/tools/registry.js.map +1 -0
  93. package/dist/src/tools/schemas.d.ts +3 -0
  94. package/dist/src/tools/schemas.js +500 -0
  95. package/dist/src/tools/schemas.js.map +1 -0
  96. package/dist/src/tools/skill-tools.d.ts +6 -0
  97. package/dist/src/tools/skill-tools.js +124 -0
  98. package/dist/src/tools/skill-tools.js.map +1 -0
  99. package/dist/src/tools/text-args.d.ts +5 -0
  100. package/dist/src/tools/text-args.js +22 -0
  101. package/dist/src/tools/text-args.js.map +1 -0
  102. package/dist/src/tools/web-search.d.ts +5 -0
  103. package/dist/src/tools/web-search.js +602 -0
  104. package/dist/src/tools/web-search.js.map +1 -0
  105. package/dist/src/tools/workspace-tools.d.ts +17 -0
  106. package/dist/src/tools/workspace-tools.js +561 -0
  107. package/dist/src/tools/workspace-tools.js.map +1 -0
  108. package/dist/src/tui/activity.d.ts +11 -0
  109. package/dist/src/tui/activity.js +75 -0
  110. package/dist/src/tui/activity.js.map +1 -0
  111. package/dist/src/tui/ansi.d.ts +24 -0
  112. package/dist/src/tui/ansi.js +131 -0
  113. package/dist/src/tui/ansi.js.map +1 -0
  114. package/dist/src/tui/app.d.ts +163 -0
  115. package/dist/src/tui/app.js +4204 -0
  116. package/dist/src/tui/app.js.map +1 -0
  117. package/dist/src/tui/cache-footer.d.ts +21 -0
  118. package/dist/src/tui/cache-footer.js +75 -0
  119. package/dist/src/tui/cache-footer.js.map +1 -0
  120. package/dist/src/tui/clarify.d.ts +14 -0
  121. package/dist/src/tui/clarify.js +187 -0
  122. package/dist/src/tui/clarify.js.map +1 -0
  123. package/dist/src/tui/composer.d.ts +79 -0
  124. package/dist/src/tui/composer.js +592 -0
  125. package/dist/src/tui/composer.js.map +1 -0
  126. package/dist/src/tui/event-view.d.ts +5 -0
  127. package/dist/src/tui/event-view.js +392 -0
  128. package/dist/src/tui/event-view.js.map +1 -0
  129. package/dist/src/tui/home.d.ts +7 -0
  130. package/dist/src/tui/home.js +92 -0
  131. package/dist/src/tui/home.js.map +1 -0
  132. package/dist/src/tui/markdown.d.ts +18 -0
  133. package/dist/src/tui/markdown.js +271 -0
  134. package/dist/src/tui/markdown.js.map +1 -0
  135. package/dist/src/tui/mode-footer.d.ts +9 -0
  136. package/dist/src/tui/mode-footer.js +62 -0
  137. package/dist/src/tui/mode-footer.js.map +1 -0
  138. package/dist/src/tui/plan-view.d.ts +8 -0
  139. package/dist/src/tui/plan-view.js +45 -0
  140. package/dist/src/tui/plan-view.js.map +1 -0
  141. package/dist/src/tui/prompt-queue.d.ts +18 -0
  142. package/dist/src/tui/prompt-queue.js +27 -0
  143. package/dist/src/tui/prompt-queue.js.map +1 -0
  144. package/dist/src/tui/resize.d.ts +7 -0
  145. package/dist/src/tui/resize.js +15 -0
  146. package/dist/src/tui/resize.js.map +1 -0
  147. package/dist/src/tui/session-picker.d.ts +10 -0
  148. package/dist/src/tui/session-picker.js +17 -0
  149. package/dist/src/tui/session-picker.js.map +1 -0
  150. package/dist/src/tui/session-transcript.d.ts +2 -0
  151. package/dist/src/tui/session-transcript.js +44 -0
  152. package/dist/src/tui/session-transcript.js.map +1 -0
  153. package/dist/src/tui/slash-notice.d.ts +2 -0
  154. package/dist/src/tui/slash-notice.js +9 -0
  155. package/dist/src/tui/slash-notice.js.map +1 -0
  156. package/dist/src/tui/slash.d.ts +21 -0
  157. package/dist/src/tui/slash.js +103 -0
  158. package/dist/src/tui/slash.js.map +1 -0
  159. package/dist/src/tui/splash.d.ts +4 -0
  160. package/dist/src/tui/splash.js +64 -0
  161. package/dist/src/tui/splash.js.map +1 -0
  162. package/dist/src/tui/tool-renderer.d.ts +6 -0
  163. package/dist/src/tui/tool-renderer.js +1024 -0
  164. package/dist/src/tui/tool-renderer.js.map +1 -0
  165. package/dist/src/tui/transcript-spacing.d.ts +1 -0
  166. package/dist/src/tui/transcript-spacing.js +4 -0
  167. package/dist/src/tui/transcript-spacing.js.map +1 -0
  168. package/dist/src/types.d.ts +220 -0
  169. package/dist/src/types.js +2 -0
  170. package/dist/src/types.js.map +1 -0
  171. package/dist/src/util/abort.d.ts +3 -0
  172. package/dist/src/util/abort.js +19 -0
  173. package/dist/src/util/abort.js.map +1 -0
  174. package/dist/src/util/clock.d.ts +2 -0
  175. package/dist/src/util/clock.js +7 -0
  176. package/dist/src/util/clock.js.map +1 -0
  177. package/dist/src/util/fs.d.ts +13 -0
  178. package/dist/src/util/fs.js +75 -0
  179. package/dist/src/util/fs.js.map +1 -0
  180. package/dist/src/util/hash.d.ts +6 -0
  181. package/dist/src/util/hash.js +50 -0
  182. package/dist/src/util/hash.js.map +1 -0
  183. package/dist/src/util/limit.d.ts +11 -0
  184. package/dist/src/util/limit.js +29 -0
  185. package/dist/src/util/limit.js.map +1 -0
  186. package/dist/src/util/types.d.ts +22 -0
  187. package/dist/src/util/types.js +33 -0
  188. package/dist/src/util/types.js.map +1 -0
  189. package/dist/src/validation/acceptance.d.ts +12 -0
  190. package/dist/src/validation/acceptance.js +251 -0
  191. package/dist/src/validation/acceptance.js.map +1 -0
  192. package/dist/src/validation/milestone.d.ts +2 -0
  193. package/dist/src/validation/milestone.js +141 -0
  194. package/dist/src/validation/milestone.js.map +1 -0
  195. package/docs/final-acceptance-task.md +193 -0
  196. package/docs/public-source-hygiene.md +21 -0
  197. package/docs/roadmap.md +265 -0
  198. package/docs/tui-product-design.md +270 -0
  199. package/package.json +67 -0
  200. package/skills/coding-workflow/SKILL.md +16 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-tools.js","sourceRoot":"","sources":["../../../src/tools/skill-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function decodeEscapedTextArgument(value: string): string;
2
+ export declare function textArgumentCandidates(value: string): Array<{
3
+ text: string;
4
+ decoded_escapes: boolean;
5
+ }>;
@@ -0,0 +1,22 @@
1
+ export function decodeEscapedTextArgument(value) {
2
+ // Handle literal escaped multiline text from tool arguments: \r\n -> \n, \n -> \n, \t -> \t, \" -> ", \\ -> \.
3
+ return value
4
+ .replace(/\\r\\n/g, "\n")
5
+ .replace(/\\n/g, "\n")
6
+ .replace(/\\t/g, "\t")
7
+ .replace(/\\r/g, "\r")
8
+ .replace(/\\"/g, '"')
9
+ .replace(/\\\\/g, "\\")
10
+ .replace(/\r\n/g, "\n");
11
+ }
12
+ export function textArgumentCandidates(value) {
13
+ const decoded = decodeEscapedTextArgument(value);
14
+ if (decoded === value) {
15
+ return [{ text: value, decoded_escapes: false }];
16
+ }
17
+ return [
18
+ { text: value, decoded_escapes: false },
19
+ { text: decoded, decoded_escapes: true },
20
+ ];
21
+ }
22
+ //# sourceMappingURL=text-args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-args.js","sourceRoot":"","sources":["../../../src/tools/text-args.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,yBAAyB,CAAC,KAAa;IACrD,+GAA+G;IAC/G,OAAO,KAAK;SACT,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC;SACxB,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC;SACrB,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC;SACrB,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC;SACrB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC;SACtB,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,KAAa;IAClD,MAAM,OAAO,GAAG,yBAAyB,CAAC,KAAK,CAAC,CAAC;IACjD,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;QACtB,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,OAAO;QACL,EAAE,IAAI,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE;QACvC,EAAE,IAAI,EAAE,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE;KACzC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { JsonObject, ToolResult } from "../types.js";
2
+ import type { ToolExecutionContext } from "./context.js";
3
+ export declare function webSearch(args: JsonObject, context: ToolExecutionContext): Promise<ToolResult>;
4
+ export declare function webFetch(args: JsonObject, context: ToolExecutionContext): Promise<ToolResult>;
5
+ export declare function webOpen(args: JsonObject, context: ToolExecutionContext): Promise<ToolResult>;
@@ -0,0 +1,602 @@
1
+ import { fail, ok, truncateText } from "../util/limit.js";
2
+ import { endpointApiKey } from "../config/config.js";
3
+ const DEFAULT_FETCH_BYTES = 1_000_000;
4
+ const MAX_FETCH_BYTES = 5_000_000;
5
+ const DEFAULT_TIMEOUT_MS = 20_000;
6
+ const DEFAULT_SEARCH_TIMEOUT_MS = 20_000;
7
+ const DDG_HTML_URL = "https://html.duckduckgo.com/html/";
8
+ const DDG_INSTANT_URL = "https://api.duckduckgo.com/";
9
+ export async function webSearch(args, context) {
10
+ const query = String(args.query ?? "").trim();
11
+ if (!query) {
12
+ return fail("web_search_missing_query", "web_search requires a non-empty query.");
13
+ }
14
+ const directUrl = firstHttpUrl(query);
15
+ if (directUrl) {
16
+ const fetched = await webFetch({
17
+ url: directUrl.toString(),
18
+ max_bytes: args.max_bytes,
19
+ timeout_ms: args.timeout_ms,
20
+ }, context);
21
+ return {
22
+ ...fetched,
23
+ summary: fetched.ok ? `Fetched direct URL from search query: ${directUrl.host}` : fetched.summary,
24
+ data: {
25
+ ...objectField(fetched.data),
26
+ query,
27
+ direct_url: directUrl.toString(),
28
+ via_search: true,
29
+ },
30
+ };
31
+ }
32
+ const limit = typeof args.limit === "number" ? Math.max(1, Math.min(args.limit, 20)) : 5;
33
+ const provider = context.config.web_search.provider;
34
+ try {
35
+ if (provider === "auto" || provider === "off") {
36
+ return await defaultSearchChain(query, limit, context, provider);
37
+ }
38
+ const configured = await configuredProviderSearch(provider, query, limit, context);
39
+ if (configured.ok) {
40
+ return configured;
41
+ }
42
+ return configured;
43
+ }
44
+ catch (error) {
45
+ return fail("web_search_failed", error instanceof Error ? error.message : String(error));
46
+ }
47
+ }
48
+ export async function webFetch(args, context) {
49
+ const parsed = normalizeHttpUrl(String(args.url ?? ""));
50
+ if (!parsed) {
51
+ return fail("web_fetch_invalid_url", "web_fetch requires an http or https URL.");
52
+ }
53
+ const maxBytes = clampNumber(args.max_bytes, DEFAULT_FETCH_BYTES, 16_384, MAX_FETCH_BYTES);
54
+ const timeoutMs = clampNumber(args.timeout_ms, DEFAULT_TIMEOUT_MS, 1_000, 120_000);
55
+ const format = typeof args.format === "string" ? args.format : "text";
56
+ const controller = new AbortController();
57
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
58
+ try {
59
+ const response = await fetch(parsed.toString(), {
60
+ headers: {
61
+ accept: "text/html,application/xhtml+xml,text/plain,application/json,*/*;q=0.8",
62
+ "user-agent": "inferoa/0.1",
63
+ },
64
+ redirect: "follow",
65
+ signal: controller.signal,
66
+ });
67
+ const contentType = response.headers.get("content-type") ?? "unknown";
68
+ const { text: raw, truncated: byteTruncated, bytes } = await readResponseText(response, maxBytes);
69
+ const extracted = format === "html" ? { text: raw } : extractReadableText(raw, contentType);
70
+ const preview = truncateText(extracted.text, 18_000);
71
+ const needsResource = preview.truncated || byteTruncated || raw.length !== extracted.text.length;
72
+ const resource = needsResource
73
+ ? context.store.putResource(context.session_id, "web_fetch.text", extracted.text, {
74
+ url: parsed.toString(),
75
+ final_url: response.url,
76
+ status: response.status,
77
+ content_type: contentType,
78
+ title: extracted.title,
79
+ byte_truncated: byteTruncated,
80
+ }).uri
81
+ : undefined;
82
+ return {
83
+ ok: response.ok,
84
+ summary: `${response.ok ? "Fetched" : "Fetch returned"} ${response.status} ${contentType} from ${new URL(response.url).host}`,
85
+ data: {
86
+ url: parsed.toString(),
87
+ final_url: response.url,
88
+ status: response.status,
89
+ ok: response.ok,
90
+ content_type: contentType,
91
+ title: extracted.title,
92
+ bytes,
93
+ byte_truncated: byteTruncated,
94
+ text: preview.text,
95
+ },
96
+ resource_uri: resource,
97
+ error: response.ok ? undefined : { code: "web_fetch_http_error", message: `HTTP ${response.status}` },
98
+ };
99
+ }
100
+ catch (error) {
101
+ if (error instanceof Error && error.name === "AbortError") {
102
+ return fail("web_fetch_timeout", `Timed out after ${timeoutMs}ms`, { url: parsed.toString(), timeout_ms: timeoutMs });
103
+ }
104
+ return fail("web_fetch_failed", error instanceof Error ? error.message : String(error), { url: parsed.toString() });
105
+ }
106
+ finally {
107
+ clearTimeout(timeout);
108
+ }
109
+ }
110
+ export async function webOpen(args, context) {
111
+ const parsed = normalizeHttpUrl(String(args.url ?? ""));
112
+ if (!parsed) {
113
+ return fail("web_open_invalid_url", "web_open requires an http or https URL.");
114
+ }
115
+ const preview = await webFetch({
116
+ url: parsed.toString(),
117
+ max_bytes: args.max_bytes ?? 500_000,
118
+ timeout_ms: args.timeout_ms,
119
+ format: args.format,
120
+ }, context);
121
+ const data = objectField(preview.data);
122
+ const note = typeof args.note === "string" ? args.note : undefined;
123
+ return {
124
+ ...preview,
125
+ summary: preview.ok
126
+ ? preview.summary.replace(/^Fetched/, "Opened")
127
+ : preview.summary.replace(/^Fetch returned/, "Open returned"),
128
+ data: {
129
+ ...data,
130
+ url: parsed.toString(),
131
+ opened: true,
132
+ note,
133
+ },
134
+ };
135
+ }
136
+ function objectField(value) {
137
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
138
+ }
139
+ function stringField(value) {
140
+ return typeof value === "string" && value.trim() ? value : undefined;
141
+ }
142
+ function firstHttpUrl(value) {
143
+ const exact = normalizeHttpUrl(value);
144
+ if (exact) {
145
+ return exact;
146
+ }
147
+ for (const match of value.matchAll(/https?:\/\/[^\s<>"'`)\]]+/gi)) {
148
+ const parsed = normalizeHttpUrl(trimTrailingUrlPunctuation(match[0] ?? ""));
149
+ if (parsed) {
150
+ return parsed;
151
+ }
152
+ }
153
+ return undefined;
154
+ }
155
+ function trimTrailingUrlPunctuation(value) {
156
+ let next = value.trim();
157
+ while (/[.,;:!?。,、;:!?]$/.test(next)) {
158
+ next = next.slice(0, -1);
159
+ }
160
+ return next;
161
+ }
162
+ async function configuredProviderSearch(provider, query, limit, context) {
163
+ if (provider === "brave") {
164
+ return await braveSearch(query, limit, context);
165
+ }
166
+ if (provider === "searxng" || provider === "custom") {
167
+ return await searxngSearch(query, limit, context);
168
+ }
169
+ if (provider === "jina") {
170
+ return await jinaSearch(query, limit, context);
171
+ }
172
+ return fail("web_search_provider_unsupported", `${provider} web_search is not implemented in this build. Choose auto, brave, jina, searxng, or custom in /setup.`, { query, provider });
173
+ }
174
+ async function defaultSearchChain(query, limit, context, mode) {
175
+ const attempts = [];
176
+ const candidates = searchQueryCandidates(query);
177
+ for (const candidate of candidates) {
178
+ const html = await tryDuckDuckGoHtml(candidate, limit, attempts);
179
+ if (html.length) {
180
+ return searchResultsOk("DuckDuckGo", candidate, html, limit, attempts, { mode });
181
+ }
182
+ if (containsCjk(candidate)) {
183
+ const regional = await tryDuckDuckGoHtml(candidate, limit, attempts, "cn-zh");
184
+ if (regional.length) {
185
+ return searchResultsOk("DuckDuckGo", candidate, regional, limit, attempts, { mode, region: "cn-zh" });
186
+ }
187
+ }
188
+ }
189
+ for (const candidate of candidates) {
190
+ const instant = await tryDuckDuckGoInstant(candidate, limit, attempts);
191
+ if (instant.length) {
192
+ return searchResultsOk("DuckDuckGo Instant", candidate, instant, limit, attempts, { mode });
193
+ }
194
+ }
195
+ const jina = await jinaSearch(query, limit, context, true);
196
+ const data = objectField(jina.data);
197
+ return {
198
+ ...jina,
199
+ data: {
200
+ ...data,
201
+ mode,
202
+ attempts: attempts,
203
+ },
204
+ };
205
+ }
206
+ function searchQueryCandidates(query) {
207
+ const normalized = query.replace(/\s+/g, " ").trim();
208
+ return normalized ? [normalized] : [];
209
+ }
210
+ async function tryDuckDuckGoHtml(query, limit, attempts, region) {
211
+ const label = region ? `duckduckgo:${region}` : "duckduckgo";
212
+ try {
213
+ const url = new URL(DDG_HTML_URL);
214
+ url.searchParams.set("q", query);
215
+ if (region) {
216
+ url.searchParams.set("kl", region);
217
+ }
218
+ const response = await fetchTextWithTimeout(url, {
219
+ accept: "text/html,application/xhtml+xml",
220
+ timeoutMs: DEFAULT_SEARCH_TIMEOUT_MS,
221
+ });
222
+ if (!response.ok) {
223
+ attempts.push({ provider: label, status: "failed", message: `HTTP ${response.status}` });
224
+ return [];
225
+ }
226
+ const results = parseDuckDuckGoHtml(response.text, limit);
227
+ attempts.push({
228
+ provider: label,
229
+ status: results.length ? "ok" : "skipped",
230
+ message: results.length ? `${results.length} results` : "no results",
231
+ });
232
+ return results;
233
+ }
234
+ catch (error) {
235
+ attempts.push({ provider: label, status: "failed", message: error instanceof Error ? error.message : String(error) });
236
+ return [];
237
+ }
238
+ }
239
+ async function tryDuckDuckGoInstant(query, limit, attempts) {
240
+ try {
241
+ const url = new URL(DDG_INSTANT_URL);
242
+ url.searchParams.set("q", query);
243
+ url.searchParams.set("format", "json");
244
+ url.searchParams.set("no_html", "1");
245
+ url.searchParams.set("skip_disambig", "1");
246
+ const response = await fetchTextWithTimeout(url, {
247
+ accept: "application/json",
248
+ timeoutMs: DEFAULT_SEARCH_TIMEOUT_MS,
249
+ });
250
+ if (!response.ok) {
251
+ attempts.push({ provider: "duckduckgo:instant", status: "failed", message: `HTTP ${response.status}` });
252
+ return [];
253
+ }
254
+ const results = parseDuckDuckGoInstant(response.text, limit);
255
+ attempts.push({
256
+ provider: "duckduckgo:instant",
257
+ status: results.length ? "ok" : "skipped",
258
+ message: results.length ? `${results.length} results` : "no results",
259
+ });
260
+ return results;
261
+ }
262
+ catch (error) {
263
+ attempts.push({ provider: "duckduckgo:instant", status: "failed", message: error instanceof Error ? error.message : String(error) });
264
+ return [];
265
+ }
266
+ }
267
+ function searchResultsOk(provider, query, results, limit, attempts, extra = {}) {
268
+ return ok(`Found ${results.length} results via ${provider}`, {
269
+ query,
270
+ provider,
271
+ fallback: true,
272
+ limit,
273
+ results: results,
274
+ results_text: formatSearchResults(query, results),
275
+ attempts: attempts,
276
+ ...extra,
277
+ });
278
+ }
279
+ function parseDuckDuckGoHtml(html, limit) {
280
+ const results = [];
281
+ const blocks = html.match(/<div[^>]+class=["'][^"']*\bresult\b[^"']*["'][\s\S]*?(?=<div[^>]+class=["'][^"']*\bresult\b|<\/body>|$)/gi) ?? [html];
282
+ for (const block of blocks) {
283
+ const link = /<a[^>]+class=["'][^"']*\bresult__a\b[^"']*["'][^>]*href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/i.exec(block)
284
+ ?? /<a[^>]+href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/i.exec(block);
285
+ if (!link?.[1] || !link[2]) {
286
+ continue;
287
+ }
288
+ const url = unwrapDuckDuckGoResultUrl(decodeHtml(link[1]));
289
+ if (!url || results.some((result) => result.url === url)) {
290
+ continue;
291
+ }
292
+ const snippetMatch = /<a[^>]+class=["'][^"']*\bresult__snippet\b[^"']*["'][^>]*>([\s\S]*?)<\/a>/i.exec(block)
293
+ ?? /<div[^>]+class=["'][^"']*\bresult__snippet\b[^"']*["'][^>]*>([\s\S]*?)<\/div>/i.exec(block);
294
+ const title = normalizeText(decodeHtml(stripTags(link[2]))) || url;
295
+ const snippet = snippetMatch?.[1] ? normalizeText(decodeHtml(stripTags(snippetMatch[1]))) : undefined;
296
+ results.push({ title, url, snippet });
297
+ if (results.length >= limit) {
298
+ break;
299
+ }
300
+ }
301
+ return results;
302
+ }
303
+ function parseDuckDuckGoInstant(text, limit) {
304
+ const payload = safeJson(text);
305
+ const results = [];
306
+ const abstract = stringField(payload.AbstractText);
307
+ const abstractUrl = stringField(payload.AbstractURL);
308
+ if (abstract) {
309
+ results.push({ title: stringField(payload.Heading) ?? abstractUrl ?? "Instant answer", url: abstractUrl ?? "https://duckduckgo.com/", snippet: abstract });
310
+ }
311
+ const answer = stringField(payload.Answer);
312
+ if (answer && !results.some((result) => result.snippet === answer)) {
313
+ results.push({ title: stringField(payload.Heading) ?? "Instant answer", url: abstractUrl ?? "https://duckduckgo.com/", snippet: answer });
314
+ }
315
+ const related = Array.isArray(payload.RelatedTopics) ? flattenInstantTopics(payload.RelatedTopics) : [];
316
+ for (const item of related) {
317
+ const topic = objectField(item);
318
+ const topicText = stringField(topic.Text);
319
+ if (!topicText) {
320
+ continue;
321
+ }
322
+ const url = stringField(topic.FirstURL) ?? "https://duckduckgo.com/";
323
+ results.push({ title: topicText.split(" - ")[0] ?? topicText, url, snippet: topicText });
324
+ if (results.length >= limit) {
325
+ break;
326
+ }
327
+ }
328
+ return results.slice(0, limit);
329
+ }
330
+ function flattenInstantTopics(values) {
331
+ const output = [];
332
+ for (const value of values) {
333
+ const item = objectField(value);
334
+ const nested = item.Topics;
335
+ if (Array.isArray(nested)) {
336
+ output.push(...flattenInstantTopics(nested));
337
+ }
338
+ else if (Object.keys(item).length) {
339
+ output.push(item);
340
+ }
341
+ }
342
+ return output;
343
+ }
344
+ function formatSearchResults(query, results) {
345
+ const lines = [`search: ${query}`];
346
+ for (const [index, result] of results.entries()) {
347
+ lines.push(`${index + 1}. ${result.title}`);
348
+ lines.push(` ${result.url}`);
349
+ if (result.snippet) {
350
+ lines.push(` ${truncateText(result.snippet, 280).text}`);
351
+ }
352
+ }
353
+ return lines.join("\n");
354
+ }
355
+ function formatJsonSearchResults(query, results) {
356
+ return formatSearchResults(query, results.map((result) => {
357
+ const title = stringField(result.title) ?? stringField(result.name) ?? stringField(result.url) ?? "Untitled";
358
+ const url = stringField(result.url) ?? stringField(result.link) ?? stringField(result.href) ?? "";
359
+ const snippet = stringField(result.description) ?? stringField(result.snippet) ?? stringField(result.content);
360
+ return { title, url, snippet };
361
+ }).filter((result) => result.url));
362
+ }
363
+ function unwrapDuckDuckGoResultUrl(rawUrl) {
364
+ const candidate = rawUrl.startsWith("//") ? `https:${rawUrl}` : rawUrl.startsWith("/") ? `https://duckduckgo.com${rawUrl}` : rawUrl;
365
+ const parsed = normalizeHttpUrl(candidate);
366
+ if (!parsed) {
367
+ return undefined;
368
+ }
369
+ if (parsed.hostname.endsWith("duckduckgo.com") && parsed.pathname.startsWith("/l/")) {
370
+ const redirect = parsed.searchParams.get("uddg");
371
+ const unwrapped = redirect ? normalizeHttpUrl(redirect) : undefined;
372
+ return unwrapped?.toString() ?? parsed.toString();
373
+ }
374
+ return parsed.toString();
375
+ }
376
+ async function fetchTextWithTimeout(url, options) {
377
+ const controller = new AbortController();
378
+ const timeout = setTimeout(() => controller.abort(), options.timeoutMs);
379
+ try {
380
+ const response = await fetch(url, {
381
+ headers: {
382
+ accept: options.accept,
383
+ "user-agent": "inferoa/0.1",
384
+ },
385
+ redirect: "follow",
386
+ signal: controller.signal,
387
+ });
388
+ return { ok: response.ok, status: response.status, text: await response.text() };
389
+ }
390
+ finally {
391
+ clearTimeout(timeout);
392
+ }
393
+ }
394
+ function containsCjk(value) {
395
+ return [...value].some((char) => {
396
+ const code = char.codePointAt(0) ?? 0;
397
+ return (code >= 0x3400 && code <= 0x9fff) || (code >= 0xf900 && code <= 0xfaff);
398
+ });
399
+ }
400
+ function stripTags(value) {
401
+ return value.replace(/<script\b[\s\S]*?<\/script>/gi, " ").replace(/<style\b[\s\S]*?<\/style>/gi, " ").replace(/<[^>]+>/g, " ");
402
+ }
403
+ function safeJson(value) {
404
+ try {
405
+ const parsed = JSON.parse(value);
406
+ return objectField(parsed);
407
+ }
408
+ catch {
409
+ return {};
410
+ }
411
+ }
412
+ async function braveSearch(query, limit, context) {
413
+ const apiKey = endpointApiKey(context.config.web_search);
414
+ if (!apiKey) {
415
+ return fail("brave_api_key_missing", "BRAVE web search requires api_key or api_key_ref.");
416
+ }
417
+ const url = new URL("https://api.search.brave.com/res/v1/web/search");
418
+ url.searchParams.set("q", query);
419
+ url.searchParams.set("count", String(limit));
420
+ const response = await fetch(url, {
421
+ headers: {
422
+ accept: "application/json",
423
+ "x-subscription-token": apiKey,
424
+ },
425
+ });
426
+ if (!response.ok) {
427
+ return fail("brave_search_failed", `Brave returned ${response.status}: ${await response.text()}`);
428
+ }
429
+ const json = (await response.json());
430
+ const results = (json.web?.results ?? []).slice(0, limit);
431
+ return ok(`Found ${results.length} Brave results`, {
432
+ query,
433
+ provider: "brave",
434
+ results: results,
435
+ results_text: formatJsonSearchResults(query, results),
436
+ limit,
437
+ });
438
+ }
439
+ async function searxngSearch(query, limit, context) {
440
+ if (!context.config.web_search.base_url) {
441
+ return fail("searxng_base_url_missing", "searxng/custom web_search requires base_url.");
442
+ }
443
+ const url = new URL(context.config.web_search.base_url.replace(/\/$/, "") + "/search");
444
+ url.searchParams.set("q", query);
445
+ url.searchParams.set("format", "json");
446
+ const response = await fetch(url, { headers: { accept: "application/json" } });
447
+ if (!response.ok) {
448
+ return fail("searxng_search_failed", `Search returned ${response.status}: ${await response.text()}`);
449
+ }
450
+ const json = (await response.json());
451
+ const results = (json.results ?? []).slice(0, limit);
452
+ return ok(`Found ${results.length} search results`, {
453
+ query,
454
+ provider: context.config.web_search.provider,
455
+ results: results,
456
+ results_text: formatJsonSearchResults(query, results),
457
+ limit,
458
+ });
459
+ }
460
+ async function jinaSearch(query, limit, context, fallback = false) {
461
+ const url = new URL("https://s.jina.ai/");
462
+ url.searchParams.set("q", query);
463
+ const apiKey = endpointApiKey(context.config.web_search);
464
+ const headers = { accept: "application/json" };
465
+ if (apiKey) {
466
+ headers.authorization = `Bearer ${apiKey}`;
467
+ }
468
+ const response = await fetch(url, { headers });
469
+ const text = await response.text();
470
+ if (!response.ok) {
471
+ return fail("jina_search_failed", `Jina returned ${response.status}: ${text}`);
472
+ }
473
+ const truncated = truncateText(text, 12_000);
474
+ const resource = truncated.truncated ? context.store.putResource(context.session_id, "web_search.raw", text, { query, provider: "jina" }).uri : undefined;
475
+ return {
476
+ ok: true,
477
+ summary: `${fallback ? "Fallback search" : "Jina search"} returned ${text.length} chars`,
478
+ data: {
479
+ query,
480
+ provider: "jina",
481
+ fallback,
482
+ results_text: truncated.text,
483
+ limit,
484
+ },
485
+ resource_uri: resource,
486
+ };
487
+ }
488
+ function normalizeHttpUrl(value) {
489
+ try {
490
+ const url = new URL(value.trim());
491
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
492
+ return undefined;
493
+ }
494
+ return url;
495
+ }
496
+ catch {
497
+ return undefined;
498
+ }
499
+ }
500
+ function clampNumber(value, fallback, min, max) {
501
+ if (typeof value !== "number" || !Number.isFinite(value)) {
502
+ return fallback;
503
+ }
504
+ return Math.max(min, Math.min(Math.trunc(value), max));
505
+ }
506
+ async function readResponseText(response, maxBytes) {
507
+ if (!response.body) {
508
+ const text = await response.text();
509
+ return { text, bytes: Buffer.byteLength(text), truncated: false };
510
+ }
511
+ const reader = response.body.getReader();
512
+ const chunks = [];
513
+ let bytes = 0;
514
+ let truncated = false;
515
+ while (true) {
516
+ const { done, value } = await reader.read();
517
+ if (done) {
518
+ break;
519
+ }
520
+ const chunk = value ?? new Uint8Array();
521
+ const remaining = maxBytes - bytes;
522
+ if (chunk.byteLength > remaining) {
523
+ chunks.push(chunk.slice(0, Math.max(0, remaining)));
524
+ bytes = maxBytes;
525
+ truncated = true;
526
+ await reader.cancel().catch(() => undefined);
527
+ break;
528
+ }
529
+ chunks.push(chunk);
530
+ bytes += chunk.byteLength;
531
+ }
532
+ return { text: new TextDecoder("utf-8", { fatal: false }).decode(concatChunks(chunks, bytes)), bytes, truncated };
533
+ }
534
+ function concatChunks(chunks, length) {
535
+ const out = new Uint8Array(length);
536
+ let offset = 0;
537
+ for (const chunk of chunks) {
538
+ out.set(chunk, offset);
539
+ offset += chunk.byteLength;
540
+ }
541
+ return out;
542
+ }
543
+ function extractReadableText(raw, contentType) {
544
+ if (!/html|xml/i.test(contentType) && !looksLikeHtml(raw)) {
545
+ return { text: normalizeText(raw) };
546
+ }
547
+ const withoutHidden = raw
548
+ .replace(/<!--[\s\S]*?-->/g, " ")
549
+ .replace(/<script\b[\s\S]*?<\/script>/gi, " ")
550
+ .replace(/<style\b[\s\S]*?<\/style>/gi, " ")
551
+ .replace(/<noscript\b[\s\S]*?<\/noscript>/gi, " ");
552
+ const titleMatch = /<title\b[^>]*>([\s\S]*?)<\/title>/i.exec(withoutHidden);
553
+ const title = titleMatch?.[1] ? normalizeText(decodeHtml(titleMatch[1].replace(/<[^>]+>/g, " "))) : undefined;
554
+ const withBreaks = withoutHidden
555
+ .replace(/<(br|hr)\b[^>]*>/gi, "\n")
556
+ .replace(/<\/(p|div|section|article|header|footer|main|li|tr|h[1-6])>/gi, "\n")
557
+ .replace(/<li\b[^>]*>/gi, "- ");
558
+ return { title, text: normalizeText(decodeHtml(withBreaks.replace(/<[^>]+>/g, " "))) };
559
+ }
560
+ function looksLikeHtml(text) {
561
+ return /<!doctype\s+html|<html\b|<body\b|<title\b/i.test(text.slice(0, 4096));
562
+ }
563
+ function normalizeText(text) {
564
+ return text
565
+ .replace(/\r\n?/g, "\n")
566
+ .split("\n")
567
+ .map((line) => line.replace(/[ \t\f\v]+/g, " ").trim())
568
+ .join("\n")
569
+ .replace(/\n{3,}/g, "\n\n")
570
+ .trim();
571
+ }
572
+ function decodeHtml(text) {
573
+ return text.replace(/&(#x?[0-9a-f]+|[a-z]+);/gi, (entity, token) => {
574
+ if (token.startsWith("#x")) {
575
+ return fromCodePoint(Number.parseInt(token.slice(2), 16), entity);
576
+ }
577
+ if (token.startsWith("#")) {
578
+ return fromCodePoint(Number.parseInt(token.slice(1), 10), entity);
579
+ }
580
+ const named = {
581
+ amp: "&",
582
+ apos: "'",
583
+ gt: ">",
584
+ lt: "<",
585
+ nbsp: " ",
586
+ quot: "\"",
587
+ };
588
+ return named[token.toLowerCase()] ?? entity;
589
+ });
590
+ }
591
+ function fromCodePoint(value, fallback) {
592
+ if (!Number.isFinite(value)) {
593
+ return fallback;
594
+ }
595
+ try {
596
+ return String.fromCodePoint(value);
597
+ }
598
+ catch {
599
+ return fallback;
600
+ }
601
+ }
602
+ //# sourceMappingURL=web-search.js.map