omo-ai 5.1.12 → 5.1.13
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.
- package/bin/lib/child-process.js +2 -2
- package/bin/lib/daemon-adopt.js +125 -0
- package/bin/lib/daemon-args.js +2 -32
- package/bin/lib/daemon-operations.js +10 -2
- package/bin/lib/daemon-status.js +21 -2
- package/bin/lib/daemon.js +32 -33
- package/bin/lib/host-status.js +59 -0
- package/bin/lib/launcher.js +31 -8
- package/bin/lib/provider-map.json +1 -1
- package/bin/lib/thread-args.js +54 -0
- package/bin/lib/thread-output.js +40 -0
- package/bin/lib/thread.js +257 -0
- package/package.json +2 -2
- package/plugin/CHANGELOG.md +48 -0
- package/plugin/extensions/gateway-store-worker.mjs +2 -0
- package/plugin/extensions/memory-run-supervisor.mjs +1 -1
- package/plugin/extensions/omo-computer-use.js +1 -1
- package/plugin/extensions/omo-init-deep-advisor.js +1 -1
- package/plugin/extensions/omo-member.js +1 -1
- package/plugin/extensions/omo-task.js +2 -2
- package/plugin/extensions/omo.js +2 -2
- package/plugin/package.json +1 -1
- package/plugin/runtime/agent-toolkit-sdk/sdk.js +2 -2
- package/plugin/runtime/ast-grep-mcp/manifest.json +1 -1
- package/plugin/runtime/rollback-migrate.js +1 -1
- package/plugin/runtime/thread-sdk/sdk.js +2 -0
- package/plugin/scripts/install.mjs +2 -0
- package/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { userInfo } from "node:os"
|
|
2
|
+
import { join } from "node:path"
|
|
3
|
+
import { pathToFileURL } from "node:url"
|
|
4
|
+
|
|
5
|
+
import { integerOption, parseArgs, THREAD_EXIT } from "./thread-args.js"
|
|
6
|
+
import { humanLines } from "./thread-output.js"
|
|
7
|
+
|
|
8
|
+
export { THREAD_EXIT } from "./thread-args.js"
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* `omo thread` - the session gateway for scripts and connectors: every thread operation the agent
|
|
12
|
+
* tools offer, run through the plugin's thread SDK (`plugin/runtime/thread-sdk/sdk.js`) as
|
|
13
|
+
* `cli:<uid>`. It never starts a host: sessions are listed from what the engine enumerates, and
|
|
14
|
+
* bindings, the outbox and receipts live in the gateway store. JSON shapes: docs/reference/omo-thread.md.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const USAGE = [
|
|
18
|
+
"usage: omo thread <list|send|read|bind|unbind|rebind|bindings|report|answer|outbox|ack> [options] [--json]",
|
|
19
|
+
"",
|
|
20
|
+
" list [--all-scope]",
|
|
21
|
+
" send <target> <text> [--mode auto|steer|follow_up] [--expected-turn <n>] [--idempotency-key <k>]",
|
|
22
|
+
" send --binding <id> [<target>] <text> [--idempotency-key <event-id>] [--mode auto|follow_up]",
|
|
23
|
+
" [--author-id <platform-user-id> --author-name <display> [--author-user-id <id>]]",
|
|
24
|
+
" read <target> [--limit <items>] [--max-bytes <n>] [--cursor <c>]",
|
|
25
|
+
" bind <session> --platform <p> --account <id> --chat <id> [--thread <id>] [--root-message <id>]",
|
|
26
|
+
" [--progress-message <id>] [--direction in|out|both] [--inbound-mode auto|follow_up]",
|
|
27
|
+
" [--events <kind,...>] [--policy <id>] [--ttl <seconds>|none] [--idempotency-key <k>]",
|
|
28
|
+
" unbind <binding-id> --revision <n> [--idempotency-key <k>]",
|
|
29
|
+
" rebind <binding-id> <session> --revision <n> [--idempotency-key <k>]",
|
|
30
|
+
" bindings [--session <s>] [--platform <p>] [--account <id>] [--chat <id>] [--thread <id>] [--status <s>] [--cursor <c>] [--limit <n>]",
|
|
31
|
+
" report <session> <milestone|report|question|completion> <text> [--binding <id>] [--request-id <id>] [--request-kind question|select|confirm|input|editor] [--idempotency-key <k>]",
|
|
32
|
+
" answer --binding <answering-binding-id> --token <reply-token> <text>",
|
|
33
|
+
" [--author-id <platform-user-id> --author-name <display> [--author-user-id <id>]]",
|
|
34
|
+
" outbox <binding-id> [--after <cursor>] [--limit <n>] [--ack]",
|
|
35
|
+
" ack <binding-id> <cursor> [--provider-message-id <id>]",
|
|
36
|
+
"",
|
|
37
|
+
" --all-scope resolve sessions in every workspace, not only this directory's",
|
|
38
|
+
" --json print the result as one JSON value",
|
|
39
|
+
].join("\n")
|
|
40
|
+
|
|
41
|
+
const COMMON = ["--json", "--all-scope"]
|
|
42
|
+
const AUTHOR_FLAGS = ["--author-id", "--author-name", "--author-user-id"]
|
|
43
|
+
|
|
44
|
+
const COMMANDS = {
|
|
45
|
+
list: { values: [], booleans: [], arity: [0, 0], call: (sdk, _p, _o, scope) => sdk.list(scope) },
|
|
46
|
+
send: {
|
|
47
|
+
values: ["--mode", "--expected-turn", "--binding", "--idempotency-key", ...AUTHOR_FLAGS],
|
|
48
|
+
booleans: [],
|
|
49
|
+
arity: [1, 2],
|
|
50
|
+
call: (sdk, p, o, scope) => sdk.send({ ...scope, ...sendTarget(p, o), mode: o["--mode"], expected_turn_id: integerOption(o, "--expected-turn"), binding_id: o["--binding"], idempotency_key: o["--idempotency-key"], author: authorInput(o) }),
|
|
51
|
+
},
|
|
52
|
+
read: {
|
|
53
|
+
values: ["--limit", "--max-bytes", "--cursor"],
|
|
54
|
+
booleans: [],
|
|
55
|
+
arity: [1, 1],
|
|
56
|
+
call: async (sdk, p, o, scope) => lastItems(await sdk.read({ ...scope, thread: p[0], max_bytes: integerOption(o, "--max-bytes"), cursor: o["--cursor"] }), integerOption(o, "--limit")),
|
|
57
|
+
},
|
|
58
|
+
bind: {
|
|
59
|
+
values: ["--platform", "--account", "--chat", "--thread", "--root-message", "--progress-message", "--direction", "--inbound-mode", "--events", "--policy", "--ttl", "--idempotency-key"],
|
|
60
|
+
booleans: [],
|
|
61
|
+
arity: [1, 1],
|
|
62
|
+
call: (sdk, p, o, scope) => sdk.bind({ ...scope, session: p[0], idempotency_key: o["--idempotency-key"], binding: bindingInput(o) }),
|
|
63
|
+
},
|
|
64
|
+
unbind: { values: ["--revision", "--idempotency-key"], booleans: [], arity: [1, 1], call: (sdk, p, o) => sdk.unbind({ binding_id: p[0], expected_revision: integerOption(o, "--revision"), idempotency_key: o["--idempotency-key"] }) },
|
|
65
|
+
rebind: { values: ["--revision", "--idempotency-key"], booleans: [], arity: [2, 2], call: (sdk, p, o, scope) => sdk.rebind({ ...scope, binding_id: p[0], session: p[1], expected_revision: integerOption(o, "--revision"), idempotency_key: o["--idempotency-key"] }) },
|
|
66
|
+
bindings: {
|
|
67
|
+
values: ["--session", "--platform", "--account", "--chat", "--thread", "--status", "--cursor", "--limit"],
|
|
68
|
+
booleans: [],
|
|
69
|
+
arity: [0, 0],
|
|
70
|
+
call: (sdk, _p, o, scope) => sdk.bindings({ ...scope, session: o["--session"], platform: o["--platform"], account_id: o["--account"], chat_id: o["--chat"], thread_id: o["--thread"], status: o["--status"], cursor: o["--cursor"], limit: integerOption(o, "--limit") }),
|
|
71
|
+
},
|
|
72
|
+
report: {
|
|
73
|
+
values: ["--binding", "--request-id", "--request-kind", "--idempotency-key"],
|
|
74
|
+
booleans: [],
|
|
75
|
+
arity: [3, 3],
|
|
76
|
+
call: (sdk, p, o, scope) => sdk.report({ ...scope, session: p[0], kind: p[1], text: p[2], binding_id: o["--binding"], request_id: o["--request-id"], request_kind: o["--request-kind"], idempotency_key: o["--idempotency-key"] }),
|
|
77
|
+
},
|
|
78
|
+
answer: { values: ["--binding", "--token", ...AUTHOR_FLAGS], booleans: [], arity: [1, 1], call: (sdk, p, o) => sdk.answer({ binding_id: o["--binding"], reply_token: o["--token"], answer: p[0], author: authorInput(o) }) },
|
|
79
|
+
outbox: { values: ["--after", "--limit"], booleans: ["--ack"], arity: [1, 1], call: (sdk, p, o, _scope, flags) => drainOutbox(sdk, p[0], o, flags.has("--ack")) },
|
|
80
|
+
ack: { values: ["--provider-message-id"], booleans: [], arity: [2, 2], call: (sdk, p, o) => sdk.ack({ binding_id: p[0], cursor: Number(p[1]), provider_message_id: o["--provider-message-id"] }) },
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const REQUIRED = { unbind: ["--revision"], rebind: ["--revision"], bind: ["--platform", "--account", "--chat"], answer: ["--binding", "--token"] }
|
|
84
|
+
const INTEGER_FLAGS = ["--expected-turn", "--limit", "--max-bytes", "--revision", "--after"]
|
|
85
|
+
const CHOICE_FLAGS = { "--mode": ["auto", "steer", "follow_up"], "--direction": ["in", "out", "both"] }
|
|
86
|
+
|
|
87
|
+
function sendTarget(positionals, options) {
|
|
88
|
+
if (positionals.length === 2) return { thread: positionals[0], text: positionals[1] }
|
|
89
|
+
return options["--binding"] === undefined ? { thread: positionals[0], text: undefined } : { text: positionals[0] }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function authorInput(o) {
|
|
93
|
+
if (o["--author-id"] === undefined) return undefined
|
|
94
|
+
return { platform_user_id: o["--author-id"], display: o["--author-name"], ...(o["--author-user-id"] === undefined ? {} : { user_id: o["--author-user-id"] }) }
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function authorProblem(o) {
|
|
98
|
+
const given = AUTHOR_FLAGS.filter((flag) => o[flag] !== undefined)
|
|
99
|
+
if (given.length === 0) return undefined
|
|
100
|
+
if (o["--binding"] === undefined) return "--author-id/--author-name/--author-user-id need --binding: only a bound external thread has authors"
|
|
101
|
+
if (o["--author-id"] === undefined || o["--author-name"] === undefined) return "--author-id and --author-name go together (--author-user-id needs both)"
|
|
102
|
+
return undefined
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function bindingInput(o) {
|
|
106
|
+
const direction = o["--direction"] === undefined ? undefined : { inbound: o["--direction"] !== "out", outbound: o["--direction"] !== "in" }
|
|
107
|
+
const ttl = o["--ttl"] === undefined ? undefined : o["--ttl"] === "none" ? null : Number(o["--ttl"])
|
|
108
|
+
return {
|
|
109
|
+
platform: o["--platform"],
|
|
110
|
+
account_id: o["--account"],
|
|
111
|
+
chat_id: o["--chat"],
|
|
112
|
+
thread_id: o["--thread"],
|
|
113
|
+
root_message_id: o["--root-message"],
|
|
114
|
+
progress_message_id: o["--progress-message"],
|
|
115
|
+
direction,
|
|
116
|
+
inbound_mode: o["--inbound-mode"],
|
|
117
|
+
outbound_events: o["--events"]?.split(",").filter(Boolean),
|
|
118
|
+
policy_id: o["--policy"],
|
|
119
|
+
ttl_seconds: ttl,
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function lastItems(result, limit) {
|
|
124
|
+
if (limit === undefined || result.kind !== "ok") return result
|
|
125
|
+
return { ...result, items: result.items.slice(Math.max(0, result.items.length - limit)) }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** The connector drain: read a page, and with `--ack` acknowledge through its newest row. */
|
|
129
|
+
async function drainOutbox(sdk, bindingId, options, ack) {
|
|
130
|
+
const page = await sdk.outbox({ binding_id: bindingId, after_cursor: integerOption(options, "--after"), limit: integerOption(options, "--limit") })
|
|
131
|
+
if (!ack || page.kind !== "ok") return page
|
|
132
|
+
const newest = page.rows.at(-1)
|
|
133
|
+
if (newest === undefined) return { ...page, acked: null }
|
|
134
|
+
const acked = await sdk.ack({ binding_id: bindingId, cursor: newest.cursor })
|
|
135
|
+
return acked.kind === "ok" ? { ...page, acked } : acked
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function validate(name, parsed) {
|
|
139
|
+
const [min, max] = COMMANDS[name].arity
|
|
140
|
+
const count = parsed.positionals.length
|
|
141
|
+
if (count < min || count > max) return `expects ${min === max ? min : `${min}-${max}`} argument(s), got ${count}`
|
|
142
|
+
for (const flag of REQUIRED[name] ?? []) if (parsed.options[flag] === undefined) return `${flag} is required`
|
|
143
|
+
for (const flag of INTEGER_FLAGS) if (Number.isNaN(integerOption(parsed.options, flag) ?? 0)) return `${flag} must be a non-negative integer`
|
|
144
|
+
for (const [flag, choices] of Object.entries(CHOICE_FLAGS)) {
|
|
145
|
+
const value = parsed.options[flag]
|
|
146
|
+
if (value !== undefined && !choices.includes(value)) return `${flag} must be one of ${choices.join(", ")}, got '${value}'`
|
|
147
|
+
}
|
|
148
|
+
if (name === "send") {
|
|
149
|
+
const binding = parsed.options["--binding"] !== undefined
|
|
150
|
+
if (!binding && count !== 2) return "needs <target> <text> (or --binding <id>)"
|
|
151
|
+
if (parsed.positionals.at(-1).trim() === "") return "<text> is empty"
|
|
152
|
+
if (binding && parsed.options["--mode"] === "steer") return "--binding takes --mode auto or follow_up (capped by the binding's inbound mode); a binding message never steers"
|
|
153
|
+
if (binding && parsed.options["--expected-turn"] !== undefined) return "--binding takes no --expected-turn: a binding message never steers"
|
|
154
|
+
}
|
|
155
|
+
if (name === "send" || name === "answer") {
|
|
156
|
+
const author = authorProblem(parsed.options)
|
|
157
|
+
if (author !== undefined) return author
|
|
158
|
+
}
|
|
159
|
+
if (name === "ack" && !/^\d+$/.test(parsed.positionals[1])) return "<cursor> must be a non-negative integer"
|
|
160
|
+
return undefined
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** With `--json`, a failure the CLI answers itself is printed in the SDK's error shape, so stdout is always one JSON value. */
|
|
164
|
+
function refuse({ stdout, stderr }, json, code, line, nextAction) {
|
|
165
|
+
if (json) stdout.write(`${JSON.stringify({ kind: "error", error: { code, message: line, next_action: nextAction } })}\n`)
|
|
166
|
+
stderr.write(`${line}\n`)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** `--json` among the options, before `--`: a usage error is still answered in JSON when the parse itself failed. */
|
|
170
|
+
function launchJson(args) {
|
|
171
|
+
const end = args.indexOf("--")
|
|
172
|
+
return (end === -1 ? args : args.slice(0, end)).includes("--json")
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export function threadExitCode(result) {
|
|
176
|
+
if (result?.kind === "ok") return THREAD_EXIT.ok
|
|
177
|
+
const code = result?.error?.code
|
|
178
|
+
if (code === "host_unavailable") return THREAD_EXIT.unavailable
|
|
179
|
+
if (code === "internal_error") return THREAD_EXIT.failed
|
|
180
|
+
return THREAD_EXIT.refused
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Loads the SDK the plugin ships. `node:sqlite` is probed lazily first (as `setup-detect.js` does):
|
|
185
|
+
* the gateway store needs it, and a runtime without it gets a named refusal, not a worker crash.
|
|
186
|
+
* The answer is `{ sdk }` or `{ error, code }`: `unsupported` for the runtime, `internal_error` for a
|
|
187
|
+
* plugin SDK that cannot be imported (a broken or partial install).
|
|
188
|
+
*/
|
|
189
|
+
export async function loadThreadSdk({ pluginRoot, agentDir, env, cwd, engine, loadSqlite, importSdk, identity }) {
|
|
190
|
+
try {
|
|
191
|
+
await (loadSqlite ?? (() => import("node:sqlite")))()
|
|
192
|
+
} catch {
|
|
193
|
+
return { code: "unsupported", error: `node:sqlite is unavailable in this runtime (${process.versions.bun ? `bun ${process.versions.bun}` : `node ${process.versions.node}`}); the session gateway store needs it` }
|
|
194
|
+
}
|
|
195
|
+
let module
|
|
196
|
+
try {
|
|
197
|
+
module = await (importSdk ?? (() => import(pathToFileURL(join(pluginRoot, "runtime", "thread-sdk", "sdk.js")).href)))()
|
|
198
|
+
} catch (error) {
|
|
199
|
+
return { code: "internal_error", error: `the plugin's thread SDK could not be loaded from ${join(pluginRoot, "runtime", "thread-sdk")}: ${error instanceof Error ? error.message : String(error)}` }
|
|
200
|
+
}
|
|
201
|
+
const who = identity ?? { uid: process.getuid?.() ?? 0, user: userInfo().username }
|
|
202
|
+
const engineStatusAll = async () => engine.run(["host", "status", "--json", "--all", "--include-workers"], { env: { ...env, OMO_AGENT_DIR: agentDir } }).stdout
|
|
203
|
+
return { sdk: module.createThreadSdk({ agentDir, cwd, uid: who.uid, user: who.user, env, engineStatusAll }) }
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export async function runThreadCommand(args, options) {
|
|
207
|
+
const { stdout, stderr, platform } = options
|
|
208
|
+
const name = args[0]
|
|
209
|
+
const json = launchJson(args)
|
|
210
|
+
if (name === "--help" || name === "-h") {
|
|
211
|
+
stdout.write(`${USAGE}\n`)
|
|
212
|
+
return THREAD_EXIT.ok
|
|
213
|
+
}
|
|
214
|
+
if (name === undefined || !Object.hasOwn(COMMANDS, name)) {
|
|
215
|
+
refuse(options, json, "invalid_arguments", `omo thread: ${name === undefined ? "expects a subcommand" : `unknown subcommand '${name}'`}`, "Run omo thread --help.")
|
|
216
|
+
stderr.write(`${USAGE}\n`)
|
|
217
|
+
return THREAD_EXIT.usage
|
|
218
|
+
}
|
|
219
|
+
// Same refusal as `omo daemon` on win32: the gateway's endpoints are unix sockets.
|
|
220
|
+
if (platform === "win32") {
|
|
221
|
+
refuse(options, json, "unsupported", "omo thread: a task host needs a unix socket, which win32 does not provide", "Run omo thread on macOS or Linux.")
|
|
222
|
+
return THREAD_EXIT.unsupported
|
|
223
|
+
}
|
|
224
|
+
const command = COMMANDS[name]
|
|
225
|
+
const parsed = parseArgs(args.slice(1), { booleans: [...COMMON, ...command.booleans], values: command.values })
|
|
226
|
+
const problem = parsed.error ?? validate(name, parsed)
|
|
227
|
+
if (problem !== undefined) {
|
|
228
|
+
refuse(options, json, "invalid_arguments", `omo thread ${name}: ${problem}`, `Run omo thread --help for the ${name} options.`)
|
|
229
|
+
return THREAD_EXIT.usage
|
|
230
|
+
}
|
|
231
|
+
const loaded = await loadThreadSdk(options)
|
|
232
|
+
if (loaded.error !== undefined && loaded.code === "internal_error") {
|
|
233
|
+
refuse(options, json, "internal_error", `omo thread: ${loaded.error}`, "Reinstall omo (omo update), then retry.")
|
|
234
|
+
return THREAD_EXIT.failed
|
|
235
|
+
}
|
|
236
|
+
if (loaded.error !== undefined) {
|
|
237
|
+
refuse(options, json, "unsupported", `omo thread: ${loaded.error}`, "Run omo thread under bun, or a node with node:sqlite.")
|
|
238
|
+
return THREAD_EXIT.unsupported
|
|
239
|
+
}
|
|
240
|
+
try {
|
|
241
|
+
const scope = parsed.flags.has("--all-scope") ? { all_scope: true } : {}
|
|
242
|
+
const result = await command.call(loaded.sdk, parsed.positionals, parsed.options, scope, parsed.flags)
|
|
243
|
+
const exitCode = threadExitCode(result)
|
|
244
|
+
if (result.kind !== "ok") {
|
|
245
|
+
if (json) stdout.write(`${JSON.stringify(result)}\n`)
|
|
246
|
+
stderr.write(`omo thread ${name}: ${result.error.code}: ${result.error.message}\n next: ${result.error.next_action}\n`)
|
|
247
|
+
return exitCode
|
|
248
|
+
}
|
|
249
|
+
if (json) stdout.write(`${JSON.stringify(name === "list" ? result.threads : result)}\n`)
|
|
250
|
+
else for (const line of humanLines(name, result)) stdout.write(`${line}\n`)
|
|
251
|
+
return exitCode
|
|
252
|
+
} finally {
|
|
253
|
+
// The command's result is already printed; a store that fails to close is logged, never a new outcome.
|
|
254
|
+
await loaded.sdk.dispose().catch((error) => stderr.write(`omo thread: closing the gateway store failed: ${error instanceof Error ? error.message : String(error)}\n`))
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omo-ai",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OmO Native - the standalone omo command with the OMO extension built in: bun add -g omo-ai",
|
|
6
6
|
"bin": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"postinstall": "node bin/senpi-patch.mjs"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@code-yeongyu/senpi": "2026.10.
|
|
20
|
+
"@code-yeongyu/senpi": "2026.10.3"
|
|
21
21
|
},
|
|
22
22
|
"repository": {
|
|
23
23
|
"type": "git",
|
package/plugin/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,52 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [5.1.13] - 2026-10-03
|
|
11
|
+
|
|
12
|
+
**MCP tools work again when memory is on.** Since 5.1.10, a finished memory child or delegated task shut the shared MCP servers down for the whole process, so every MCP call failed with `MCP server <name> is disabled`. This release runs on senpi 2026.10.3, which gives each session its own binding to the shared servers; it was verified with the shipped bundle. If you can't update yet, turn memory off until you do: set `"memory": { "enabled": false }` in `~/.omo/omo.json`, or start omo with `--omo-senpi-memory-disabled=true`.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
**MCP calls no longer fail with `MCP server <name> is disabled` after a child session ends.** A memory child or a delegated task that finished released the MCP service for every session in the process; now it releases only its own binding, and the shared servers stay up. Thanks to @Tygb99 for the report. ([#9461](https://github.com/code-yeongyu/oh-my-openagent/issues/9461), [senpi#2524](https://github.com/code-yeongyu/senpi/pull/2524))
|
|
17
|
+
|
|
18
|
+
**Codex edition (LazyCodex): a project's own registered agent roles can be spawned.** The spawn guard accepted only LazyCodex's 12 bundled roles, so a role registered in `.codex/agents` or `$CODEX_HOME/agents` was refused even though Codex offered it; it now accepts any role with a registered role file and still refuses unregistered ones. Thanks to @aconley-vultr for the report. ([lazycodex#171](https://github.com/code-yeongyu/lazycodex/issues/171), [lazycodex#164](https://github.com/code-yeongyu/lazycodex/issues/164), [#9462](https://github.com/code-yeongyu/oh-my-openagent/pull/9462))
|
|
19
|
+
|
|
20
|
+
**Cancelling a delegated task while its host can't list its sessions keeps the cancel pending** instead of finishing it with the session still open; it completes once the host answers again. ([#9450](https://github.com/code-yeongyu/oh-my-openagent/issues/9450), [#9459](https://github.com/code-yeongyu/oh-my-openagent/pull/9459))
|
|
21
|
+
|
|
22
|
+
**Skills are listed in a stable order**, so the tool prefix of a prompt stays the same between turns and keeps hitting the prompt cache. ([#9433](https://github.com/code-yeongyu/oh-my-openagent/pull/9433))
|
|
23
|
+
|
|
24
|
+
**OpenCode edition fixes, thanks to @cynkai:** an explicitly chosen model no longer falls back through the built-in chain ([#8808](https://github.com/code-yeongyu/oh-my-openagent/pull/8808)); a plugin-load telemetry failure no longer prints into the TUI ([#8804](https://github.com/code-yeongyu/oh-my-openagent/pull/8804)); a background task whose session stopped on an error is finalized ([#8814](https://github.com/code-yeongyu/oh-my-openagent/pull/8814)) and skips fallback models no connected provider serves ([#8844](https://github.com/code-yeongyu/oh-my-openagent/pull/8844)); Sisyphus stays available when Hephaestus isn't registered ([#8841](https://github.com/code-yeongyu/oh-my-openagent/pull/8841)); and `omo.schema.json` embeds the `[opencode]` schema once and no longer marks defaulted fields as required ([#8871](https://github.com/code-yeongyu/oh-my-openagent/pull/8871), [#8873](https://github.com/code-yeongyu/oh-my-openagent/pull/8873)). Tool argument rewrites in the OpenCode edition also keep the original arguments object ([#9466](https://github.com/code-yeongyu/oh-my-openagent/pull/9466)).
|
|
25
|
+
|
|
26
|
+
`omo host status --all` and `omo thread list` no longer show an older session entry as the latest activity when the final JSONL entry is large, partial or invalid. Both surfaces use the same bounded final-record policy, show `null` when freshness cannot be proved, and list known activity newest-first with unknown activity last. ([#9222](https://github.com/code-yeongyu/oh-my-openagent/pull/9222))
|
|
27
|
+
|
|
28
|
+
A message to a published terminal session that the engine still reports as not answering is kept offline instead of being sent straight to its socket, so `omo thread list`, a send and a steer always agree on whether that session can be reached right now; the message is delivered once a later check lists the session live again. A bound send that names its session no longer pays the same lookup twice. ([#9222](https://github.com/code-yeongyu/oh-my-openagent/pull/9222))
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
**omo runs on senpi 2026.10.3** (the MCP fix above, plus the Bun `-e` host-launch and WebView readiness fixes). Full list: [senpi 2026.10.3](https://github.com/code-yeongyu/senpi/releases/tag/v2026.10.3).
|
|
33
|
+
|
|
34
|
+
**OpenGateway tasks run without a concurrency limit by default.** ([#9427](https://github.com/code-yeongyu/oh-my-openagent/pull/9427))
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
|
|
38
|
+
_The session gateway entries below are its store foundation; the thread tools become usable with 5.1.14._
|
|
39
|
+
|
|
40
|
+
**Every session can reach every other one, terminal sessions included.** ([#9143](https://github.com/code-yeongyu/oh-my-openagent/issues/9143)) Messages between sessions now go through a session gateway: one small database in the agent directory, with no daemon to run and nothing to configure. A terminal session opens a private control socket, so a Desktop thread, a task child or a script can list it, read it and send to it; the thread tools list terminal sessions with their real names and times. A message never interrupts what you are doing: while you are typing, or a submission of yours is on its way, it waits, and the session shows one line saying a remote message is queued. A message to a session that is not running is kept for 24 hours and taken when the session runs again. Fixed limits stop runaway loops: a session cannot message itself or reply straight back into the chain that messaged it, a chain of messages stops after 4 hops or 64 messages, one turn reaches at most 16 sessions, and one sender gets a burst of 8 messages to a session, then one every 5 seconds.
|
|
41
|
+
|
|
42
|
+
**`omo thread` talks to running sessions from scripts and chat connectors.** ([#9143](https://github.com/code-yeongyu/oh-my-openagent/issues/9143)) `omo thread list|send|read|bind|unbind|rebind|bindings|report|answer|outbox|ack` runs the thread tools' operations without an agent session, with `--json` output that is one JSON value (also on failure) and exit codes a script can branch on: 0 done, 1 refused, 2 usage, 3 nothing answering, 4 unsupported here, 5 internal error. JavaScript can import the same operations from the plugin (`runtime/thread-sdk/sdk.js`) without spawning `omo`. It never starts a host. Reference: [`docs/reference/omo-thread.md`](https://github.com/code-yeongyu/oh-my-openagent/blob/dev/docs/reference/omo-thread.md).
|
|
43
|
+
|
|
44
|
+
**A session can be bound to a chat thread, and report back through it.** ([#9143](https://github.com/code-yeongyu/oh-my-openagent/issues/9143)) A binding attaches one session to one external thread (any platform; OmO ships no chat connector itself). Messages from the thread arrive with `omo thread send --binding`, admitted once per platform event. The session posts milestones, reports, questions and its completion to the binding's outbox with `thread_report`, and a connector reads them with `omo thread outbox` and acknowledges them. A question carries a reply token that only an answer through the same binding can use. A completion is written only when you ask for one, and survives a restart. At most one active binding holds a thread; unbinding and rebinding name the revision they expect, and a rebind never extends the binding's lifetime.
|
|
45
|
+
|
|
46
|
+
**A chat connector can say who wrote each message, and how it should land.** ([#9143](https://github.com/code-yeongyu/oh-my-openagent/issues/9143)) `omo thread send --binding` takes `--author-id` and `--author-name` (and `--author-user-id`). The session sees the author as quoted fields in the message's provenance header, outside the text, so a message cannot pretend to come from someone else. Each author gets their own rate budget in a busy thread. `--mode follow_up` lets one message land more gently than its binding allows, and never more strongly. `answer` takes the same author flags, and the outbox records who answered a question. A connector can watch `<agent dir>/gateway/outbox.marker` to learn about new outbox rows. The reference now spells out that outbox delivery is at-least-once, and that `(binding_id, cursor)` is the key to dedupe by.
|
|
47
|
+
|
|
48
|
+
**`omo host status --all` shows when each terminal session was last active.** ([#9143](https://github.com/code-yeongyu/oh-my-openagent/issues/9143)) Every terminal (`tui`) row now carries `last_activity_at`: the time of the newest entry in its session file, the same time `omo thread list` shows, or `null` when it is not known.
|
|
49
|
+
|
|
50
|
+
**`omo daemon adopt` moves a session from a host into your terminal.** ([#9143](https://github.com/code-yeongyu/oh-my-openagent/issues/9143)) `omo daemon adopt <session>` asks the host holding a Desktop thread or a background session to hand it over, then resumes it in the current terminal, in the session's own directory. A session in the middle of a turn is refused unless you pass `--interrupt`, and input the interrupt took out of its queue becomes your first prompts. A session a Desktop window has open is refused unless you pass `--force`. `omo daemon status` now lists terminal sessions as `tui` rows, and `handoff` and `stop --all` leave them alone.
|
|
51
|
+
|
|
52
|
+
### Removed
|
|
53
|
+
|
|
54
|
+
**`omo daemon attach` and the shared-host opt-in env (`OMO_ENABLE_SHARED_HOST`) are removed; interactive sessions always run standalone.** ([#9143](https://github.com/code-yeongyu/oh-my-openagent/issues/9143)) A terminal session no longer joins an engine host; it always runs its own session in its own process, and other sessions reach it through the gateway. `OMO_ENABLE_SHARED_HOST` no longer changes anything. To continue a session that lives on a host in a terminal, use `omo daemon adopt`.
|
|
55
|
+
|
|
10
56
|
## [5.1.12] - 2026-10-03
|
|
11
57
|
|
|
12
58
|
**The desktop app can now see when computer use is waiting on a system permission, and a cancelled task on Windows no longer shows up as a crash.** This release runs on the senpi 2026.10.2 engine, which carries the upstream pi v1.0.0 changes.
|
|
@@ -35,6 +81,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
35
81
|
|
|
36
82
|
Cancelling a delegated task finishes only once the host confirms the child closed, a stopped task whose handle was let go still ends as cancelled, and a stopped task is never continued afterwards. ([#9407](https://github.com/code-yeongyu/oh-my-openagent/pull/9407))
|
|
37
83
|
|
|
84
|
+
**The OpenCode edition's skill tool lists skills and commands in a stable order, so its tool definitions stay cacheable.** Skills and commands in the same scope were listed in discovery order, which varies between processes, so the tool definition changed from session to session and each new session and subagent missed the prompt cache. They are now ordered by scope, then by name. Thanks to @kimchupa-l10n for the report. ([#9432](https://github.com/code-yeongyu/oh-my-openagent/issues/9432))
|
|
85
|
+
|
|
38
86
|
## [5.1.10] - 2026-10-02
|
|
39
87
|
|
|
40
88
|
**Hotfix: `omo -p` exits again after a delegated task.** Since 5.1.8, a headless or scripted run whose agent handed work to an in-process task printed its answer and then never exited, so CI jobs, cron entries and wrappers that wait on it hung until killed. Interactive sessions leaked a loopback bridge server and its socket for every such task. This release runs on the senpi 2026.10.1-3 engine.
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// omo:haTcOnW4Q7NFRriYnPezqeOoaLFn_eHDlCpcX3dHCV4:ELjiv3uXvehilVGUyp2URd8J4PhruHKfVy8EzTtMliw
|
|
2
|
+
import{chmodSync as e,closeSync as i,existsSync as t,mkdirSync as n,openSync as r}from"node:fs";import{join as d}from"node:path";import{setTimeout as s}from"node:timers/promises";import{parentPort as a}from"node:worker_threads";function o(e,i,t){return Object.assign(Error(`gateway store lock wait exceeded: ${e} waited ${i} ms for the write lock (limit ${t} ms); another process holds it`),{code:"gateway_lock_wait_exceeded"})}import{join as _}from"node:path";function u(e){return _(e,"gateway")}function l(e,i){return _(u(e),"inbox",i)}import{execFile as c}from"node:child_process";var p="epoch:",E=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function g(e){return new Promise(i=>{c("ps",["-o","lstart=","-p",String(e)],{env:{...process.env,LC_ALL:"C",LANG:"C",TZ:"UTC"},windowsHide:!0,timeout:5e3},(e,t)=>{let n=null===e?function(e){let i=/^[A-Z][a-z]{2} ([A-Z][a-z]{2}) +(\d{1,2}) (\d{2}):(\d{2}):(\d{2}) (\d{4})$/.exec(e.trim());if(null===i)return null;let[,t,n,r,d,s,a]=i,o=E.indexOf(t);return o<0?null:Date.UTC(Number(a),o,Number(n),Number(r),Number(d),Number(s))/1e3}(t):null;i(null===n?null:`${p}${n}`)})})}async function m(e){if(!function(e){try{return process.kill(e,0),!0}catch(e){return!(e instanceof Error&&"code"in e&&"ESRCH"===e.code)}}(e.pid))return!0;if(null===e.process_start_time||!e.process_start_time.startsWith(p))return!1;let i=await g(e.pid);return null!==i&&i!==e.process_start_time}function b(e,i){return e.pid===i.pid&&e.process_start_time===i.process_start_time&&e.instance_id===i.instance_id}class f{params=[];sinkRows=[];db;constructor(e){this.db=e,e.function("gw_p",{deterministic:!1},e=>this.params[e]??null),e.function("gw_sink",{varargs:!0,deterministic:!1},(...e)=>(this.sinkRows.push(e),null))}exec(e){this.db.exec(e)}run(e,i=[]){this.params=i;try{this.db.exec(T(e))}finally{this.params=[]}return Number(this.all(["n"],"SELECT changes() AS n")[0]?.n??0)}all(e,i,t=[],n){this.params=t,this.sinkRows=[];try{let t=void 0===n?"0":`row_number() OVER (ORDER BY ${n})`;return this.db.exec(`SELECT gw_sink(${t}, ${e.join(", ")}) FROM (${T(i)})${void 0===n?"":` ORDER BY ${n}`}`),(void 0===n?this.sinkRows:this.sinkRows.toSorted((e,i)=>Number(e[0])-Number(i[0]))).map(i=>Object.fromEntries(e.map((e,t)=>[e,i[t+1]??null])))}finally{this.params=[],this.sinkRows=[]}}one(e,i,t=[]){return this.all(e,i,t)[0]}}function T(e){let i=0;return e.replace(/\?/g,()=>`gw_p(${i++})`)}function N(e){if("object"!=typeof e||null===e)return!1;let i=e;return 5===i.errcode||6===i.errcode||"string"==typeof i.message&&/database is (locked|busy)/i.test(i.message)}import{createHash as y,randomUUID as v}from"node:crypto";import{closeSync as h,constants as w,mkdirSync as L,openSync as k,readdirSync as R,readFileSync as O,rmSync as S,writeSync as A}from"node:fs";import{userInfo as q}from"node:os";import{join as x}from"node:path";function I(e,i,t){return i===t||function(e,i,t){let n=new Map;for(let i of e){let e=n.get(i.from);void 0===e?n.set(i.from,[i.to]):e.push(i.to)}let r=new Set([i]),d=[i];for(;d.length>0;){let e=d.pop();if(e===t)return!0;for(let i of n.get(e)??[])r.has(i)||(r.add(i),d.push(i))}return!1}(e,t,i)}var D=5e3,U=864e5,C=6048e5,M=1048576,H=2592e6,W=2592e6,X=256,F="session_released";import{existsSync as $,readFileSync as G}from"node:fs";import{join as P}from"node:path";function B(e){let i=P(e,"mailbox.jsonl");if($(i))return function(e){let i=e.slice(0,e.lastIndexOf("\n")+1),t=new Map;for(let e of i.split("\n")){if(0===e.length)continue;let i=JSON.parse(e);if(!j(i)||1!==i.version)throw Error("invalid legacy mailbox event");if("snapshot"===i.kind&&Array.isArray(i.items)){t.clear();for(let e of i.items){let i=K(e);t.set(i.message_seq,i)}}else if("enqueue"===i.kind){let e=K(i.item);t.set(e.message_seq,e)}else{if("remove"!==i.kind||"number"!=typeof i.message_seq)throw Error("invalid legacy mailbox event");t.delete(i.message_seq)}}return J([...t.values()])}(G(i,"utf8"));let t=P(e,"mailbox.json");if(!$(t))return null;let n=JSON.parse(G(t,"utf8"));if(!j(n)||!j(n.queues))throw Error(`invalid legacy mailbox state: ${t}`);let r=[];for(let e of Object.values(n.queues)){if(!Array.isArray(e))throw Error(`invalid legacy mailbox queue: ${t}`);for(let i of e)r.push(K(i))}return J(r)}function J(e){return e.toSorted((e,i)=>e.message_seq-i.message_seq)}function K(e){if(!j(e)||"string"!=typeof e.target||"string"!=typeof e.message||"number"!=typeof e.message_seq||!Number.isInteger(e.message_seq)||"auto"!==e.delivery&&"steer"!==e.delivery&&"follow_up"!==e.delivery||void 0!==e.expected_turn_id&&"string"!=typeof e.expected_turn_id||"string"!=typeof e.operation_id||"string"!=typeof e.accepted_at)throw Error("invalid legacy mailbox item");return{target:e.target,message:e.message,message_seq:e.message_seq,delivery:e.delivery,expected_turn_id:void 0===e.expected_turn_id?null:Y(e.expected_turn_id),operation_id:e.operation_id,accepted_at:e.accepted_at}}function Y(e){let i=/^turn-(0|[1-9]\d*)$/.exec(e);if(null===i)return null;let t=Number(i[1]);return Number.isSafeInteger(t)?t:null}function j(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}import{createHash as V,createHmac as z,randomUUID as Z,timingSafeEqual as Q}from"node:crypto";var ee=2592e6;function ie(e){return new Date(e).toISOString()}function te(e){return Buffer.from(e).toString("base64url")}function ne(e,i){return te(JSON.stringify({v:1,as_of:e,after:i}))}var re="rt1";function de(e,i){return z("sha256",e).update(`${re}.${i}`).digest().subarray(0,16).toString("base64url")}var se=new WeakMap;function ae(e,i,t){return ye(e,"DELETE FROM receipts WHERE principal = ? AND operation = ? AND idempotency_key = ? AND expires_at <= ?",[i.principal,i.operation,i.idempotency_key,t])}function oe(e,i,t=0){if(i<(se.get(e)??Number.NEGATIVE_INFINITY))return null;let n=function(e,i,t=256){let n=X,r=ye(e,"DELETE FROM receipts WHERE rowid IN (SELECT rowid FROM receipts WHERE expires_at <= ? LIMIT ?)",[i,t]),d=ye(e,"DELETE FROM deliveries WHERE delivery_id IN (SELECT d.delivery_id FROM deliveries d WHERE d.state IN ('applied', 'refused') AND d.updated_at <= ? AND NOT EXISTS (SELECT 1 FROM receipts r WHERE r.delivery_id = d.delivery_id) LIMIT ?)",[i-W,n]),s=ye(e,"DELETE FROM causal_edges WHERE rowid IN (SELECT e.rowid FROM causal_edges e JOIN causal_roots r ON r.root_id = e.root_id WHERE r.expires_at <= ? LIMIT ?)",[i,n]),a=ye(e,"DELETE FROM causal_roots WHERE root_id IN (SELECT r.root_id FROM causal_roots r WHERE r.expires_at <= ? AND NOT EXISTS (SELECT 1 FROM causal_edges e WHERE e.root_id = r.root_id) LIMIT ?)",[i,n]),o=ye(e,"DELETE FROM rate_buckets WHERE rowid IN (SELECT rowid FROM rate_buckets WHERE updated_at <= ? LIMIT ?)",[i-4e4,n]),_=ye(e,`DELETE FROM bindings WHERE binding_id IN (SELECT b.binding_id FROM bindings b WHERE b.status != 'active' AND b.updated_at <= ?\n AND NOT EXISTS (SELECT 1 FROM outbox o WHERE o.binding_id = b.binding_id)\n AND NOT EXISTS (SELECT 1 FROM completion_arms a WHERE a.binding_id = b.binding_id)\n AND NOT EXISTS (SELECT 1 FROM deliveries d WHERE d.binding_id = b.binding_id AND d.state IN ${ge}) LIMIT ?)`,[ie(i-ee),n]),u=ye(e,"DELETE FROM outbox_cursors WHERE binding_id IN (SELECT c.binding_id FROM outbox_cursors c WHERE NOT EXISTS (SELECT 1 FROM bindings b WHERE b.binding_id = c.binding_id) LIMIT ?)",[n]),l=ye(e,"DELETE FROM session_meta WHERE durable_id IN (SELECT m.durable_id FROM session_meta m WHERE\n m.incarnation IS NULL\n AND NOT EXISTS (SELECT 1 FROM deliveries d WHERE d.target_durable_id = m.durable_id)\n AND NOT EXISTS (SELECT 1 FROM bindings b WHERE b.session_durable_id = m.durable_id)\n AND NOT EXISTS (SELECT 1 FROM outbox o WHERE o.session_durable_id = m.durable_id)\n AND NOT EXISTS (SELECT 1 FROM completion_arms a WHERE a.session_durable_id = m.durable_id) LIMIT ?)",[n]);return{receipts:r,deliveries:d,causal_edges:s,causal_roots:a,rate_buckets:o,bindings:_,outbox_cursors:u,session_meta:l}}(e,i,Math.max(X-t,0)),r=n.receipts+t>=X||Object.values(n).some(e=>e>=X);return se.set(e,r?i:i+36e5),n}var _e=new Set(["invalid_arguments","caller_context_missing","not_found","ambiguous_target","scope_denied","name_conflict","not_resumable","orphaned","foreign_live_owner","no_active_turn","turn_conflict","not_steerable","message_too_large","queue_full","cursor_invalid","cursor_stale","idempotency_conflict","idempotency_in_progress","idempotency_uncertain","approval_unavailable","approval_route_locked","partial_commit","unsupported","overloaded","transport_closed","host_unavailable","internal_error","model_not_found","model_ambiguous","thinking_level_unsupported","loop_detected","binding_conflict","binding_mismatch","binding_inactive","stale_revision","stale_token","already_answered","answer_in_progress"]);function ue(e,i,t,n){if("string"!=typeof(r=e)||!_e.has(r))throw Error(`unknown thread error code: ${String(e)}`);var r;return{code:e,message:i,next_action:t,...void 0===n?{}:{details:n}}}var le={not_steerable:{code:"not_steerable",next:"Send with delivery auto or follow_up; a steer needs a running turn."},turn_conflict:{code:"turn_conflict",next:"Read the target again and retry with its current turn id, or send with delivery auto."},expired:{code:"not_resumable",next:"The target did not take the message within its lifetime; send it again if it still matters."},binding_closed:{code:"invalid_arguments",next:"The binding this message was queued under was detached or rebound; re-read the binding and send again."}};function ce(e,i,t,n,r){let d={kind:"ok",thread_id:e.target_durable_id,delivery_id:e.delivery_id,message_seq:e.seq,effective_mode:e.mode_effective??e.mode_requested,endpoint_kind:t,deduplicated:n};if("admitted"===e.state||"applied"===e.state)return"started"===e.admission_kind||"steered"===e.admission_kind?{...d,delivery:{kind:e.admission_kind,turn_id:String(e.turn_epoch??0)}}:{...d,delivery:{kind:"queued",queue_position:Math.max(i,1)}};if("refused"===e.state){let i=le[e.reason??""]??{code:"internal_error",next:"Call thread_list and check the target."};return{kind:"error",error:ue(i.code,`Delivery ${e.delivery_id} was refused: ${e.reason??"unknown"}.`,i.next,{delivery_id:e.delivery_id})}}return"uncertain"===e.state?{kind:"error",error:ue("idempotency_uncertain",`Delivery ${e.delivery_id} may or may not have reached the target.`,"Read the target transcript before deciding whether to send again.",{delivery_id:e.delivery_id})}:{...d,delivery:{kind:r?"queued_offline":"queued",queue_position:Math.max(i,1)}}}var pe=[["CREATE TABLE deliveries (\n delivery_id TEXT PRIMARY KEY,\n target_durable_id TEXT NOT NULL,\n seq INTEGER NOT NULL,\n sender TEXT NOT NULL,\n sender_turn TEXT,\n envelope TEXT NOT NULL,\n body TEXT NOT NULL,\n bytes INTEGER NOT NULL,\n mode_requested TEXT NOT NULL CHECK (mode_requested IN ('auto', 'steer', 'follow_up')),\n mode_effective TEXT CHECK (mode_effective IS NULL OR mode_effective IN ('steer', 'follow_up')),\n expected_turn_id INTEGER,\n state TEXT NOT NULL CHECK (state IN ('queued', 'admitting', 'admitted', 'applied', 'refused', 'uncertain')),\n reason TEXT,\n admitted_by TEXT,\n claimed_at INTEGER,\n attempt INTEGER NOT NULL DEFAULT 0,\n admission_kind TEXT,\n turn_epoch INTEGER,\n root_id TEXT NOT NULL,\n hop INTEGER NOT NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n binding_id TEXT,\n binding_revision INTEGER,\n UNIQUE (target_durable_id, seq)\n )","CREATE INDEX deliveries_target_state_seq ON deliveries (target_durable_id, state, seq)","CREATE INDEX deliveries_root ON deliveries (root_id)","CREATE INDEX deliveries_sender_turn ON deliveries (sender, sender_turn)","CREATE TABLE receipts (\n principal TEXT NOT NULL,\n operation TEXT NOT NULL,\n idempotency_key TEXT NOT NULL,\n args_hash TEXT NOT NULL,\n status TEXT NOT NULL CHECK (status IN ('prepared', 'completed', 'uncertain')),\n delivery_id TEXT,\n owner_instance TEXT NOT NULL,\n result TEXT,\n error_note TEXT,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n PRIMARY KEY (principal, operation, idempotency_key)\n )","CREATE INDEX receipts_expiry ON receipts (expires_at)","CREATE TABLE causal_roots (\n root_id TEXT PRIMARY KEY,\n origin_principal TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL\n )","CREATE TABLE causal_edges (\n root_id TEXT NOT NULL,\n from_durable_id TEXT NOT NULL,\n to_durable_id TEXT NOT NULL,\n delivery_id TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n PRIMARY KEY (root_id, from_durable_id, to_durable_id)\n )","CREATE TABLE rate_buckets (\n sender TEXT NOT NULL,\n target_durable_id TEXT NOT NULL,\n tokens REAL NOT NULL,\n updated_at INTEGER NOT NULL,\n PRIMARY KEY (sender, target_durable_id)\n )","CREATE TABLE session_meta (\n durable_id TEXT PRIMARY KEY,\n next_seq INTEGER NOT NULL,\n applied_seq INTEGER NOT NULL DEFAULT 0\n )","CREATE TABLE bindings (\n seq INTEGER PRIMARY KEY AUTOINCREMENT,\n binding_id TEXT NOT NULL UNIQUE,\n schema_version INTEGER NOT NULL DEFAULT 1,\n revision INTEGER NOT NULL CHECK (revision >= 1),\n status TEXT NOT NULL CHECK (status IN ('active', 'detached', 'expired')),\n platform TEXT NOT NULL CHECK (platform IN ('discord', 'telegram', 'slack', 'notion', 'feishu', 'herdr', 'custom')),\n account_id TEXT NOT NULL,\n chat_id TEXT NOT NULL,\n thread_id TEXT NOT NULL,\n root_message_id TEXT,\n progress_message_id TEXT,\n session_realm_id TEXT NOT NULL,\n session_durable_id TEXT NOT NULL,\n direction_inbound INTEGER NOT NULL CHECK (direction_inbound IN (0, 1)),\n direction_outbound INTEGER NOT NULL CHECK (direction_outbound IN (0, 1)),\n inbound_mode TEXT NOT NULL CHECK (inbound_mode IN ('auto', 'follow_up')),\n outbound_events TEXT NOT NULL,\n policy_id TEXT NOT NULL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n lease_started_at TEXT NOT NULL,\n ttl_seconds INTEGER,\n expires_at TEXT,\n CHECK (direction_inbound = 1 OR direction_outbound = 1)\n )","CREATE UNIQUE INDEX bindings_one_active_thread ON bindings (platform, account_id, chat_id, thread_id) WHERE status = 'active'","CREATE INDEX bindings_session ON bindings (session_durable_id, status)","CREATE TABLE outbox (\n cursor INTEGER PRIMARY KEY AUTOINCREMENT,\n binding_id TEXT NOT NULL,\n revision INTEGER NOT NULL,\n event_kind TEXT NOT NULL CHECK (event_kind IN ('milestone', 'report', 'question', 'completion', 'question_closed')),\n payload TEXT NOT NULL,\n state TEXT NOT NULL CHECK (state IN ('pending', 'acked')),\n provider_message_id TEXT,\n created_at INTEGER NOT NULL,\n acked_at INTEGER\n )","CREATE INDEX outbox_binding_cursor ON outbox (binding_id, cursor)","CREATE TABLE gateway_meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n )"],["ALTER TABLE session_meta ADD COLUMN incarnation TEXT","ALTER TABLE outbox ADD COLUMN session_durable_id TEXT","ALTER TABLE outbox ADD COLUMN reply_token TEXT","ALTER TABLE outbox ADD COLUMN ui_request_id TEXT","ALTER TABLE outbox ADD COLUMN incarnation TEXT","ALTER TABLE outbox ADD COLUMN question_state TEXT CHECK (question_state IS NULL OR question_state IN ('pending', 'answered', 'expired', 'cancelled'))","ALTER TABLE outbox ADD COLUMN answer TEXT","ALTER TABLE outbox ADD COLUMN answered_at INTEGER","ALTER TABLE outbox ADD COLUMN outcome TEXT CHECK (outcome IS NULL OR outcome IN ('completed', 'failed', 'cancelled'))","CREATE UNIQUE INDEX outbox_reply_token ON outbox (reply_token) WHERE reply_token IS NOT NULL","CREATE TABLE outbox_cursors (\n binding_id TEXT PRIMARY KEY,\n acked_cursor INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n )","CREATE TABLE completion_arms (\n arm_seq INTEGER PRIMARY KEY AUTOINCREMENT,\n session_durable_id TEXT NOT NULL,\n binding_id TEXT NOT NULL,\n revision INTEGER NOT NULL,\n text TEXT NOT NULL,\n armed_at INTEGER NOT NULL\n )","CREATE INDEX completion_arms_session ON completion_arms (session_durable_id, armed_at)","INSERT OR IGNORE INTO gateway_meta (key, value) VALUES ('realm_id', 'realm-' || lower(hex(randomblob(16))))","INSERT OR IGNORE INTO gateway_meta (key, value) VALUES ('token_secret', lower(hex(randomblob(32))))"],["ALTER TABLE outbox ADD COLUMN ui_request_kind TEXT CHECK (ui_request_kind IS NULL OR ui_request_kind IN ('question', 'select', 'confirm', 'input', 'editor'))","ALTER TABLE outbox ADD COLUMN answer_state TEXT CHECK (answer_state IS NULL OR answer_state IN ('in_flight', 'delivered'))"],["ALTER TABLE outbox ADD COLUMN answered_by TEXT"],["ALTER TABLE session_meta ADD COLUMN endpoint_socket TEXT","ALTER TABLE session_meta ADD COLUMN endpoint_kind TEXT CHECK (endpoint_kind IS NULL OR endpoint_kind IN ('tui', 'rpc_host'))"]],Ee=["delivery_id","target_durable_id","seq","sender","sender_turn","envelope","body","bytes","mode_requested","mode_effective","expected_turn_id","state","reason","admitted_by","claimed_at","attempt","admission_kind","turn_epoch","root_id","hop","created_at","updated_at","expires_at","binding_id","binding_revision"],ge="('queued', 'admitting', 'admitted')",me=/^[A-Za-z0-9][A-Za-z0-9._-]{0,199}$/;function be(e,i,t){return{kind:"refused",code:e,message:i,...void 0===t?{}:{details:t}}}function fe(e){let i=e=>null==e?null:Number(e);return{delivery_id:String(e.delivery_id),target_durable_id:String(e.target_durable_id),seq:Number(e.seq),sender:String(e.sender),sender_turn:null===e.sender_turn?null:String(e.sender_turn),envelope:JSON.parse(String(e.envelope)),body:String(e.body),bytes:Number(e.bytes),mode_requested:e.mode_requested,mode_effective:e.mode_effective??null,expected_turn_id:i(e.expected_turn_id),state:e.state,reason:null===e.reason?null:String(e.reason),admitted_by:null===e.admitted_by?null:JSON.parse(String(e.admitted_by)),claimed_at:i(e.claimed_at),attempt:Number(e.attempt),admission_kind:null===e.admission_kind?null:String(e.admission_kind),turn_epoch:i(e.turn_epoch),root_id:String(e.root_id),hop:Number(e.hop),created_at:Number(e.created_at),updated_at:Number(e.updated_at),expires_at:Number(e.expires_at),binding_id:null===e.binding_id?null:String(e.binding_id),binding_revision:i(e.binding_revision)}}function Te(e,i,t,n){return e.sql.all(Ee,`SELECT ${Ee.join(", ")} FROM deliveries WHERE ${i}`,t,n).map(fe)}function Ne(e,i){return Te(e,"delivery_id = ?",[i])[0]}function ye(e,i,t=[]){let n=e.sql.run(i,t);return e.stats.writes+=n,n}function ve(e,i){if("queued"!==i.state&&"admitting"!==i.state&&"admitted"!==i.state)return 0;let t=e.sql.one(["n"],`SELECT COUNT(*) AS n FROM deliveries WHERE target_durable_id = ? AND state IN ${ge} AND seq <= ?`,[i.target_durable_id,i.seq]);return Number(t?.n??1)}async function he(e,i,t){let n=Date.now();for(;;)try{return e.sql.exec("BEGIN IMMEDIATE"),e.stats.transactions++,!0}catch(r){if(!N(r))throw r;if(e.emit({kind:"busy",op:i}),!t)return!1;let d=Date.now()-n;if(d+2*e.config.busy_timeout_ms>e.config.lock_wait_max_ms)throw e.emit({kind:"lock_wait_exceeded",op:i,waited_ms:d}),o(i,d,e.config.lock_wait_max_ms);await e.delay(e.config.busy_timeout_ms)}}function we(e){try{e.sql.exec("ROLLBACK")}catch{return}}async function Le(e,i,t){await he(e,i,!0);try{let i=t();return e.sql.exec("COMMIT"),i}catch(i){throw we(e),i}}function ke(e,i,t,n){let r=l(e.config.agent_dir,i);L(r,{recursive:!0,mode:448});let d,s=x(r,t);try{d=k(s,w.O_CREAT|w.O_EXCL|w.O_WRONLY,384)}catch(e){if(n&&e instanceof Error&&"code"in e&&"EEXIST"===e.code)return s;throw e}try{A(d,JSON.stringify({pid:e.self.pid,process_start_time:e.self.process_start_time}))}finally{h(d)}return s}function Re(e,i,t){let n=x(l(e.config.agent_dir,i),t);try{S(n),e.stats.marker_unlinks++}catch(e){if(!(e instanceof Error&&"code"in e&&"ENOENT"===e.code))throw e}}function Oe(e,i){try{return R(l(e.config.agent_dir,i)).filter(e=>!e.startsWith("."))}catch(e){if(e instanceof Error&&"code"in e&&"ENOENT"===e.code)return[];throw e}}function Se(e,i){let t=e.sql.one(["next_seq"],"SELECT next_seq FROM session_meta WHERE durable_id = ?",[i]),n=Number(void 0===t?e.sql.one(["m"],"SELECT COALESCE(MAX(seq), 0) + 1 AS m FROM deliveries WHERE target_durable_id = ?",[i])?.m??1:t.next_seq);return ye(e,"INSERT INTO session_meta (durable_id, next_seq) VALUES (?, ?) ON CONFLICT(durable_id) DO UPDATE SET next_seq = excluded.next_seq",[i,n+1]),n}function Ae(e,i){ye(e,`INSERT INTO deliveries (${Ee.join(", ")}) VALUES (${Ee.map(()=>"?").join(", ")})`,[i.delivery_id,i.target_durable_id,i.seq,i.sender,i.sender_turn,JSON.stringify(i.envelope),i.body,i.bytes,i.mode_requested,i.mode_effective,i.expected_turn_id,i.state,i.reason,null===i.admitted_by?null:JSON.stringify(i.admitted_by),i.claimed_at,i.attempt,i.admission_kind,i.turn_epoch,i.root_id,i.hop,i.created_at,i.updated_at,i.expires_at,i.binding_id,i.binding_revision])}function qe(e){return y("sha256").update(JSON.stringify(e)).digest("hex")}function xe(e){return Number(e.sql.one(["user_version"],"SELECT user_version FROM pragma_user_version()")?.user_version??0)}function Ie(e,i,t){let n=e.sql.one(["args_hash","status","delivery_id","owner_instance","result","expires_at"],"SELECT args_hash, status, delivery_id, owner_instance, result, expires_at FROM receipts WHERE principal = ? AND operation = 'deliver' AND idempotency_key = ?",[i,t]);if(void 0!==n)return{args_hash:String(n.args_hash),status:n.status,delivery_id:null===n.delivery_id?null:String(n.delivery_id),owner_instance:String(n.owner_instance),result:null===n.result?null:String(n.result),expires_at:Number(n.expires_at)}}function De(e,i,t){if(t.args_hash!==i.receipt.args_hash)return be("idempotency_conflict","The idempotency key was already used with different arguments.");if("completed"===t.status&&null!==t.result)return{kind:"replay",result:JSON.parse(t.result)};let n=null===t.delivery_id?void 0:Ne(e,t.delivery_id),r=void 0!==n&&("admitted"===n.state||"applied"===n.state||"refused"===n.state);if("prepared"===t.status&&!r&&t.owner_instance===e.config.instance_id)return be("idempotency_in_progress","The same delivery is already in progress.");if("prepared"===t.status&&r){let t={...ce(n,ve(e,n),i.endpoint_kind,!0,!1)};return ye(e,"UPDATE receipts SET status = 'completed', result = ?, updated_at = ? WHERE principal = ? AND operation = 'deliver' AND idempotency_key = ?",[JSON.stringify(t),i.now,i.sender_principal,i.receipt.idempotency_key]),{kind:"replay",result:t}}return"prepared"===t.status&&ye(e,"UPDATE receipts SET status = 'uncertain', error_note = ?, updated_at = ? WHERE principal = ? AND operation = 'deliver' AND idempotency_key = ?",["the sender lost the acknowledgement before the target admitted the delivery",i.now,i.sender_principal,i.receipt.idempotency_key]),be("idempotency_uncertain","The earlier delivery may or may not reach the target; it is never sent twice.",{delivery_id:t.delivery_id,state:n?.state??null})}async function Ue(e,i){if(!me.test(i.target_durable_id)||!me.test(i.delivery_id))return be("invalid_arguments","The target session id is not a durable session id.");if(!await he(e,"enqueue",!1))return{kind:"busy"};let t=null,n=!1;try{let r=ae(e,{principal:i.sender_principal,operation:"deliver",idempotency_key:i.receipt.idempotency_key},i.now),d=Ie(e,i.sender_principal,i.receipt.idempotency_key);if(void 0!==d){let t=De(e,i,d);return e.sql.exec("COMMIT"),n=!0,t}let s=function(e,i){if(null===i.binding)return{expires_at:null};let t=e.sql.one(["revision","status","session_durable_id","direction_inbound","expires_at"],"SELECT revision, status, session_durable_id, direction_inbound, expires_at FROM bindings WHERE binding_id = ?",[i.binding.binding_id]),n=null==t?.expires_at?null:Date.parse(String(t.expires_at));return void 0===t||"active"!==t.status||Number(t.revision)!==i.binding.revision||String(t.session_durable_id)!==i.target_durable_id||1!==Number(t.direction_inbound)||null!==n&&n<=i.now?be("invalid_arguments","The binding is not active for this session at this revision.",{binding:i.binding.binding_id}):{expires_at:n}}(e,i);if("kind"in s)return we(e),s;let a=e.sql.one(["n","b"],`SELECT COUNT(*) AS n, COALESCE(SUM(bytes), 0) AS b FROM deliveries WHERE target_durable_id = ? AND state IN ${ge}`,[i.target_durable_id]),o=Buffer.byteLength(i.body);if(Number(a?.n??0)>=128||Number(a?.b??0)+o>M)return we(e),be("queue_full","The target's delivery backlog is full.",{max_messages:128,max_bytes:M});let _=function(e,i){let t;if(null!==i.cause_delivery_id){let n=Ne(e,i.cause_delivery_id);if(void 0===n||n.target_durable_id!==i.sender_node||"admitting"!==n.state&&"admitted"!==n.state&&"applied"!==n.state)return be("invalid_arguments","The delivery this send continues is not one the sender received.",{guard:"unknown_cause"});t={root_id:n.root_id,hop:n.hop+1,via:[...n.envelope.via,i.sender_node],new_root:!1}}else t={root_id:`root-${v()}`,hop:1,via:[i.sender_node],new_root:!0};if(null!==i.claimed_root_id&&i.claimed_root_id!==t.root_id)return be("invalid_arguments","The causal root is derived by the gateway and cannot be chosen by the caller.",{guard:"forged_root"});if(!t.new_root){let n=e.sql.one(["expires_at"],"SELECT expires_at FROM causal_roots WHERE root_id = ?",[t.root_id]);if(void 0===n||Number(n.expires_at)<=i.now)return be("loop_detected","This causal chain is older than its lifetime.",{guard:"root_expired",root_id:t.root_id})}if(i.target_durable_id===i.sender_node)return be("loop_detected","A session cannot deliver to itself through the gateway.",{guard:"self_send"});if(t.hop>4)return be("loop_detected",`This delivery would be hop ${t.hop}; at most 4 are allowed.`,{guard:"hop_limit",hop:t.hop});let n=Number(e.sql.one(["n"],"SELECT COUNT(*) AS n FROM deliveries WHERE root_id = ? AND state != 'refused'",[t.root_id])?.n??0);return n>=64?be("loop_detected",`This causal chain already carried ${n} deliveries.`,{guard:"causal_budget",root_id:t.root_id}):I(e.sql.all(["from_durable_id","to_durable_id"],"SELECT from_durable_id, to_durable_id FROM causal_edges WHERE root_id = ?",[t.root_id]).map(e=>({from:String(e.from_durable_id),to:String(e.to_durable_id)})),i.sender_node,i.target_durable_id)?be("loop_detected","The target already leads back to the sender in this causal chain.",{guard:"cycle",root_id:t.root_id}):t}(e,i);if("kind"in _)return we(e),_;let u=function(e,i){if(null===i.sender_turn)return;let t=new Set(e.sql.all(["t"],"SELECT DISTINCT target_durable_id AS t FROM deliveries WHERE sender = ? AND sender_turn = ? AND state != 'refused'",[i.sender_principal,i.sender_turn]).map(e=>String(e.t)));return t.has(i.target_durable_id)||t.size<16?void 0:be("overloaded","One turn may reach at most 16 sessions.",{budget:"fanout"})}(e,i)??function(e,i){let t=i.rate_principal??i.sender_principal,n=e.sql.one(["tokens","updated_at"],"SELECT tokens, updated_at FROM rate_buckets WHERE sender = ? AND target_durable_id = ?",[t,i.target_durable_id]),r=void 0===n?8:Math.min(8,Number(n.tokens)+Math.max(0,i.now-Number(n.updated_at))/D);if(r<1)return be("overloaded","Too many deliveries to this session; wait before sending again.",{budget:"pair_rate",retry_after_ms:Math.ceil((1-r)*D)});ye(e,"INSERT INTO rate_buckets (sender, target_durable_id, tokens, updated_at) VALUES (?, ?, ?, ?) ON CONFLICT(sender, target_durable_id) DO UPDATE SET tokens = excluded.tokens, updated_at = excluded.updated_at",[t,i.target_durable_id,r-1,i.now])}(e,i);if(void 0!==u)return we(e),u;_.new_root&&ye(e,"INSERT INTO causal_roots (root_id, origin_principal, created_at, expires_at) VALUES (?, ?, ?, ?)",[_.root_id,i.sender_principal,i.now,i.now+C]),ye(e,"INSERT OR IGNORE INTO causal_edges (root_id, from_durable_id, to_durable_id, delivery_id, created_at) VALUES (?, ?, ?, ?, ?)",[_.root_id,i.sender_node,i.target_durable_id,i.delivery_id,i.now]);let l={delivery_id:i.delivery_id,target_durable_id:i.target_durable_id,seq:Se(e,i.target_durable_id),sender:i.sender_principal,sender_turn:i.sender_turn,envelope:{origin:i.origin,actor:i.actor,via:_.via,root_id:_.root_id,hop:_.hop,delivery_id:i.delivery_id},body:i.body,bytes:o,mode_requested:i.mode,mode_effective:null,expected_turn_id:i.expected_turn_id,state:"queued",reason:null,admitted_by:null,claimed_at:null,attempt:0,admission_kind:null,turn_epoch:null,root_id:_.root_id,hop:_.hop,created_at:i.now,updated_at:i.now,expires_at:Math.min(i.now+U,s.expires_at??Number.POSITIVE_INFINITY),binding_id:i.binding?.binding_id??null,binding_revision:i.binding?.revision??null};Ae(e,l),ye(e,"INSERT INTO receipts (principal, operation, idempotency_key, args_hash, status, delivery_id, owner_instance, created_at, updated_at, expires_at) VALUES (?, 'deliver', ?, ?, 'prepared', ?, ?, ?, ?, ?)",[i.sender_principal,i.receipt.idempotency_key,i.receipt.args_hash,l.delivery_id,e.config.instance_id,i.now,i.now,i.now+H]),t=ke(e,l.target_durable_id,l.delivery_id,!1);let c=ve(e,l);return oe(e,i.now,r),await e.hook("beforeDbCommit"),e.sql.exec("COMMIT"),n=!0,await e.hook("afterDbCommit"),{kind:"inserted",row:l,queue_position:c}}catch(i){throw n||(we(e),null!==t&&S(t,{force:!0})),i}}function Ce(e,i){if(null===e)return"";let t=i.get(e);if(void 0===t){try{t=O(e,"utf8")}catch(e){if(!(e instanceof Error&&"code"in e&&"ENOENT"===e.code))throw e;t=""}i.set(e,t)}return t}function Me(e,i,t){if(null===e.runtime_instance||null===i)return!1;let n=t().get(e.runtime_instance);return void 0!==n&&i<=n}function He(e,i,t){for(let n of Ce(e,t).split("\n")){if(!n.includes(i))continue;let e;try{e=JSON.parse(n)}catch{continue}if("object"!=typeof e||null===e)continue;let t=e;if("custom_message"===t.type&&"session_control_delivery"===t.customType&&t.details?.delivery_id===i)return!0}return!1}function We(e){return`${JSON.stringify(e.admitted_by)}#${e.attempt}`}function Xe(e,i,t,n,r={}){"queued"!==t?"refused"!==t?(ye(e,"UPDATE deliveries SET state = ?, updated_at = ? WHERE delivery_id = ?",[t,n,i.delivery_id]),"applied"===t&&ye(e,"UPDATE session_meta SET applied_seq = MAX(applied_seq, ?) WHERE durable_id = ?",[i.seq,i.target_durable_id])):ye(e,"UPDATE deliveries SET state = 'refused', reason = ?, updated_at = ? WHERE delivery_id = ?",[r.reason??null,n,i.delivery_id]):ye(e,"UPDATE deliveries SET state = 'queued', admitted_by = NULL, claimed_at = NULL, mode_effective = NULL, admission_kind = NULL, turn_epoch = NULL, updated_at = ? WHERE delivery_id = ?",[n,i.delivery_id])}async function Fe(e,i){let t,n=i.target_durable_id,r=new Map,d=new Map,s=new Map,a=()=>(t??=function(e,i){let t=new Map;for(let n of Ce(e,i).split("\n")){if(!n.includes(F))continue;let e;try{e=JSON.parse(n)}catch{continue}let i=e;if("custom"!==i.type||i.customType!==F)continue;let r=i.data?.host_instance,d="string"==typeof i.data?.released_at?Date.parse(i.data.released_at):Number.NaN;"string"==typeof r&&0!==r.length&&Number.isFinite(d)&&t.set(r,Math.max(d,t.get(r)??d))}return t}(i.session_path,d),t);for(let t of Te(e,"target_durable_id = ? AND state IN ('admitting', 'admitted')",[n])){if(null===t.admitted_by||b(t.admitted_by,i.self))continue;let e=JSON.stringify(t.admitted_by),n=s.get(e);void 0===n&&(n=await m(t.admitted_by),s.set(e,n));let o=n||Me(t.admitted_by,t.claimed_at,a)?He(i.session_path,t.delivery_id,d)?"applied":"queued":"dual";r.set(t.delivery_id,{fingerprint:We(t),to:o})}return!0===e.config.test_hooks.announceBarrier&&e.emit({kind:"barrier",op:"reconcile"}),await Le(e,"reconcile",()=>{let t=new Set(i.ledger.pending),d=new Set(i.ledger.emitted),s=[],a=[];for(let o of Te(e,`target_durable_id = ? AND state IN ${ge}`,[n],"seq")){let n=o.state;if("queued"!==o.state){if(null!==o.admitted_by&&b(o.admitted_by,i.self))n=d.has(o.delivery_id)?"applied":t.has(o.delivery_id)?"admitted":"queued";else if(null===o.admitted_by)n="queued";else{let e=r.get(o.delivery_id);if(void 0===e||e.fingerprint!==We(o)||"dual"===e.to){a.push(o.delivery_id);continue}n=e.to}n!==o.state&&(Xe(e,o,n,i.now),s.push({delivery_id:o.delivery_id,from:o.state,to:n}))}else o.expires_at<=i.now&&(Xe(e,o,"refused",i.now,{reason:"expired"}),s.push({delivery_id:o.delivery_id,from:o.state,to:"refused"}))}for(let i of Oe(e,n))"queued"!==e.sql.one(["state"],"SELECT state FROM deliveries WHERE delivery_id = ?",[i])?.state&&Re(e,n,i);return{queued:Te(e,"target_durable_id = ? AND state = 'queued'",[n],"seq"),transitions:s,dual_runtime:a}})}function $e(){try{return q().username}catch{return"unknown"}}import{randomUUID as Ge}from"node:crypto";import{renameSync as Pe,writeFileSync as Be}from"node:fs";var Je=["question","select","confirm","input","editor"];var Ke=new Map([["yes",!0],["y",!0],["true",!0],["no",!1],["n",!1],["false",!1]]);function Ye(e){return""===e.replace(/[\s\p{Cf}]/gu,"")}function je(e){let i=Ke.get(e.trim().toLowerCase());return void 0===i?{value:e,answers:{},comment:e}:{value:e,answers:{},comment:e,confirmed:i}}function Ve(e,i){switch(e){case null:return Ye(i)?{ok:!1,reason:"The question declared no request kind, so the answer needs text; this one is blank. An input or editor that takes an empty answer must be reported with its request kind."}:{ok:!0,fields:je(i)};case"input":case"editor":return{ok:!0,fields:{value:i}};case"select":return Ye(i)?{ok:!1,reason:"A select answer names one of its options; the text is blank."}:{ok:!0,fields:{value:i}};case"question":return Ye(i)?{ok:!1,reason:"A question answer needs text; this one is blank."}:{ok:!0,fields:{answers:{},comment:i}};case"confirm":{let e=Ke.get(i.trim().toLowerCase());return void 0===e?{ok:!1,reason:"A confirm answer is yes or no (also y/n, true/false; any case, surrounding spaces ignored)."}:{ok:!0,fields:{confirmed:e}}}default:return function(e){throw Error(`unknown extension UI request kind: ${String(e)}`)}(e)}}var ze=["binding_id","schema_version","revision","status","platform","account_id","chat_id","thread_id","root_message_id","progress_message_id","session_realm_id","session_durable_id","direction_inbound","direction_outbound","inbound_mode","outbound_events","policy_id","created_at","updated_at","lease_started_at","ttl_seconds","expires_at"],Ze=["cursor","binding_id","revision","event_kind","payload","state","provider_message_id","created_at","reply_token","question_state","outcome","answered_by"];function Qe(e,i,t){return{kind:"refused",code:e,message:i,...void 0===t?{}:{details:t}}}function ei(e){return null==e?null:String(e)}function ii(e){return null==e?null:JSON.stringify(e)}function ti(e){return null==e?null:JSON.parse(String(e))}function ni(e,i,t,n){let r=(s=e.config.agent_dir,_(u(s),"outbox.marker")),d=`${r}.${process.pid}.${Ge()}.tmp`;var s;Be(d,JSON.stringify({binding_id:i,cursor:t,written_at:ie(n)}),{mode:384}),Pe(d,r)}function ri(e){return{schema_version:1,binding_id:String(e.binding_id),revision:Number(e.revision),status:e.status,platform:e.platform,account_id:String(e.account_id),chat_id:String(e.chat_id),thread_id:String(e.thread_id),root_message_id:ei(e.root_message_id),progress_message_id:ei(e.progress_message_id),session_realm_id:String(e.session_realm_id),session_durable_id:String(e.session_durable_id),direction:{inbound:1===Number(e.direction_inbound),outbound:1===Number(e.direction_outbound)},inbound_mode:e.inbound_mode,outbound_events:JSON.parse(String(e.outbound_events)),policy_id:String(e.policy_id),created_at:String(e.created_at),updated_at:String(e.updated_at),lease_started_at:String(e.lease_started_at),ttl_seconds:null===e.ttl_seconds||void 0===e.ttl_seconds?null:Number(e.ttl_seconds),expires_at:ei(e.expires_at)}}function di(e,i,t,n){let r=`SELECT ${ze.join(", ")} FROM bindings WHERE ${i}${void 0===n?"":` ORDER BY ${n.orderBy} LIMIT ?`}`;return e.sql.all(ze,r,void 0===n?t:[...t,n.limit],n?.orderBy).map(ri)}function si(e,i){return di(e,"binding_id = ?",[i])[0]}function ai(e,i){let t=e.sql.one(["value"],"SELECT value FROM gateway_meta WHERE key = ?",[i]);if(void 0===t)throw Error(`gateway_meta ${i} is missing`);return String(t.value)}function oi(e,i){let t=ie(i);ye(e,"UPDATE bindings SET status = 'expired', updated_at = ? WHERE status = 'active' AND expires_at IS NOT NULL AND expires_at <= ?",[t,t])}function _i(e,i){ye(e,"DELETE FROM outbox WHERE state = 'acked' AND acked_at IS NOT NULL AND acked_at <= ?",[i-ee]),ye(e,"DELETE FROM outbox WHERE state = 'pending' AND binding_id IN (SELECT binding_id FROM bindings WHERE status != 'active' AND updated_at <= ?)",[ie(i-ee)])}function ui(e,i){let t=e.sql.one(["args_hash","status","owner_instance","result"],"SELECT args_hash, status, owner_instance, result FROM receipts WHERE principal = ? AND operation = ? AND idempotency_key = ?",[i.principal,i.operation,i.idempotency_key]);if(void 0!==t)return{args_hash:String(t.args_hash),status:String(t.status),owner_instance:String(t.owner_instance),result:ei(t.result)}}async function li(e,i,t,n,r){return await Le(e,i,()=>{oi(e,t);let i=null===n?0:ae(e,n,t),d=function(e,i){if(null===i)return;let t=ui(e,i);return void 0!==t?t.args_hash!==i.args_hash?Qe("idempotency_conflict","The idempotency key was already used with different arguments."):"completed"===t.status&&null!==t.result?{...JSON.parse(t.result),kind:"ok",deduplicated:!0}:Qe("idempotency_uncertain","An earlier call under this key did not record its outcome."):void 0}(e,n);if(void 0!==d)return d;let s=r();return"ok"===s.kind&&function(e,i,t,n){null!==i&&ye(e,"INSERT INTO receipts (principal, operation, idempotency_key, args_hash, status, delivery_id, owner_instance, result, created_at, updated_at, expires_at) VALUES (?, ?, ?, ?, 'completed', NULL, ?, ?, ?, ?, ?)",[i.principal,i.operation,i.idempotency_key,i.args_hash,e.config.instance_id,JSON.stringify(n),t,t,t+H])}(e,n,t,{...s,deduplicated:!1}),oe(e,t,i),"ok"===s.kind?{...s,deduplicated:!1}:s})}async function ci(e,i){return await Le(e,"tool_receipt_begin",()=>{let t=ae(e,i,i.now),n=function(e,i){let t=ui(e,i);if(void 0===t)return ye(e,"INSERT INTO receipts (principal, operation, idempotency_key, args_hash, status, delivery_id, owner_instance, created_at, updated_at, expires_at) VALUES (?, ?, ?, ?, 'prepared', NULL, ?, ?, ?, ?)",[i.principal,i.operation,i.idempotency_key,i.args_hash,e.config.instance_id,i.now,i.now,i.now+H]),{kind:"accepted"};if(t.args_hash!==i.args_hash)return{kind:"conflict"};if("completed"===t.status)return{kind:"replay",result:null===t.result?null:JSON.parse(t.result)};if("prepared"===t.status&&t.owner_instance===e.config.instance_id)return{kind:"in_progress"};"prepared"===t.status&&ye(e,"UPDATE receipts SET status = 'uncertain', error_note = ?, updated_at = ? WHERE principal = ? AND operation = ? AND idempotency_key = ?",["the process that began this call ended before recording its outcome",i.now,i.principal,i.operation,i.idempotency_key]);let n=e.sql.one(["error_note"],"SELECT error_note FROM receipts WHERE principal = ? AND operation = ? AND idempotency_key = ?",[i.principal,i.operation,i.idempotency_key]);return{kind:"uncertain",error_note:ei(n?.error_note)}}(e,i);return oe(e,i.now,t),n})}function pi(e,i){return e.sql.all(["delivery_id"],`SELECT delivery_id, seq FROM deliveries WHERE binding_id = ? AND state IN ${ge}`,[i],"seq").map(e=>String(e.delivery_id))}async function Ei(e,i){let t=void 0===i.cursor?null:function(e){try{let i=JSON.parse(Buffer.from(e,"base64url").toString("utf8"));if(1!==i.v||"number"!=typeof i.as_of||!Number.isInteger(i.as_of))return null;let t=i.after;return null===t||Array.isArray(t)&&2===t.length&&t.every(e=>"string"==typeof e)?{v:1,as_of:i.as_of,after:t}:null}catch{return null}}(i.cursor);if(void 0!==i.cursor&&null===t)return Qe("cursor_invalid","The bindings cursor is not one this gateway issued.");let n=Math.min(Math.max(i.limit??50,1),200);return await Le(e,"list_bindings",()=>{oi(e,i.now);let r=t?.as_of??Number(e.sql.one(["m"],"SELECT COALESCE(MAX(rowid), 0) AS m FROM bindings")?.m??0),d=["rowid <= ?"],s=[r],a=[["session_durable_id","session_durable_id"],["platform","platform"],["account_id","account_id"],["chat_id","chat_id"],["thread_id","thread_id"],["status","status"]];for(let[e,t]of a){let n=i.filter[e];void 0!==n&&(d.push(`${t} = ?`),s.push(n))}null!=t?.after&&(d.push("(created_at > ? OR (created_at = ? AND binding_id > ?))"),s.push(t.after[0],t.after[0],t.after[1]));let o=di(e,d.join(" AND "),s,{orderBy:"created_at, binding_id",limit:n+1}),_=o.slice(0,n),u=_.at(-1);return{kind:"ok",bindings:_,next_cursor:o.length>n&&void 0!==u?ne(r,[u.created_at,u.binding_id]):null}})}function gi(e,i){return ei(e.sql.one(["incarnation"],"SELECT incarnation FROM session_meta WHERE durable_id = ?",[i])?.incarnation)}function mi(e,i){ye(e,"INSERT INTO outbox (binding_id, revision, event_kind, payload, state, provider_message_id, created_at, acked_at, session_durable_id, reply_token, ui_request_id, ui_request_kind, incarnation, question_state, answer, answered_at, outcome) VALUES (?, ?, ?, ?, 'pending', NULL, ?, NULL, ?, ?, ?, ?, ?, ?, NULL, NULL, ?)",[i.binding.binding_id,i.binding.revision,i.event,JSON.stringify({text:i.text}),i.now,i.binding.session_durable_id,i.reply_token??null,i.ui_request_id??null,i.ui_request_kind??null,i.incarnation??null,void 0===i.reply_token?null:"pending",i.outcome??null]);let t=Number(e.sql.one(["c"],"SELECT last_insert_rowid() AS c")?.c);return ni(e,i.binding.binding_id,t,i.now),t}async function bi(e,i){return await li(e,"report",i.now,i.receipt,()=>{let t=null===i.binding_id?function(e,i,t,n){let r=[...new Set(t.flatMap(t=>{let n=e.sql.one(["binding_id"],"SELECT binding_id FROM deliveries WHERE delivery_id = ? AND target_durable_id = ?",[t,i]),r=ei(n?.binding_id);return null===r?[]:[r]}))].sort(),d=e.sql.all(["binding_id"],"SELECT binding_id FROM bindings WHERE session_durable_id = ? AND status = 'active' AND direction_outbound = 1",[i],"binding_id").map(e=>String(e.binding_id)),[s,...a]=r;if(void 0!==s&&a.length>0)return Qe("invalid_arguments",`This session's current run answers messages from ${r.length} bound threads; name binding_id.`,{binding_ids:r});if(void 0!==s&&n&&d.some(e=>e!==s))return Qe("invalid_arguments","This session's current run answers a bound thread's message and a user message (typed in its terminal or sent by an extension) together; name binding_id.",{binding_ids:d});if(void 0!==s)return{binding_id:s};let[o,..._]=d;return void 0!==o&&0===_.length?{binding_id:o}:void 0===o?Qe("invalid_arguments","This session has no active outbound binding and its current run answers no bound message; name binding_id."):Qe("invalid_arguments",`This session has ${d.length} active outbound bindings and its current run answers no bound message; name binding_id.`,{binding_ids:d})}(e,i.session_durable_id,i.origin_delivery_ids,!0===i.origin_local_input):{binding_id:i.binding_id};if("kind"in t)return t;let n=t.binding_id,r=si(e,n);if(void 0===r)return Qe("not_found","No binding has this id.",{binding_id:n});if(r.session_durable_id!==i.session_durable_id)return Qe("scope_denied","The binding is attached to another session.",{binding_id:n});if("active"!==r.status)return Qe("binding_inactive",`The binding is ${r.status}.`,{binding_id:n,status:r.status});if(!r.direction.outbound)return Qe("unsupported","The binding carries no outbound direction.",{binding_id:n,direction:r.direction});if(!r.outbound_events.includes(i.event))return Qe("unsupported",`The binding is not subscribed to ${i.event} events.`,{binding_id:n,outbound_events:r.outbound_events});if(null!==i.ui_request_kind&&"question"!==i.event)return Qe("invalid_arguments","Only a question names a request kind.");let d={binding_id:n,revision:r.revision,event:i.event};if("completion"===i.event){ye(e,"INSERT INTO completion_arms (session_durable_id, binding_id, revision, text, armed_at) VALUES (?, ?, ?, ?, ?)",[i.session_durable_id,n,r.revision,i.text,i.now]);let t=Number(e.sql.one(["s"],"SELECT last_insert_rowid() AS s")?.s);return{kind:"ok",...d,cursor:null,reply_token:null,armed:!0,arm_seq:t}}if("question"===i.event){if(null===i.ui_request_id)return Qe("invalid_arguments","A question names the session's pending extension UI request (request_id).");let t=gi(e,i.session_durable_id),s=function(e,i){let t={b:i.binding_id,r:i.revision,s:i.session_durable_id,i:i.incarnation,q:i.ui_request_id,n:Z()},n=te(JSON.stringify(t));return`${re}.${n}.${de(e,n)}`}(ai(e,"token_secret"),{binding_id:n,revision:r.revision,session_durable_id:i.session_durable_id,incarnation:t,ui_request_id:i.ui_request_id}),a=mi(e,{binding:r,event:"question",text:i.text,now:i.now,reply_token:s,ui_request_id:i.ui_request_id,...null===i.ui_request_kind?{}:{ui_request_kind:i.ui_request_kind},incarnation:t});return _i(e,i.now),{kind:"ok",...d,cursor:a,reply_token:s,armed:!1,arm_seq:null}}let s=mi(e,{binding:r,event:i.event,text:i.text,now:i.now});return _i(e,i.now),{kind:"ok",...d,cursor:s,reply_token:null,armed:!1,arm_seq:null}})}function fi(e,i){return Number(e.sql.one(["acked_cursor"],"SELECT acked_cursor FROM outbox_cursors WHERE binding_id = ?",[i])?.acked_cursor??0)}async function Ti(e,i){let t=Math.min(Math.max(i.limit??100,1),500);return await Le(e,"read_outbox",()=>{oi(e,i.now),_i(e,i.now);let n=si(e,i.binding_id);if(void 0===n)return Qe("not_found","No binding has this id.",{binding_id:i.binding_id});let r=fi(e,n.binding_id),d=i.after_cursor??r,s=e.sql.all(Ze,`SELECT ${Ze.join(", ")} FROM outbox WHERE binding_id = ? AND cursor > ? ORDER BY cursor LIMIT ?`,[n.binding_id,d,t],"cursor").map(e=>function(e,i){let t=e.event_kind;return{cursor:Number(e.cursor),binding_id:String(e.binding_id),revision:Number(e.revision),event:t,text:String(JSON.parse(String(e.payload)).text??""),state:e.state,created_at:ie(Number(e.created_at)),edit_message_id:"milestone"===t?i.progress_message_id:null,provider_message_id:ei(e.provider_message_id),reply_token:ei(e.reply_token),question_state:e.question_state??null,outcome:e.outcome??null,answered_by:ti(e.answered_by)}}(e,n));return oe(e,i.now),{kind:"ok",binding_id:n.binding_id,revision:n.revision,status:n.status,rows:s,next_cursor:s.at(-1)?.cursor??d,acked_cursor:r}})}async function Ni(e,i){return await Le(e,"claim_answer",()=>{oi(e,i.now);let t=function(e,i){let t=i.split(".");if(3!==t.length||t[0]!==re)return null;let n=Buffer.from(de(e,t[1])),r=Buffer.from(t[2]);if(n.length!==r.length||!Q(n,r))return null;try{let e=JSON.parse(Buffer.from(t[1],"base64url").toString("utf8"));return"string"!=typeof e.b||"number"!=typeof e.r||"string"!=typeof e.s||"string"!=typeof e.q||null!==e.i&&"string"!=typeof e.i?null:{binding_id:e.b,revision:e.r,session_durable_id:e.s,incarnation:e.i??null,ui_request_id:e.q}}catch{return null}}(ai(e,"token_secret"),i.reply_token);if(null===t)return Qe("invalid_arguments","This is not a reply token this gateway issued.");if(t.binding_id!==i.binding_id)return Qe("binding_mismatch","The answer arrived through a different binding than the one that asked the question.",{binding_id:i.binding_id});let n=e.sql.one(["cursor","question_state","answer_state","answer","answered_at","answered_by","ui_request_id","ui_request_kind","session"],"SELECT cursor, question_state, answer_state, answer, answered_at, answered_by, ui_request_id, ui_request_kind, session_durable_id AS session FROM outbox WHERE reply_token = ? AND binding_id = ?",[i.reply_token,t.binding_id]);if(void 0===n)return Qe("not_found","The question this token belongs to is no longer in the outbox.");let r="answered"===n.question_state&&"delivered"!==n.answer_state,d=r&&Number(n.answered_at)+12e4<=i.now;if(r&&!d)return Qe("answer_in_progress","Another answer to this question is still being handed to the session.",{cursor:Number(n.cursor)});if("answered"===n.question_state&&!d)return Qe("already_answered",null===n.answer&&"delivered"===n.answer_state?"The session no longer waits for this question (answered or closed elsewhere).":"This question was already answered.",{cursor:Number(n.cursor)});let s="string"==typeof(o=n.ui_request_kind)&&Je.includes(o)?n.ui_request_kind:null,a=Ve(s,i.answer);var o;if(!a.ok)return Qe("invalid_arguments",a.reason,{ui_request_kind:s});let _=si(e,t.binding_id);return void 0===_||"active"!==_.status||_.revision!==t.revision||_.session_durable_id!==t.session_durable_id||gi(e,t.session_durable_id)!==t.incarnation||ei(n.ui_request_id)!==t.ui_request_id?Qe("stale_token","The binding or the session changed since the question was asked.",{binding_id:t.binding_id}):(ye(e,"UPDATE outbox SET question_state = 'answered', answer_state = 'in_flight', answer = ?, answered_at = ?, answered_by = ? WHERE reply_token = ?",[i.answer,i.now,ii(i.answered_by),i.reply_token]),{kind:"ok",session_durable_id:t.session_durable_id,ui_request_id:t.ui_request_id,ui_request_kind:s,cursor:Number(n.cursor),claimed_at:i.now,taken_over:d?{answer:ei(n.answer),answered_at:null===n.answered_at||void 0===n.answered_at?null:Number(n.answered_at),answered_by:ti(n.answered_by)}:null})})}var yi=a;if(null===yi)throw Error("the gateway store worker must run as a worker thread");var vi,hi,wi=[],Li=new Map,ki=!1;function Ri(e){yi?.postMessage({type:"event",event:e})}async function Oi(a,l){if("init"===a)return await async function(a){let{config:l}=a,c=u(l.agent_dir);n(d(c,"inbox"),{recursive:!0,mode:448}),e(c,448);let p=(E=l.agent_dir,_(u(E),"gateway.sqlite"));var E;i(r(p,"a",384)),e(p,384);let m=await(import("node:sqlite"));hi=new m.DatabaseSync(p,{timeout:l.busy_timeout_ms});let b=new f(hi);b.exec(`PRAGMA busy_timeout = ${Math.trunc(l.busy_timeout_ms)}`);let T=Date.now();for(;;)try{b.exec("PRAGMA journal_mode = WAL");break}catch(e){if(!N(e))throw e;let i=Date.now()-T;if(i+10>l.lock_wait_max_ms)throw Ri({kind:"lock_wait_exceeded",op:"open",waited_ms:i}),o("open",i,l.lock_wait_max_ms);await s(10)}b.exec("PRAGMA synchronous = FULL");for(let i of["-wal","-shm"])t(`${p}${i}`)&&e(`${p}${i}`,384);let y={pid:process.pid,process_start_time:await g(process.pid),instance_id:l.instance_id,runtime_instance:l.runtime_instance};vi={sql:b,config:l,self:y,stats:{writes:0,marker_unlinks:0,transactions:0},emit:Ri,hook:Si,delay:e=>s(e)},await async function(e){if(!(xe(e)>=pe.length))for(;;)if(!await Le(e,"migrate",()=>{let i=xe(e);if(i>=pe.length)return!1;for(let t of pe[i])e.sql.exec(t);return e.sql.exec(`PRAGMA user_version = ${i+1}`),!0}))return}(vi);let h=await async function(e,i){let t=0;for(let n of e.config.legacy_mailbox_directories){let r,d=`legacy_mailbox:${n}`;if(void 0!==e.sql.one(["value"],"SELECT value FROM gateway_meta WHERE key = ?",[d]))continue;try{r=B(n)}catch(i){e.emit({kind:"legacy_mailbox_invalid",directory:n,error:i instanceof Error?i.message:String(i)});continue}if(null===r)continue;let s=$e(),a=r.filter(e=>!me.test(e.target)).map(e=>({message_seq:e.message_seq,target:e.target,reason:"invalid_target"})),o=r.filter(e=>me.test(e.target));t+=await Le(e,"migrate_legacy",()=>{let t=0;for(let r of o){let d=`legacy-${qe([n,r.message_seq]).slice(0,32)}`;if(void 0!==Ne(e,d))continue;let a=`root-${v()}`,o=`legacy:${n}`;ye(e,"INSERT INTO causal_roots (root_id, origin_principal, created_at, expires_at) VALUES (?, ?, ?, ?)",[a,o,i,i+C]);let _=Date.parse(r.accepted_at);Ae(e,{delivery_id:d,target_durable_id:r.target,seq:Se(e,r.target),sender:o,sender_turn:null,envelope:{origin:{external:{platform:"legacy_mailbox",account_id:s,chat_id:n,thread_id:"@chat",message_id:r.operation_id}},actor:"legacy thread mailbox",via:[o],root_id:a,hop:1,delivery_id:d},body:r.message,bytes:Buffer.byteLength(r.message),mode_requested:r.delivery,mode_effective:null,expected_turn_id:r.expected_turn_id,state:"queued",reason:null,admitted_by:null,claimed_at:null,attempt:0,admission_kind:null,turn_epoch:null,root_id:a,hop:1,created_at:Number.isFinite(_)?_:i,updated_at:i,expires_at:i+U,binding_id:null,binding_revision:null}),ke(e,r.target,d,!0),t++}return ye(e,"INSERT INTO gateway_meta (key, value) VALUES (?, ?)",[d,JSON.stringify({migrated_at:i,count:t,skipped:a})]),t}),a.length>0&&e.emit({kind:"legacy_mailbox_skipped",directory:n,items:a})}return t}(vi,a.now);return vi.stats.writes=0,vi.stats.transactions=0,vi.stats.marker_unlinks=0,{self:y,legacy_migrated:h}}(l);if("close"===a)return hi?.close(),hi=void 0,vi=void 0,null;let c=function(){if(void 0===vi)throw Error("the gateway store is not open");return vi}();switch(a){case"enqueue":return await Ue(c,l);case"reconcile":return await Fe(c,l);case"claim":return await async function(e,i){return await Le(e,"claim",()=>{let t=Ne(e,i.delivery_id);return void 0===t||"queued"!==t.state?{kind:"lost",state:t?.state??null}:t.expires_at<=i.now?(Xe(e,t,"refused",i.now,{reason:"expired"}),Re(e,t.target_durable_id,t.delivery_id),{kind:"lost",state:"refused"}):(ye(e,"UPDATE deliveries SET state = 'admitting', admitted_by = ?, claimed_at = ?, attempt = attempt + 1, mode_effective = ?, updated_at = ? WHERE delivery_id = ? AND state = 'queued'",[JSON.stringify(i.self),i.now,i.lane,i.now,i.delivery_id]),Re(e,t.target_durable_id,t.delivery_id),{kind:"claimed",row:Ne(e,i.delivery_id)})})}(c,l);case"record_outcome":return await async function(e,i){return await Le(e,"record_outcome",()=>{let t=Ne(e,i.delivery_id);if(void 0===t||"admitting"!==t.state&&"admitted"!==t.state||null===t.admitted_by||!b(t.admitted_by,i.self))return{kind:"lost",state:t?.state??null};let n=i.outcome;return"requeue"===n.kind?Xe(e,t,"queued",i.now):"refused"===n.kind?Xe(e,t,"refused",i.now,{reason:n.reason}):(ye(e,"UPDATE deliveries SET admission_kind = ?, turn_epoch = ?, updated_at = ? WHERE delivery_id = ?",[n.admission_kind,n.turn_epoch,i.now,t.delivery_id]),t.state!==n.kind&&Xe(e,t,n.kind,i.now)),{kind:"claimed",row:Ne(e,i.delivery_id)}})}(c,l);case"refuse_queued":return await async function(e,i){return await Le(e,"refuse",()=>{let t=Ne(e,i.delivery_id);return void 0!==t&&"queued"===t.state&&(Xe(e,t,"refused",i.now,{reason:i.reason}),Re(e,t.target_durable_id,t.delivery_id),!0)})}(c,l);case"complete_receipt":return await async function(e,i){return await Le(e,"complete_receipt",()=>1===ye(e,"UPDATE receipts SET status = 'completed', result = ?, updated_at = ? WHERE principal = ? AND operation = 'deliver' AND idempotency_key = ? AND status = 'prepared' AND owner_instance = ?",[JSON.stringify(i.result),i.now,i.principal,i.idempotency_key,e.config.instance_id]))}(c,l);case"abandon_receipt":return await async function(e,i){return await Le(e,"abandon_receipt",()=>1===ye(e,"UPDATE receipts SET status = 'uncertain', error_note = ?, updated_at = ? WHERE principal = ? AND operation = 'deliver' AND idempotency_key = ? AND status = 'prepared' AND owner_instance = ?",[i.error_note,i.now,i.principal,i.idempotency_key,e.config.instance_id]))}(c,l);case"delivery_view":return function(e,i){let t=Ne(e,i);return void 0===t?null:{row:t,queue_position:ve(e,t)}}(c,l);case"delivery_receipt":return function(e,i){let t=Ie(e,i.principal,i.idempotency_key);if(void 0===t||t.expires_at<=i.now||null===t.delivery_id)return null;let n=Ne(e,t.delivery_id);if(void 0===n)return null;let r="completed"===t.status&&null!==t.result;return{args_hash:t.args_hash,completed:r,result:r?JSON.parse(t.result):null,target_durable_id:n.target_durable_id,binding_revision:n.binding_revision}}(c,l);case"recover_delivery":return await async function(e,i){return await Le(e,"recover_delivery",()=>{let t=Ie(e,i.principal,i.idempotency_key);return void 0===t||t.expires_at<=i.now?null:De(e,{now:i.now,sender_principal:i.principal,endpoint_kind:null,receipt:{idempotency_key:i.idempotency_key,args_hash:i.args_hash}},t)})}(c,l);case"list":return function(e,i){return void 0!==i.target_durable_id?Te(e,"target_durable_id = ?",[i.target_durable_id],"seq"):void 0!==i.root_id?Te(e,"root_id = ?",[i.root_id],"created_at, seq"):Te(e,"1 = 1",[],"created_at, seq")}(c,l);case"is_referenced":return function(e,i){return Number(e.sql.one(["n"],`SELECT COUNT(*) AS n FROM deliveries WHERE target_durable_id = ? AND state IN ${ge}`,[i])?.n??0)>0||Number(e.sql.one(["n"],"SELECT COUNT(*) AS n FROM bindings WHERE session_durable_id = ? AND status = 'active'",[i])?.n??0)>0||Oe(e,i).length>0}(c,l);case"journal_mode":return function(e){return String(e.sql.one(["journal_mode"],"SELECT journal_mode FROM pragma_journal_mode()")?.journal_mode??"")}(c);case"stats":return function(e){return{...e.stats}}(c);case"tool_receipt_begin":return await ci(c,l);case"tool_receipt_settle":return await async function(e,i){return await Le(e,"tool_receipt_settle",()=>{let t="result"in i;return 1===ye(e,`UPDATE receipts SET status = ?, ${t?"result":"error_note"} = ?, updated_at = ? WHERE principal = ? AND operation = ? AND idempotency_key = ? AND status = 'prepared' AND owner_instance = ?`,[t?"completed":"uncertain",t?JSON.stringify(i.result):i.error_note,i.now,i.principal,i.operation,i.idempotency_key,e.config.instance_id])})}(c,l);case"bind":return await async function(e,i){let t=i.binding;return await li(e,"bind",i.now,i.receipt,()=>{let n=di(e,"platform = ? AND account_id = ? AND chat_id = ? AND thread_id = ? AND status = 'active'",[t.platform,t.account_id,t.chat_id,t.thread_id])[0];if(void 0!==n)return Qe("binding_conflict",n.session_durable_id===t.session_durable_id?"This thread is already bound to that session.":"This thread is bound to another session; rebind it explicitly to move it.",{binding_id:n.binding_id,revision:n.revision,session:n.session_durable_id});let r=ie(i.now),d={schema_version:1,binding_id:`bnd-${Z()}`,revision:1,status:"active",platform:t.platform,account_id:t.account_id,chat_id:t.chat_id,thread_id:t.thread_id,root_message_id:t.root_message_id,progress_message_id:t.progress_message_id,session_realm_id:ai(e,"realm_id"),session_durable_id:t.session_durable_id,direction:t.direction,inbound_mode:t.inbound_mode,outbound_events:t.outbound_events,policy_id:t.policy_id,created_at:r,updated_at:r,lease_started_at:r,ttl_seconds:t.ttl_seconds,expires_at:null===t.ttl_seconds?null:ie(i.now+1e3*t.ttl_seconds)};return ye(e,`INSERT INTO bindings (${ze.join(", ")}) VALUES (${ze.map(()=>"?").join(", ")})`,[d.binding_id,d.schema_version,d.revision,d.status,d.platform,d.account_id,d.chat_id,d.thread_id,d.root_message_id,d.progress_message_id,d.session_realm_id,d.session_durable_id,d.direction.inbound?1:0,d.direction.outbound?1:0,d.inbound_mode,JSON.stringify(d.outbound_events),d.policy_id,d.created_at,d.updated_at,d.lease_started_at,d.ttl_seconds,d.expires_at]),{kind:"ok",binding:d}})}(c,l);case"unbind":return await async function(e,i){return await li(e,"unbind",i.now,i.receipt,()=>{let t=si(e,i.binding_id);if(void 0===t)return Qe("not_found","No binding has this id.",{binding_id:i.binding_id});if("active"!==t.status)return{kind:"ok",binding:t,already_closed:!0,in_flight:pi(e,t.binding_id)};if(t.revision!==i.expected_revision)return Qe("stale_revision","The binding changed since that revision.",{binding_id:t.binding_id,revision:t.revision});let n=ie(i.now);return ye(e,"UPDATE bindings SET status = 'detached', revision = revision + 1, updated_at = ? WHERE binding_id = ? AND revision = ?",[n,t.binding_id,t.revision]),ye(e,"DELETE FROM completion_arms WHERE binding_id = ?",[t.binding_id]),{kind:"ok",binding:si(e,t.binding_id),already_closed:!1,in_flight:pi(e,t.binding_id)}})}(c,l);case"rebind":return await async function(e,i){return await li(e,"rebind",i.now,i.receipt,()=>{let t=si(e,i.binding_id);if(void 0===t)return Qe("not_found","No binding has this id.",{binding_id:i.binding_id});if("active"!==t.status)return Qe("binding_inactive",`The binding is ${t.status}.`,{binding_id:t.binding_id,status:t.status});if(t.revision!==i.expected_revision)return Qe("stale_revision","The binding changed since that revision.",{binding_id:t.binding_id,revision:t.revision});if(t.session_durable_id===i.session_durable_id)return Qe("invalid_arguments","The binding is already attached to that session.",{binding_id:t.binding_id});let n=ie(i.now),r=e.sql.all(["delivery_id","target"],"SELECT delivery_id, target_durable_id AS target, seq FROM deliveries WHERE binding_id = ? AND binding_revision = ? AND state = 'queued'",[t.binding_id,t.revision],"seq").map(e=>({delivery_id:String(e.delivery_id),target:String(e.target)}));for(let t of r)ye(e,"UPDATE deliveries SET state = 'refused', reason = 'binding_closed', updated_at = ? WHERE delivery_id = ? AND state = 'queued'",[i.now,t.delivery_id]),Re(e,t.target,t.delivery_id);return ye(e,"UPDATE bindings SET session_durable_id = ?, revision = revision + 1, lease_started_at = ?, updated_at = ? WHERE binding_id = ? AND revision = ?",[i.session_durable_id,n,n,t.binding_id,t.revision]),ye(e,"DELETE FROM completion_arms WHERE binding_id = ?",[t.binding_id]),{kind:"ok",binding:si(e,t.binding_id),closed:r.map(e=>e.delivery_id)}})}(c,l);case"list_bindings":return await Ei(c,l);case"binding_view":return await async function(e,i){return await Le(e,"binding_view",()=>(oi(e,i.now),si(e,i.binding_id)??null))}(c,l);case"register_incarnation":return await async function(e,i){await Le(e,"register_incarnation",()=>{ye(e,"INSERT INTO session_meta (durable_id, next_seq, incarnation, endpoint_socket, endpoint_kind)\n VALUES (?, (SELECT COALESCE(MAX(seq), 0) + 1 FROM deliveries WHERE target_durable_id = ?), ?, ?, ?)\n ON CONFLICT(durable_id) DO UPDATE SET incarnation = excluded.incarnation,\n endpoint_socket = excluded.endpoint_socket, endpoint_kind = excluded.endpoint_kind",[i.durable_id,i.durable_id,i.incarnation,i.endpoint?.socket??null,i.endpoint?.kind??null])})}(c,l);case"clear_endpoint":return await async function(e,i){await Le(e,"clear_endpoint",()=>{ye(e,"UPDATE session_meta SET endpoint_socket = NULL, endpoint_kind = NULL WHERE durable_id = ? AND incarnation = ?",[i.durable_id,i.incarnation])})}(c,l);case"session_owner":return function(e,i){let t=e.sql.one(["incarnation","endpoint_socket","endpoint_kind"],"SELECT incarnation, endpoint_socket, endpoint_kind FROM session_meta WHERE durable_id = ?",[i]);return void 0===t||"string"!=typeof t.incarnation?null:{incarnation:t.incarnation,endpoint:"string"!=typeof t.endpoint_socket||"tui"!==t.endpoint_kind&&"rpc_host"!==t.endpoint_kind?null:{socket:t.endpoint_socket,kind:t.endpoint_kind}}}(c,l);case"report":return await bi(c,l);case"emit_completions":return await async function(e,i){return await Le(e,"emit_completions",()=>{oi(e,i.now);let t=["arm_seq","binding_id","revision","text"],n=void 0===i.through_arm_seq?e.sql.all(t,"SELECT arm_seq, binding_id, revision, text FROM completion_arms WHERE session_durable_id = ?",[i.session_durable_id],"arm_seq"):e.sql.all(t,"SELECT arm_seq, binding_id, revision, text FROM completion_arms WHERE session_durable_id = ? AND arm_seq <= ?",[i.session_durable_id,i.through_arm_seq],"arm_seq"),r=new Map;for(let i of n)ye(e,"DELETE FROM completion_arms WHERE arm_seq = ?",[Number(i.arm_seq)]),r.set(String(i.binding_id),i);let d=[];for(let t of[...r.values()].toSorted((e,i)=>String(e.binding_id)<String(i.binding_id)?-1:1)){let n=si(e,String(t.binding_id));void 0!==n&&"active"===n.status&&n.revision===Number(t.revision)&&n.session_durable_id===i.session_durable_id&&n.direction.outbound&&n.outbound_events.includes("completion")&&d.push({binding_id:n.binding_id,cursor:mi(e,{binding:n,event:"completion",text:String(t.text),now:i.now,outcome:i.outcome})})}return d}).then(t=>(e.emit({kind:"completions_emitted",session_durable_id:i.session_durable_id,cursors:t.map(e=>e.cursor)}),t))}(c,l);case"pending_completion_arms":return function(e,i){return Number(e.sql.one(["n"],"SELECT COUNT(*) AS n FROM completion_arms WHERE session_durable_id = ?",[i])?.n??0)}(c,l);case"latest_completion_arm":return function(e,i){let t=e.sql.one(["s"],"SELECT MAX(arm_seq) AS s FROM completion_arms WHERE session_durable_id = ?",[i])?.s;return null==t?null:Number(t)}(c,l);case"read_outbox":return await Ti(c,l);case"ack_outbox":return await async function(e,i){return await Le(e,"ack_outbox",()=>{oi(e,i.now);let t=si(e,i.binding_id);if(void 0===t)return Qe("not_found","No binding has this id.",{binding_id:i.binding_id});let n=fi(e,t.binding_id);if(i.cursor<=n)return{kind:"ok",binding_id:t.binding_id,acked_cursor:n,changed:!1};if(void 0===e.sql.one(["cursor"],"SELECT cursor FROM outbox WHERE binding_id = ? AND cursor = ?",[t.binding_id,i.cursor])){let n=Number(e.sql.one(["m"],"SELECT COALESCE(MAX(cursor), 0) AS m FROM outbox WHERE binding_id = ?",[t.binding_id])?.m??0);return Qe("cursor_invalid",i.cursor>n?"The cursor is past the newest outbox row of this binding.":"The cursor names no outbox row of this binding.",{newest:n})}return ye(e,"UPDATE outbox SET state = 'acked', acked_at = ? WHERE binding_id = ? AND cursor <= ? AND state = 'pending'",[i.now,t.binding_id,i.cursor]),ye(e,"INSERT INTO outbox_cursors (binding_id, acked_cursor, updated_at) VALUES (?, ?, ?) ON CONFLICT(binding_id) DO UPDATE SET acked_cursor = excluded.acked_cursor, updated_at = excluded.updated_at",[t.binding_id,i.cursor,i.now]),void 0!==i.provider_message_id&&(ye(e,"UPDATE outbox SET provider_message_id = ? WHERE binding_id = ? AND cursor = ?",[i.provider_message_id,t.binding_id,i.cursor]),"milestone"===e.sql.one(["event_kind"],"SELECT event_kind FROM outbox WHERE binding_id = ? AND cursor = ?",[t.binding_id,i.cursor])?.event_kind&&null===t.progress_message_id&&ye(e,"UPDATE bindings SET progress_message_id = ?, updated_at = ? WHERE binding_id = ?",[i.provider_message_id,ie(i.now),t.binding_id])),{kind:"ok",binding_id:t.binding_id,acked_cursor:i.cursor,changed:!0}})}(c,l);case"claim_answer":return await Ni(c,l);case"release_answer":return await async function(e,i){return await Le(e,"release_answer",()=>1===ye(e,"UPDATE outbox SET question_state = 'pending', answer_state = NULL, answer = NULL, answered_at = NULL, answered_by = NULL WHERE reply_token = ? AND question_state = 'answered' AND answer_state = 'in_flight' AND answered_at = ?",[i.reply_token,i.claimed_at]))}(c,l);case"confirm_answer":return await async function(e,i){return await Le(e,"confirm_answer",()=>1===ye(e,"UPDATE outbox SET question_state = 'answered', answer_state = 'delivered', answer = ?, answered_at = ?, answered_by = ? WHERE reply_token = ? AND answer_state IS NOT 'delivered'",[i.answer,i.claimed_at,ii(i.answered_by),i.reply_token]))}(c,l);case"mark_prior_delivered":return await async function(e,i){return await Le(e,"mark_prior_delivered",()=>1===ye(e,"UPDATE outbox SET answer_state = 'delivered', answer = ?, answered_at = ?, answered_by = ? WHERE reply_token = ? AND question_state = 'answered' AND answer_state = 'in_flight' AND answered_at = ?",[i.prior.answer,i.prior.answered_at,ii(i.prior.answered_by),i.reply_token,i.claimed_at]))}(c,l);default:throw Error(`unknown gateway store op: ${a}`)}}async function Si(e){let i=vi?.config.test_hooks[e];if(void 0===i)return;if("throw"===i)throw Error(`gateway test hook ${e}`);"sigkill"===i&&(process.kill(process.pid,"SIGKILL"),await new Promise(()=>{}));let t=new Promise(i=>Li.set(e,i));Ri({kind:"paused",hook:e}),await t}yi.on("message",e=>{if("resume"===e.type)return Li.get(e.hook)?.(),void Li.delete(e.hook);wi.push(e),async function(){if(ki)return;ki=!0;try{for(let e=wi.shift();void 0!==e;e=wi.shift())try{let i=await Oi(e.op,e.args);yi?.postMessage({type:"response",id:e.id,ok:!0,value:i})}catch(i){yi?.postMessage({type:"response",id:e.id,ok:!1,error:{message:i instanceof Error?i.message:String(i),stack:i instanceof Error?i.stack:void 0,code:"string"==typeof i?.code?i.code:void 0}})}}finally{ki=!1}}()});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// omo:
|
|
2
|
+
// omo:DpZ357q4T3X3RMz5-rqiZKBbvPmUOEKPaqhOIVpM9vM:xE1V0Tu0M-W7qbPAWE96oZWECfAaCG1VE1qlEbZRthk
|
|
3
3
|
import{spawn as t}from"node:child_process";import*as e from"node:fs";import*as r from"node:fs/promises";function n(t){if(t instanceof Error&&"code"in t)return"string"==typeof t.code?t.code:void 0}async function i(t){for(let e=0;;e+=1)try{return await t()}catch(t){if("EINTR"!==n(t)||e>=128)throw t}}function o(t){for(let e=0;;e+=1)try{return t()}catch(t){if("EINTR"!==n(t)||e>=128)throw t}}import{Buffer as a}from"node:buffer";import{constants as s}from"node:fs";function l(t){return"number"==typeof t?0!==(t&s.O_EXCL):"string"==typeof t&&t.toLowerCase().includes("x")}async function c(t,e,r,n){let o="string"==typeof e?a.from(e,r??"utf8"):e,s=0;for(;s<o.length;){n?.throwIfAborted();let{bytesWritten:e}=await i(()=>t.write(o,s));if(e<=0)throw Error(`fs write made no progress at offset ${s}`);s+=e}}function u(t){return"function"==typeof t}function d(t){return(...e)=>i(async()=>t(...e))}function f(t){return(...e)=>o(()=>t(...e))}function p(t,e){let r="async"===e?d:f,n=new Map;return new Proxy(t,{get(t,e){if(n.has(e))return n.get(e);let i=Reflect.get(t,e);if(!u(i))return i;let o=r(i),a=Reflect.get(i,"native");return u(a)&&Object.assign(o,{native:r(a)}),n.set(e,o),o}})}var m=new Set(["stat","sync","datasync","chmod","chown","utimes","truncate"]);var w=p(r,"async"),h=p(e,"sync"),{access:y,chmod:g,copyFile:v,cp:b,link:E,lstat:S,mkdir:x,mkdtemp:_,readFile:I,readdir:N,realpath:O,rename:k,rm:P,rmdir:T,stat:M,unlink:R}=w,{accessSync:A,chmodSync:$,fsyncSync:L,linkSync:C,lstatSync:D,mkdirSync:U,readFileSync:q,readdirSync:j,realpathSync:F,statSync:J,unlinkSync:G,writeFileSync:H,writeSync:B}=h,{constants:V,watch:Y}=e,K=async(...t)=>{let e=()=>r.open(...t);return function(t){return new Proxy(t,{get(t,e){let r=Reflect.get(t,e);if(!u(r))return r;let o=e=>Reflect.apply(r,t,[...e]);return"close"===e||e===Symbol.asyncDispose?(...t)=>{let e=o(t);return e instanceof Promise?e.catch(t=>{if("EINTR"!==n(t))throw t}):e}:"string"==typeof e&&m.has(e)?(...t)=>{let e=o(t);return e instanceof Promise?e.catch(e=>{if("EINTR"!==n(e))throw e;return i(async()=>o(t))}):e}:(...t)=>o(t)}})}(await(l(t[1]??"r")?e():i(e)))},z=(t,r,n)=>function(t,e,r,n){return l(r)?t(e,r,n):o(()=>t(e,r,n))}(e.openSync,t,r,n??void 0);function X(t){try{e.closeSync(t)}catch(t){if("EINTR"!==n(t))throw t}}function Z(t){try{return o(()=>e.statSync(t)),!0}catch{return!1}}import{join as W}from"node:path";import{fileURLToPath as Q}from"node:url";import{randomUUID as tt}from"node:crypto";import{dirname as et}from"node:path";async function rt(t){return JSON.parse(await I(t,"utf8"))}async function nt(t,e,r=384){let n=`${t}.tmp-${process.pid}-${tt()}`,i=await K(n,"wx",r),o=!1;try{try{await i.writeFile(`${JSON.stringify(e,null,2)}\n`,"utf8"),await i.sync()}finally{await i.close()}await k(n,t),o=!0,await async function(t){try{let e=await K(t,"r");try{await e.sync()}finally{await e.close()}}catch(t){let e=t instanceof Error&&"code"in t?t.code:void 0;if("win32"!==process.platform||!["EISDIR","EPERM"].includes(String(e)))throw t}}(et(t))}finally{o||await ot(n)}}async function it(t,e){let r=await rt(t);await nt(t,{...r,...e})}async function ot(t){try{await R(t)}catch(t){if(!(t instanceof Error&&"code"in t&&"ENOENT"===t.code))throw t}}import{spawn as at,spawnSync as st}from"node:child_process";import{execFile as lt}from"node:child_process";var ct=null;function ut(){return ct??=async function(){if("darwin"!==process.platform)return null;try{let{dlopen:t,FFIType:e}=await(import("bun:ffi")),r=t("/usr/lib/libSystem.B.dylib",{proc_pidinfo:{args:[e.i32,e.i32,e.u64,e.ptr,e.i32],returns:e.i32}});return(t,e,n,i,o)=>Number(r.symbols.proc_pidinfo(t,e,n,i,o))}catch{return null}}(),ct}var dt=null;async function ft(t){if("win32"!==process.platform)return null;if(!Number.isSafeInteger(t)||t<=0)return null;dt??=async function(){if("win32"!==process.platform)return null;try{let{dlopen:t,FFIType:e}=await(import("bun:ffi"));return t("kernel32.dll",{OpenProcess:{args:[e.u32,e.i32,e.u32],returns:e.ptr},GetProcessTimes:{args:[e.ptr,e.ptr,e.ptr,e.ptr,e.ptr],returns:e.i32},CloseHandle:{args:[e.ptr],returns:e.i32}}).symbols}catch{return null}}();let e=await dt;if(null===e)return null;let r=e.OpenProcess(4096,0,t);if(null===r||0===r||0n===r)return null;try{let t=new BigUint64Array(1),n=e.GetProcessTimes(r,t,new BigUint64Array(1),new BigUint64Array(1),new BigUint64Array(1)),i=t[0]??0n;return 0===n||0n===i?null:i}finally{e.CloseHandle(r)}}async function pt(t,e){return await new Promise(r=>{lt(t,e,{encoding:"utf8",timeout:2e3,windowsHide:!0},(t,e)=>{if(null!==t)return void r(null);let n=e.trim();r(n.length>0?n:null)})})}var mt=function(t,e){let r;return n=>n!==e?t(n):(r??=t(n).then(t=>(null===t&&(r=void 0),t),t=>{throw r=void 0,t}),r)}(async function(t){if("linux"===process.platform)return await async function(t){try{let e=await I(`/proc/${t}/stat`,"utf8"),r=e.lastIndexOf(")");if(r<0)return null;let n=e.slice(r+2).trim().split(/\s+/)[19];return void 0===n?null:`linux-proc-start-ticks:${n}`}catch{return null}}(t);if("darwin"===process.platform||"freebsd"===process.platform){if("dead"===ht(t))return null;let e=await async function(t){if("darwin"!==process.platform)return null;if(!Number.isSafeInteger(t)||t<=0)return null;let e=await ut();if(null===e)return null;let r=new Uint8Array(136),n=0;try{n=e(t,3,0n,r,136)}catch{return null}if(136!==n)return null;let i=new DataView(r.buffer,r.byteOffset,r.byteLength),o=Number(i.getBigUint64(120,!0));return o>0?o:null}(t);if(null!==e)return`proc-start-epoch:${e}`;let r=await pt("/bin/ps",["-o","lstart=","-p",String(t)]);return null===r?null:`ps-lstart:${r.replace(/\s+/g," ")}`}return"win32"===process.platform?await async function(t){if("dead"===ht(t))return null;let e=await ft(t);if(null!==e)return`win32-creation-filetime:${e}`;let r=await pt("powershell.exe",["-NoProfile","-Command",`(Get-Process -Id ${t} -ErrorAction SilentlyContinue).StartTime.ToUniversalTime().ToString('o')`]);return null===r?null:`win32-creation-date:${r}`}(t):null},process.pid);function wt(t){let e=t.indexOf(":");return e<=0?null:t.slice(0,e)}function ht(t){try{return process.kill(t,0),"alive"}catch(t){let e=function(t){if(t instanceof Error&&"code"in t)return"string"==typeof t.code?t.code:void 0}(t);return"ESRCH"===e?"dead":"EPERM"===e?"alive":"unknown"}}function yt(){return"1"===process.env.OMO_MEMORY_SUPERVISOR_ALLOW_TEST_SEAMS}function gt(){if(yt()){let t=process.env.OMO_MEMORY_SUPERVISOR_PLATFORM;if("posix"===t||"win32"===t)return t}return"win32"===process.platform?"win32":"posix"}function vt(t,e){let r=yt()?process.env.OMO_MEMORY_SUPERVISOR_CLOCK_PATH:void 0;if(void 0===r){let r=setTimeout(e,Math.max(0,t-Date.now()));return()=>clearTimeout(r)}let n=!1,i=()=>{if(n)return;let i=Et(r);!Number.isFinite(i)||i<t||(n=!0,o?.close(),clearInterval(a),e())};if(Et(r)>=t)return n=!0,e(),()=>{};let o=Y(r,i),a=setInterval(i,bt);return i(),()=>{n||(n=!0,o.close(),clearInterval(a))}}var bt=25;function Et(t){let e=j(t).map(t=>/^(\d+)-(-?\d+(?:\.\d+)?)$/.exec(t)).filter(t=>null!==t).sort((t,e)=>Number(t[1])-Number(e[1])).at(-1);return void 0===e?Number.NaN:Number(e[2])}function St(t,e){if(!yt())return;let r=process.env.OMO_MEMORY_SUPERVISOR_TASKKILL_RUN_DIR;void 0!==r&&H(`${r}/${t}-${process.pid}.json`,`${JSON.stringify({targetPid:e})}\n`,"utf8")}function xt(t){if(!yt())return;let e=process.env[t];if(void 0===e)return;let r=JSON.parse(e);if(!Array.isArray(r)||!r.every(t=>"string"==typeof t)||0===r.length)throw TypeError(`${t} must be a non-empty string array`);return r}function _t(t,e,r){let[n,...i]=t;if(void 0===n)throw TypeError("termination command is required");if(r){let t=st(n,[...i,...e],{env:process.env,stdio:"ignore",windowsHide:!0});if(void 0!==t.error)throw t.error;return}at(n,[...i,...e],{env:process.env,stdio:"ignore",windowsHide:!0}).once("error",t=>process.stderr.write(`${t.message}\n`))}function It(t,e){St(`posix-${e}`,t);let r=xt("OMO_MEMORY_SUPERVISOR_POSIX_SIGNAL_COMMAND");if(void 0===r)try{process.kill(-t,e)}catch(t){if(!(t instanceof Error&&"code"in t&&"ESRCH"===t.code))throw t}else _t(r,["--signal-group",String(t),e],!1)}function Nt(t){void 0!==t&&St("win32-graceful",t)}function Ot(t,e){"win32"===t?(Nt(e.pid),e.kill()):void 0!==e.pid&&It(e.pid,"SIGTERM")}function kt(t,e,r=!1){void 0!==e&&("win32"===t?function(t,e){_t(xt("OMO_MEMORY_SUPERVISOR_TASKKILL_COMMAND")??["taskkill"],["/pid",String(t),"/T","/F"],e)}(e,r):It(e,"SIGKILL"))}async function Pt(t){return await mt(t)}import{join as Tt}from"node:path";function Mt(t){return"object"==typeof t&&null!==t}function Rt(t,e){try{return t?.[e]}catch(t){return void Error}}function At(t,e){let r=Rt(t,e);return Mt(r)?r:void 0}function $t(t){if(!t)return"";if("string"==typeof t)return t.toLowerCase();if(!Mt(t))try{return JSON.stringify(t).toLowerCase()}catch(t){if(!(t instanceof Error))throw t;return""}let e=At(t,"data"),r=[e,At(t,"error"),t,At(e,"error")].filter(t=>void 0!==t);for(let t of r){let e=Rt(t,"message");if("string"==typeof e&&e.length>0)return e.toLowerCase()}let n=Rt(t,"name");if("string"==typeof n&&n.length>0){let t=n.match(/:\s*(.+)/);if(t)return t[1]?.trim().toLowerCase()??""}try{return JSON.stringify(t).toLowerCase()}catch(t){if(!(t instanceof Error))throw t;return""}}function Lt(t,e){if(function(t){return"object"==typeof t&&null!==t}(t))try{return t[e]}catch(t){return void Error}}function Ct(t){return"terminal_quota_exhausted"===function(t){let e=Lt(t,"data"),r=Lt(t,"detail")??Lt(e,"detail")??t,n=Lt(r,"error")??r,i=Lt(n,"type")??Lt(r,"type");return"string"==typeof i?i.toLowerCase():void 0}(t)||(e=$t(t),!/\bnon[-\s]+terminal\s+quota\b/i.test(e)&&!/\bnon[-\s]+terminal\s+billing\s+limit\b/i.test(e)&&(/\bterminal\s+quota\b/i.test(e)||/\bterminal\s+billing\s+limit\b/i.test(e)||/\bhard\s+billing\s+limit\b/i.test(e)));var e}function Dt(t){if(Ct(t))return"abort";let e=$t(t),r=function(t){if(!Mt(t))return;let e=At(t,"data"),r=[t,e,At(t,"error"),At(e,"error")].filter(t=>void 0!==t);for(let t of r){let e=Rt(t,"name");if("string"==typeof e&&e.length>0)return e}}(t)?.toLowerCase().replace(/[_-]/g,"");return r?.includes("messageabortederror")||r?.includes("aborterror")?"abort":"contextoverflowerror"===r?"context_overflow":r?.includes("ailoadapikeyerror")||r?.includes("loadapi")||/api.?key.?is.?missing/i.test(e)&&/environment variable/i.test(e)?"missing_api_key":/api.?key/i.test(e)&&/must be a string/i.test(e)?"invalid_api_key":r?.includes("providermodelnotfounderror")||r?.includes("modelnotfounderror")||r?.includes("unknownerror")&&/model\s+not\s+found/i.test(e)?"model_not_found":r?.includes("quotaexceeded")||r?.includes("insufficientquota")||r?.includes("billingerror")||r?.includes("resourceexhausted")||r?.includes("insufficientcredits")||r?.includes("usagelimit")||/quota.?exceeded/i.test(e)||/exceeded.*quota/i.test(e)||/quota\b.*\breset/i.test(e)||/usage\s*quota/i.test(e)||/subscription.?(?:quota|limit)/i.test(e)||/insufficient.?(?:quota|balance|funds?|credits?)/i.test(e)||/credits?\s+exhausted/i.test(e)||/\b(?:session|weekly|monthly|daily|hourly|\d+[-\s]hour|plan|call)\s+limit\b/i.test(e)||/\bhit\s+your\b[^.]*\blimit\b/i.test(e)||/\bin\s+arrears\b/i.test(e)||/\brecharge\s+and\s+try\b/i.test(e)||/billing.?(?:hard.?)?limit/i.test(e)||/exhausted\s+your\s+capacity/i.test(e)||/resource.?exhausted/i.test(e)||/out\s+of\s+credits?/i.test(e)||/payment.?required/i.test(e)||/usage\s+limit/i.test(e)||/credit\s+balance.*too\s+low/i.test(e)||/limit\s+exhausted/i.test(e)||/使用上限/.test(e)||/用量上限/.test(e)||/达到.*限制/.test(e)||/额度.*不足/.test(e)||/余额.*不足/.test(e)||/已耗尽/.test(e)||function(t){return/预扣费额度失败/i.test(t)&&/用户剩余额度/i.test(t)||/用户剩余额度/i.test(t)&&/需要预扣费额度/i.test(t)}(e)?"quota_exceeded":void 0}var Ut=new Set(["providermodelnotfounderror","ratelimiterror","modelunavailableerror","providerconnectionerror","authenticationerror"]),qt=new Set(["messageabortederror","permissiondeniederror","contextlengtherror","timeouterror","validationerror","syntaxerror","usererror"]),jt=["rate_limit","rate limit","usage_limit_reached","usage limit has been reached","quota","all credentials for model","cooling down","exhausted your capacity","not found","unavailable","insufficient","too many requests","over limit","overloaded","bad gateway","bad request","unknown provider","provider not found","model_not_supported","model not supported","model is not supported","connection error","network error","timeout","service unavailable","internal_server_error","free usage","usage exceeded","credit","balance","temporarily unavailable","try again","请稍后重试","503","502","504","429","529","selected provider is forbidden","provider is forbidden","频率限制","请求过于频繁","暂时不可用","服务不可用","server_error","an error occurred while processing","upstream request failed"],Ft=["rate limit","cooling down","credentials for model"];function Jt(t){let e=t.name?.toLowerCase();if(void 0!==e&&qt.has(e))return!1;if(Ct(t))return!1;if("quota_exceeded"===Dt(t))return!0;if(void 0!==e&&Ut.has(e))return!0;let r=t.message?.toLowerCase()??"";return!(!(n=r).includes("retrying in")||!Ft.some(t=>n.includes(t)))||(null!=t.statusCode&&(429===t.statusCode||503===t.statusCode||529===t.statusCode)||jt.some(t=>r.includes(t)));var n}var Gt=[/prompt is too long/i,/request_too_large/i,/input is too long for requested model/i,/exceeds the context window/i,/exceeds (?:the )?(?:model'?s )?maximum context length(?: of [\d,]+ tokens?|\s*\([\d,]+\))/i,/input token count.*exceeds the maximum/i,/maximum prompt length is \d+/i,/reduce the length of the messages/i,/maximum context length is \d+ tokens/i,/exceeds (?:the )?maximum allowed input length of [\d,]+ tokens?/i,/input \(\d+ tokens\) is longer than the model'?s context length \d+ tokens/i,/exceeds the limit of \d+/i,/exceeds the available context size/i,/greater than the context length/i,/context window exceeds limit/i,/exceeded model token limit/i,/too large for model with \d+ maximum context length/i,/prompt has [\d,]+ tokens?, but the configured context size is [\d,]+ tokens?/i,/prompt too long; exceeded (?:max )?context length/i,/range of input length should be/i,/model_context_window_exceeded/i,/context[_ ]length[_ ]exceeded/i,/too many tokens/i,/token limit exceeded/i,/^4(?:00|13)\s*(?:status code)?\s*\(no body\)/i,/(?:request[ _])?(?:body|entity|payload)[_ ]too[_ ]large/i,/Request payload is \d+ (?:bytes, over the \d+ byte|tokens, over the \d+ token) limit Kiro accepts\./i,/Model context limit reached\. Conversation size exceeds model capacity\./i],Ht=[/^(Throttling error|Service unavailable):/i,/rate limit/i,/too many requests/i];var Bt=/^Error: Model "([^"]+)" not found\. Use --list-models to see available models\.$/m,Vt=/^(?:Error:\s*)?No API key found for\s+([^\s.]+)/m,Yt=/(?:^|\s)(\d{3})\s*:/;function Kt(t){if(t.timedOut||0===t.code)return;let e=`${t.stderr}\n${t.stdout}`,r=Bt.exec(e)?.[1];if(void 0!==r)return{kind:"model_not_visible",id:r};let n=Vt.exec(e)?.[1];if(void 0!==n)return{kind:"auth_missing",provider:n};let i=function(t){for(let e of[t.stderr,t.stdout]){let t=e.split("\n").map(t=>t.trim()).find(t=>t.length>0);if(void 0!==t)return t.slice(0,200)}return}(t);if(void 0===i)return;if(o=i,!Ht.some(t=>t.test(o))&&Gt.some(t=>t.test(o)))return{kind:"context_overflow",detail:i};var o;let a=Number.parseInt(Yt.exec(i)?.[1]??"",10);return Jt({message:i,...Number.isNaN(a)?{}:{statusCode:a}})?{kind:"provider_unavailable",detail:i}:void 0}import{randomUUID as zt}from"node:crypto";import{dirname as Xt,join as Zt}from"node:path";import{randomUUID as Wt}from"node:crypto";import{hostname as Qt}from"node:os";import te from"node:path";import ee from"node:path";var re=new Set;function ne(t){re.add(t)}function ie(t){re.delete(t)}var oe=/\.candidate-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function ae(t){if(t instanceof Error&&"code"in t)return"string"==typeof t.code?t.code:void 0}function se(t,e){try{t.onFailure?.(e)}catch{}}function le(t){if("win32"!==process.platform)return!1;let e=ae(t);return"EBUSY"===e||"EPERM"===e||"EACCES"===e}import{randomUUID as ce}from"node:crypto";import{hostname as ue}from"node:os";function de(t){return"string"==typeof t&&t.length>0}function fe(t){let e;try{e=JSON.parse(t)}catch{return null}if("object"!=typeof e||null===e||Array.isArray(e))return null;let r=e;return!Number.isInteger(r.pid)||Number(r.pid)<=0?null:de(r.process_start)&&de(r.hostname)&&de(r.nonce)?!de(r.created_at)||Number.isNaN(Date.parse(r.created_at))?null:de(r.purpose)&&(void 0===r.run_id||de(r.run_id))?{pid:Number(r.pid),process_start:r.process_start,hostname:r.hostname,nonce:r.nonce,created_at:r.created_at,purpose:r.purpose,...void 0===r.run_id?{}:{run_id:r.run_id}}:null:null}async function pe(t,e={}){if(0===t.length)throw Error("lock purpose must not be empty");let r=await mt(process.pid);return{pid:process.pid,process_start:r??"unavailable",hostname:ue(),nonce:ce(),created_at:(new Date).toISOString(),purpose:t,...void 0===e.runId?{}:{run_id:e.runId}}}var me=new Set(["EACCES","EPERM","ENOTSUP"]);class we extends Error{lockPath;owner;retriable=!0;constructor(t,e){super(`Lock is held: ${t}`),this.lockPath=t,this.owner=e,this.name="LockContentionError"}}function he(t){if(t instanceof Error&&"code"in t)return"string"==typeof t.code?t.code:void 0}function ye(t,e){if(void 0!==e)return e(t);if("win32"!==process.platform)return!1;let r=he(t);return"EBUSY"===r||"EPERM"===r||"EACCES"===r}async function ge(t){for(let e=0;e<3;e+=1)try{return await(xe.unlink??R)(t),ie(t),!0}catch(r){if("ENOENT"===he(r))return ie(t),!0;if(!ye(r,xe.isSharingError))throw ne(t),_e(te.dirname(t)),r;if(e+1===3)return ne(t),_e(te.dirname(t)),!1}return!1}function ve(t,e){return e?.throwIfAborted(),new Promise((r,n)=>{let i=setTimeout(a,t),o=()=>a(e?.reason??new DOMException("The operation was aborted","AbortError"));function a(t){clearTimeout(i),e?.removeEventListener("abort",o),void 0===t?r():n(t)}e?.addEventListener("abort",o,{once:!0})})}async function be(t){try{let e=await I(t,"utf8"),r=await M(t,{bigint:!0});return{raw:e,record:fe(e),dev:r.dev,ino:r.ino,mtimeMs:Number(r.mtimeMs)}}catch(t){let e=he(t);if("ENOENT"===e)return null;if("\\"===te.sep&&"EPERM"===e)return{raw:"",record:null,dev:0,ino:0,mtimeMs:Date.now()};throw t}}async function Ee(t,e){await x(te.dirname(t),{recursive:!0,mode:448});let{candidatePath:r,handle:n}=await async function(t){for(let e=0;;e+=1){let r=`${t}.candidate-${Wt()}`;try{return{candidatePath:r,handle:await K(r,"wx",384)}}catch(n){if(await ge(r)||_e(te.dirname(t)),"EINTR"!==he(n)||e>=128)throw n}}}(t);try{try{await c(n,`${JSON.stringify(e)}\n`,"utf8"),await n.sync()}finally{await n.close()}try{return await(xe.link??E)(r,t),!0}catch(r){if(function(t){let e=he(t);return"EEXIST"===e||"ENOENT"===e}(r))return!1;if(me.has(he(r)??""))return await async function(t,e){let r;try{r=await K(t,"wx",384)}catch(t){if("EEXIST"===he(t))return!1;throw t}try{return await(xe.writeFallback??c)(r,`${JSON.stringify(e)}\n`,"utf8"),await r.sync(),!0}finally{await r.close()}}(t,e);throw r}}finally{await ge(r)||_e(te.dirname(t))}}var Se=new Set,xe={};function _e(t){Se.delete(t)}async function Ie(t){if(t.hostname!==Qt())return!1;let e=ht(t.pid);if("dead"===e)return!0;if("unknown"===e)return!1;let r=await mt(t.pid);return null!==r&&"unavailable"!==t.process_start&&function(t,e){let r=wt(t);return null!==r&&r===wt(e)&&t!==e}(t.process_start,r)}function Ne(t,e){return t.dev===e.dev&&t.ino===e.ino&&t.mtimeMs===e.mtimeMs&&t.raw===e.raw}async function Oe(t,e,r){return null!==t.record?Ie(t.record):e-t.mtimeMs>r}async function ke(t,e,r){let n=await be(t);if(null===n||!await Oe(n,e,r))return!1;let i=`${t}.reaping-${Wt()}`;try{await k(t,i)}catch(t){if("ENOENT"===he(t))return!1;if(ye(t))return!1;throw t}let o=await be(i);if(null!==o&&Ne(o,n))return await R(i),!0;try{await E(i,t)}catch(t){if("EEXIST"!==he(t))throw t}return await R(i),!1}async function Pe(t,e,r,n,i){if(!await Oe(e,n,i))return!1;let o=`${t}.recovery`,a={...r,nonce:Wt(),created_at:(new Date).toISOString(),purpose:`${r.purpose}:recovery`};for(let t=0;!await Ee(o,a);t+=1)if(t>0||!await ke(o,n,i))return!1;try{let r=await be(t);if(null===r)return!0;if(!Ne(r,e))return!1;if(!await Oe(r,n,i))return!1;let s=await be(o);return null!==s&&s.record?.nonce===a.nonce&&(await R(t),!0)}finally{await Me(o,a)}}async function Te(t,e,r={}){let n=r.waitTimeoutMs??0,i=r.retryDelayMs??25,o=r.incompleteLockGraceMs??5e3,a=r.now??Date.now;if(n<0||i<=0||o<0)throw Error("lock wait options must be positive");let s=te.dirname(t);Se.has(s)||(Se.add(s),await async function(t,e=Date.now,r={}){let n;try{n=await N(t)}catch(e){if("ENOENT"===ae(e)){for(let e of re)ee.dirname(e)===t&&ie(e);return 0}throw e}let i=0;for(let o of n){if(!oe.test(o))continue;let n=ee.join(t,o);try{let t=await M(n);if(!re.has(n)&&e()-t.mtimeMs<=36e5)continue;let o=!1;for(let t=0;t<3;t+=1)try{await(r.unlink??R)(n),ie(n),o=!0;break}catch(e){if("ENOENT"===ae(e)){ie(n),o=!0;break}if(!(r.isSharingError?.(e)??le(e)))throw e;t+1===3&&se(r,n)}o&&(i+=1)}catch(t){"ENOENT"===ae(t)&&ie(n),se(r,n)}}return i}(s,Date.now,{...void 0===xe.unlink?{}:{unlink:xe.unlink},...void 0===xe.isSharingError?{}:{isSharingError:xe.isSharingError},onFailure:()=>_e(s)}).catch(()=>{_e(s)}));let l=a()+n;for(;;){r.signal?.throwIfAborted();let n=await be(t);if(null===n){if(await Ee(t,e))return;if(r.signal?.throwIfAborted(),n=await be(t),null===n)continue}if(!await Pe(t,n,e,a(),o)){if(r.signal?.throwIfAborted(),a()>=l)throw new we(t,n.record);await ve(Math.min(i,Math.max(1,l-a())),r.signal)}}}async function Me(t,e){let r=await be(t);if(null===r||r.record?.nonce!==e.nonce)return!1;try{return await R(t),!0}catch(t){if("ENOENT"===he(t))return!1;throw t}}async function Re(t,e,r,n){await Te(t,e,n);try{return await r()}finally{await Me(t,e)}}Promise.resolve();var Ae=[["\\bAKIA[0-9A-Z]{16}\\b",""],["\\b(?:bearer|token|api[_-]?key|secret|password|passwd|pwd)\\s*[=:]\\s*\\S{1,256}","i"],["\\bAuthorization\\s*:\\s*Bearer\\s+\\S{1,256}","i"],["\\bsk-(?:proj-)?[-_A-Za-z0-9]+\\b",""],["\\b(?:ghp|github_pat|glpat|xox[baprs])-[-_A-Za-z0-9]+\\b",""]];Ae.map(([t,e])=>new RegExp(t,e)),Ae.map(([t,e])=>new RegExp(t,`${e}g`));new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0});import{dirname as $e}from"node:path";import{fileURLToPath as Le}from"node:url";$e(Le(import.meta.url));import{dirname as Ce}from"node:path";import{fileURLToPath as De}from"node:url";Ce(De(import.meta.url)),new Date(0).toISOString();var Ue="\\p{Script=Hangul}\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}\\u30fc";new RegExp(`[${Ue}]+|(?:(?![${Ue}])[\\p{L}\\p{M}\\p{N}])+`,"gu"),new RegExp(`^[${Ue}]+$`,"u"),new RegExp(`[${Ue}]`,"u"),new RegExp(`[${Ue}]`,"gu"),new RegExp(`[\\p{L}${Ue}]`,"gu");import{dirname as qe}from"node:path";import{fileURLToPath as je}from"node:url";qe(je(import.meta.url));function Fe(t){return Zt(t,"terminal-claim.json")}function Je(t,e,r){return t.runId===e.runId&&t.attempt===e.attempt&&(void 0===r||t.kind===r)}function Ge(t,e){let r=`${t}.${process.pid}.${zt()}.candidate`;!function(t,e){let r=z(t,"wx",384);try{H(r,`${JSON.stringify(e,null,2)}\n`,"utf8"),L(r)}finally{X(r)}}(r,e);try{C(r,t)}catch(t){if("EEXIST"===ze(t))return!1;throw t}finally{Ve(r)}return function(t){let e;try{e=z(t,"r")}catch(t){if("win32"===process.platform&&["EISDIR","EPERM"].includes(ze(t)??""))return;throw t}try{L(e)}catch(t){if("win32"!==process.platform||!["EPERM","EACCES","EINVAL"].includes(ze(t)??""))throw t}finally{X(e)}}(Xt(t)),!0}function He(t){let e;try{e=q(t,"utf8")}catch(t){if("ENOENT"===ze(t))return;throw t}try{return{raw:e,claim:Ke(JSON.parse(e))}}catch{return{raw:e,claim:void 0}}}async function Be(t,e,r,n,i,o){let a=await pe("reflection-finalize",{runId:i.runId});return Re(Zt(t,"terminal-claim-recovery.lock"),a,async()=>{let t=He(e);if(void 0!==t){if(t.raw!==r.raw)return t.claim;if("invalid"===n){if(void 0!==t.claim)return t.claim}else{if(void 0===t.claim)return;if("publish"!==t.claim.kind||!Ye(t.claim,o))return t.claim}Ve(e)}},{waitTimeoutMs:Number.POSITIVE_INFINITY})}function Ve(t){try{G(t)}catch(t){if("ENOENT"!==ze(t))throw t}}function Ye(t,e){return"dead"===(e.getPidLiveness??ht)(t.claimantPid)}function Ke(t){if(!function(t){return null!==t&&"object"==typeof t&&!Array.isArray(t)}(t)||1!==t.version||"publish"!==t.kind&&"abandon"!==t.kind||"string"!=typeof t.runId||!Number.isInteger(t.attempt)||!Number.isInteger(t.claimantPid)||Number(t.claimantPid)<=0)throw TypeError("Invalid run terminal claim");return{version:1,kind:t.kind,runId:t.runId,attempt:Number(t.attempt),claimantPid:Number(t.claimantPid)}}function ze(t){return t instanceof Error&&"code"in t?String(t.code):void 0}import{join as Xe}from"node:path";async function Ze(t,e,r){let n={runId:e.runId,attempt:e.attempt??1},i=await async function(t,e,r,n={},i=process.pid){let o=Fe(t),a={version:1,kind:r,runId:e.runId,attempt:e.attempt,claimantPid:i},s=0;for(;;){if(Ge(o,a))return a;let i=He(o);if(void 0===i)continue;let l=i.claim;if(void 0===l){if(s>0)throw TypeError("Invalid run terminal claim");s+=1,await(n.beforeRecovery?.("invalid"));let r=await Be(t,o,i,"invalid",e,n);if(void 0!==r)return r;continue}if(Je(l,e,r))return l;if("publish"!==l.kind||!Ye(l,n))return l;await(n.beforeRecovery?.("dead-publish"));let c=await Be(t,o,i,"dead-publish",e,n);if(void 0!==c)return c}}(t,n,"publish");Je(i,n,"publish")&&(await nt(Tt(t,"publishing.json"),{version:1,...n,finishedAt:r.finishedAt}),await async function(t,e,r,n=Re,i=pe){let o=await i("reflection-finalize",{runId:e});return n(Xe(t,"terminalization.lock"),o,r,{waitTimeoutMs:Number.POSITIVE_INFINITY})}(t,e.runId,async()=>{if(Z(Tt(t,"final.json"))||Z(Tt(t,"abandoned.json")))return;if(!Je(function(t){return Ke(JSON.parse(q(Fe(t),"utf8")))}(t),n,"publish"))return;let i=void 0!==Kt({code:r.childExit.code,stdout:q(e.stdoutPath,"utf8"),stderr:q(e.stderrPath,"utf8"),timedOut:r.timedOut});i&&void 0!==e.nextAttempt&&await it(Tt(t,"ledger.json"),{attempt:e.nextAttempt.attempt,model:e.nextAttempt.model,...void 0===e.nextAttempt.thinking?{thinking:void 0}:{thinking:e.nextAttempt.thinking},launching:!0,pid:void 0,processStart:void 0,childPid:void 0,childProcessStart:void 0}),await nt(Tt(t,"outcome.json"),r),i&&await ot(Fe(t))}))}function We(t){try{B(3,`${JSON.stringify(t)}\n`)}catch(t){if(!(t instanceof Error&&"code"in t&&["EPIPE","EBADF"].includes(String(t.code))))throw t}}var Qe=process.argv.slice(2);try{if("--child-bootstrap"===Qe[0]){if(void 0===Qe[1])throw TypeError("run directory is required");await async function(e){if(!await async function(){for await(let t of process.stdin)if(Buffer.byteLength(t)>0)return!0;return!1}())return;let r=await rt(W(e,"launch.json")),n=gt(),i=t(r.command,[...r.args],{cwd:r.cwd,env:r.env,detached:!1,stdio:["ignore","inherit","inherit"],windowsHide:!0});We({code:i.pid??null,signal:"MODEL_PID"});let o=()=>{"win32"!==n&&"win32"!==process.platform||i.kill()};process.on("SIGTERM",o),process.on("SIGINT",o);let a=vt(r.hardDeadlineAt,()=>{"win32"===n?Ot(n,i):It(process.pid,"SIGTERM")}),s=vt(r.hardDeadlineAt+r.terminationGraceMs,()=>{kt(n,process.pid)});We(await new Promise(t=>{let e=!1;i.once("error",()=>{e||(e=!0,t({code:null,signal:null}))}),i.once("close",(r,n)=>{e||(e=!0,t({code:r,signal:n}))})}).finally(()=>{a(),s()}))}(Qe[1])}else{if(void 0===Qe[0])throw TypeError("run directory is required");await async function(e){let r=W(e,"launch.json"),n=W(e,"ledger.json"),i=await rt(r),o=gt();await it(n,{launching:!1,pid:process.pid,processStart:await Pt(process.pid)});let a,s=z(i.stdoutPath,"w"),l=z(i.stderrPath,"w"),c=t(process.execPath,[Q(import.meta.url),"--child-bootstrap",e],{env:process.env,detached:!0,stdio:["pipe",s,l,"pipe"],windowsHide:!0}),u=c.pid,d="",f=c.stdio[3];null!=f&&"setEncoding"in f&&(f.setEncoding("utf8"),f.on("data",t=>{d+=t;for(let t of d.split("\n"))try{let e=JSON.parse(t);"MODEL_PID"===e.signal&&"number"==typeof e.code&&(a=e.code)}catch(t){if(!(t instanceof SyntaxError))throw t}}));let p=(t=!1)=>{try{kt(o,u,t)}catch(t){process.stderr.write(`${t instanceof Error?t.message:String(t)}\n`)}};if(process.once("exit",()=>p(!0)),process.once("SIGTERM",()=>{p(),u=void 0,process.exit(143)}),process.once("SIGINT",()=>{p(),u=void 0,process.exit(130)}),void 0===c.pid)throw Error("child bootstrap did not receive a pid");await it(n,{childPid:c.pid,childProcessStart:await Pt(c.pid)}),c.stdin?.end("1\n");let m,w=!1,h=Promise.resolve();"win32"===o&&(h=new Promise(t=>{m=t}));let y=vt(i.hardDeadlineAt,()=>{w=!0,"win32"===o?Nt(c.pid):Ot(o,c)}),g=vt(i.hardDeadlineAt+i.terminationGraceMs,()=>{kt(o,a??u),m?.()}),v=await new Promise((t,e)=>{let r=!1;c.once("error",t=>{r||(r=!0,e(t))}),c.once("close",(e,n)=>{r||(r=!0,t({code:e,signal:n}))})}),b=function(t){let e=t.trim().split("\n").at(-1);if(void 0!==e&&0!==e.length)try{let t=JSON.parse(e),r="number"==typeof t.code||null===t.code?t.code:void 0,n="string"==typeof t.signal||null===t.signal?t.signal:void 0;return void 0===r||void 0===n||"MODEL_PID"===n?void 0:{code:r,signal:n}}catch{return}}(d);"win32"===o&&w&&void 0===b&&await h,y(),g(),u=void 0,X(s),X(l);let E=function(){let t=yt()?process.env.OMO_MEMORY_SUPERVISOR_CLOCK_PATH:void 0;return void 0===t?Date.now():Et(t)}(),S=(new Date).toISOString(),x={version:1,runId:i.runId,attempt:i.attempt,finishedAt:S,childExit:b??v,timedOut:w||Number.isFinite(E)&&E>=i.hardDeadlineAt};await Ze(e,i,x),await ot(r),process.exit(0)}(Qe[0])}}catch(t){process.stderr.write(`${t instanceof Error?t.stack??t.message:String(t)}\n`),process.exitCode=1}
|