@onepointfour-packs/flaredeck-agent 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 (148) hide show
  1. package/LICENSE.md +14 -0
  2. package/README.md +102 -0
  3. package/dist/agent.d.ts +104 -0
  4. package/dist/agent.js +329 -0
  5. package/dist/agent.js.map +1 -0
  6. package/dist/approval.d.ts +72 -0
  7. package/dist/approval.js +161 -0
  8. package/dist/approval.js.map +1 -0
  9. package/dist/approvals.d.ts +2 -0
  10. package/dist/approvals.js +148 -0
  11. package/dist/approvals.js.map +1 -0
  12. package/dist/auth.d.ts +79 -0
  13. package/dist/auth.js +181 -0
  14. package/dist/auth.js.map +1 -0
  15. package/dist/automode.d.ts +33 -0
  16. package/dist/automode.js +69 -0
  17. package/dist/automode.js.map +1 -0
  18. package/dist/branches.d.ts +25 -0
  19. package/dist/branches.js +81 -0
  20. package/dist/branches.js.map +1 -0
  21. package/dist/cli.d.ts +2 -0
  22. package/dist/cli.js +12 -0
  23. package/dist/cli.js.map +1 -0
  24. package/dist/codesearch.d.ts +27 -0
  25. package/dist/codesearch.js +111 -0
  26. package/dist/codesearch.js.map +1 -0
  27. package/dist/concurrency.d.ts +14 -0
  28. package/dist/concurrency.js +52 -0
  29. package/dist/concurrency.js.map +1 -0
  30. package/dist/config.d.ts +106 -0
  31. package/dist/config.js +119 -0
  32. package/dist/config.js.map +1 -0
  33. package/dist/engine-antigravity.d.ts +23 -0
  34. package/dist/engine-antigravity.js +357 -0
  35. package/dist/engine-antigravity.js.map +1 -0
  36. package/dist/engine-claude.d.ts +18 -0
  37. package/dist/engine-claude.js +64 -0
  38. package/dist/engine-claude.js.map +1 -0
  39. package/dist/engine.d.ts +122 -0
  40. package/dist/engine.js +36 -0
  41. package/dist/engine.js.map +1 -0
  42. package/dist/env.d.ts +1 -0
  43. package/dist/env.js +10 -0
  44. package/dist/env.js.map +1 -0
  45. package/dist/environment.d.ts +39 -0
  46. package/dist/environment.js +100 -0
  47. package/dist/environment.js.map +1 -0
  48. package/dist/flaredeck-check.d.ts +21 -0
  49. package/dist/flaredeck-check.js +12 -0
  50. package/dist/flaredeck-check.js.map +1 -0
  51. package/dist/flaredeck-proxy.d.ts +60 -0
  52. package/dist/flaredeck-proxy.js +186 -0
  53. package/dist/flaredeck-proxy.js.map +1 -0
  54. package/dist/flaredeck.d.ts +132 -0
  55. package/dist/flaredeck.js +106 -0
  56. package/dist/flaredeck.js.map +1 -0
  57. package/dist/gemini.d.ts +21 -0
  58. package/dist/gemini.js +59 -0
  59. package/dist/gemini.js.map +1 -0
  60. package/dist/gitguard.d.ts +2 -0
  61. package/dist/gitguard.js +90 -0
  62. package/dist/gitguard.js.map +1 -0
  63. package/dist/github.d.ts +38 -0
  64. package/dist/github.js +153 -0
  65. package/dist/github.js.map +1 -0
  66. package/dist/githubauth.d.ts +21 -0
  67. package/dist/githubauth.js +90 -0
  68. package/dist/githubauth.js.map +1 -0
  69. package/dist/intake.d.ts +124 -0
  70. package/dist/intake.js +383 -0
  71. package/dist/intake.js.map +1 -0
  72. package/dist/jam.d.ts +45 -0
  73. package/dist/jam.js +385 -0
  74. package/dist/jam.js.map +1 -0
  75. package/dist/jev.d.ts +31 -0
  76. package/dist/jev.js +75 -0
  77. package/dist/jev.js.map +1 -0
  78. package/dist/jevguard.d.ts +28 -0
  79. package/dist/jevguard.js +213 -0
  80. package/dist/jevguard.js.map +1 -0
  81. package/dist/mailbox.d.ts +22 -0
  82. package/dist/mailbox.js +51 -0
  83. package/dist/mailbox.js.map +1 -0
  84. package/dist/main.d.ts +2 -0
  85. package/dist/main.js +764 -0
  86. package/dist/main.js.map +1 -0
  87. package/dist/markdown.d.ts +5 -0
  88. package/dist/markdown.js +81 -0
  89. package/dist/markdown.js.map +1 -0
  90. package/dist/oauth.d.ts +30 -0
  91. package/dist/oauth.js +216 -0
  92. package/dist/oauth.js.map +1 -0
  93. package/dist/permissions.d.ts +43 -0
  94. package/dist/permissions.js +57 -0
  95. package/dist/permissions.js.map +1 -0
  96. package/dist/preflight.d.ts +71 -0
  97. package/dist/preflight.js +116 -0
  98. package/dist/preflight.js.map +1 -0
  99. package/dist/providers.d.ts +26 -0
  100. package/dist/providers.js +27 -0
  101. package/dist/providers.js.map +1 -0
  102. package/dist/repopicker.d.ts +3 -0
  103. package/dist/repopicker.js +111 -0
  104. package/dist/repopicker.js.map +1 -0
  105. package/dist/runs.d.ts +59 -0
  106. package/dist/runs.js +211 -0
  107. package/dist/runs.js.map +1 -0
  108. package/dist/sandbox.d.ts +13 -0
  109. package/dist/sandbox.js +110 -0
  110. package/dist/sandbox.js.map +1 -0
  111. package/dist/schedules.d.ts +11 -0
  112. package/dist/schedules.js +85 -0
  113. package/dist/schedules.js.map +1 -0
  114. package/dist/secretguard.d.ts +4 -0
  115. package/dist/secretguard.js +115 -0
  116. package/dist/secretguard.js.map +1 -0
  117. package/dist/secrets.d.ts +27 -0
  118. package/dist/secrets.js +51 -0
  119. package/dist/secrets.js.map +1 -0
  120. package/dist/serve.d.ts +17 -0
  121. package/dist/serve.js +1206 -0
  122. package/dist/serve.js.map +1 -0
  123. package/dist/status.d.ts +73 -0
  124. package/dist/status.js +98 -0
  125. package/dist/status.js.map +1 -0
  126. package/dist/stream.d.ts +91 -0
  127. package/dist/stream.js +103 -0
  128. package/dist/stream.js.map +1 -0
  129. package/dist/streamtoken.d.ts +2 -0
  130. package/dist/streamtoken.js +30 -0
  131. package/dist/streamtoken.js.map +1 -0
  132. package/dist/team.d.ts +61 -0
  133. package/dist/team.js +136 -0
  134. package/dist/team.js.map +1 -0
  135. package/dist/ui.d.ts +110 -0
  136. package/dist/ui.js +348 -0
  137. package/dist/ui.js.map +1 -0
  138. package/dist/updater.d.ts +15 -0
  139. package/dist/updater.js +178 -0
  140. package/dist/updater.js.map +1 -0
  141. package/dist/workspace.d.ts +115 -0
  142. package/dist/workspace.js +247 -0
  143. package/dist/workspace.js.map +1 -0
  144. package/dist/worktree.d.ts +42 -0
  145. package/dist/worktree.js +140 -0
  146. package/dist/worktree.js.map +1 -0
  147. package/package.json +52 -0
  148. package/python/sidecar.py +178 -0
@@ -0,0 +1,28 @@
1
+ import type { HookCallbackMatcher, HookEvent } from '@anthropic-ai/claude-agent-sdk';
2
+ import type { Decider } from './permissions.js';
3
+ export type GuardOutcome = 'ran' | 'asked-allowed' | 'asked-denied' | 'refused' | 'unchecked';
4
+ export type GuardConfig = {
5
+ apiKey: string;
6
+ /** Where a question goes when one is worth asking. */
7
+ decider: Decider;
8
+ /** The pane. */
9
+ log: (text: string) => void;
10
+ /** Which agent and repo this is, for the audit file. */
11
+ agent: string;
12
+ repo: string;
13
+ /** The card being worked, when there is one. */
14
+ card: () => string | null;
15
+ };
16
+ export declare function audit(entry: Record<string, unknown>): void;
17
+ /**
18
+ * Should this command run? One decision, shared.
19
+ *
20
+ * The Claude engine asks through a PreToolUse hook; the Gemini engine asks over loopback from its
21
+ * Python sidecar. Both land here, so there is one set of thresholds, one audit trail and one place
22
+ * to change the rules — rather than the same policy written twice and quietly diverging.
23
+ */
24
+ export declare function judgeCommand(cfg: GuardConfig, command: string): Promise<{
25
+ allow: boolean;
26
+ reason?: string;
27
+ }>;
28
+ export declare function jevGuard(cfg: GuardConfig): Partial<Record<HookEvent, HookCallbackMatcher[]>>;
@@ -0,0 +1,213 @@
1
+ import { appendFileSync, mkdirSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { dirname, join } from 'node:path';
4
+ /**
5
+ * The gate that lets the agent work.
6
+ *
7
+ * Running the SDK on `auto` meant a model classifier judged every call with no knowledge of this
8
+ * machine, and it refused ordinary work — a build, a deploy script, an edit through a heredoc —
9
+ * which left the agent reporting itself blocked and waiting for a person to type the command.
10
+ * That is the opposite of what FlareDeck is for. So permissions are bypassed and ONE question is
11
+ * asked instead, of a model that only answers questions: would this destroy or expose something
12
+ * that cannot be got back?
13
+ *
14
+ * Almost nothing is asked about. A regex prefilter finds the commands that could conceivably be
15
+ * irreversible; everything else — the overwhelming majority — runs untouched and costs nothing.
16
+ *
17
+ * This is a RATE reducer, not a boundary. Jev reads the command text, so a DROP reached through a
18
+ * migration, an ORM call or `npm run reset-db` is a string it has no opinion about. The boundaries
19
+ * that actually hold are elsewhere and do not depend on anybody's judgement: read-only database
20
+ * credentials, no production secrets on the machine, point-in-time recovery proved by a restore,
21
+ * branch protection on the remote. Keep those and this is a sensible trade; skip them and this is
22
+ * the only thing standing between an agent and your data, which it is not good enough to be.
23
+ */
24
+ const ENDPOINT = 'https://openrouter.ai/api/alpha/decisions';
25
+ const MODEL = 'typesafe/jev-1.13';
26
+ /**
27
+ * The tiers are set on the assumption that ASKING IS WEAK.
28
+ *
29
+ * Someone who has lost contact with the work approves everything to get it moving, which is no
30
+ * permission system at all — just a slower one with a name attached. So the band that asks is
31
+ * deliberately narrow: things that can be undone RUN, things that cannot are REFUSED outright,
32
+ * and a person is only asked in the strip of genuine uncertainty between them. A refusal the
33
+ * agent can read and route around (the production-run flow, a note on the card) is worth more
34
+ * than a yes nobody meant.
35
+ */
36
+ const REFUSE_AT = 0.6;
37
+ /** Above this, a person is asked on the card. Below it, the command runs. */
38
+ const ESCALATE_AT = 0.4;
39
+ /** Reading a credential into the transcript is not "destructive", so it is judged on its own. */
40
+ const EXPOSE_AT = 0.6;
41
+ /**
42
+ * Commands worth a question. Deliberately broad — a false positive costs a fraction of a cent and
43
+ * a second, a false negative costs the thing that was deleted.
44
+ */
45
+ const INTERESTING = [
46
+ /\brm\b.*(-[a-z]*r|--recursive)/i,
47
+ /\b(drop|truncate|delete\s+from)\b/i,
48
+ /\b(psql|mysql|mongo|mongosh|redis-cli|sqlite3|dbmate|flyway|liquibase)\b/i,
49
+ /\b(prisma|sequelize|knex|typeorm|alembic|rails)\b.*\b(migrate|reset|drop|db:drop|db:reset)\b/i,
50
+ /\bgcloud\b.*\b(delete|destroy|remove)\b/i,
51
+ /\b(aws|az)\b.*\b(rm|delete|destroy|terminate)\b/i,
52
+ /\bgsutil\b.*\brm\b/i,
53
+ /\bfirebase\b.*\b(delete|destroy)\b/i,
54
+ /\bterraform\b.*\b(destroy|apply)\b/i,
55
+ /\bkubectl\b.*\b(delete|drain)\b/i,
56
+ /\bdocker\b.*\b(system\s+prune|volume\s+rm)\b/i,
57
+ /\bgit\b.*(--force|-f\b|reset\s+--hard|clean\s+-[a-z]*f)/i,
58
+ /\b(chmod|chown)\b.*-R/i,
59
+ /\b(shutdown|reboot|mkfs|dd)\b/i,
60
+ // Sending data OFF the machine. `\b` does NOT sit between a space and a hyphen — both are
61
+ // non-word characters — so `\b-d\b` never matched ` -d @.env`, and the probe walked an `.env`
62
+ // POST straight through. Flags are matched on whitespace, not on word boundaries.
63
+ /\b(curl|wget|http|httpie)\b[^\n]*(^|\s)(-d|-F|-T|--data|--data-binary|--data-raw|--form|--upload-file)(\s|=)/i,
64
+ /\b(scp|rsync|ncat|nc)\b/i,
65
+ // Secrets, by name, anywhere a command could read them and pipe them somewhere.
66
+ /\.(env|pem|key|p12|p8)\b|\b(id_rsa|credentials|service-?account|secrets?\.(json|ya?ml))\b/i,
67
+ // Fetch-and-execute: the fetched text is nobody's reviewed code.
68
+ /\b(curl|wget)\b[^|]*\|\s*(ba)?sh\b/i,
69
+ />\s*\/dev\/(sd|nvme)/i,
70
+ /\b(deploy|promote|release|publish)\b/i,
71
+ ];
72
+ /** One line per decision, appended forever: what was asked, what Jev said, what happened. */
73
+ const auditPath = () => join(process.env['XDG_CONFIG_HOME'] || join(homedir(), '.config'), 'flaredeck-agent', 'decisions.jsonl');
74
+ export function audit(entry) {
75
+ try {
76
+ const path = auditPath();
77
+ mkdirSync(dirname(path), { recursive: true });
78
+ appendFileSync(path, `${JSON.stringify({ at: new Date().toISOString(), ...entry })}\n`);
79
+ }
80
+ catch {
81
+ // An audit line that cannot be written must not stop the work it is describing.
82
+ }
83
+ }
84
+ async function ask(command, apiKey) {
85
+ const started = Date.now();
86
+ const res = await fetch(ENDPOINT, {
87
+ method: 'POST',
88
+ headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' },
89
+ body: JSON.stringify({
90
+ model: MODEL,
91
+ state: `A software agent working unattended in a git checkout wants to run this shell command:\n\n${command}`,
92
+ questions: {
93
+ destructive: {
94
+ type: 'noul',
95
+ instructions: 'Would running this command destroy, overwrite or expose something that CANNOT be recovered from the git repository — dropping, truncating or deleting rows from a database; deleting storage buckets, volumes or production files; destroying infrastructure; revoking or rotating credentials; rewriting or force-pushing shared history; or sending secrets off the machine? Building, testing, installing dependencies, reading, and deleting files inside the checkout are NOT destructive: everything in the checkout is recoverable from git.',
96
+ },
97
+ reversible: {
98
+ type: 'noul',
99
+ instructions: 'If this command did the wrong thing, could the previous state be put back WITHOUT a database restore and without losing data — by deploying again, reverting a commit, reinstalling, or re-running it? A deploy, a build, a dependency install and a config change are reversible. Dropping or truncating a table, deleting rows, deleting a bucket or an instance, and destroying infrastructure are NOT.',
100
+ },
101
+ exposes: {
102
+ type: 'noul',
103
+ instructions: 'Would running this put a SECRET where it does not belong — printing, copying, encoding or uploading a private key, an API key, a token, a password, a .env file or a service-account file? Reading application source, configuration without secrets in it, or logs is NOT exposure.',
104
+ },
105
+ blast: {
106
+ type: 'choice',
107
+ instructions: 'If this command went wrong, what would it reach?',
108
+ criteria: {
109
+ local: 'Only this checkout or this machine — recoverable from git or by reinstalling',
110
+ shared: 'A shared branch, a CI pipeline, a staging environment or a team account',
111
+ production: 'Production data, live customer data, production infrastructure or credentials',
112
+ },
113
+ },
114
+ },
115
+ }),
116
+ });
117
+ const body = await res.json().catch(() => ({}));
118
+ if (!res.ok)
119
+ throw new Error(`OpenRouter ${res.status}: ${body?.error?.message ?? 'request failed'}`);
120
+ return {
121
+ destructive: Number(body.answers?.destructive?.noul ?? 1),
122
+ reversible: Number(body.answers?.reversible?.noul ?? 0),
123
+ exposes: Number(body.answers?.exposes?.noul ?? 1),
124
+ blast: String(body.answers?.blast?.choice ?? 'unknown'),
125
+ cost: Number(body.usage?.cost ?? 0),
126
+ ms: Date.now() - started,
127
+ };
128
+ }
129
+ /**
130
+ * Should this command run? One decision, shared.
131
+ *
132
+ * The Claude engine asks through a PreToolUse hook; the Gemini engine asks over loopback from its
133
+ * Python sidecar. Both land here, so there is one set of thresholds, one audit trail and one place
134
+ * to change the rules — rather than the same policy written twice and quietly diverging.
135
+ */
136
+ export async function judgeCommand(cfg, command) {
137
+ const card = cfg.card();
138
+ const base = { agent: cfg.agent, repo: cfg.repo, card, command: command.slice(0, 500) };
139
+ if (!INTERESTING.some((re) => re.test(command)))
140
+ return { allow: true };
141
+ let verdict;
142
+ try {
143
+ // No key is not a reason to skip the guard — it is a reason to ask a person. Thrown rather
144
+ // than called out to OpenRouter first: a 401 per risky command is a round trip that can only
145
+ // ever fail, and the handler below is already exactly the right behaviour for it.
146
+ if (!cfg.apiKey)
147
+ throw new Error('no OpenRouter key on this machine');
148
+ verdict = await ask(command, cfg.apiKey);
149
+ }
150
+ catch (e) {
151
+ // Fail CLOSED, but to a person rather than to a refusal: an unreachable decision model must
152
+ // not become an agent that stops, and must not become one that proceeds.
153
+ const why = e instanceof Error ? e.message : String(e);
154
+ cfg.log(`jev unreachable (${why}) — asking a person instead`);
155
+ const decision = await cfg.decider({ toolName: 'Bash', input: { command } }, { signal: new AbortController().signal });
156
+ audit({ ...base, outcome: decision.allow ? 'asked-allowed' : 'asked-denied', jev: null, error: why });
157
+ return decision.allow ? { allow: true } : { allow: false, reason: `Not approved. ${decision.reason}` };
158
+ }
159
+ const jev = { destructive: verdict.destructive, reversible: verdict.reversible, exposes: verdict.exposes, blast: verdict.blast, cost_usd: verdict.cost, ms: verdict.ms };
160
+ // A secret read into the transcript is already out — there is nothing to approve afterwards,
161
+ // so this one never asks.
162
+ if (verdict.exposes >= EXPOSE_AT) {
163
+ cfg.log(`refused: it would put a secret in the open (${Math.round(verdict.exposes * 100)}%)`);
164
+ audit({ ...base, outcome: 'refused', why: 'exposes', jev });
165
+ return {
166
+ allow: false,
167
+ reason: 'That would put a secret where it does not belong — a key, a token, a .env or a service-account file — and once it is in this transcript it cannot be taken back.\n\n' +
168
+ 'Read what you need from the application config instead, or say on the card which credential you need and why.',
169
+ };
170
+ }
171
+ // REVERSIBILITY is the line, not blast radius. A deploy reaches production and is meant to — it
172
+ // can be deployed again. A TRUNCATE reaches production and cannot be undone.
173
+ if (verdict.destructive >= REFUSE_AT && verdict.reversible < 0.5) {
174
+ cfg.log(`refused a ${verdict.blast} command (${Math.round(verdict.destructive * 100)}% destructive, no way back)`);
175
+ audit({ ...base, outcome: 'refused', why: 'irreversible', jev });
176
+ return {
177
+ allow: false,
178
+ reason: `This cannot be undone (${Math.round(verdict.destructive * 100)}% destructive, reaching ${verdict.blast}, no way back without a restore), so it was not run.\n\n` +
179
+ `If it genuinely needs doing, request it as a production run — a person approves that with the script in front of them — or say on the card what you need and why.`,
180
+ };
181
+ }
182
+ // Destructive but reversible: run it, and leave a line in the audit. Asking here is the rubber
183
+ // stamp — somebody out of touch with the work says yes to everything to get it moving.
184
+ if (verdict.destructive >= REFUSE_AT) {
185
+ cfg.log(`ran a ${verdict.blast} command that can be put back (${Math.round(verdict.reversible * 100)}% reversible)`);
186
+ audit({ ...base, outcome: 'ran', why: 'reversible', jev });
187
+ return { allow: true };
188
+ }
189
+ if (verdict.destructive >= ESCALATE_AT) {
190
+ cfg.log(`asking a person: ${command.slice(0, 60)} (${Math.round(verdict.destructive * 100)}% destructive, ${verdict.blast})`);
191
+ const decision = await cfg.decider({ toolName: 'Bash', input: { command } }, { signal: new AbortController().signal });
192
+ audit({ ...base, outcome: decision.allow ? 'asked-allowed' : 'asked-denied', jev });
193
+ return decision.allow ? { allow: true } : { allow: false, reason: `Not approved. ${decision.reason}` };
194
+ }
195
+ audit({ ...base, outcome: 'ran', jev });
196
+ return { allow: true };
197
+ }
198
+ export function jevGuard(cfg) {
199
+ return {
200
+ PreToolUse: [
201
+ {
202
+ matcher: 'Bash',
203
+ hooks: [
204
+ async (input) => {
205
+ const verdict = await judgeCommand(cfg, String(input?.tool_input?.command ?? ''));
206
+ return verdict.allow ? { continue: true } : { decision: 'block', reason: verdict.reason };
207
+ },
208
+ ],
209
+ },
210
+ ],
211
+ };
212
+ }
213
+ //# sourceMappingURL=jevguard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jevguard.js","sourceRoot":"","sources":["../src/jevguard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { SDKUserMessage } from '@anthropic-ai/claude-agent-sdk';
2
+ /**
3
+ * Everything the agent is told, in one queue: card events from FlareDeck and whatever you type.
4
+ *
5
+ * The SDK takes an async iterable as its prompt, so a session is not one question and one answer
6
+ * — it is a conversation the harness keeps feeding. That is what makes steering possible at all:
7
+ * a running turn can be given a new instruction rather than being interrupted and restarted.
8
+ */
9
+ export declare class Mailbox {
10
+ private waiting;
11
+ private queued;
12
+ private closed;
13
+ /**
14
+ * `human` marks input that came from a person at the keyboard. It matters: the SDK treats an
15
+ * unstamped message as unattributed and fails closed at trust gates, and it SHOULD — a line you
16
+ * typed deserves more weight than a comment someone left on a card.
17
+ */
18
+ push(text: string, human?: boolean): void;
19
+ close(): void;
20
+ get pending(): number;
21
+ [Symbol.asyncIterator](): AsyncIterator<SDKUserMessage>;
22
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Everything the agent is told, in one queue: card events from FlareDeck and whatever you type.
3
+ *
4
+ * The SDK takes an async iterable as its prompt, so a session is not one question and one answer
5
+ * — it is a conversation the harness keeps feeding. That is what makes steering possible at all:
6
+ * a running turn can be given a new instruction rather than being interrupted and restarted.
7
+ */
8
+ export class Mailbox {
9
+ waiting = [];
10
+ queued = [];
11
+ closed = false;
12
+ /**
13
+ * `human` marks input that came from a person at the keyboard. It matters: the SDK treats an
14
+ * unstamped message as unattributed and fails closed at trust gates, and it SHOULD — a line you
15
+ * typed deserves more weight than a comment someone left on a card.
16
+ */
17
+ push(text, human = false) {
18
+ const message = {
19
+ type: 'user',
20
+ message: { role: 'user', content: text },
21
+ parent_tool_use_id: null,
22
+ ...(human ? { origin: { kind: 'human' }, priority: 'now' } : {}),
23
+ };
24
+ const next = this.waiting.shift();
25
+ if (next)
26
+ next({ value: message, done: false });
27
+ else
28
+ this.queued.push(message);
29
+ }
30
+ close() {
31
+ this.closed = true;
32
+ for (const w of this.waiting.splice(0))
33
+ w({ value: undefined, done: true });
34
+ }
35
+ get pending() {
36
+ return this.queued.length;
37
+ }
38
+ [Symbol.asyncIterator]() {
39
+ return {
40
+ next: () => {
41
+ const queued = this.queued.shift();
42
+ if (queued)
43
+ return Promise.resolve({ value: queued, done: false });
44
+ if (this.closed)
45
+ return Promise.resolve({ value: undefined, done: true });
46
+ return new Promise((resolve) => this.waiting.push(resolve));
47
+ },
48
+ };
49
+ }
50
+ }
51
+ //# sourceMappingURL=mailbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mailbox.js","sourceRoot":"","sources":["../src/mailbox.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,OAAO,OAAO;IACV,OAAO,GAAoD,EAAE,CAAC;IAC9D,MAAM,GAAqB,EAAE,CAAC;IAC9B,MAAM,GAAG,KAAK,CAAC;IAEvB;;;;OAIG;IACH,IAAI,CAAC,IAAY,EAAE,KAAK,GAAG,KAAK;QAC9B,MAAM,OAAO,GAAmB;YAC9B,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;YACxC,kBAAkB,EAAE,IAAI;YACxB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,OAAgB,EAAE,EAAE,QAAQ,EAAE,KAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACnF,CAAC;QACF,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAClC,IAAI,IAAI;YAAE,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;;YAC3C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YAAE,CAAC,CAAC,EAAE,KAAK,EAAE,SAAkB,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACvF,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;IAC5B,CAAC;IAED,CAAC,MAAM,CAAC,aAAa,CAAC;QACpB,OAAO;YACL,IAAI,EAAE,GAAG,EAAE;gBACT,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;gBACnC,IAAI,MAAM;oBAAE,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;gBACnE,IAAI,IAAI,CAAC,MAAM;oBAAE,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,SAAkB,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;gBACnF,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;YAC9D,CAAC;SACF,CAAC;IACJ,CAAC;CACF"}
package/dist/main.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import './env.js';