@vextlabs/theron-cli 0.2.1 → 0.4.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 (191) hide show
  1. package/dist/api.d.ts +8 -0
  2. package/dist/api.js +3 -0
  3. package/dist/api.js.map +1 -1
  4. package/dist/auth.js +51 -1
  5. package/dist/auth.js.map +1 -1
  6. package/dist/banner.js +3 -2
  7. package/dist/banner.js.map +1 -1
  8. package/dist/checkpoints.d.ts +32 -0
  9. package/dist/checkpoints.js +61 -0
  10. package/dist/checkpoints.js.map +1 -0
  11. package/dist/index.js +61 -5
  12. package/dist/index.js.map +1 -1
  13. package/dist/input.d.ts +61 -0
  14. package/dist/input.js +574 -0
  15. package/dist/input.js.map +1 -0
  16. package/dist/profiles/index.js +5 -0
  17. package/dist/profiles/index.js.map +1 -1
  18. package/dist/profiles/methodologies/build_domains.d.ts +6 -0
  19. package/dist/profiles/methodologies/build_domains.js +170 -0
  20. package/dist/profiles/methodologies/build_domains.js.map +1 -0
  21. package/dist/profiles/methodologies/operate_domains.d.ts +8 -0
  22. package/dist/profiles/methodologies/operate_domains.js +1239 -0
  23. package/dist/profiles/methodologies/operate_domains.js.map +1 -0
  24. package/dist/profiles/methodologies/regulated_domains.d.ts +6 -0
  25. package/dist/profiles/methodologies/regulated_domains.js +153 -0
  26. package/dist/profiles/methodologies/regulated_domains.js.map +1 -0
  27. package/dist/profiles/methodologies/research_domains.d.ts +8 -0
  28. package/dist/profiles/methodologies/research_domains.js +179 -0
  29. package/dist/profiles/methodologies/research_domains.js.map +1 -0
  30. package/dist/profiles/methodologies/strategy_domains.d.ts +15 -0
  31. package/dist/profiles/methodologies/strategy_domains.js +193 -0
  32. package/dist/profiles/methodologies/strategy_domains.js.map +1 -0
  33. package/dist/profiles/seeds.js +241 -95
  34. package/dist/profiles/seeds.js.map +1 -1
  35. package/dist/receipt.d.ts +17 -0
  36. package/dist/receipt.js +46 -0
  37. package/dist/receipt.js.map +1 -0
  38. package/dist/render.d.ts +4 -1
  39. package/dist/render.js +95 -28
  40. package/dist/render.js.map +1 -1
  41. package/dist/repl.d.ts +8 -1
  42. package/dist/repl.js +420 -62
  43. package/dist/repl.js.map +1 -1
  44. package/dist/sessions.d.ts +14 -0
  45. package/dist/sessions.js +100 -0
  46. package/dist/sessions.js.map +1 -1
  47. package/dist/ship.d.ts +2 -0
  48. package/dist/ship.js +62 -0
  49. package/dist/ship.js.map +1 -0
  50. package/dist/skills/catalog.d.ts +13 -0
  51. package/dist/skills/catalog.js +86 -0
  52. package/dist/skills/catalog.js.map +1 -0
  53. package/dist/tools/bash.js +81 -14
  54. package/dist/tools/bash.js.map +1 -1
  55. package/dist/tools/edit.js +21 -1
  56. package/dist/tools/edit.js.map +1 -1
  57. package/dist/tools/glob.js +4 -1
  58. package/dist/tools/glob.js.map +1 -1
  59. package/dist/tools/grep.d.ts +5 -0
  60. package/dist/tools/grep.js +101 -2
  61. package/dist/tools/grep.js.map +1 -1
  62. package/dist/tools/index.d.ts +22 -0
  63. package/dist/tools/index.js +177 -41
  64. package/dist/tools/index.js.map +1 -1
  65. package/dist/tools/ls.d.ts +3 -0
  66. package/dist/tools/ls.js +23 -12
  67. package/dist/tools/ls.js.map +1 -1
  68. package/dist/tools/multiedit.d.ts +12 -0
  69. package/dist/tools/multiedit.js +79 -0
  70. package/dist/tools/multiedit.js.map +1 -0
  71. package/dist/tools/stoa.d.ts +1 -1
  72. package/dist/tools/stoa.js +7 -3
  73. package/dist/tools/stoa.js.map +1 -1
  74. package/dist/tools/task.d.ts +9 -0
  75. package/dist/tools/task.js +166 -0
  76. package/dist/tools/task.js.map +1 -0
  77. package/dist/tools/todowrite.d.ts +12 -0
  78. package/dist/tools/todowrite.js +38 -0
  79. package/dist/tools/todowrite.js.map +1 -0
  80. package/dist/tools/webfetch.d.ts +6 -0
  81. package/dist/tools/webfetch.js +98 -0
  82. package/dist/tools/webfetch.js.map +1 -0
  83. package/dist/tools/websearch.d.ts +7 -0
  84. package/dist/tools/websearch.js +83 -0
  85. package/dist/tools/websearch.js.map +1 -0
  86. package/dist/tools/write.js +17 -1
  87. package/dist/tools/write.js.map +1 -1
  88. package/dist/verifiers/calc_gate.d.ts +2 -0
  89. package/dist/verifiers/calc_gate.js +112 -0
  90. package/dist/verifiers/calc_gate.js.map +1 -0
  91. package/dist/verifiers/citation_gate.d.ts +2 -0
  92. package/dist/verifiers/citation_gate.js +130 -0
  93. package/dist/verifiers/citation_gate.js.map +1 -0
  94. package/dist/verifiers/confidence_marked.d.ts +2 -0
  95. package/dist/verifiers/confidence_marked.js +49 -0
  96. package/dist/verifiers/confidence_marked.js.map +1 -0
  97. package/dist/verifiers/disclaimer_gate.d.ts +2 -0
  98. package/dist/verifiers/disclaimer_gate.js +57 -0
  99. package/dist/verifiers/disclaimer_gate.js.map +1 -0
  100. package/dist/verifiers/evidence_gate.d.ts +2 -0
  101. package/dist/verifiers/evidence_gate.js +108 -0
  102. package/dist/verifiers/evidence_gate.js.map +1 -0
  103. package/dist/verifiers/index.d.ts +5 -0
  104. package/dist/verifiers/index.js +28 -7
  105. package/dist/verifiers/index.js.map +1 -1
  106. package/dist/verifiers/lint.js +4 -3
  107. package/dist/verifiers/lint.js.map +1 -1
  108. package/dist/verifiers/promoted_kernels.d.ts +8 -0
  109. package/dist/verifiers/promoted_kernels.js +190 -0
  110. package/dist/verifiers/promoted_kernels.js.map +1 -0
  111. package/dist/verifiers/source_gate.d.ts +2 -0
  112. package/dist/verifiers/source_gate.js +125 -0
  113. package/dist/verifiers/source_gate.js.map +1 -0
  114. package/dist/verifiers/test_smoke.js +30 -0
  115. package/dist/verifiers/test_smoke.js.map +1 -1
  116. package/dist/verifiers/types.d.ts +3 -0
  117. package/package.json +4 -2
  118. package/skills/README.md +123 -0
  119. package/skills/ab-test.md +89 -0
  120. package/skills/api-design.md +175 -0
  121. package/skills/architecture-design.md +185 -0
  122. package/skills/business-case.md +77 -0
  123. package/skills/causal-inference.md +77 -0
  124. package/skills/clinical-guideline.md +98 -0
  125. package/skills/code-review.md +98 -0
  126. package/skills/cold-outreach.md +268 -0
  127. package/skills/competitive-teardown.md +223 -0
  128. package/skills/component-spec.md +121 -0
  129. package/skills/content-calendar.md +280 -0
  130. package/skills/contract-review.md +155 -0
  131. package/skills/data-analysis.md +187 -0
  132. package/skills/debug.md +91 -0
  133. package/skills/design-audit.md +121 -0
  134. package/skills/differential-diagnosis.md +79 -0
  135. package/skills/discovery-call.md +206 -0
  136. package/skills/edit-pass.md +80 -0
  137. package/skills/engineering-calc.md +101 -0
  138. package/skills/estimate.md +70 -0
  139. package/skills/experiment-design.md +105 -0
  140. package/skills/fact-check.md +82 -0
  141. package/skills/financial-model.md +104 -0
  142. package/skills/grant-proposal.md +93 -0
  143. package/skills/harmony-analysis.md +93 -0
  144. package/skills/hypothesis-generation.md +99 -0
  145. package/skills/incident-response.md +134 -0
  146. package/skills/interview-loop.md +62 -0
  147. package/skills/job-scorecard.md +92 -0
  148. package/skills/kb-article.md +174 -0
  149. package/skills/launch-plan.md +85 -0
  150. package/skills/lease-review.md +93 -0
  151. package/skills/lesson-plan.md +198 -0
  152. package/skills/literature-review.md +69 -0
  153. package/skills/market-entry.md +137 -0
  154. package/skills/market-sizing.md +159 -0
  155. package/skills/meta-analysis.md +140 -0
  156. package/skills/migrate.md +117 -0
  157. package/skills/optimize.md +88 -0
  158. package/skills/options-strategy.md +166 -0
  159. package/skills/peer-review.md +96 -0
  160. package/skills/pentest-plan.md +193 -0
  161. package/skills/pitch-review.md +132 -0
  162. package/skills/plan.md +88 -0
  163. package/skills/policy-brief.md +124 -0
  164. package/skills/positioning.md +192 -0
  165. package/skills/postmortem.md +168 -0
  166. package/skills/prd.md +105 -0
  167. package/skills/prioritize.md +162 -0
  168. package/skills/proof.md +91 -0
  169. package/skills/property-underwrite.md +159 -0
  170. package/skills/recipe-develop.md +109 -0
  171. package/skills/red-team.md +142 -0
  172. package/skills/refactor.md +58 -0
  173. package/skills/reflection-session.md +115 -0
  174. package/skills/regulatory-compliance.md +136 -0
  175. package/skills/reproduce.md +87 -0
  176. package/skills/runbook.md +344 -0
  177. package/skills/security-audit.md +154 -0
  178. package/skills/seo-brief.md +201 -0
  179. package/skills/sql-query.md +161 -0
  180. package/skills/story-craft.md +163 -0
  181. package/skills/tdd.md +59 -0
  182. package/skills/term-sheet.md +298 -0
  183. package/skills/theory-of-change.md +88 -0
  184. package/skills/threat-model.md +104 -0
  185. package/skills/ticket-triage.md +200 -0
  186. package/skills/tolerance-analysis.md +149 -0
  187. package/skills/training-program.md +151 -0
  188. package/skills/translate.md +64 -0
  189. package/skills/unit-economics.md +238 -0
  190. package/skills/valuation.md +112 -0
  191. package/skills/write-tests.md +77 -0
@@ -0,0 +1,166 @@
1
+ // Task tool — bounded read-only subagent over fetch to /api/cli/chat.
2
+ // Allows only Read/Grep/Glob/LS. Aggregate AbortController timeout (default 300s).
3
+ // No agent_type param (CLI version).
4
+ import { execRead } from "./read.js";
5
+ import { execGrep } from "./grep.js";
6
+ import { execGlob } from "./glob.js";
7
+ import { execLs } from "./ls.js";
8
+ import { buildLocalToolSchemas } from "@vextlabs/theron-agent-sdk";
9
+ const MAX_TURNS = 10;
10
+ const DEFAULT_TIMEOUT_SECONDS = 300;
11
+ // Read-only tool schemas for the sub-agent.
12
+ const READ_ONLY_SCHEMAS = buildLocalToolSchemas({
13
+ Read: "Read a file from the workspace.",
14
+ Grep: "Search file contents with a regex.",
15
+ Glob: "Find files by glob pattern.",
16
+ LS: "List files and directories in a path.",
17
+ });
18
+ const READ_ONLY_NAMES = new Set(["Read", "Grep", "Glob", "LS"]);
19
+ const READ_ONLY_TOOL_SCHEMAS = READ_ONLY_SCHEMAS.filter((s) => READ_ONLY_NAMES.has(s.function.name));
20
+ export async function execTask(args, ctx) {
21
+ if (!args.prompt || !args.prompt.trim()) {
22
+ return "[error] prompt must be a non-empty string.";
23
+ }
24
+ if (!ctx.apiUrl) {
25
+ return "[error] apiUrl not configured — cannot spawn subagent.";
26
+ }
27
+ const timeoutMs = Math.max(10_000, (args.timeout_seconds ?? DEFAULT_TIMEOUT_SECONDS) * 1000);
28
+ const abort = new AbortController();
29
+ const timer = setTimeout(() => abort.abort(new Error(`Task timed out after ${timeoutMs / 1000}s`)), timeoutMs);
30
+ try {
31
+ return await runTask(args, ctx, abort.signal);
32
+ }
33
+ finally {
34
+ clearTimeout(timer);
35
+ }
36
+ }
37
+ async function runTask(args, ctx, signal) {
38
+ const messages = [
39
+ { role: "user", content: args.prompt.trim() },
40
+ ];
41
+ const accumulatedText = [];
42
+ const label = args.description ? `[Task: ${args.description}]` : "[Task]";
43
+ for (let turn = 0; turn < MAX_TURNS; turn++) {
44
+ if (signal.aborted) {
45
+ return `${label}\n[error] Task timed out.\n${accumulatedText.join("")}`;
46
+ }
47
+ let response;
48
+ try {
49
+ const turnSignal = AbortSignal.any
50
+ ? AbortSignal.any([signal, AbortSignal.timeout(60_000)])
51
+ : signal;
52
+ response = await fetch(`${ctx.apiUrl.replace(/\/$/, "")}/api/cli/chat`, {
53
+ method: "POST",
54
+ headers: {
55
+ "content-type": "application/json",
56
+ ...(ctx.apiKey ? { authorization: `Bearer ${ctx.apiKey}` } : {}),
57
+ accept: "application/x-ndjson",
58
+ },
59
+ body: JSON.stringify({
60
+ messages,
61
+ tools: READ_ONLY_TOOL_SCHEMAS,
62
+ surface: "cli",
63
+ }),
64
+ signal: turnSignal,
65
+ });
66
+ }
67
+ catch (err) {
68
+ return `${label}\n[error] Network error on turn ${turn + 1}: ${err instanceof Error ? err.message : String(err)}\n${accumulatedText.join("")}`;
69
+ }
70
+ if (!response.ok || !response.body) {
71
+ let detail = "";
72
+ try {
73
+ detail = (await response.text()).slice(0, 300);
74
+ }
75
+ catch { /* ignore */ }
76
+ return `${label}\n[error] HTTP ${response.status} on turn ${turn + 1}: ${detail}\n${accumulatedText.join("")}`;
77
+ }
78
+ const reader = response.body.getReader();
79
+ const decoder = new TextDecoder();
80
+ let buf = "";
81
+ let turnText = "";
82
+ const toolCalls = [];
83
+ let stopReason = "end_turn";
84
+ try {
85
+ outer: while (true) {
86
+ const { done, value } = await reader.read();
87
+ if (done)
88
+ break;
89
+ buf += decoder.decode(value, { stream: true });
90
+ let idx;
91
+ while ((idx = buf.indexOf("\n")) >= 0) {
92
+ const line = buf.slice(0, idx).trim();
93
+ buf = buf.slice(idx + 1);
94
+ if (!line)
95
+ continue;
96
+ let frame;
97
+ try {
98
+ frame = JSON.parse(line);
99
+ }
100
+ catch {
101
+ continue;
102
+ }
103
+ if (frame.type === "text_delta" && frame.delta) {
104
+ turnText += frame.delta;
105
+ }
106
+ else if (frame.type === "tool_call" && frame.id && frame.name && frame.args) {
107
+ toolCalls.push({ id: frame.id, name: frame.name, args: frame.args });
108
+ }
109
+ else if (frame.type === "turn_end" && frame.stop_reason) {
110
+ stopReason = frame.stop_reason;
111
+ break outer;
112
+ }
113
+ else if (frame.type === "error" && frame.message) {
114
+ return `${label}\n[error] Subagent error: ${frame.message}\n${accumulatedText.join("")}`;
115
+ }
116
+ }
117
+ }
118
+ }
119
+ catch (err) {
120
+ return `${label}\n[error] Stream error on turn ${turn + 1}: ${err instanceof Error ? err.message : String(err)}\n${accumulatedText.join("")}`;
121
+ }
122
+ if (turnText)
123
+ accumulatedText.push(turnText);
124
+ messages.push({ role: "assistant", content: turnText, tool_calls: toolCalls });
125
+ if (stopReason !== "tool_use" || toolCalls.length === 0)
126
+ break;
127
+ for (const call of toolCalls) {
128
+ if (!READ_ONLY_NAMES.has(call.name)) {
129
+ messages.push({
130
+ role: "tool",
131
+ tool_call_id: call.id,
132
+ content: `[error] Tool "${call.name}" is not available in a read-only subagent.`,
133
+ });
134
+ continue;
135
+ }
136
+ let result;
137
+ try {
138
+ switch (call.name) {
139
+ case "Read":
140
+ result = await execRead(call.args, ctx);
141
+ break;
142
+ case "Grep":
143
+ result = await execGrep(call.args, ctx);
144
+ break;
145
+ case "Glob":
146
+ result = await execGlob(call.args, ctx);
147
+ break;
148
+ case "LS":
149
+ result = await execLs(call.args, ctx);
150
+ break;
151
+ default:
152
+ result = `[error] Unknown read-only tool: ${call.name}`;
153
+ }
154
+ }
155
+ catch (err) {
156
+ result = `[error] ${call.name} threw: ${err instanceof Error ? err.message : String(err)}`;
157
+ }
158
+ messages.push({ role: "tool", tool_call_id: call.id, content: result });
159
+ }
160
+ }
161
+ const finalText = accumulatedText.join("").trim();
162
+ if (!finalText)
163
+ return `${label}\n[subagent returned no text]`;
164
+ return `${label}\n${finalText}`;
165
+ }
166
+ //# sourceMappingURL=task.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task.js","sourceRoot":"","sources":["../../src/tools/task.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { ToolContext } from "./index.js";
2
+ export interface TodoItem {
3
+ content: string;
4
+ status: "pending" | "in_progress" | "completed";
5
+ activeForm?: string;
6
+ }
7
+ interface TodoWriteArgs {
8
+ todos: TodoItem[];
9
+ }
10
+ export declare function execTodoWrite(args: TodoWriteArgs, _ctx: ToolContext): Promise<string>;
11
+ export declare function describeCurrentList(): string;
12
+ export {};
@@ -0,0 +1,38 @@
1
+ // TodoWrite tool — structured task list for the current session.
2
+ // Module-level state persists across tool calls within one CLI session.
3
+ // Module-level state — persists for the CLI session.
4
+ let todoList = [];
5
+ export async function execTodoWrite(args, _ctx) {
6
+ if (!Array.isArray(args.todos)) {
7
+ return "[error] todos must be an array.";
8
+ }
9
+ for (const item of args.todos) {
10
+ if (typeof item.content !== "string" || !item.content.trim()) {
11
+ return "[error] Each todo must have a non-empty string content field.";
12
+ }
13
+ if (!["pending", "in_progress", "completed"].includes(item.status)) {
14
+ return `[error] Invalid status "${item.status}" — must be pending, in_progress, or completed.`;
15
+ }
16
+ }
17
+ todoList = args.todos.map((t) => ({
18
+ content: t.content,
19
+ status: t.status,
20
+ activeForm: t.activeForm ?? "",
21
+ }));
22
+ return renderList(todoList);
23
+ }
24
+ function renderList(list) {
25
+ if (list.length === 0)
26
+ return "Todo list is empty.";
27
+ const lines = list.map((item) => {
28
+ const mark = item.status === "completed" ? "[x]" :
29
+ item.status === "in_progress" ? "[~]" :
30
+ "[ ]";
31
+ return `${mark} ${item.content}`;
32
+ });
33
+ return lines.join("\n");
34
+ }
35
+ export function describeCurrentList() {
36
+ return renderList(todoList);
37
+ }
38
+ //# sourceMappingURL=todowrite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"todowrite.js","sourceRoot":"","sources":["../../src/tools/todowrite.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,wEAAwE;AAUxE,qDAAqD;AACrD,IAAI,QAAQ,GAAe,EAAE,CAAC;AAM9B,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAmB,EAAE,IAAiB;IACxE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,iCAAiC,CAAC;IAC3C,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;YAC7D,OAAO,+DAA+D,CAAC;QACzE,CAAC;QACD,IAAI,CAAC,CAAC,SAAS,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACnE,OAAO,2BAA2B,IAAI,CAAC,MAAM,iDAAiD,CAAC;QACjG,CAAC;IACH,CAAC;IACD,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAChC,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,UAAU,EAAE,CAAC,CAAC,UAAU,IAAI,EAAE;KAC/B,CAAC,CAAC,CAAC;IACJ,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,UAAU,CAAC,IAAgB;IAClC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,qBAAqB,CAAC;IACpD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAC9B,MAAM,IAAI,GACR,IAAI,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACrC,IAAI,CAAC,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;gBACvC,KAAK,CAAC;QACR,OAAO,GAAG,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;IACnC,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { ToolContext } from "./index.js";
2
+ interface WebFetchArgs {
3
+ url: string;
4
+ }
5
+ export declare function execWebFetch(args: WebFetchArgs, ctx: ToolContext): Promise<string>;
6
+ export {};
@@ -0,0 +1,98 @@
1
+ // WebFetch tool — fetches a URL, strips HTML to readable text, 15s timeout,
2
+ // truncates to ctx.maxBytes. SSRF guard rejects file://, loopback, and
3
+ // private IP ranges.
4
+ // Patterns to strip from HTML before returning to the model.
5
+ const SCRIPT_STYLE_RE = /<(script|style)[^>]*>[\s\S]*?<\/\1>/gi;
6
+ const HTML_COMMENT_RE = /<!--[\s\S]*?-->/g;
7
+ const HTML_TAG_RE = /<[^>]+>/g;
8
+ const MULTI_BLANK_RE = /\n{3,}/g;
9
+ /** Returns an error string if the URL should be rejected, else null. */
10
+ function ssrfCheck(parsed) {
11
+ if (parsed.protocol === "file:")
12
+ return "file: protocol is not allowed.";
13
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
14
+ return `protocol "${parsed.protocol}" is not allowed; only http: and https: are permitted.`;
15
+ }
16
+ const host = parsed.hostname.toLowerCase();
17
+ if (host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]") {
18
+ return `host "${host}" is a loopback address and is not allowed.`;
19
+ }
20
+ const v4 = host.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
21
+ if (v4) {
22
+ const [, a, b] = v4.map(Number);
23
+ if (a === 10)
24
+ return `host "${host}" is in a private IP range and is not allowed.`;
25
+ if (a === 172 && b >= 16 && b <= 31)
26
+ return `host "${host}" is in a private IP range and is not allowed.`;
27
+ if (a === 192 && b === 168)
28
+ return `host "${host}" is in a private IP range and is not allowed.`;
29
+ if (a === 169 && b === 254)
30
+ return `host "${host}" is a link-local address and is not allowed.`;
31
+ }
32
+ return null;
33
+ }
34
+ export async function execWebFetch(args, ctx) {
35
+ let parsed;
36
+ try {
37
+ parsed = new URL(args.url);
38
+ }
39
+ catch {
40
+ return `[error] Invalid URL: ${args.url}`;
41
+ }
42
+ const ssrfErr = ssrfCheck(parsed);
43
+ if (ssrfErr)
44
+ return `[error] SSRF guard: ${ssrfErr}`;
45
+ const url = parsed.toString();
46
+ let response;
47
+ try {
48
+ response = await fetch(url, {
49
+ headers: {
50
+ "user-agent": "Mozilla/5.0 (compatible; TheronCLI/1.0; +https://itstheron.com)",
51
+ "accept": "text/html,application/xhtml+xml,text/plain;q=0.9,*/*;q=0.8",
52
+ },
53
+ signal: AbortSignal.timeout(15_000),
54
+ });
55
+ }
56
+ catch (err) {
57
+ return `[error] Fetch failed for ${url}: ${err instanceof Error ? err.message : String(err)}`;
58
+ }
59
+ if (!response.ok) {
60
+ return `[error] HTTP ${response.status} ${response.statusText} for ${url}`;
61
+ }
62
+ const contentType = response.headers.get("content-type") ?? "";
63
+ let body;
64
+ try {
65
+ body = await response.text();
66
+ }
67
+ catch (err) {
68
+ return `[error] Could not read response body: ${err instanceof Error ? err.message : String(err)}`;
69
+ }
70
+ let text;
71
+ if (contentType.includes("html")) {
72
+ text = body
73
+ .replace(SCRIPT_STYLE_RE, " ")
74
+ .replace(HTML_COMMENT_RE, " ")
75
+ .replace(HTML_TAG_RE, " ")
76
+ .replace(/&nbsp;/g, " ")
77
+ .replace(/&amp;/g, "&")
78
+ .replace(/&lt;/g, "<")
79
+ .replace(/&gt;/g, ">")
80
+ .replace(/&quot;/g, '"')
81
+ .replace(/&#39;/g, "'")
82
+ .replace(/[ \t]+/g, " ")
83
+ .replace(/^ +/gm, "")
84
+ .replace(MULTI_BLANK_RE, "\n\n")
85
+ .trim();
86
+ }
87
+ else {
88
+ text = body;
89
+ }
90
+ const cap = ctx.maxBytes;
91
+ const note = Buffer.byteLength(text, "utf-8") > cap ? "\n[content truncated to maxBytes]" : "";
92
+ if (Buffer.byteLength(text, "utf-8") > cap) {
93
+ const buf = Buffer.from(text, "utf-8");
94
+ text = buf.slice(0, cap).toString("utf-8");
95
+ }
96
+ return `${url}\n${text}${note}`;
97
+ }
98
+ //# sourceMappingURL=webfetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webfetch.js","sourceRoot":"","sources":["../../src/tools/webfetch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { ToolContext } from "./index.js";
2
+ interface WebSearchArgs {
3
+ query: string;
4
+ max_results?: number;
5
+ }
6
+ export declare function execWebSearch(args: WebSearchArgs, _ctx: ToolContext): Promise<string>;
7
+ export {};
@@ -0,0 +1,83 @@
1
+ // WebSearch tool — DuckDuckGo HTML scrape returning title + URL + snippet.
2
+ // No API key required.
3
+ const MAX_RESULTS_CAP = 20;
4
+ const DEFAULT_MAX = 10;
5
+ const RESULT_LINK_RE = /<a[^>]+class="[^"]*result__a[^"]*"[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/gi;
6
+ const HTML_ENTITY_RE = /&[a-z]+;|&#\d+;/gi;
7
+ const HTML_TAG_INLINE_RE = /<[^>]+>/g;
8
+ function decodeEntities(s) {
9
+ return s
10
+ .replace(/&amp;/g, "&")
11
+ .replace(/&lt;/g, "<")
12
+ .replace(/&gt;/g, ">")
13
+ .replace(/&quot;/g, '"')
14
+ .replace(/&#39;/g, "'")
15
+ .replace(/&nbsp;/g, " ")
16
+ .replace(HTML_ENTITY_RE, " ");
17
+ }
18
+ function stripTags(s) {
19
+ return s.replace(HTML_TAG_INLINE_RE, "").trim();
20
+ }
21
+ export async function execWebSearch(args, _ctx) {
22
+ if (!args.query || !args.query.trim()) {
23
+ return "[error] query must be a non-empty string.";
24
+ }
25
+ const maxResults = Math.min(args.max_results && args.max_results > 0 ? args.max_results : DEFAULT_MAX, MAX_RESULTS_CAP);
26
+ const encoded = encodeURIComponent(args.query.trim());
27
+ const searchUrl = `https://html.duckduckgo.com/html/?q=${encoded}`;
28
+ let response;
29
+ try {
30
+ response = await fetch(searchUrl, {
31
+ headers: {
32
+ "user-agent": "Mozilla/5.0 (compatible; TheronCLI/1.0; +https://itstheron.com)",
33
+ "accept": "text/html,*/*;q=0.8",
34
+ "accept-language": "en-US,en;q=0.9",
35
+ },
36
+ signal: AbortSignal.timeout(15_000),
37
+ });
38
+ }
39
+ catch (err) {
40
+ return `[error] Search request failed: ${err instanceof Error ? err.message : String(err)}`;
41
+ }
42
+ if (!response.ok) {
43
+ return `[error] DuckDuckGo returned HTTP ${response.status} for "${args.query}"`;
44
+ }
45
+ let html;
46
+ try {
47
+ html = await response.text();
48
+ }
49
+ catch (err) {
50
+ return `[error] Could not read search response: ${err instanceof Error ? err.message : String(err)}`;
51
+ }
52
+ const results = [];
53
+ let match;
54
+ RESULT_LINK_RE.lastIndex = 0;
55
+ while ((match = RESULT_LINK_RE.exec(html)) !== null && results.length < maxResults) {
56
+ const rawHref = match[1];
57
+ const rawTitle = match[2];
58
+ const title = decodeEntities(stripTags(rawTitle)).replace(/\s+/g, " ").trim();
59
+ if (!title)
60
+ continue;
61
+ let url = rawHref;
62
+ try {
63
+ const hrefUrl = new URL(rawHref, "https://html.duckduckgo.com");
64
+ const uddg = hrefUrl.searchParams.get("uddg");
65
+ if (uddg) {
66
+ url = decodeURIComponent(uddg);
67
+ }
68
+ else {
69
+ url = hrefUrl.toString();
70
+ }
71
+ }
72
+ catch { /* keep rawHref */ }
73
+ if (!url || url.startsWith("https://duckduckgo.com"))
74
+ continue;
75
+ results.push({ title, url });
76
+ }
77
+ if (results.length === 0) {
78
+ return `[no results found for "${args.query}"]`;
79
+ }
80
+ const lines = results.map((r, i) => `${i + 1}. ${r.title}\n ${r.url}`);
81
+ return `Web search: "${args.query}" (${results.length} result${results.length === 1 ? "" : "s"})\n\n${lines.join("\n\n")}`;
82
+ }
83
+ //# sourceMappingURL=websearch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websearch.js","sourceRoot":"","sources":["../../src/tools/websearch.ts"],"names":[],"mappings":"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"}
@@ -3,13 +3,29 @@
3
3
  // already passed.
4
4
  import { promises as fs } from "node:fs";
5
5
  import path from "node:path";
6
+ import { sha256Hex, receiptLocalAction } from "../receipt.js";
7
+ import { snapshot } from "../checkpoints.js";
6
8
  export async function execWrite(args, ctx) {
7
9
  const target = path.isAbsolute(args.file_path)
8
10
  ? args.file_path
9
11
  : path.resolve(ctx.cwd, args.file_path);
12
+ // Snapshot the file's current content BEFORE overwriting so /rewind can
13
+ // restore it. Fail-safe: a read error (file missing, permission denied)
14
+ // is swallowed — the write still proceeds normally.
15
+ await snapshot(target).catch(() => undefined);
10
16
  await fs.mkdir(path.dirname(target), { recursive: true });
11
17
  await fs.writeFile(target, args.content, "utf-8");
18
+ const byteLen = Buffer.byteLength(args.content, "utf-8");
12
19
  const lineCount = args.content.split(/\r?\n/).length;
13
- return `Wrote ${target} (${lineCount} lines, ${Buffer.byteLength(args.content, "utf-8")} bytes)`;
20
+ const baseResult = `Wrote ${target} (${lineCount} lines, ${byteLen} bytes)`;
21
+ // Mint a STOA receipt for this write. Fail-open: if the receipt POST
22
+ // fails, the base result is returned unmodified.
23
+ const postSha256 = sha256Hex(args.content);
24
+ const verifyUrl = await receiptLocalAction(ctx.apiUrl, ctx.apiKey, "local_write", {
25
+ path: target,
26
+ bytes: byteLen,
27
+ post_sha256: postSha256,
28
+ }).catch(() => null);
29
+ return verifyUrl ? baseResult + "\nsigned -- verify: " + verifyUrl : baseResult;
14
30
  }
15
31
  //# sourceMappingURL=write.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/tools/write.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,qEAAqE;AACrE,kBAAkB;AAElB,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAQ7B,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAe,EAAE,GAAgB;IAC/D,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC;QAC5C,CAAC,CAAC,IAAI,CAAC,SAAS;QAChB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAE1C,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,MAAM,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;IACrD,OAAO,SAAS,MAAM,KAAK,SAAS,WAAW,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC;AACnG,CAAC"}
1
+ {"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/tools/write.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,qEAAqE;AACrE,kBAAkB;AAElB,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAO7C,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAe,EAAE,GAAgB;IAC/D,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC;QAC5C,CAAC,CAAC,IAAI,CAAC,SAAS;QAChB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAE1C,wEAAwE;IACxE,yEAAyE;IACzE,oDAAoD;IACpD,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAE9C,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,MAAM,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACzD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;IACrD,MAAM,UAAU,GAAG,SAAS,MAAM,KAAK,SAAS,WAAW,OAAO,SAAS,CAAC;IAE5E,qEAAqE;IACrE,iDAAiD;IACjD,MAAM,UAAU,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,MAAM,kBAAkB,CACxC,GAAG,CAAC,MAAM,EACV,GAAG,CAAC,MAAM,EACV,aAAa,EACb;QACE,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,OAAO;QACd,WAAW,EAAE,UAAU;KACxB,CACF,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAEpB,OAAO,SAAS,CAAC,CAAC,CAAC,UAAU,GAAG,sBAAsB,GAAG,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC;AAClF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Verifier } from "./types.js";
2
+ export declare const calcGateKernel: Verifier;
@@ -0,0 +1,112 @@
1
+ // Calc-gate verifier — the deterministic teeth behind the numeric
2
+ // methodology's "show the work" invariant.
3
+ //
4
+ // The throughline for finance / data / math (and the numeric trades —
5
+ // trader / engineer / realtor) is: a number you COMPUTED must arrive with
6
+ // the computation that produced it. A bare asserted result figure — "the
7
+ // IRR is 14.3%", "the LTV/CAC is 3.2x", "the NPV is $1.24M", "the deflection
8
+ // is 4.7mm" — with no derivation is the failure mode this gate catches. It
9
+ // runs on the numeric profiles only.
10
+ //
11
+ // How it differs from arithmetic_recheck (the existing numeric kernel):
12
+ // - arithmetic_recheck takes an explicit "X op Y = Z" line and re-evaluates
13
+ // it — it catches WRONG math that's already shown.
14
+ // - calc_gate catches MISSING math: a derived headline figure asserted with
15
+ // no visible derivation at all. The two are complementary — recheck
16
+ // proves shown work is right; calc_gate proves the work was shown.
17
+ //
18
+ // How it works:
19
+ // 1. Scan the output for a COMPUTED-RESULT assertion: a named computed
20
+ // quantity (IRR, NPV, ROI, LTV/CAC, margin, CAGR, payback, deflection,
21
+ // stress, mean, median, std dev, p-value, total, etc.) stated as a
22
+ // concrete value ("= 14.3%", "is $1.24M", "comes to 3.2x").
23
+ // 2. If such a claim is present, check for DERIVATION evidence anywhere in
24
+ // the output: an arithmetic line (a + b = c), a formula, a fenced code/
25
+ // calc block, a python calculator call, a stated set of inputs, or a
26
+ // worked table. Any of these proves the number wasn't conjured.
27
+ // 3. A computed figure asserted with NO derivation is a BLOCK — fed back so
28
+ // the model shows the steps before the number stands.
29
+ //
30
+ // Conservative by design: it only fires when a RESULT-NAMED quantity is
31
+ // stated as a hard value. Round-number context ("we have ~10 customers"),
32
+ // inputs the user gave ("at a 10% discount rate"), questions, and figures the
33
+ // model explicitly flags as estimates/assumptions all pass. The guard below
34
+ // keeps it off honest "rough estimate" language.
35
+ const APPLIES_TO_PROFILES = new Set([
36
+ "finance",
37
+ "data",
38
+ "math",
39
+ "trader",
40
+ "engineer",
41
+ "realtor",
42
+ ]);
43
+ // Only gate substantive outputs — a one-line "the total is 5" aside isn't a
44
+ // derivation-worthy result.
45
+ const MIN_LENGTH_TO_GATE = 160;
46
+ // COMPUTED-RESULT assertion: a named, derived quantity stated as a concrete
47
+ // value. The quantity name is what marks it as COMPUTED (you don't "measure"
48
+ // an IRR, you compute it), so a bare value next to one of these names implies
49
+ // a calculation must exist.
50
+ const NAMED_RESULT = "irr|npv|roi|roic|roe|cagr|ltv\\s*/?\\s*cac|ltv|cac|payback(?:\\s+period)?|gross\\s+margin|net\\s+margin|ebitda|arr|mrr|burn\\s+rate|runway|wacc|dcf|cap\\s+rate|cash[- ]on[- ]cash|dscr|noi|break[- ]even|deflection|bending\\s+(?:moment|stress)|shear|torque|stress|strain|moment\\s+of\\s+inertia|resistance|voltage|current|the\\s+mean|the\\s+median|the\\s+average|std(?:\\.|\\s+dev)?|standard\\s+deviation|variance|p[- ]value|correlation|r\\^?2|r[- ]squared|the\\s+total|the\\s+sum|the\\s+result|the\\s+(?:projected|expected)\\s+\\w+";
51
+ // A concrete value token: a number with optional currency/unit/percent/x.
52
+ const VALUE = "[\\$€£]?-?\\d[\\d,]*(?:\\.\\d+)?\\s*(?:%|x|bps|mm|cm|m|kg|n|nm|kn|mpa|psi|v|a|ω|ohm|years?|months?|days?|k|m|b|bn|mn)?";
53
+ const CLAIM_PATTERNS = [
54
+ // "the IRR is 14.3%", "NPV = $1.24M", "LTV/CAC comes to 3.2x"
55
+ new RegExp(`\\b(?:${NAMED_RESULT})\\b[^.\\n]{0,30}\\b(?:is|=|comes?\\s+(?:to|out\\s+to)|works?\\s+out\\s+to|equals?|totals?|of)\\b\\s*(?:approximately\\s+|roughly\\s+|about\\s+|~)?${VALUE}`, "i"),
56
+ // "= 14.3%" immediately following a named result within a tight window
57
+ new RegExp(`\\b(?:${NAMED_RESULT})\\b[^=\\n]{0,20}=\\s*${VALUE}`, "i"),
58
+ ];
59
+ // GUARD: the model being honest that a figure is a rough estimate / placeholder
60
+ // / illustrative, or asking for inputs, doesn't need a full derivation shown —
61
+ // that's honest uncertainty, which we reward. Also guards values the user
62
+ // themselves supplied as an input ("at your stated 10% rate").
63
+ const GUARD = /\b(?:rough(?:ly)?\s+estimate|ballpark|placeholder|illustrative|for\s+example|let'?s\s+(?:say|assume)|hypothetical|order\s+of\s+magnitude|i\s+don'?t\s+have|i\s+can'?t\s+(?:compute|calculate)|need\s+(?:the|more)\s+(?:inputs?|data|numbers?)|what\s+(?:is|are)\s+your|you\s+(?:said|gave|specified|provided)|as\s+you\s+(?:stated|noted))\b/i;
64
+ // DERIVATION evidence — proof the number came from a calculation.
65
+ const DERIVATION_EVIDENCE = [
66
+ /[\$€£]?-?\d[\d,]*(?:\.\d+)?\s*[+\-*/×÷]\s*[\$€£]?-?\d[\d,]*(?:\.\d+)?/, // an arithmetic expression a op b
67
+ /=\s*[\$€£]?-?\d[\d,]*(?:\.\d+)?\s*[+\-*/×÷]/, // = a op b ...
68
+ /```[\s\S]*?```/, // a fenced calc / code block
69
+ /\bpython3?\b[^.\n]{0,40}\b(?:-c|print|=)/i, // a python calculator call
70
+ /\b(?:formula|equation|derivation|calculation|computed\s+as|worked\s+out|step\s*\d|step[- ]by[- ]step)\b/i,
71
+ /\b(?:where|given|inputs?|assumptions?)\b\s*[:\-][^.\n]{0,40}=/i, // a "given: x = ..., y = ..." inputs block
72
+ /\|\s*[-:]+\s*\|/, // a markdown table separator (a worked table)
73
+ /\b(?:sum|total|mean|average)\s*(?:of)?\s*\([^)]*[+,][^)]*\)/i, // sum(a, b, c) / mean(...)
74
+ /\(\s*[\$€£]?-?\d[\d,]*(?:\.\d+)?[^)]*[+\-*/×÷][^)]*\)/, // a parenthesized expression (a + b)
75
+ ];
76
+ function anyMatch(patterns, text) {
77
+ return patterns.some((re) => re.test(text));
78
+ }
79
+ export const calcGateKernel = {
80
+ slug: "calc_gate",
81
+ describe: "Numeric domains: a computed result figure (IRR, NPV, margin, deflection, mean, …) must show the calculation/derivation, not just assert the number",
82
+ async run(ctx) {
83
+ if (!APPLIES_TO_PROFILES.has(ctx.profile))
84
+ return [];
85
+ const text = ctx.assistantText;
86
+ if (text.length < MIN_LENGTH_TO_GATE)
87
+ return [];
88
+ // Is there a named computed-result assertion at all?
89
+ const claimMatch = CLAIM_PATTERNS.map((re) => re.exec(text)).find(Boolean);
90
+ if (!claimMatch)
91
+ return [];
92
+ // Guard: rough estimate / user-supplied input / "I can't compute" — these
93
+ // don't need a derivation shown. Inspect a window around the match.
94
+ const idx = claimMatch.index ?? 0;
95
+ const window = text.slice(Math.max(0, idx - 90), idx + (claimMatch[0]?.length ?? 0) + 90);
96
+ if (GUARD.test(window))
97
+ return [];
98
+ // Does the output show the work anywhere?
99
+ if (anyMatch(DERIVATION_EVIDENCE, text))
100
+ return [];
101
+ return [
102
+ {
103
+ severity: "block",
104
+ kernel: "calc_gate",
105
+ message: `A computed figure ("${claimMatch[0].slice(0, 60).trim()}…") is asserted with no visible calculation. ` +
106
+ `Per the methodology for numeric work: show the work — the arithmetic, formula, inputs, or a worked table that produces the number. ` +
107
+ `A bare result the reader can't reproduce is a hypothesis, not an answer.`,
108
+ },
109
+ ];
110
+ },
111
+ };
112
+ //# sourceMappingURL=calc_gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calc_gate.js","sourceRoot":"","sources":["../../src/verifiers/calc_gate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Verifier } from "./types.js";
2
+ export declare const citationGateKernel: Verifier;