@inbrowser/agent 0.0.0-placeholder → 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 (202) hide show
  1. package/AGENTS.md +270 -0
  2. package/README.md +117 -2
  3. package/bin/agent.ts +10 -0
  4. package/dist/cli/commands/describe.d.ts +14 -0
  5. package/dist/cli/commands/describe.d.ts.map +1 -0
  6. package/dist/cli/commands/describe.js +179 -0
  7. package/dist/cli/commands/describe.js.map +1 -0
  8. package/dist/cli/commands/events.d.ts +21 -0
  9. package/dist/cli/commands/events.d.ts.map +1 -0
  10. package/dist/cli/commands/events.js +59 -0
  11. package/dist/cli/commands/events.js.map +1 -0
  12. package/dist/cli/commands/fleet.d.ts +15 -0
  13. package/dist/cli/commands/fleet.d.ts.map +1 -0
  14. package/dist/cli/commands/fleet.js +149 -0
  15. package/dist/cli/commands/fleet.js.map +1 -0
  16. package/dist/cli/commands/help.d.ts +15 -0
  17. package/dist/cli/commands/help.d.ts.map +1 -0
  18. package/dist/cli/commands/help.js +93 -0
  19. package/dist/cli/commands/help.js.map +1 -0
  20. package/dist/cli/commands/migrate.d.ts +27 -0
  21. package/dist/cli/commands/migrate.d.ts.map +1 -0
  22. package/dist/cli/commands/migrate.js +109 -0
  23. package/dist/cli/commands/migrate.js.map +1 -0
  24. package/dist/cli/commands/run.d.ts +38 -0
  25. package/dist/cli/commands/run.d.ts.map +1 -0
  26. package/dist/cli/commands/run.js +535 -0
  27. package/dist/cli/commands/run.js.map +1 -0
  28. package/dist/cli/commands/schema.d.ts +8 -0
  29. package/dist/cli/commands/schema.d.ts.map +1 -0
  30. package/dist/cli/commands/schema.js +12 -0
  31. package/dist/cli/commands/schema.js.map +1 -0
  32. package/dist/cli/commands/serve.d.ts +39 -0
  33. package/dist/cli/commands/serve.d.ts.map +1 -0
  34. package/dist/cli/commands/serve.js +65 -0
  35. package/dist/cli/commands/serve.js.map +1 -0
  36. package/dist/cli/commands/undo.d.ts +36 -0
  37. package/dist/cli/commands/undo.d.ts.map +1 -0
  38. package/dist/cli/commands/undo.js +132 -0
  39. package/dist/cli/commands/undo.js.map +1 -0
  40. package/dist/cli/fixtures.d.ts +17 -0
  41. package/dist/cli/fixtures.d.ts.map +1 -0
  42. package/dist/cli/fixtures.js +107 -0
  43. package/dist/cli/fixtures.js.map +1 -0
  44. package/dist/cli/hardening.d.ts +39 -0
  45. package/dist/cli/hardening.d.ts.map +1 -0
  46. package/dist/cli/hardening.js +68 -0
  47. package/dist/cli/hardening.js.map +1 -0
  48. package/dist/cli/index.d.ts +28 -0
  49. package/dist/cli/index.d.ts.map +1 -0
  50. package/dist/cli/index.js +19 -0
  51. package/dist/cli/index.js.map +1 -0
  52. package/dist/cli/llm/openrouter.d.ts +33 -0
  53. package/dist/cli/llm/openrouter.d.ts.map +1 -0
  54. package/dist/cli/llm/openrouter.js +285 -0
  55. package/dist/cli/llm/openrouter.js.map +1 -0
  56. package/dist/cli/main.d.ts +32 -0
  57. package/dist/cli/main.d.ts.map +1 -0
  58. package/dist/cli/main.js +106 -0
  59. package/dist/cli/main.js.map +1 -0
  60. package/dist/cli/output.d.ts +36 -0
  61. package/dist/cli/output.d.ts.map +1 -0
  62. package/dist/cli/output.js +95 -0
  63. package/dist/cli/output.js.map +1 -0
  64. package/dist/cli/parse.d.ts +26 -0
  65. package/dist/cli/parse.d.ts.map +1 -0
  66. package/dist/cli/parse.js +160 -0
  67. package/dist/cli/parse.js.map +1 -0
  68. package/dist/cli/session-log.d.ts +34 -0
  69. package/dist/cli/session-log.d.ts.map +1 -0
  70. package/dist/cli/session-log.js +52 -0
  71. package/dist/cli/session-log.js.map +1 -0
  72. package/dist/cli/spec.d.ts +62 -0
  73. package/dist/cli/spec.d.ts.map +1 -0
  74. package/dist/cli/spec.js +510 -0
  75. package/dist/cli/spec.js.map +1 -0
  76. package/dist/cli/ui/RunView.d.ts +134 -0
  77. package/dist/cli/ui/RunView.d.ts.map +1 -0
  78. package/dist/cli/ui/RunView.js +341 -0
  79. package/dist/cli/ui/RunView.js.map +1 -0
  80. package/dist/events/codec.d.ts +79 -0
  81. package/dist/events/codec.d.ts.map +1 -0
  82. package/dist/events/codec.js +142 -0
  83. package/dist/events/codec.js.map +1 -0
  84. package/dist/events/log-core.d.ts +76 -0
  85. package/dist/events/log-core.d.ts.map +1 -0
  86. package/dist/events/log-core.js +73 -0
  87. package/dist/events/log-core.js.map +1 -0
  88. package/dist/events/log.d.ts +60 -0
  89. package/dist/events/log.d.ts.map +1 -0
  90. package/dist/events/log.js +193 -0
  91. package/dist/events/log.js.map +1 -0
  92. package/dist/events/replay.d.ts +106 -0
  93. package/dist/events/replay.d.ts.map +1 -0
  94. package/dist/events/replay.js +137 -0
  95. package/dist/events/replay.js.map +1 -0
  96. package/dist/events/wrap.d.ts +100 -0
  97. package/dist/events/wrap.d.ts.map +1 -0
  98. package/dist/events/wrap.js +141 -0
  99. package/dist/events/wrap.js.map +1 -0
  100. package/dist/index.d.ts +52 -0
  101. package/dist/index.d.ts.map +1 -0
  102. package/dist/index.js +37 -0
  103. package/dist/index.js.map +1 -0
  104. package/dist/llm-adapter.d.ts +96 -0
  105. package/dist/llm-adapter.d.ts.map +1 -0
  106. package/dist/llm-adapter.js +132 -0
  107. package/dist/llm-adapter.js.map +1 -0
  108. package/dist/mcp/serve.d.ts +70 -0
  109. package/dist/mcp/serve.d.ts.map +1 -0
  110. package/dist/mcp/serve.js +154 -0
  111. package/dist/mcp/serve.js.map +1 -0
  112. package/dist/metrics/runs.d.ts +58 -0
  113. package/dist/metrics/runs.d.ts.map +1 -0
  114. package/dist/metrics/runs.js +99 -0
  115. package/dist/metrics/runs.js.map +1 -0
  116. package/dist/metrics.d.ts +38 -0
  117. package/dist/metrics.d.ts.map +1 -0
  118. package/dist/metrics.js +123 -0
  119. package/dist/metrics.js.map +1 -0
  120. package/dist/node.d.ts +22 -0
  121. package/dist/node.d.ts.map +1 -0
  122. package/dist/node.js +22 -0
  123. package/dist/node.js.map +1 -0
  124. package/dist/session.d.ts +10 -0
  125. package/dist/session.d.ts.map +1 -0
  126. package/dist/session.js +179 -0
  127. package/dist/session.js.map +1 -0
  128. package/dist/storage.d.ts +14 -0
  129. package/dist/storage.d.ts.map +1 -0
  130. package/dist/storage.js +58 -0
  131. package/dist/storage.js.map +1 -0
  132. package/dist/strategy.d.ts +26 -0
  133. package/dist/strategy.d.ts.map +1 -0
  134. package/dist/strategy.js +200 -0
  135. package/dist/strategy.js.map +1 -0
  136. package/dist/tools.d.ts +26 -0
  137. package/dist/tools.d.ts.map +1 -0
  138. package/dist/tools.js +129 -0
  139. package/dist/tools.js.map +1 -0
  140. package/dist/types/agent.d.ts +94 -0
  141. package/dist/types/agent.d.ts.map +1 -0
  142. package/dist/types/agent.js +17 -0
  143. package/dist/types/agent.js.map +1 -0
  144. package/dist/types/capabilities.d.ts +17 -0
  145. package/dist/types/capabilities.d.ts.map +1 -0
  146. package/dist/types/capabilities.js +13 -0
  147. package/dist/types/capabilities.js.map +1 -0
  148. package/dist/types/chat.d.ts +74 -0
  149. package/dist/types/chat.d.ts.map +1 -0
  150. package/dist/types/chat.js +10 -0
  151. package/dist/types/chat.js.map +1 -0
  152. package/dist/types/events.d.ts +115 -0
  153. package/dist/types/events.d.ts.map +1 -0
  154. package/dist/types/events.js +30 -0
  155. package/dist/types/events.js.map +1 -0
  156. package/dist/types/llm.d.ts +89 -0
  157. package/dist/types/llm.d.ts.map +1 -0
  158. package/dist/types/llm.js +12 -0
  159. package/dist/types/llm.js.map +1 -0
  160. package/dist/types/metrics.d.ts +34 -0
  161. package/dist/types/metrics.d.ts.map +1 -0
  162. package/dist/types/metrics.js +10 -0
  163. package/dist/types/metrics.js.map +1 -0
  164. package/dist/types/observer.d.ts +41 -0
  165. package/dist/types/observer.d.ts.map +1 -0
  166. package/dist/types/observer.js +41 -0
  167. package/dist/types/observer.js.map +1 -0
  168. package/dist/types/project-context.d.ts +18 -0
  169. package/dist/types/project-context.d.ts.map +1 -0
  170. package/dist/types/project-context.js +11 -0
  171. package/dist/types/project-context.js.map +1 -0
  172. package/dist/types/runtime.d.ts +71 -0
  173. package/dist/types/runtime.d.ts.map +1 -0
  174. package/dist/types/runtime.js +21 -0
  175. package/dist/types/runtime.js.map +1 -0
  176. package/dist/types/session.d.ts +103 -0
  177. package/dist/types/session.d.ts.map +1 -0
  178. package/dist/types/session.js +11 -0
  179. package/dist/types/session.js.map +1 -0
  180. package/dist/types/storage.d.ts +20 -0
  181. package/dist/types/storage.d.ts.map +1 -0
  182. package/dist/types/storage.js +41 -0
  183. package/dist/types/storage.js.map +1 -0
  184. package/dist/types/strategy.d.ts +76 -0
  185. package/dist/types/strategy.d.ts.map +1 -0
  186. package/dist/types/strategy.js +10 -0
  187. package/dist/types/strategy.js.map +1 -0
  188. package/dist/types/tools.d.ts +136 -0
  189. package/dist/types/tools.d.ts.map +1 -0
  190. package/dist/types/tools.js +11 -0
  191. package/dist/types/tools.js.map +1 -0
  192. package/dist/types/trace.d.ts +125 -0
  193. package/dist/types/trace.d.ts.map +1 -0
  194. package/dist/types/trace.js +24 -0
  195. package/dist/types/trace.js.map +1 -0
  196. package/dist/types/workspace.d.ts +29 -0
  197. package/dist/types/workspace.d.ts.map +1 -0
  198. package/dist/types/workspace.js +18 -0
  199. package/dist/types/workspace.js.map +1 -0
  200. package/package.json +45 -14
  201. package/skills/agent-cli.md +218 -0
  202. package/index.js +0 -2
@@ -0,0 +1,65 @@
1
+ /**
2
+ * `agent serve` — inverse-mode MCP server entrypoint.
3
+ *
4
+ * Boots a stdio MCP server exposing every injected agent's tools as
5
+ * one flat catalog to an external host (Claude Code, Claude Desktop,
6
+ * Cursor, ...). Tool-surface minimization is the host's concern
7
+ * (allowlists in Claude Code settings, etc.); this command doesn't
8
+ * filter.
9
+ *
10
+ * The process holds stdin/stdout for the MCP transport, so:
11
+ * - no events go to stdout outside of --dry-run
12
+ * - the function never returns under normal operation; it resolves
13
+ * when the parent closes the transport.
14
+ *
15
+ * Agents come from `io.agents`. The CLI itself ships zero built-in
16
+ * agents — host packages (e.g. `firebase-agent-sdk`) wire their own
17
+ * agent definitions and call this command as a library.
18
+ */
19
+ import { serveAgentsOverStdio } from '../../mcp/serve.js';
20
+ import { UsageError } from '../parse.js';
21
+ export async function serveCommand(args, io) {
22
+ const emit = io.emit;
23
+ const now = io.now ?? (() => new Date().toISOString());
24
+ const projectId = args.options['project'];
25
+ if (!projectId) {
26
+ throw new UsageError('missing --project: pass the Firebase project id for log routing', 'Example: --project my-app');
27
+ }
28
+ const eventsDir = args.options['events-dir'];
29
+ const agents = io.agents ?? [];
30
+ if (agents.length === 0) {
31
+ throw new UsageError('no agents wired into this serve command', 'Host packages compose `@inbrowser/agent` and call serveCommand with their own AgentDefinitions. The bare `agent serve` CLI ships zero built-ins.');
32
+ }
33
+ const agentApp = io.agentApp;
34
+ if (args.options['dry-run']) {
35
+ emit.event({
36
+ type: 'dry_run_plan',
37
+ ts: now(),
38
+ command: 'serve',
39
+ projectId,
40
+ liveMode: agentApp ? { projectId: agentApp.projectId } : null,
41
+ agents: agents.map((a) => ({
42
+ name: a.name,
43
+ tools: a.tools.map((t) => t.name),
44
+ })),
45
+ ...(eventsDir ? { eventsDir } : {}),
46
+ }, () => `[plan] serve · project=${projectId} · live=${agentApp ? agentApp.projectId : 'off'} · agents=${agents.map((a) => `${a.name}(${a.tools.length})`).join(',')}`);
47
+ emit.finish();
48
+ return 0;
49
+ }
50
+ const serve = io.serve ?? serveAgentsOverStdio;
51
+ const handle = await serve({
52
+ agents,
53
+ projectId,
54
+ ...(eventsDir ? { eventsDir } : {}),
55
+ ...(agentApp ? { agentApp } : {}),
56
+ });
57
+ // Wait until stdin closes (parent host disconnects).
58
+ await new Promise((resolve) => {
59
+ process.stdin.on('end', () => resolve());
60
+ process.stdin.on('close', () => resolve());
61
+ });
62
+ await handle.close();
63
+ return 0;
64
+ }
65
+ //# sourceMappingURL=serve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve.js","sourceRoot":"","sources":["../../../src/cli/commands/serve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * `agent undo` — reverse a previously-committed mutation.
3
+ *
4
+ * Lookup flow:
5
+ * 1. Open the project's event log.
6
+ * 2. Find the `commit`-phase event with id === --event.
7
+ * 3. Refuse if `reversible: false` or `reverseOp` is missing.
8
+ * 4. Refuse if a `rollback`-phase event already references this id
9
+ * (already undone — idempotent).
10
+ * 5. Otherwise emit either:
11
+ * - A `undo_plan` event (when --dry-run is set), or
12
+ * - An `undo_invocation` plan describing the recorded reverseOp.
13
+ *
14
+ * **This subcommand does NOT actually invoke the reverseOp tool.**
15
+ * That requires a `ToolRegistry` + `ToolContext` (LLM provider,
16
+ * sandbox, etc.) which the headless CLI doesn't have — those live in
17
+ * the host (the playground, or a specialized-agent process). The CLI
18
+ * surfaces the plan + appends a `rollback` event to the log; the host
19
+ * dispatches the actual reverse op when it re-reads the log.
20
+ *
21
+ * This split matches the rest of the CLI: it's a controller surface,
22
+ * not a Firebase admin tool. Hosting the dispatch in-CLI would force
23
+ * us to import @pyric/sandbox + @pyric/admin runtime deps just to
24
+ * run an undo, which doesn't fit the "small, scriptable, headless"
25
+ * design point.
26
+ */
27
+ import { openEventLog } from '../../events/log.js';
28
+ import type { Emitter } from '../output.js';
29
+ import type { ParsedArgs } from '../parse.js';
30
+ export interface UndoCommandIO {
31
+ emit: Emitter;
32
+ openLog?: typeof openEventLog;
33
+ now?: () => string;
34
+ }
35
+ export declare function undoCommand(args: ParsedArgs, io: UndoCommandIO): number;
36
+ //# sourceMappingURL=undo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"undo.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/undo.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,YAAY,CAAC;IAC9B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,aAAa,GAAG,MAAM,CA0HvE"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * `agent undo` — reverse a previously-committed mutation.
3
+ *
4
+ * Lookup flow:
5
+ * 1. Open the project's event log.
6
+ * 2. Find the `commit`-phase event with id === --event.
7
+ * 3. Refuse if `reversible: false` or `reverseOp` is missing.
8
+ * 4. Refuse if a `rollback`-phase event already references this id
9
+ * (already undone — idempotent).
10
+ * 5. Otherwise emit either:
11
+ * - A `undo_plan` event (when --dry-run is set), or
12
+ * - An `undo_invocation` plan describing the recorded reverseOp.
13
+ *
14
+ * **This subcommand does NOT actually invoke the reverseOp tool.**
15
+ * That requires a `ToolRegistry` + `ToolContext` (LLM provider,
16
+ * sandbox, etc.) which the headless CLI doesn't have — those live in
17
+ * the host (the playground, or a specialized-agent process). The CLI
18
+ * surfaces the plan + appends a `rollback` event to the log; the host
19
+ * dispatches the actual reverse op when it re-reads the log.
20
+ *
21
+ * This split matches the rest of the CLI: it's a controller surface,
22
+ * not a Firebase admin tool. Hosting the dispatch in-CLI would force
23
+ * us to import @pyric/sandbox + @pyric/admin runtime deps just to
24
+ * run an undo, which doesn't fit the "small, scriptable, headless"
25
+ * design point.
26
+ */
27
+ import { buildRollbackEvent } from '../../events/log-core.js';
28
+ import { openEventLog } from '../../events/log.js';
29
+ export function undoCommand(args, io) {
30
+ const projectId = args.options['project'];
31
+ const eventId = args.options['event'];
32
+ if (!projectId)
33
+ throw new Error('agent undo: --project is required');
34
+ if (!eventId)
35
+ throw new Error('agent undo: --event is required');
36
+ const eventsDir = args.options['events-dir'];
37
+ const dryRun = Boolean(args.options['dry-run']);
38
+ const openLog = io.openLog ?? openEventLog;
39
+ const now = io.now ?? (() => new Date().toISOString());
40
+ const log = openLog({
41
+ projectId,
42
+ ...(eventsDir ? { logDir: eventsDir } : {}),
43
+ });
44
+ try {
45
+ const all = log.read();
46
+ const target = all.find((e) => e.id === eventId);
47
+ if (!target) {
48
+ io.emit.event({
49
+ type: 'error',
50
+ name: 'NotFound',
51
+ message: `event ${eventId} not found in project ${projectId}`,
52
+ }, () => `error: event ${eventId} not found`);
53
+ io.emit.finish();
54
+ return 64;
55
+ }
56
+ if (target.phase !== 'commit') {
57
+ io.emit.event({
58
+ type: 'error',
59
+ name: 'NotCommit',
60
+ message: `event ${eventId} is phase=${target.phase}; only commit events can be undone`,
61
+ }, () => `error: event ${eventId} is phase=${target.phase}; not a commit`);
62
+ io.emit.finish();
63
+ return 64;
64
+ }
65
+ if (!target.reversible || !target.reverseOp) {
66
+ io.emit.event({
67
+ type: 'error',
68
+ name: 'Irreversible',
69
+ message: `event ${eventId} is marked reversible:false`,
70
+ reason: target.irreversibleReason ?? '(no reason recorded)',
71
+ }, () => `error: event ${eventId} is irreversible (${target.irreversibleReason ?? 'no reason recorded'})`);
72
+ io.emit.finish();
73
+ return 64;
74
+ }
75
+ const alreadyUndone = all.find((e) => e.phase === 'rollback' &&
76
+ typeof e.metadata?.['originalEventId'] === 'string' &&
77
+ e.metadata['originalEventId'] === eventId);
78
+ if (alreadyUndone) {
79
+ io.emit.event({
80
+ type: 'error',
81
+ name: 'AlreadyUndone',
82
+ message: `event ${eventId} was already undone by ${alreadyUndone.id}`,
83
+ }, () => `error: event ${eventId} was already undone by ${alreadyUndone.id}`);
84
+ io.emit.finish();
85
+ return 64;
86
+ }
87
+ const plan = buildUndoPlan(target, now);
88
+ if (dryRun) {
89
+ io.emit.event({ type: 'undo_plan', ...plan }, () => `[plan] undo · event=${eventId} · tool=${target.tool} → reverse with ${target.reverseOp?.tool}\n` +
90
+ ` target: ${target.target.kind}:${target.target.path}\n` +
91
+ ` args: ${JSON.stringify(target.reverseOp?.args)}`);
92
+ io.emit.finish();
93
+ return 0;
94
+ }
95
+ // Append a rollback event so the host (or the auditor) can see
96
+ // that the undo was *requested*. The host is responsible for
97
+ // actually invoking the reverseOp.tool against its dispatch.
98
+ const rollback = log.append(buildRollbackEvent({
99
+ original: target,
100
+ reason: 'undo',
101
+ reverseOp: target.reverseOp,
102
+ agent: target.agent,
103
+ sessionId: target.sessionId,
104
+ }));
105
+ io.emit.event({
106
+ type: 'undo_recorded',
107
+ rollbackEventId: rollback.id,
108
+ ...plan,
109
+ nextStep: `Invoke ${target.reverseOp.tool} via your host's ToolDispatch with the recorded args. ` +
110
+ `The CLI cannot invoke tools directly — see undo.ts header for rationale.`,
111
+ }, () => `[recorded] rollback ${rollback.id} for event ${eventId}\n` +
112
+ ` reverseOp: ${target.reverseOp?.tool}(${JSON.stringify(target.reverseOp?.args)})\n` +
113
+ ` next: invoke that tool via your host's ToolDispatch.`);
114
+ io.emit.finish();
115
+ return 0;
116
+ }
117
+ finally {
118
+ log.close();
119
+ }
120
+ }
121
+ function buildUndoPlan(target, now) {
122
+ return {
123
+ ts: now(),
124
+ eventId: target.id,
125
+ originalTool: target.tool,
126
+ originalAgent: target.agent,
127
+ originalSessionId: target.sessionId,
128
+ target: target.target,
129
+ reverseOp: target.reverseOp,
130
+ };
131
+ }
132
+ //# sourceMappingURL=undo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"undo.js","sourceRoot":"","sources":["../../../src/cli/commands/undo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Scripted LLM fixtures + fake sandbox used by the headless CLI. Real
3
+ * provider wiring lives in the host (the playground UI). These live
4
+ * here so `agent run` and `agent fleet` can run end-to-end without
5
+ * any API credentials.
6
+ */
7
+ import type { LlmClient, SandboxHandle, ToolHandler } from '../index.js';
8
+ export type ScenarioId = 'echo' | 'write-rules';
9
+ export declare function scriptedLlm(scenario: ScenarioId, marker?: string): LlmClient;
10
+ export declare function fakeSandbox(): SandboxHandle;
11
+ export declare const writeRulesTool: ToolHandler<{
12
+ source: string;
13
+ }>;
14
+ export declare const writeCodeTool: ToolHandler<{
15
+ code: string;
16
+ }>;
17
+ //# sourceMappingURL=fixtures.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../../src/cli/fixtures.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAa,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEpF,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,aAAa,CAAC;AAEhD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAK,GAAG,SAAS,CAuDxE;AAED,wBAAgB,WAAW,IAAI,aAAa,CAc3C;AAED,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAgB1D,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAWvD,CAAC"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Scripted LLM fixtures + fake sandbox used by the headless CLI. Real
3
+ * provider wiring lives in the host (the playground UI). These live
4
+ * here so `agent run` and `agent fleet` can run end-to-end without
5
+ * any API credentials.
6
+ */
7
+ export function scriptedLlm(scenario, marker = '') {
8
+ let callCount = 0;
9
+ return {
10
+ id: `fixture-${scenario}`,
11
+ supportsTools: true,
12
+ chat(req) {
13
+ const turn = callCount++;
14
+ return (async function* () {
15
+ if (scenario === 'write-rules') {
16
+ if (turn === 0) {
17
+ yield { kind: 'thinking', chunk: 'Planning a minimal owner-only rule.\n' };
18
+ yield {
19
+ kind: 'tool_call',
20
+ id: `c1${marker ? `-${marker}` : ''}`,
21
+ name: 'writeRules',
22
+ args: {
23
+ source: `// ${marker || 'default'} rules\nrules_version='2';\nservice cloud.firestore {\n match /{path=**} {\n allow read, write: if request.auth != null;\n }\n}\n`,
24
+ },
25
+ };
26
+ yield {
27
+ kind: 'turn_complete',
28
+ usage: { promptTokens: 200, completionTokens: 50 },
29
+ details: { requestedModel: 'fixture-1' },
30
+ };
31
+ return;
32
+ }
33
+ yield { kind: 'text', chunk: 'Rules deployed. Read/write is gated on request.auth.' };
34
+ yield {
35
+ kind: 'turn_complete',
36
+ usage: { promptTokens: 250, completionTokens: 12 },
37
+ details: { requestedModel: 'fixture-1' },
38
+ };
39
+ return;
40
+ }
41
+ // echo — scan backward for the latest user message.
42
+ let userMsg = req.messages[req.messages.length - 1];
43
+ for (let i = req.messages.length - 1; i >= 0; i--) {
44
+ const m = req.messages[i];
45
+ if (m?.role === 'user') {
46
+ userMsg = m;
47
+ break;
48
+ }
49
+ }
50
+ const text = `[echo] ${userMsg?.text ?? '(no input)'}`;
51
+ for (const word of text.split(' ')) {
52
+ yield { kind: 'text', chunk: word + ' ' };
53
+ }
54
+ yield {
55
+ kind: 'turn_complete',
56
+ usage: { promptTokens: 12, completionTokens: text.split(' ').length },
57
+ details: { requestedModel: 'fixture-1' },
58
+ };
59
+ })();
60
+ },
61
+ };
62
+ }
63
+ export function fakeSandbox() {
64
+ return {
65
+ async run() {
66
+ return { ok: true, durationMs: 0, docsTouched: 0, errors: 0, entries: [] };
67
+ },
68
+ async deployRules() {
69
+ return { ok: true, messages: [] };
70
+ },
71
+ async readState() {
72
+ return {};
73
+ },
74
+ reseed() { },
75
+ dispose() { },
76
+ };
77
+ }
78
+ export const writeRulesTool = {
79
+ name: 'writeRules',
80
+ description: 'Write the Firestore rules source.',
81
+ parameters: {
82
+ type: 'object',
83
+ properties: { source: { type: 'string', description: 'Rules text' } },
84
+ required: ['source'],
85
+ },
86
+ async execute({ source }) {
87
+ return {
88
+ ok: true,
89
+ summary: `wrote ${source.length} chars of rules`,
90
+ data: { source },
91
+ workspacePatch: { rules: source },
92
+ };
93
+ },
94
+ };
95
+ export const writeCodeTool = {
96
+ name: 'writeCode',
97
+ description: 'Write the JS code source.',
98
+ parameters: {
99
+ type: 'object',
100
+ properties: { code: { type: 'string' } },
101
+ required: ['code'],
102
+ },
103
+ async execute({ code }) {
104
+ return { ok: true, summary: `wrote ${code.length} chars of code`, workspacePatch: { code } };
105
+ },
106
+ };
107
+ //# sourceMappingURL=fixtures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixtures.js","sourceRoot":"","sources":["../../src/cli/fixtures.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Input hardening — Agent DX CLI axis 5.
3
+ *
4
+ * Defends against agent-specific failure modes:
5
+ * - control chars in resource ids → break logs and downstream tools
6
+ * - path traversal (`..`, `%2e`, raw URL-encoded segments) → escape
7
+ * the intended sandbox (e.g. --log-dir, --json file path)
8
+ * - embedded query params (`?`, `#`, raw `&`) in ids that the agent
9
+ * would otherwise let through as part of a hallucinated URL
10
+ * - oversized inputs that would balloon the session log
11
+ *
12
+ * Failure mode: throw `InputHardeningError`. The CLI top-level catches
13
+ * it and emits `{type:"error", code:"INPUT_HARDENED", field, reason}`
14
+ * as a single NDJSON event with exit code 64 (EX_USAGE).
15
+ */
16
+ export declare class InputHardeningError extends Error {
17
+ readonly field: string;
18
+ readonly reason: string;
19
+ readonly value: string;
20
+ readonly name = "InputHardeningError";
21
+ constructor(field: string, reason: string, value: string);
22
+ }
23
+ export interface HardeningRules {
24
+ rejectControlChars?: boolean;
25
+ rejectPathTraversal?: boolean;
26
+ rejectQueryChars?: boolean;
27
+ maxLength?: number;
28
+ pattern?: string;
29
+ }
30
+ export declare function hardenString(field: string, value: string, rules: HardeningRules): string;
31
+ /**
32
+ * Path hardening: in addition to string hardening, validate that the
33
+ * resolved path is either absolute or stays within CWD. Symlinks and
34
+ * platform-specific normalization are out of scope at this layer —
35
+ * the resolved path is returned and consumers are responsible for
36
+ * `realpath`-ing if they care.
37
+ */
38
+ export declare function hardenPath(field: string, raw: string, rules: HardeningRules, cwd: string): string;
39
+ //# sourceMappingURL=hardening.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hardening.d.ts","sourceRoot":"","sources":["../../src/cli/hardening.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,qBAAa,mBAAoB,SAAQ,KAAK;IAG1C,QAAQ,CAAC,KAAK,EAAE,MAAM;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM;IAJxB,SAAkB,IAAI,yBAAyB;gBAEpC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM;CAIzB;AAOD,MAAM,WAAW,cAAc;IAC7B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,MAAM,CA0BxF;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAKjG"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Input hardening — Agent DX CLI axis 5.
3
+ *
4
+ * Defends against agent-specific failure modes:
5
+ * - control chars in resource ids → break logs and downstream tools
6
+ * - path traversal (`..`, `%2e`, raw URL-encoded segments) → escape
7
+ * the intended sandbox (e.g. --log-dir, --json file path)
8
+ * - embedded query params (`?`, `#`, raw `&`) in ids that the agent
9
+ * would otherwise let through as part of a hallucinated URL
10
+ * - oversized inputs that would balloon the session log
11
+ *
12
+ * Failure mode: throw `InputHardeningError`. The CLI top-level catches
13
+ * it and emits `{type:"error", code:"INPUT_HARDENED", field, reason}`
14
+ * as a single NDJSON event with exit code 64 (EX_USAGE).
15
+ */
16
+ export class InputHardeningError extends Error {
17
+ field;
18
+ reason;
19
+ value;
20
+ name = 'InputHardeningError';
21
+ constructor(field, reason, value) {
22
+ super(`Input hardening rejected ${field}: ${reason}`);
23
+ this.field = field;
24
+ this.reason = reason;
25
+ this.value = value;
26
+ }
27
+ }
28
+ const CONTROL_CHAR_RE = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/;
29
+ const PATH_TRAVERSAL_RE = /(^|[\\/])\.\.([\\/]|$)/;
30
+ const PERCENT_ENCODED_DOT_RE = /%2e/i;
31
+ const QUERY_CHARS_RE = /[?#]/;
32
+ export function hardenString(field, value, rules) {
33
+ if (rules.maxLength !== undefined && value.length > rules.maxLength) {
34
+ throw new InputHardeningError(field, `exceeds max length ${rules.maxLength} (got ${value.length})`, value);
35
+ }
36
+ if (rules.rejectControlChars && CONTROL_CHAR_RE.test(value)) {
37
+ throw new InputHardeningError(field, 'contains control characters', value);
38
+ }
39
+ if (rules.rejectPathTraversal) {
40
+ if (PATH_TRAVERSAL_RE.test(value)) {
41
+ throw new InputHardeningError(field, 'contains path traversal segment "../"', value);
42
+ }
43
+ if (PERCENT_ENCODED_DOT_RE.test(value)) {
44
+ throw new InputHardeningError(field, 'contains percent-encoded dot (%2e)', value);
45
+ }
46
+ }
47
+ if (rules.rejectQueryChars && QUERY_CHARS_RE.test(value)) {
48
+ throw new InputHardeningError(field, 'contains URL query/fragment chars (? #)', value);
49
+ }
50
+ if (rules.pattern && !new RegExp(rules.pattern).test(value)) {
51
+ throw new InputHardeningError(field, `does not match required pattern ${rules.pattern}`, value);
52
+ }
53
+ return value;
54
+ }
55
+ /**
56
+ * Path hardening: in addition to string hardening, validate that the
57
+ * resolved path is either absolute or stays within CWD. Symlinks and
58
+ * platform-specific normalization are out of scope at this layer —
59
+ * the resolved path is returned and consumers are responsible for
60
+ * `realpath`-ing if they care.
61
+ */
62
+ export function hardenPath(field, raw, rules, cwd) {
63
+ hardenString(field, raw, { ...rules, rejectControlChars: rules.rejectControlChars ?? true });
64
+ return raw.startsWith('/') || /^[A-Za-z]:[\\/]/.test(raw)
65
+ ? raw
66
+ : `${cwd.replace(/\/$/, '')}/${raw}`;
67
+ }
68
+ //# sourceMappingURL=hardening.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hardening.js","sourceRoot":"","sources":["../../src/cli/hardening.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAGjC;IACA;IACA;IAJO,IAAI,GAAG,qBAAqB,CAAC;IAC/C,YACW,KAAa,EACb,MAAc,EACd,KAAa;QAEtB,KAAK,CAAC,4BAA4B,KAAK,KAAK,MAAM,EAAE,CAAC,CAAC;QAJ7C,UAAK,GAAL,KAAK,CAAQ;QACb,WAAM,GAAN,MAAM,CAAQ;QACd,UAAK,GAAL,KAAK,CAAQ;IAGxB,CAAC;CACF;AAED,MAAM,eAAe,GAAG,kCAAkC,CAAC;AAC3D,MAAM,iBAAiB,GAAG,wBAAwB,CAAC;AACnD,MAAM,sBAAsB,GAAG,MAAM,CAAC;AACtC,MAAM,cAAc,GAAG,MAAM,CAAC;AAU9B,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,KAAa,EAAE,KAAqB;IAC9E,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;QACpE,MAAM,IAAI,mBAAmB,CAC3B,KAAK,EACL,sBAAsB,KAAK,CAAC,SAAS,SAAS,KAAK,CAAC,MAAM,GAAG,EAC7D,KAAK,CACN,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,kBAAkB,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,mBAAmB,CAAC,KAAK,EAAE,6BAA6B,EAAE,KAAK,CAAC,CAAC;IAC7E,CAAC;IACD,IAAI,KAAK,CAAC,mBAAmB,EAAE,CAAC;QAC9B,IAAI,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,mBAAmB,CAAC,KAAK,EAAE,uCAAuC,EAAE,KAAK,CAAC,CAAC;QACvF,CAAC;QACD,IAAI,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACvC,MAAM,IAAI,mBAAmB,CAAC,KAAK,EAAE,oCAAoC,EAAE,KAAK,CAAC,CAAC;QACpF,CAAC;IACH,CAAC;IACD,IAAI,KAAK,CAAC,gBAAgB,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,mBAAmB,CAAC,KAAK,EAAE,yCAAyC,EAAE,KAAK,CAAC,CAAC;IACzF,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,mBAAmB,CAAC,KAAK,EAAE,mCAAmC,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC,CAAC;IAClG,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa,EAAE,GAAW,EAAE,KAAqB,EAAE,GAAW;IACvF,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,GAAG,KAAK,EAAE,kBAAkB,EAAE,KAAK,CAAC,kBAAkB,IAAI,IAAI,EAAE,CAAC,CAAC;IAC7F,OAAO,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC;QACvD,CAAC,CAAC,GAAG;QACL,CAAC,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC;AACzC,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * `@inbrowser/agent/cli` — programmatic entry to the same CLI surface
3
+ * the `agent` binary exposes. Use this when embedding the CLI inside
4
+ * another process (e.g. an MCP server, an in-process supervisor) so
5
+ * that argv parsing, hardening, and output emission stay consistent.
6
+ */
7
+ export { main } from './main.js';
8
+ export type { MainOptions } from './main.js';
9
+ export { runCommand } from './commands/run.js';
10
+ export type { RunCommandIO, RunPayload } from './commands/run.js';
11
+ export { fleetCommand } from './commands/fleet.js';
12
+ export type { FleetCommandIO } from './commands/fleet.js';
13
+ export { describeCommand } from './commands/describe.js';
14
+ export { schemaCommand } from './commands/schema.js';
15
+ export { helpCommand, versionCommand } from './commands/help.js';
16
+ export { parseArgs, UsageError, InputHardeningError } from './parse.js';
17
+ export type { ParsedArgs } from './parse.js';
18
+ export { createEmitter, errorEvent, pickMode } from './output.js';
19
+ export type { Emitter, OutputMode, OutputOptions } from './output.js';
20
+ export { hardenString, hardenPath } from './hardening.js';
21
+ export type { HardeningRules } from './hardening.js';
22
+ export { openSessionLog, defaultLogDir } from './session-log.js';
23
+ export type { SessionLog, OpenSessionLogOptions } from './session-log.js';
24
+ export { scriptedLlm, fakeSandbox, writeRulesTool, writeCodeTool } from './fixtures.js';
25
+ export type { ScenarioId } from './fixtures.js';
26
+ export { CLI_SPEC, findCommand } from './spec.js';
27
+ export type { CliSpec, CommandSpec, OptionSpec, OptionType } from './spec.js';
28
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACxE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAClE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC1D,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjE,YAAY,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACxF,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAClD,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * `@inbrowser/agent/cli` — programmatic entry to the same CLI surface
3
+ * the `agent` binary exposes. Use this when embedding the CLI inside
4
+ * another process (e.g. an MCP server, an in-process supervisor) so
5
+ * that argv parsing, hardening, and output emission stay consistent.
6
+ */
7
+ export { main } from './main.js';
8
+ export { runCommand } from './commands/run.js';
9
+ export { fleetCommand } from './commands/fleet.js';
10
+ export { describeCommand } from './commands/describe.js';
11
+ export { schemaCommand } from './commands/schema.js';
12
+ export { helpCommand, versionCommand } from './commands/help.js';
13
+ export { parseArgs, UsageError, InputHardeningError } from './parse.js';
14
+ export { createEmitter, errorEvent, pickMode } from './output.js';
15
+ export { hardenString, hardenPath } from './hardening.js';
16
+ export { openSessionLog, defaultLogDir } from './session-log.js';
17
+ export { scriptedLlm, fakeSandbox, writeRulesTool, writeCodeTool } from './fixtures.js';
18
+ export { CLI_SPEC, findCommand } from './spec.js';
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAExE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAElE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE1D,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAExF,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * OpenRouter `LlmClient` for the CLI's `agent run`.
3
+ *
4
+ * Distinct from the playground's `openrouterProvider` in
5
+ * `examples/admin-compat-browser/src/openrouter.ts` (which is browser-
6
+ * specific — reads keys from localStorage, surfaces BYOK forms, etc.).
7
+ * This module is CLI-native: it takes its config explicitly at
8
+ * construction time (no env-var sniffing here — the caller decides
9
+ * how to source the key) and implements the narrow `LlmClient`
10
+ * contract that `@inbrowser/agent`' strategy + session expect.
11
+ *
12
+ * Streams via OpenAI-compatible SSE. Function-calling supported via
13
+ * `tools` + `tool_choice: 'auto'`. Reasoning surfaced through
14
+ * `reasoning.effort` + `include_reasoning` headers for models that
15
+ * carry extended thinking (GLM, DeepSeek-R1, Claude, GPT reasoning
16
+ * models). Cost surfaced through OpenRouter's per-call `usage.cost`
17
+ * field so the agent's `MetricsCollector` doesn't need a per-model
18
+ * pricing table for OpenRouter-served models.
19
+ */
20
+ import type { LlmClient } from '../../types/llm.js';
21
+ export interface OpenRouterConfig {
22
+ apiKey: string;
23
+ /** OpenRouter model id, e.g. `z-ai/glm-4.6`. */
24
+ model: string;
25
+ reasoningEffort?: 'off' | 'low' | 'medium' | 'high';
26
+ /** Override the endpoint (e.g. for an OpenAI-compatible proxy). */
27
+ baseUrl?: string;
28
+ /** Optional referer / title headers OpenRouter shows on the dashboard. */
29
+ referer?: string;
30
+ title?: string;
31
+ }
32
+ export declare function openRouterClient(config: OpenRouterConfig): LlmClient;
33
+ //# sourceMappingURL=openrouter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openrouter.d.ts","sourceRoot":"","sources":["../../../src/cli/llm/openrouter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAA0B,SAAS,EAAY,MAAM,oBAAoB,CAAC;AAItF,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACpD,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,SAAS,CA+KpE"}