@moxxy/cli 0.13.0 → 0.13.1
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/dist/bin.js +704 -286
- package/dist/bin.js.map +1 -1
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -14,7 +14,7 @@ import Stream, { Readable as Readable$1, PassThrough as PassThrough$2, Stream as
|
|
|
14
14
|
import http, { createServer } from 'http';
|
|
15
15
|
import https from 'https';
|
|
16
16
|
import zlib from 'zlib';
|
|
17
|
-
import { webcrypto, randomBytes, createHash,
|
|
17
|
+
import { randomUUID, webcrypto, randomBytes, createHash, scryptSync, createCipheriv, createDecipheriv, createHmac, timingSafeEqual } from 'crypto';
|
|
18
18
|
import 'zod/v3';
|
|
19
19
|
import * as z4mini from 'zod/v4-mini';
|
|
20
20
|
import * as z53 from 'zod/v4';
|
|
@@ -223,6 +223,8 @@ var init_log = __esm({
|
|
|
223
223
|
this.now = opts.now ?? Date.now;
|
|
224
224
|
for (const e3 of seed)
|
|
225
225
|
this.events.push(e3);
|
|
226
|
+
if (seed.length > 0)
|
|
227
|
+
this.base = seed[0].seq;
|
|
226
228
|
}
|
|
227
229
|
get length() {
|
|
228
230
|
return this.events.length;
|
|
@@ -447,15 +449,20 @@ async function streamChildEventToParent(parentSession, parentTurnId, label3, chi
|
|
|
447
449
|
const mapped = mapChildEvent(label3, childSessionId, childEvt);
|
|
448
450
|
if (!mapped)
|
|
449
451
|
return;
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
452
|
+
try {
|
|
453
|
+
await parentSession.log.append({
|
|
454
|
+
type: "plugin_event",
|
|
455
|
+
sessionId: parentSession.id,
|
|
456
|
+
turnId: parentTurnId,
|
|
457
|
+
source: "plugin",
|
|
458
|
+
pluginId: SUBAGENT_PLUGIN_ID,
|
|
459
|
+
subtype: mapped.subtype,
|
|
460
|
+
payload: mapped.payload
|
|
461
|
+
});
|
|
462
|
+
} catch (err) {
|
|
463
|
+
process.stderr.write(`moxxy: dropped subagent progress event (${mapped.subtype}) \u2014 parent log append failed: ${err instanceof Error ? err.message : String(err)}
|
|
464
|
+
`);
|
|
465
|
+
}
|
|
459
466
|
}
|
|
460
467
|
function mapChildEvent(label3, childSessionId, childEvt) {
|
|
461
468
|
const payload = {
|
|
@@ -1561,7 +1568,16 @@ var init_providers = __esm({
|
|
|
1561
1568
|
if (instance)
|
|
1562
1569
|
this.instances.set(def.name, instance);
|
|
1563
1570
|
}
|
|
1564
|
-
/**
|
|
1571
|
+
/**
|
|
1572
|
+
* Overwrite an existing def (also drops the cached instance so the new
|
|
1573
|
+
* createClient gets called).
|
|
1574
|
+
*
|
|
1575
|
+
* Invariant: replacing the ACTIVE provider's def leaves `active` pointing at
|
|
1576
|
+
* it but with no cached instance, so `getActive()` throws until the caller
|
|
1577
|
+
* rebuilds the instance. Callers replacing the active provider MUST follow
|
|
1578
|
+
* with `setActive(name, config)` (replace can't rebuild itself — it has no
|
|
1579
|
+
* config). The sole production caller does exactly that.
|
|
1580
|
+
*/
|
|
1565
1581
|
replace(def, instance) {
|
|
1566
1582
|
this.defs.set(def.name, def);
|
|
1567
1583
|
this.instances.delete(def.name);
|
|
@@ -1654,8 +1670,12 @@ var init_modes = __esm({
|
|
|
1654
1670
|
}
|
|
1655
1671
|
replace(mode) {
|
|
1656
1672
|
this.modes.set(mode.name, mode);
|
|
1657
|
-
if (!this.active)
|
|
1673
|
+
if (!this.active) {
|
|
1658
1674
|
this.activate(mode);
|
|
1675
|
+
} else if (this.active === mode.name) {
|
|
1676
|
+
for (const fn of this.changeListeners)
|
|
1677
|
+
fn();
|
|
1678
|
+
}
|
|
1659
1679
|
}
|
|
1660
1680
|
/**
|
|
1661
1681
|
* Remove a mode. If it was active, the active slot is cleared —
|
|
@@ -1994,16 +2014,17 @@ function coerceValue(tag2, name, value, spec, errors2) {
|
|
|
1994
2014
|
}
|
|
1995
2015
|
return num;
|
|
1996
2016
|
}
|
|
2017
|
+
const decoded = decodeEntities(value);
|
|
1997
2018
|
if (spec.type === "enum") {
|
|
1998
|
-
if (!spec.values?.includes(
|
|
2019
|
+
if (!spec.values?.includes(decoded)) {
|
|
1999
2020
|
errors2.push({ message: `<${tag2}> attribute "${name}" must be one of: ${spec.values?.join(", ")}` });
|
|
2000
2021
|
}
|
|
2001
|
-
return
|
|
2022
|
+
return decoded;
|
|
2002
2023
|
}
|
|
2003
|
-
if ((name === "href" || name === "src") && !isSafeViewUrl(
|
|
2024
|
+
if ((name === "href" || name === "src") && !isSafeViewUrl(decoded, name)) {
|
|
2004
2025
|
errors2.push({ message: `<${tag2}> attribute "${name}" has a disallowed URL scheme` });
|
|
2005
2026
|
}
|
|
2006
|
-
return
|
|
2027
|
+
return decoded;
|
|
2007
2028
|
}
|
|
2008
2029
|
function coerceAttrs(b3, spec, errors2) {
|
|
2009
2030
|
const out = {};
|
|
@@ -2015,7 +2036,8 @@ function coerceAttrs(b3, spec, errors2) {
|
|
|
2015
2036
|
}
|
|
2016
2037
|
const aspec = spec?.attrs[a2.name];
|
|
2017
2038
|
if (!aspec) {
|
|
2018
|
-
|
|
2039
|
+
if (spec)
|
|
2040
|
+
errors2.push({ message: `<${b3.tag}> unknown attribute "${a2.name}"` });
|
|
2019
2041
|
continue;
|
|
2020
2042
|
}
|
|
2021
2043
|
seen.add(a2.name);
|
|
@@ -2229,10 +2251,13 @@ var init_localhost = __esm({
|
|
|
2229
2251
|
"../core/dist/tunnel/localhost.js"() {
|
|
2230
2252
|
localhostTunnel = defineTunnelProvider({
|
|
2231
2253
|
name: "localhost",
|
|
2232
|
-
open: (opts) =>
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2254
|
+
open: (opts) => {
|
|
2255
|
+
const host = opts.host.includes(":") ? `[${opts.host}]` : opts.host;
|
|
2256
|
+
return Promise.resolve({
|
|
2257
|
+
url: `http://${host}:${opts.port}`,
|
|
2258
|
+
close: () => Promise.resolve()
|
|
2259
|
+
});
|
|
2260
|
+
},
|
|
2236
2261
|
isAvailable: () => Promise.resolve(true)
|
|
2237
2262
|
});
|
|
2238
2263
|
}
|
|
@@ -3092,7 +3117,7 @@ function matchRule(rule, call, intent) {
|
|
|
3092
3117
|
if (!input || typeof input !== "object")
|
|
3093
3118
|
return false;
|
|
3094
3119
|
for (const [k3, v3] of Object.entries(rule.inputMatches)) {
|
|
3095
|
-
const candidate =
|
|
3120
|
+
const candidate = stringifyCandidate(input[k3]);
|
|
3096
3121
|
let re2;
|
|
3097
3122
|
try {
|
|
3098
3123
|
re2 = new RegExp(v3);
|
|
@@ -3108,6 +3133,18 @@ function matchRule(rule, call, intent) {
|
|
|
3108
3133
|
}
|
|
3109
3134
|
return true;
|
|
3110
3135
|
}
|
|
3136
|
+
function stringifyCandidate(value) {
|
|
3137
|
+
if (value === null || value === void 0)
|
|
3138
|
+
return "";
|
|
3139
|
+
if (typeof value === "object") {
|
|
3140
|
+
try {
|
|
3141
|
+
return JSON.stringify(value) ?? "";
|
|
3142
|
+
} catch {
|
|
3143
|
+
return String(value);
|
|
3144
|
+
}
|
|
3145
|
+
}
|
|
3146
|
+
return String(value);
|
|
3147
|
+
}
|
|
3111
3148
|
function warnBadPattern(ruleName, field, pattern, intent, err) {
|
|
3112
3149
|
const detail = err instanceof Error ? err.message : String(err);
|
|
3113
3150
|
const resolution = intent === "deny" ? "failing closed (rule still denies)" : "this field cannot match (rule will not grant)";
|
|
@@ -3760,7 +3797,16 @@ async function loadDir(dir, scope, logger) {
|
|
|
3760
3797
|
if (!entry.isFile() || !entry.name.endsWith(".md"))
|
|
3761
3798
|
continue;
|
|
3762
3799
|
const full = path3.join(dir, entry.name);
|
|
3763
|
-
|
|
3800
|
+
let raw;
|
|
3801
|
+
try {
|
|
3802
|
+
raw = await promises.readFile(full, "utf8");
|
|
3803
|
+
} catch (err) {
|
|
3804
|
+
logger?.warn("skill: unreadable file, skipping", {
|
|
3805
|
+
path: full,
|
|
3806
|
+
error: err instanceof Error ? err.message : String(err)
|
|
3807
|
+
});
|
|
3808
|
+
continue;
|
|
3809
|
+
}
|
|
3764
3810
|
const { frontmatter, body } = parseSkillFile(raw);
|
|
3765
3811
|
const parsed = skillFrontmatterSchema.safeParse(frontmatter);
|
|
3766
3812
|
if (!parsed.success) {
|
|
@@ -4211,6 +4257,17 @@ var init_persistence = __esm({
|
|
|
4211
4257
|
this.indexUpdateScheduled = false;
|
|
4212
4258
|
await this.writeIndex();
|
|
4213
4259
|
}
|
|
4260
|
+
/**
|
|
4261
|
+
* Resolve once every event-log write queued so far has settled. Appends are
|
|
4262
|
+
* enqueued fire-and-forget (`enqueueAppend`), so callers that need to observe
|
|
4263
|
+
* the on-disk result of prior appends — graceful shutdown, or a test that
|
|
4264
|
+
* mutates the filesystem between writes — await this to drain the queue
|
|
4265
|
+
* rather than guessing at timing. Enqueues a no-op at the tail of the same
|
|
4266
|
+
* mutex, so it can only resolve after all earlier appends/truncates have run.
|
|
4267
|
+
*/
|
|
4268
|
+
async settleWrites() {
|
|
4269
|
+
await this.writeQueue.run(() => void 0);
|
|
4270
|
+
}
|
|
4214
4271
|
/**
|
|
4215
4272
|
* Manually update header fields (provider/model) when the user
|
|
4216
4273
|
* switches mid-session. The /model picker calls this so the index
|
|
@@ -4233,7 +4290,7 @@ var init_persistence = __esm({
|
|
|
4233
4290
|
};
|
|
4234
4291
|
this.scheduleIndexWrite();
|
|
4235
4292
|
const line = JSON.stringify(event) + "\n";
|
|
4236
|
-
void this.writeQueue.run(() => promises.appendFile(this.logPath, line, "utf8")).then(() => this.noteWriteOk()).catch((err) => this.noteWriteFailure("append", err));
|
|
4293
|
+
void this.writeQueue.run(() => this.ensureReady().then(() => promises.appendFile(this.logPath, line, "utf8"))).then(() => this.noteWriteOk()).catch((err) => this.noteWriteFailure("append", err));
|
|
4237
4294
|
}
|
|
4238
4295
|
/**
|
|
4239
4296
|
* True while event-log writes are failing (history is no longer being
|
|
@@ -4274,7 +4331,7 @@ var init_persistence = __esm({
|
|
|
4274
4331
|
lastActivity: (/* @__PURE__ */ new Date()).toISOString()
|
|
4275
4332
|
};
|
|
4276
4333
|
this.scheduleIndexWrite();
|
|
4277
|
-
void this.writeQueue.run(() => promises.writeFile(this.logPath, "", "utf8")).then(() => this.noteWriteOk()).catch((err) => this.noteWriteFailure("truncate", err));
|
|
4334
|
+
void this.writeQueue.run(() => this.ensureReady().then(() => promises.writeFile(this.logPath, "", "utf8"))).then(() => this.noteWriteOk()).catch((err) => this.noteWriteFailure("truncate", err));
|
|
4278
4335
|
}
|
|
4279
4336
|
scheduleIndexWrite() {
|
|
4280
4337
|
if (this.indexUpdateScheduled)
|
|
@@ -30607,7 +30664,7 @@ var require_api = __commonJS({
|
|
|
30607
30664
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30608
30665
|
exports.Api = void 0;
|
|
30609
30666
|
var client_js_1 = require_client();
|
|
30610
|
-
var
|
|
30667
|
+
var Api2 = class {
|
|
30611
30668
|
/**
|
|
30612
30669
|
* Constructs a new instance of `Api`. It is independent from all other
|
|
30613
30670
|
* instances of this class. For example, this lets you install a custom set
|
|
@@ -32942,7 +32999,7 @@ var require_api = __commonJS({
|
|
|
32942
32999
|
return this.raw.getGameHighScores({ inline_message_id, user_id }, signal);
|
|
32943
33000
|
}
|
|
32944
33001
|
};
|
|
32945
|
-
exports.Api =
|
|
33002
|
+
exports.Api = Api2;
|
|
32946
33003
|
}
|
|
32947
33004
|
});
|
|
32948
33005
|
|
|
@@ -32986,7 +33043,7 @@ var require_bot = __commonJS({
|
|
|
32986
33043
|
"chat_boost",
|
|
32987
33044
|
"removed_chat_boost"
|
|
32988
33045
|
];
|
|
32989
|
-
var
|
|
33046
|
+
var Bot2 = class extends composer_js_1.Composer {
|
|
32990
33047
|
/**
|
|
32991
33048
|
* Creates a new Bot with the given token.
|
|
32992
33049
|
*
|
|
@@ -33352,7 +33409,7 @@ var require_bot = __commonJS({
|
|
|
33352
33409
|
await sleep7(sleepSeconds);
|
|
33353
33410
|
}
|
|
33354
33411
|
};
|
|
33355
|
-
exports.Bot =
|
|
33412
|
+
exports.Bot = Bot2;
|
|
33356
33413
|
async function withRetries(task, signal) {
|
|
33357
33414
|
const INITIAL_DELAY = 50;
|
|
33358
33415
|
let lastDelay = INITIAL_DELAY;
|
|
@@ -49252,11 +49309,25 @@ function renderResult(content, isError) {
|
|
|
49252
49309
|
else if (block.type === "image")
|
|
49253
49310
|
parts.push(`[image:${block.mimeType}]`);
|
|
49254
49311
|
else if (block.type === "resource")
|
|
49255
|
-
parts.push(
|
|
49312
|
+
parts.push(renderResource(block.resource));
|
|
49256
49313
|
}
|
|
49257
49314
|
const text = parts.join("\n");
|
|
49258
49315
|
return isError ? `[error] ${text}` : text;
|
|
49259
49316
|
}
|
|
49317
|
+
function renderResource(resource) {
|
|
49318
|
+
if (resource && typeof resource === "object") {
|
|
49319
|
+
const r2 = resource;
|
|
49320
|
+
if (typeof r2.text === "string")
|
|
49321
|
+
return r2.text;
|
|
49322
|
+
const meta = [
|
|
49323
|
+
typeof r2.uri === "string" ? r2.uri : null,
|
|
49324
|
+
typeof r2.mimeType === "string" ? r2.mimeType : null
|
|
49325
|
+
].filter((v3) => v3 !== null);
|
|
49326
|
+
if (meta.length > 0)
|
|
49327
|
+
return `[resource:${meta.join(" ")}]`;
|
|
49328
|
+
}
|
|
49329
|
+
return `[resource]`;
|
|
49330
|
+
}
|
|
49260
49331
|
var MCP_CALL_TIMEOUT_MS;
|
|
49261
49332
|
var init_wrap = __esm({
|
|
49262
49333
|
"../plugin-mcp/dist/wrap.js"() {
|
|
@@ -49264,13 +49335,16 @@ var init_wrap = __esm({
|
|
|
49264
49335
|
MCP_CALL_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
49265
49336
|
}
|
|
49266
49337
|
});
|
|
49267
|
-
var mcpStoredServerSchema,
|
|
49338
|
+
var mcpStoredServerSchema, mcpStoredConfigRootSchema;
|
|
49268
49339
|
var init_config_schema = __esm({
|
|
49269
49340
|
"../plugin-mcp/dist/admin/config-schema.js"() {
|
|
49270
49341
|
mcpStoredServerSchema = z$1.object({
|
|
49271
49342
|
name: z$1.string().min(1)
|
|
49272
49343
|
}).passthrough();
|
|
49273
|
-
|
|
49344
|
+
mcpStoredConfigRootSchema = z$1.object({
|
|
49345
|
+
servers: z$1.array(z$1.unknown())
|
|
49346
|
+
}).passthrough();
|
|
49347
|
+
z$1.object({
|
|
49274
49348
|
servers: z$1.array(mcpStoredServerSchema)
|
|
49275
49349
|
}).passthrough().transform((value) => value);
|
|
49276
49350
|
}
|
|
@@ -49281,10 +49355,17 @@ function mcpConfigPath() {
|
|
|
49281
49355
|
async function readMcpConfig() {
|
|
49282
49356
|
try {
|
|
49283
49357
|
const raw = await promises.readFile(mcpConfigPath(), "utf8");
|
|
49284
|
-
const
|
|
49285
|
-
if (
|
|
49286
|
-
return
|
|
49358
|
+
const root = mcpStoredConfigRootSchema.safeParse(JSON.parse(raw));
|
|
49359
|
+
if (!root.success) {
|
|
49360
|
+
return { servers: [] };
|
|
49361
|
+
}
|
|
49362
|
+
const servers = [];
|
|
49363
|
+
for (const entry of root.data.servers) {
|
|
49364
|
+
const parsed = mcpStoredServerSchema.safeParse(entry);
|
|
49365
|
+
if (parsed.success)
|
|
49366
|
+
servers.push(parsed.data);
|
|
49287
49367
|
}
|
|
49368
|
+
return { servers };
|
|
49288
49369
|
} catch {
|
|
49289
49370
|
}
|
|
49290
49371
|
return { servers: [] };
|
|
@@ -49917,23 +49998,19 @@ __export(dist_exports2, {
|
|
|
49917
49998
|
});
|
|
49918
49999
|
async function createMcpPlugin(opts) {
|
|
49919
50000
|
const factory2 = opts.clientFactory ?? defaultClientFactory;
|
|
49920
|
-
const
|
|
49921
|
-
const
|
|
49922
|
-
|
|
49923
|
-
|
|
49924
|
-
|
|
49925
|
-
|
|
49926
|
-
|
|
49927
|
-
|
|
49928
|
-
|
|
49929
|
-
|
|
49930
|
-
});
|
|
49931
|
-
tools.push(...wrapped);
|
|
49932
|
-
}
|
|
49933
|
-
} catch (err) {
|
|
49934
|
-
await Promise.allSettled(clients.map((c2) => c2.close()));
|
|
49935
|
-
throw err;
|
|
50001
|
+
const opened = [];
|
|
50002
|
+
const results = await Promise.allSettled(opts.servers.map(async (server) => {
|
|
50003
|
+
const client = await factory2(server, opts);
|
|
50004
|
+
opened.push(client);
|
|
50005
|
+
return wrapMcpServerTools({ server, client, toolNamePrefix: opts.toolNamePrefix });
|
|
50006
|
+
}));
|
|
50007
|
+
const failure = results.find((r2) => r2.status === "rejected");
|
|
50008
|
+
if (failure) {
|
|
50009
|
+
await Promise.allSettled(opened.map((c2) => c2.close()));
|
|
50010
|
+
throw failure.reason;
|
|
49936
50011
|
}
|
|
50012
|
+
const tools = results.flatMap((r2) => r2.value);
|
|
50013
|
+
const clients = opened;
|
|
49937
50014
|
return definePlugin({
|
|
49938
50015
|
name: "@moxxy/plugin-mcp",
|
|
49939
50016
|
version: "0.0.0",
|
|
@@ -51297,7 +51374,7 @@ var require_react_development = __commonJS({
|
|
|
51297
51374
|
var dispatcher = resolveDispatcher();
|
|
51298
51375
|
return dispatcher.useRef(initialValue);
|
|
51299
51376
|
}
|
|
51300
|
-
function
|
|
51377
|
+
function useEffect18(create2, deps) {
|
|
51301
51378
|
var dispatcher = resolveDispatcher();
|
|
51302
51379
|
return dispatcher.useEffect(create2, deps);
|
|
51303
51380
|
}
|
|
@@ -52080,7 +52157,7 @@ var require_react_development = __commonJS({
|
|
|
52080
52157
|
exports.useContext = useContext7;
|
|
52081
52158
|
exports.useDebugValue = useDebugValue;
|
|
52082
52159
|
exports.useDeferredValue = useDeferredValue;
|
|
52083
|
-
exports.useEffect =
|
|
52160
|
+
exports.useEffect = useEffect18;
|
|
52084
52161
|
exports.useId = useId;
|
|
52085
52162
|
exports.useImperativeHandle = useImperativeHandle;
|
|
52086
52163
|
exports.useInsertionEffect = useInsertionEffect;
|
|
@@ -84849,7 +84926,11 @@ function parseInputChunk(chunk, ctx) {
|
|
|
84849
84926
|
continue;
|
|
84850
84927
|
}
|
|
84851
84928
|
if (c2 === "") {
|
|
84852
|
-
|
|
84929
|
+
if (ctx.onInterrupt)
|
|
84930
|
+
ctx.onInterrupt();
|
|
84931
|
+
else
|
|
84932
|
+
process.exit(0);
|
|
84933
|
+
return remainder;
|
|
84853
84934
|
}
|
|
84854
84935
|
if (c2 === "\x7F" || c2 === "\b") {
|
|
84855
84936
|
ctx.dispatch({ type: "delete-back" });
|
|
@@ -84973,7 +85054,7 @@ var init_PromptInput = __esm({
|
|
|
84973
85054
|
init_external_insert();
|
|
84974
85055
|
init_reducer();
|
|
84975
85056
|
init_parse_input();
|
|
84976
|
-
PromptInput = ({ onSubmit, disabled, placeholder, slashCommands = BUILTIN_SLASH_COMMANDS, onPasteText, commandHotkeys, onShiftTab, externalInsert }) => {
|
|
85057
|
+
PromptInput = ({ onSubmit, disabled, placeholder, slashCommands = BUILTIN_SLASH_COMMANDS, onPasteText, commandHotkeys, onShiftTab, onInterrupt, externalInsert }) => {
|
|
84977
85058
|
const [state, dispatch3] = (0, import_react26.useReducer)(reducer, INITIAL);
|
|
84978
85059
|
const [slashCursor, setSlashCursor] = import_react26.default.useState(0);
|
|
84979
85060
|
const stateRef = (0, import_react26.useRef)(state);
|
|
@@ -85033,6 +85114,8 @@ var init_PromptInput = __esm({
|
|
|
85033
85114
|
commandHotkeysRef.current = commandHotkeys;
|
|
85034
85115
|
const onShiftTabRef = (0, import_react26.useRef)(onShiftTab);
|
|
85035
85116
|
onShiftTabRef.current = onShiftTab;
|
|
85117
|
+
const onInterruptRef = (0, import_react26.useRef)(onInterrupt);
|
|
85118
|
+
onInterruptRef.current = onInterrupt;
|
|
85036
85119
|
const lastExternalInsertIdRef = (0, import_react26.useRef)(null);
|
|
85037
85120
|
(0, import_react26.useEffect)(() => {
|
|
85038
85121
|
const decision = nextExternalInsertAction(lastExternalInsertIdRef.current, externalInsert);
|
|
@@ -85058,6 +85141,13 @@ var init_PromptInput = __esm({
|
|
|
85058
85141
|
onSlashDown: () => setSlashCursor((c2) => Math.min(slashMatchesRef.current.length - 1, c2 + 1)),
|
|
85059
85142
|
onSlashAccept: handleSlashAccept,
|
|
85060
85143
|
onShiftTab: () => onShiftTabRef.current?.(),
|
|
85144
|
+
onInterrupt: () => {
|
|
85145
|
+
const fn = onInterruptRef.current;
|
|
85146
|
+
if (fn)
|
|
85147
|
+
fn();
|
|
85148
|
+
else
|
|
85149
|
+
process.exit(0);
|
|
85150
|
+
},
|
|
85061
85151
|
onPasteText: (text) => onPasteTextRef.current?.(text) ?? text,
|
|
85062
85152
|
slashOpen: false,
|
|
85063
85153
|
bufferRef: { current: { buffer: "", cursor: 0 } },
|
|
@@ -87122,8 +87212,37 @@ var init_image_attachments = __esm({
|
|
|
87122
87212
|
};
|
|
87123
87213
|
}
|
|
87124
87214
|
});
|
|
87215
|
+
function reapStale(dir, now = Date.now()) {
|
|
87216
|
+
let entries;
|
|
87217
|
+
try {
|
|
87218
|
+
entries = readdirSync(dir);
|
|
87219
|
+
} catch {
|
|
87220
|
+
return;
|
|
87221
|
+
}
|
|
87222
|
+
for (const name of entries) {
|
|
87223
|
+
const m3 = CLIP_NAME_RE.exec(name);
|
|
87224
|
+
if (!m3)
|
|
87225
|
+
continue;
|
|
87226
|
+
const stamp = Number(m3[1]);
|
|
87227
|
+
let age = Number.isFinite(stamp) ? now - stamp : Number.NaN;
|
|
87228
|
+
if (!Number.isFinite(age)) {
|
|
87229
|
+
try {
|
|
87230
|
+
age = now - statSync(path3__default.join(dir, name)).mtimeMs;
|
|
87231
|
+
} catch {
|
|
87232
|
+
continue;
|
|
87233
|
+
}
|
|
87234
|
+
}
|
|
87235
|
+
if (age > CACHE_TTL_MS) {
|
|
87236
|
+
try {
|
|
87237
|
+
unlinkSync(path3__default.join(dir, name));
|
|
87238
|
+
} catch {
|
|
87239
|
+
}
|
|
87240
|
+
}
|
|
87241
|
+
}
|
|
87242
|
+
}
|
|
87125
87243
|
function ensureCacheDir() {
|
|
87126
87244
|
mkdirSync(CACHE_DIR, { recursive: true });
|
|
87245
|
+
reapStale(CACHE_DIR, Date.now());
|
|
87127
87246
|
return CACHE_DIR;
|
|
87128
87247
|
}
|
|
87129
87248
|
function nextCachePath() {
|
|
@@ -87208,10 +87327,12 @@ function readClipboardImageSync() {
|
|
|
87208
87327
|
return readClipboardImageLinux();
|
|
87209
87328
|
return null;
|
|
87210
87329
|
}
|
|
87211
|
-
var CACHE_DIR;
|
|
87330
|
+
var CACHE_DIR, CACHE_TTL_MS, CLIP_NAME_RE;
|
|
87212
87331
|
var init_clipboard_image = __esm({
|
|
87213
87332
|
"../plugin-cli/dist/clipboard-image.js"() {
|
|
87214
87333
|
CACHE_DIR = moxxyPath("image-cache");
|
|
87334
|
+
CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
87335
|
+
CLIP_NAME_RE = /^clip-(\d+)-[a-z0-9]+\.png$/;
|
|
87215
87336
|
}
|
|
87216
87337
|
});
|
|
87217
87338
|
|
|
@@ -89063,11 +89184,11 @@ var init_OverlayOrNotice = __esm({
|
|
|
89063
89184
|
});
|
|
89064
89185
|
|
|
89065
89186
|
// ../plugin-cli/dist/components/PermissionDialog.js
|
|
89066
|
-
var import_jsx_runtime32,
|
|
89187
|
+
var import_jsx_runtime32, PermissionDialog;
|
|
89067
89188
|
var init_PermissionDialog = __esm({
|
|
89068
89189
|
async "../plugin-cli/dist/components/PermissionDialog.js"() {
|
|
89069
89190
|
import_jsx_runtime32 = __toESM(require_jsx_runtime());
|
|
89070
|
-
|
|
89191
|
+
__toESM(require_react());
|
|
89071
89192
|
await init_build2();
|
|
89072
89193
|
init_theme();
|
|
89073
89194
|
await init_Modal();
|
|
@@ -89083,8 +89204,6 @@ var init_PermissionDialog = __esm({
|
|
|
89083
89204
|
else if (ch === "n" || key.escape)
|
|
89084
89205
|
onDecide({ mode: "deny", reason: "user declined" });
|
|
89085
89206
|
});
|
|
89086
|
-
(0, import_react60.useEffect)(() => {
|
|
89087
|
-
}, []);
|
|
89088
89207
|
const title = queueDepth > 0 ? `Tool permission requested (${queueDepth} more queued)` : "Tool permission requested";
|
|
89089
89208
|
return (0, import_jsx_runtime32.jsxs)(Modal, { title, hints: "y allow \xB7 a session \xB7 p always \xB7 n deny", children: [(0, import_jsx_runtime32.jsxs)(Text, { children: ["Tool: ", (0, import_jsx_runtime32.jsx)(Text, { bold: true, children: call.name }), toolDescription ? (0, import_jsx_runtime32.jsxs)(Text, { dimColor: true, children: [" \u2014 ", toolDescription] }) : null] }), (0, import_jsx_runtime32.jsxs)(Text, { dimColor: true, children: ["Input: ", JSON.stringify(call.input).slice(0, 200)] }), (0, import_jsx_runtime32.jsxs)(Text, { children: [(0, import_jsx_runtime32.jsx)(Text, { children: "[y]" }), (0, import_jsx_runtime32.jsx)(Text, { dimColor: true, children: " allow once \xB7 " }), (0, import_jsx_runtime32.jsx)(Text, { children: "[a]" }), (0, import_jsx_runtime32.jsx)(Text, { dimColor: true, children: " allow session \xB7 " }), (0, import_jsx_runtime32.jsx)(Text, { children: "[p]" }), (0, import_jsx_runtime32.jsx)(Text, { dimColor: true, children: " always \xB7 " }), (0, import_jsx_runtime32.jsx)(Text, { color: Colors.danger, children: "[n]" }), (0, import_jsx_runtime32.jsx)(Text, { dimColor: true, children: " deny" })] })] });
|
|
89090
89209
|
};
|
|
@@ -89092,6 +89211,11 @@ var init_PermissionDialog = __esm({
|
|
|
89092
89211
|
});
|
|
89093
89212
|
|
|
89094
89213
|
// ../plugin-cli/dist/components/ApprovalDialog.js
|
|
89214
|
+
function jkScrolls(letter, renderedLineCount, options) {
|
|
89215
|
+
if (renderedLineCount <= MAX_BODY_LINES)
|
|
89216
|
+
return false;
|
|
89217
|
+
return !options.some((o2) => o2.hotkey === letter);
|
|
89218
|
+
}
|
|
89095
89219
|
function isDiffBody(body) {
|
|
89096
89220
|
return /```diff\b/.test(body) || /^\s*diff --git\b/m.test(body);
|
|
89097
89221
|
}
|
|
@@ -89148,6 +89272,10 @@ var init_ApprovalDialog = __esm({
|
|
|
89148
89272
|
const [cursor, setCursor] = (0, import_react61.useState)(initialCursor);
|
|
89149
89273
|
const [textEntry, setTextEntry] = (0, import_react61.useState)(null);
|
|
89150
89274
|
const [scrollOffset, setScrollOffset] = (0, import_react61.useState)(0);
|
|
89275
|
+
const rawLines = request.body.split("\n");
|
|
89276
|
+
const diffMode = isDiffBody(request.body);
|
|
89277
|
+
const rendered = diffMode ? renderDiffLines(rawLines) : rawLines.map((text) => ({ text }));
|
|
89278
|
+
const scrollClaims = (letter) => jkScrolls(letter, rendered.length, request.options);
|
|
89151
89279
|
use_input_default((input, key) => {
|
|
89152
89280
|
if (textEntry) {
|
|
89153
89281
|
if (key.return) {
|
|
@@ -89171,11 +89299,12 @@ var init_ApprovalDialog = __esm({
|
|
|
89171
89299
|
}
|
|
89172
89300
|
return;
|
|
89173
89301
|
}
|
|
89174
|
-
|
|
89175
|
-
|
|
89302
|
+
const maxScroll = Math.max(0, rendered.length - MAX_BODY_LINES);
|
|
89303
|
+
if (input === "j" && scrollClaims("j") || key.pageDown) {
|
|
89304
|
+
setScrollOffset((o2) => Math.min(maxScroll, o2 + Math.max(1, Math.floor(MAX_BODY_LINES / 2))));
|
|
89176
89305
|
return;
|
|
89177
89306
|
}
|
|
89178
|
-
if (input === "k" || key.pageUp) {
|
|
89307
|
+
if (input === "k" && scrollClaims("k") || key.pageUp) {
|
|
89179
89308
|
setScrollOffset((o2) => Math.max(0, o2 - Math.max(1, Math.floor(MAX_BODY_LINES / 2))));
|
|
89180
89309
|
return;
|
|
89181
89310
|
}
|
|
@@ -89223,9 +89352,6 @@ var init_ApprovalDialog = __esm({
|
|
|
89223
89352
|
}
|
|
89224
89353
|
onDecide({ optionId: id });
|
|
89225
89354
|
};
|
|
89226
|
-
const rawLines = request.body.split("\n");
|
|
89227
|
-
const diffMode = isDiffBody(request.body);
|
|
89228
|
-
const rendered = diffMode ? renderDiffLines(rawLines) : rawLines.map((text) => ({ text }));
|
|
89229
89355
|
const maxOffset = Math.max(0, rendered.length - MAX_BODY_LINES);
|
|
89230
89356
|
const offset = Math.min(scrollOffset, maxOffset);
|
|
89231
89357
|
const visible = rendered.slice(offset, offset + MAX_BODY_LINES);
|
|
@@ -113398,7 +113524,7 @@ async function provisionWorkspace(opts) {
|
|
|
113398
113524
|
if (install.code !== 0) {
|
|
113399
113525
|
const loose = await run("pnpm", ["install"], dir);
|
|
113400
113526
|
if (loose.code !== 0)
|
|
113401
|
-
return { ok: false, message: `pnpm install failed: ${trunc(
|
|
113527
|
+
return { ok: false, message: `pnpm install failed: ${trunc(loose.output, 400)}`, repoDir: dir };
|
|
113402
113528
|
}
|
|
113403
113529
|
return { ok: true, message: "workspace provisioned", repoDir: dir };
|
|
113404
113530
|
}
|
|
@@ -114031,6 +114157,23 @@ async function escalate(deps, ctx, journal, reason) {
|
|
|
114031
114157
|
}
|
|
114032
114158
|
|
|
114033
114159
|
// src/argv.ts
|
|
114160
|
+
var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
114161
|
+
"help",
|
|
114162
|
+
"h",
|
|
114163
|
+
"version",
|
|
114164
|
+
"v",
|
|
114165
|
+
"yes",
|
|
114166
|
+
"y",
|
|
114167
|
+
"verbose",
|
|
114168
|
+
"allow-all",
|
|
114169
|
+
"standalone",
|
|
114170
|
+
"attach",
|
|
114171
|
+
"reload",
|
|
114172
|
+
"all",
|
|
114173
|
+
"stop",
|
|
114174
|
+
"status",
|
|
114175
|
+
"background"
|
|
114176
|
+
]);
|
|
114034
114177
|
function parseArgv(argv) {
|
|
114035
114178
|
const result = { command: "", flags: {}, positional: [] };
|
|
114036
114179
|
if (argv.length === 0) {
|
|
@@ -114053,7 +114196,7 @@ function parseArgv(argv) {
|
|
|
114053
114196
|
} else {
|
|
114054
114197
|
const key = a2.slice(2);
|
|
114055
114198
|
const next = argv[i2 + 1];
|
|
114056
|
-
if (next && !next.startsWith("-")) {
|
|
114199
|
+
if (next && !next.startsWith("-") && !BOOLEAN_FLAGS.has(key)) {
|
|
114057
114200
|
result.flags[key] = next;
|
|
114058
114201
|
i2++;
|
|
114059
114202
|
} else {
|
|
@@ -114063,7 +114206,7 @@ function parseArgv(argv) {
|
|
|
114063
114206
|
} else if (a2.startsWith("-")) {
|
|
114064
114207
|
const key = a2.slice(1);
|
|
114065
114208
|
const next = argv[i2 + 1];
|
|
114066
|
-
if (next && !next.startsWith("-")) {
|
|
114209
|
+
if (next && !next.startsWith("-") && !BOOLEAN_FLAGS.has(key)) {
|
|
114067
114210
|
result.flags[key] = next;
|
|
114068
114211
|
i2++;
|
|
114069
114212
|
} else {
|
|
@@ -114317,17 +114460,19 @@ async function loadOne(filePath) {
|
|
|
114317
114460
|
}
|
|
114318
114461
|
return parsed.data;
|
|
114319
114462
|
}
|
|
114320
|
-
var cachedJiti =
|
|
114463
|
+
var cachedJiti = /* @__PURE__ */ new Map();
|
|
114321
114464
|
async function getJiti2(cwd2) {
|
|
114322
|
-
|
|
114323
|
-
|
|
114465
|
+
const existing = cachedJiti.get(cwd2);
|
|
114466
|
+
if (existing)
|
|
114467
|
+
return existing;
|
|
114324
114468
|
try {
|
|
114325
114469
|
const mod = await Promise.resolve().then(() => (init_jiti(), jiti_exports));
|
|
114326
114470
|
const factory2 = mod.createJiti ?? mod.default;
|
|
114327
114471
|
if (!factory2)
|
|
114328
114472
|
return null;
|
|
114329
|
-
|
|
114330
|
-
|
|
114473
|
+
const instance = factory2(cwd2, { interopDefault: true });
|
|
114474
|
+
cachedJiti.set(cwd2, instance);
|
|
114475
|
+
return instance;
|
|
114331
114476
|
} catch {
|
|
114332
114477
|
return null;
|
|
114333
114478
|
}
|
|
@@ -114586,9 +114731,22 @@ function decrypt(blob, key) {
|
|
|
114586
114731
|
return plaintext.toString("utf8");
|
|
114587
114732
|
}
|
|
114588
114733
|
function randomCode(digits = 6) {
|
|
114589
|
-
|
|
114590
|
-
|
|
114591
|
-
|
|
114734
|
+
if (!Number.isInteger(digits) || digits < 1) {
|
|
114735
|
+
throw new Error(`randomCode: digits must be a positive integer, got ${digits}`);
|
|
114736
|
+
}
|
|
114737
|
+
const modulus = 10n ** BigInt(digits);
|
|
114738
|
+
const byteLen = Math.ceil(digits * Math.log2(10) / 8) + 1;
|
|
114739
|
+
const space = 1n << BigInt(byteLen * 8);
|
|
114740
|
+
const limit2 = space - space % modulus;
|
|
114741
|
+
for (; ; ) {
|
|
114742
|
+
let value = 0n;
|
|
114743
|
+
for (const byte of randomBytes(byteLen)) {
|
|
114744
|
+
value = value << 8n | BigInt(byte);
|
|
114745
|
+
}
|
|
114746
|
+
if (value < limit2) {
|
|
114747
|
+
return (value % modulus).toString().padStart(digits, "0");
|
|
114748
|
+
}
|
|
114749
|
+
}
|
|
114592
114750
|
}
|
|
114593
114751
|
|
|
114594
114752
|
// ../plugin-vault/dist/keysource.js
|
|
@@ -114609,10 +114767,10 @@ function createCombinedKeySource(opts) {
|
|
|
114609
114767
|
},
|
|
114610
114768
|
async obtain(salt) {
|
|
114611
114769
|
const envName = opts.envVar ?? "MOXXY_VAULT_PASSPHRASE";
|
|
114612
|
-
const
|
|
114613
|
-
if (
|
|
114770
|
+
const envValue2 = process.env[envName];
|
|
114771
|
+
if (envValue2) {
|
|
114614
114772
|
resolvedName = `env:${envName}`;
|
|
114615
|
-
return deriveKey(
|
|
114773
|
+
return deriveKey(envValue2, salt);
|
|
114616
114774
|
}
|
|
114617
114775
|
if (!opts.disableKeytar) {
|
|
114618
114776
|
const fromKeychain = await tryKeychainGet();
|
|
@@ -115404,7 +115562,7 @@ async function safeRead(filePath) {
|
|
|
115404
115562
|
const result = memoryFrontmatterSchema.safeParse(parsed.frontmatter);
|
|
115405
115563
|
if (!result.success)
|
|
115406
115564
|
return null;
|
|
115407
|
-
return { frontmatter: result.data, body: parsed.body };
|
|
115565
|
+
return { frontmatter: result.data, body: parsed.body.trim() };
|
|
115408
115566
|
} catch {
|
|
115409
115567
|
return null;
|
|
115410
115568
|
}
|
|
@@ -117036,6 +117194,14 @@ async function syncSkillSchedules(registry, store) {
|
|
|
117036
117194
|
}
|
|
117037
117195
|
|
|
117038
117196
|
// ../plugin-scheduler/dist/poller.js
|
|
117197
|
+
function cronBaseline(entry) {
|
|
117198
|
+
return entry.lastRunAt ?? entry.createdAt;
|
|
117199
|
+
}
|
|
117200
|
+
function nextCronFire(entry) {
|
|
117201
|
+
if (!entry.cron)
|
|
117202
|
+
return null;
|
|
117203
|
+
return nextFireTime(entry.cron, new Date(cronBaseline(entry)), entry.timeZone);
|
|
117204
|
+
}
|
|
117039
117205
|
function isDue(entry, now) {
|
|
117040
117206
|
if (!entry.enabled)
|
|
117041
117207
|
return false;
|
|
@@ -117044,8 +117210,7 @@ function isDue(entry, now) {
|
|
|
117044
117210
|
}
|
|
117045
117211
|
if (!entry.cron)
|
|
117046
117212
|
return false;
|
|
117047
|
-
const
|
|
117048
|
-
const next = nextFireTime(entry.cron, new Date(since), entry.timeZone);
|
|
117213
|
+
const next = nextCronFire(entry);
|
|
117049
117214
|
if (!next)
|
|
117050
117215
|
return false;
|
|
117051
117216
|
return next.getTime() <= now;
|
|
@@ -117079,23 +117244,12 @@ var SchedulerPoller = class {
|
|
|
117079
117244
|
await this.tickPromise.catch(() => void 0);
|
|
117080
117245
|
}
|
|
117081
117246
|
/** Fire any due schedules right now, ignoring the timer cadence.
|
|
117082
|
-
* Returns the number of schedules that
|
|
117247
|
+
* Returns the number of due schedules that were attempted — counted at the
|
|
117248
|
+
* attempt point, so a schedule that fired but failed mid-run (e.g. a
|
|
117249
|
+
* store.update throw) is still counted, unlike piggy-backing on onFired
|
|
117250
|
+
* (which only fires on a clean run). */
|
|
117083
117251
|
async tickOnce() {
|
|
117084
|
-
|
|
117085
|
-
const original = this.opts.onFired;
|
|
117086
|
-
let wrapped;
|
|
117087
|
-
if (original) {
|
|
117088
|
-
wrapped = (entry, outcome) => {
|
|
117089
|
-
count += 1;
|
|
117090
|
-
original(entry, outcome);
|
|
117091
|
-
};
|
|
117092
|
-
} else {
|
|
117093
|
-
wrapped = () => {
|
|
117094
|
-
count += 1;
|
|
117095
|
-
};
|
|
117096
|
-
}
|
|
117097
|
-
await this.tickWith(wrapped);
|
|
117098
|
-
return count;
|
|
117252
|
+
return this.tickWith(this.opts.onFired);
|
|
117099
117253
|
}
|
|
117100
117254
|
async tick() {
|
|
117101
117255
|
if (!this.running)
|
|
@@ -117120,11 +117274,13 @@ var SchedulerPoller = class {
|
|
|
117120
117274
|
this.opts.logger?.error?.("scheduler: failed to read store", {
|
|
117121
117275
|
err: err instanceof Error ? err.message : String(err)
|
|
117122
117276
|
});
|
|
117123
|
-
return;
|
|
117277
|
+
return 0;
|
|
117124
117278
|
}
|
|
117279
|
+
let attempted = 0;
|
|
117125
117280
|
for (const entry of schedules) {
|
|
117126
117281
|
if (!isDue(entry, now))
|
|
117127
117282
|
continue;
|
|
117283
|
+
attempted += 1;
|
|
117128
117284
|
try {
|
|
117129
117285
|
const outcome = await runSchedule(entry, this.opts.runner, this.opts.store, this.opts.inbox);
|
|
117130
117286
|
this.opts.logger?.info?.("scheduler: fired", {
|
|
@@ -117140,6 +117296,7 @@ var SchedulerPoller = class {
|
|
|
117140
117296
|
});
|
|
117141
117297
|
}
|
|
117142
117298
|
}
|
|
117299
|
+
return attempted;
|
|
117143
117300
|
}
|
|
117144
117301
|
};
|
|
117145
117302
|
|
|
@@ -117382,11 +117539,9 @@ var cronOrTimestamp = z$1.object({
|
|
|
117382
117539
|
message: "provide either `cron` or `runAt`"
|
|
117383
117540
|
});
|
|
117384
117541
|
function describeEntry(entry) {
|
|
117385
|
-
const now = Date.now();
|
|
117386
117542
|
let nextFireAt = null;
|
|
117387
117543
|
if (entry.cron) {
|
|
117388
|
-
const
|
|
117389
|
-
const next = nextFireTime(entry.cron, new Date(since), entry.timeZone);
|
|
117544
|
+
const next = nextCronFire(entry);
|
|
117390
117545
|
nextFireAt = next ? next.getTime() : null;
|
|
117391
117546
|
} else if (entry.runAt && entry.enabled) {
|
|
117392
117547
|
nextFireAt = entry.runAt;
|
|
@@ -117680,7 +117835,8 @@ function defaultWebhookInboxDir() {
|
|
|
117680
117835
|
async function writeInbox2(trigger, result, deliveryId, opts = {}) {
|
|
117681
117836
|
const dir = opts.dir ?? defaultWebhookInboxDir();
|
|
117682
117837
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
117683
|
-
const
|
|
117838
|
+
const suffix = deliveryId ? deliveryId.replace(/[^A-Za-z0-9._-]/g, "_") : randomUUID().slice(0, 8);
|
|
117839
|
+
const file = path3__default.join(dir, `${stamp}-${trigger.name}-${suffix}.md`);
|
|
117684
117840
|
const header = [
|
|
117685
117841
|
"---",
|
|
117686
117842
|
`webhook: ${trigger.name}`,
|
|
@@ -118047,14 +118203,6 @@ var WebhookServer = class {
|
|
|
118047
118203
|
res.end(JSON.stringify({ error: "verification_failed" }));
|
|
118048
118204
|
return;
|
|
118049
118205
|
}
|
|
118050
|
-
if (!shouldFire(trigger.filters, { headers: req.headers, body })) {
|
|
118051
|
-
this.opts.logger?.info?.("webhooks: filtered out, not firing", {
|
|
118052
|
-
trigger: trigger.name
|
|
118053
|
-
});
|
|
118054
|
-
res.writeHead(200, { "content-type": "application/json" });
|
|
118055
|
-
res.end(JSON.stringify({ status: "filtered" }));
|
|
118056
|
-
return;
|
|
118057
|
-
}
|
|
118058
118206
|
const idempKey = idempotencyKey(trigger, req.headers);
|
|
118059
118207
|
if (idempKey && !this.dedupe.check(trigger.id, idempKey)) {
|
|
118060
118208
|
this.opts.logger?.info?.("webhooks: duplicate delivery, dropped", {
|
|
@@ -118065,6 +118213,14 @@ var WebhookServer = class {
|
|
|
118065
118213
|
res.end(JSON.stringify({ status: "duplicate" }));
|
|
118066
118214
|
return;
|
|
118067
118215
|
}
|
|
118216
|
+
if (!shouldFire(trigger.filters, { headers: req.headers, body })) {
|
|
118217
|
+
this.opts.logger?.info?.("webhooks: filtered out, not firing", {
|
|
118218
|
+
trigger: trigger.name
|
|
118219
|
+
});
|
|
118220
|
+
res.writeHead(200, { "content-type": "application/json" });
|
|
118221
|
+
res.end(JSON.stringify({ status: "filtered" }));
|
|
118222
|
+
return;
|
|
118223
|
+
}
|
|
118068
118224
|
res.writeHead(202, { "content-type": "application/json" });
|
|
118069
118225
|
res.end(JSON.stringify({ status: "accepted", trigger: trigger.name }));
|
|
118070
118226
|
const prompt = renderPrompt({
|
|
@@ -119138,17 +119294,28 @@ function isPathKey(key) {
|
|
|
119138
119294
|
function isUrlKey(key) {
|
|
119139
119295
|
return tokenize4(key).some((w4) => URL_WORDS.has(w4));
|
|
119140
119296
|
}
|
|
119297
|
+
var INVALID_FILE_URL_PATH = "/\0moxxy-invalid-file-url";
|
|
119141
119298
|
function extractPaths(input) {
|
|
119142
119299
|
const out = [];
|
|
119143
119300
|
walkStrings(input, (key, value) => {
|
|
119144
|
-
if (
|
|
119301
|
+
if (value.startsWith("file://")) {
|
|
119302
|
+
out.push(fileUrlPath(value));
|
|
119303
|
+
} else if (isPathKey(key)) {
|
|
119145
119304
|
out.push(value);
|
|
119146
|
-
} else if (value.startsWith("file://")) {
|
|
119147
|
-
out.push(value.slice("file://".length));
|
|
119148
119305
|
}
|
|
119149
119306
|
});
|
|
119150
119307
|
return out;
|
|
119151
119308
|
}
|
|
119309
|
+
function fileUrlPath(value) {
|
|
119310
|
+
try {
|
|
119311
|
+
const url2 = new URL(value);
|
|
119312
|
+
if (url2.host)
|
|
119313
|
+
return INVALID_FILE_URL_PATH;
|
|
119314
|
+
return decodeURIComponent(url2.pathname);
|
|
119315
|
+
} catch {
|
|
119316
|
+
return INVALID_FILE_URL_PATH;
|
|
119317
|
+
}
|
|
119318
|
+
}
|
|
119152
119319
|
function extractUrls(input) {
|
|
119153
119320
|
const out = [];
|
|
119154
119321
|
walkStrings(input, (key, value) => {
|
|
@@ -119181,11 +119348,20 @@ function resolvePattern(pattern, cwd2) {
|
|
|
119181
119348
|
}
|
|
119182
119349
|
return path3.isAbsolute(pattern) ? path3.normalize(pattern) : path3.resolve(cwd2, pattern);
|
|
119183
119350
|
}
|
|
119351
|
+
var globRegexCache = /* @__PURE__ */ new Map();
|
|
119352
|
+
function compileGlob(pattern) {
|
|
119353
|
+
let re2 = globRegexCache.get(pattern);
|
|
119354
|
+
if (!re2) {
|
|
119355
|
+
const src = "^" + pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "<<DOUBLESTAR>>").replace(/\*/g, "[^/]*").replace(/<<DOUBLESTAR>>/g, ".*") + "$";
|
|
119356
|
+
re2 = new RegExp(src);
|
|
119357
|
+
globRegexCache.set(pattern, re2);
|
|
119358
|
+
}
|
|
119359
|
+
return re2;
|
|
119360
|
+
}
|
|
119184
119361
|
function matchesGlob(p3, pattern) {
|
|
119185
119362
|
if (pattern.endsWith("/**") && p3 === pattern.slice(0, -3))
|
|
119186
119363
|
return true;
|
|
119187
|
-
|
|
119188
|
-
return new RegExp(re2).test(p3);
|
|
119364
|
+
return compileGlob(pattern).test(p3);
|
|
119189
119365
|
}
|
|
119190
119366
|
function hostMatches(host, pattern) {
|
|
119191
119367
|
if (pattern.startsWith("*.")) {
|
|
@@ -119297,6 +119473,7 @@ var IsolatorRegistry2 = class {
|
|
|
119297
119473
|
}
|
|
119298
119474
|
};
|
|
119299
119475
|
var MAX_BROKER_OUTPUT_BYTES = 8 * 1024 * 1024;
|
|
119476
|
+
var BROKER_KILL_GRACE_MS = 2e3;
|
|
119300
119477
|
var MAX_FETCH_REDIRECTS = 5;
|
|
119301
119478
|
var BLOCKED_HANDLER_MODULES = Object.freeze([
|
|
119302
119479
|
"node:fs",
|
|
@@ -119589,12 +119766,21 @@ async function brokerExec(args, { caps, cwd: cwd2, signal }) {
|
|
|
119589
119766
|
const errChunks = [];
|
|
119590
119767
|
let total = 0;
|
|
119591
119768
|
let settled = false;
|
|
119592
|
-
|
|
119769
|
+
let killTimer = null;
|
|
119770
|
+
const terminate2 = () => {
|
|
119593
119771
|
child.kill("SIGTERM");
|
|
119772
|
+
if (killTimer)
|
|
119773
|
+
return;
|
|
119774
|
+
killTimer = setTimeout(() => child.kill("SIGKILL"), BROKER_KILL_GRACE_MS);
|
|
119775
|
+
killTimer.unref?.();
|
|
119776
|
+
};
|
|
119777
|
+
const timer = opts.timeoutMs ? setTimeout(() => {
|
|
119778
|
+
terminate2();
|
|
119594
119779
|
finish(() => reject(new Error(`[broker:exec] '${command}' exceeded ${opts.timeoutMs}ms`)));
|
|
119595
119780
|
}, opts.timeoutMs) : null;
|
|
119596
119781
|
const onAbort = () => {
|
|
119597
|
-
|
|
119782
|
+
terminate2();
|
|
119783
|
+
finish(() => reject(new Error(`[broker:exec] '${command}' aborted`)));
|
|
119598
119784
|
};
|
|
119599
119785
|
const finish = (settle) => {
|
|
119600
119786
|
if (settled)
|
|
@@ -119605,12 +119791,18 @@ async function brokerExec(args, { caps, cwd: cwd2, signal }) {
|
|
|
119605
119791
|
signal.removeEventListener("abort", onAbort);
|
|
119606
119792
|
settle();
|
|
119607
119793
|
};
|
|
119794
|
+
const clearKill = () => {
|
|
119795
|
+
if (killTimer) {
|
|
119796
|
+
clearTimeout(killTimer);
|
|
119797
|
+
killTimer = null;
|
|
119798
|
+
}
|
|
119799
|
+
};
|
|
119608
119800
|
const accumulate = (chunks, b3) => {
|
|
119609
119801
|
if (settled)
|
|
119610
119802
|
return;
|
|
119611
119803
|
total += b3.byteLength;
|
|
119612
119804
|
if (total > MAX_BROKER_OUTPUT_BYTES) {
|
|
119613
|
-
|
|
119805
|
+
terminate2();
|
|
119614
119806
|
finish(() => reject(new Error(`[broker:exec] '${command}' output exceeded the ${MAX_BROKER_OUTPUT_BYTES}-byte limit`)));
|
|
119615
119807
|
return;
|
|
119616
119808
|
}
|
|
@@ -119620,9 +119812,11 @@ async function brokerExec(args, { caps, cwd: cwd2, signal }) {
|
|
|
119620
119812
|
child.stderr.on("data", (b3) => accumulate(errChunks, b3));
|
|
119621
119813
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
119622
119814
|
child.on("error", (e3) => {
|
|
119815
|
+
clearKill();
|
|
119623
119816
|
finish(() => reject(e3));
|
|
119624
119817
|
});
|
|
119625
119818
|
child.on("close", (exitCode) => {
|
|
119819
|
+
clearKill();
|
|
119626
119820
|
finish(() => resolve12({
|
|
119627
119821
|
stdout: Buffer.concat(outChunks).toString("utf8"),
|
|
119628
119822
|
stderr: Buffer.concat(errChunks).toString("utf8"),
|
|
@@ -119899,7 +120093,8 @@ function createWorkerIsolator(opts = {}) {
|
|
|
119899
120093
|
let terminated = false;
|
|
119900
120094
|
const hardTerminate = () => {
|
|
119901
120095
|
terminated = true;
|
|
119902
|
-
|
|
120096
|
+
worker.terminate().catch(() => {
|
|
120097
|
+
});
|
|
119903
120098
|
};
|
|
119904
120099
|
const finish = (action, graceful = false) => {
|
|
119905
120100
|
if (settled)
|
|
@@ -120263,6 +120458,7 @@ async function invoke(call, caps, _signal) {
|
|
|
120263
120458
|
if (typeof exports.alloc !== "function") {
|
|
120264
120459
|
throw new Error(`[security:wasm] module does not export 'alloc(size: i32) -> i32'`);
|
|
120265
120460
|
}
|
|
120461
|
+
memoryHolder.alloc = (size) => exports.alloc(size);
|
|
120266
120462
|
const handler = exports[call.moduleRef.export];
|
|
120267
120463
|
if (typeof handler !== "function") {
|
|
120268
120464
|
throw new Error(`[security:wasm] export '${call.moduleRef.export}' is ${typeof handler}, expected function`);
|
|
@@ -120295,8 +120491,10 @@ function buildWasmHostImports(memoryHolder, caps, cwd2) {
|
|
|
120295
120491
|
return new TextDecoder().decode(new Uint8Array(memOf().buffer, ptr, len));
|
|
120296
120492
|
};
|
|
120297
120493
|
const sendBytes = (outPtrOut, outLenOut, bytes) => {
|
|
120298
|
-
const region = reserveScratch(memOf(), bytes.length);
|
|
120299
|
-
|
|
120494
|
+
const region = bytes.length === 0 ? SCRATCH_BASE : memoryHolder.alloc ? memoryHolder.alloc(bytes.length) : reserveScratch(memOf(), bytes.length);
|
|
120495
|
+
if (bytes.length > 0) {
|
|
120496
|
+
new Uint8Array(memOf().buffer, region, bytes.length).set(bytes);
|
|
120497
|
+
}
|
|
120300
120498
|
writePtrPair(memOf(), outPtrOut, outLenOut, region, bytes.length);
|
|
120301
120499
|
};
|
|
120302
120500
|
const sendStr = (outPtrOut, outLenOut, s2) => {
|
|
@@ -120337,13 +120535,13 @@ function buildWasmHostImports(memoryHolder, caps, cwd2) {
|
|
|
120337
120535
|
*/
|
|
120338
120536
|
broker_fs_write_file: (pathPtr, pathLen, dataPtr, dataLen, outPtrOut, outLenOut) => {
|
|
120339
120537
|
const filePath = readStr(pathPtr, pathLen);
|
|
120340
|
-
const data =
|
|
120538
|
+
const data = new Uint8Array(memOf().buffer, dataPtr, dataLen).slice();
|
|
120341
120539
|
if (!pathInScope(filePath, caps.fs, cwd2, "write")) {
|
|
120342
120540
|
return sendErr(outPtrOut, outLenOut, `[broker:fs.writeFile] path '${filePath}' is outside the tool's declared fs.write capability`);
|
|
120343
120541
|
}
|
|
120344
120542
|
try {
|
|
120345
120543
|
mkdirSync(path3.dirname(filePath), { recursive: true });
|
|
120346
|
-
writeFileSync(filePath, data
|
|
120544
|
+
writeFileSync(filePath, Buffer$1.from(data));
|
|
120347
120545
|
writePtrPair(memOf(), outPtrOut, outLenOut, 0, 0);
|
|
120348
120546
|
return SUCCESS;
|
|
120349
120547
|
} catch (e3) {
|
|
@@ -124450,6 +124648,8 @@ var AnthropicProvider = class {
|
|
|
124450
124648
|
const parts = [this.oauth?.systemPreamble, system, req.system].filter((s2) => typeof s2 === "string" && s2.length > 0);
|
|
124451
124649
|
const systemForCount = parts.length > 0 ? parts.join("\n\n") : void 0;
|
|
124452
124650
|
try {
|
|
124651
|
+
if (this.oauth)
|
|
124652
|
+
await this.ensureFreshOauth();
|
|
124453
124653
|
const result = await this.client.messages.countTokens({
|
|
124454
124654
|
model: req.model || this.defaultModel,
|
|
124455
124655
|
...systemForCount !== void 0 ? { system: systemForCount } : {},
|
|
@@ -130898,7 +131098,16 @@ var OpenAIProvider = class {
|
|
|
130898
131098
|
...tools ? { tools } : {},
|
|
130899
131099
|
...req.temperature !== void 0 ? { temperature: req.temperature } : {},
|
|
130900
131100
|
...req.maxTokens ? { [tokenLimitKey]: req.maxTokens } : {},
|
|
130901
|
-
|
|
131101
|
+
// Send `reasoning_effort` independently of the token-field heuristic.
|
|
131102
|
+
// The two are unrelated concerns: `usesCompletionTokens` picks the cap
|
|
131103
|
+
// FIELD NAME for the OpenAI-hosted reasoning models, while effort applies
|
|
131104
|
+
// to any reasoning backend. OpenAI-compatible vendors (z.ai GLM,
|
|
131105
|
+
// DeepSeek-R1, vLLM, Ollama) honor reasoning_effort but their model ids
|
|
131106
|
+
// never match the gpt-5/o1/o3 regex, so gating effort on it silently
|
|
131107
|
+
// dropped a user-requested effort for exactly those backends. The
|
|
131108
|
+
// descriptor's `supportsReasoning` already gates this upstream via
|
|
131109
|
+
// req.reasoning.
|
|
131110
|
+
...emitReasoning && reasoningEffort ? { reasoning_effort: reasoningEffort } : {},
|
|
130902
131111
|
stream: true,
|
|
130903
131112
|
// OpenAI only emits the final `usage` chunk when this is set;
|
|
130904
131113
|
// without it `raw.usage` is null on every chunk and token usage
|
|
@@ -131162,7 +131371,6 @@ function waitForCallback(opts) {
|
|
|
131162
131371
|
if (err) {
|
|
131163
131372
|
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
131164
131373
|
res.end(htmlPage("OAuth error", `${err}${errDesc ? `: ${errDesc}` : ""}`));
|
|
131165
|
-
clearTimeout(timer);
|
|
131166
131374
|
const denied = err === "access_denied";
|
|
131167
131375
|
settle(() => reject(new MoxxyError({
|
|
131168
131376
|
code: denied ? "OAUTH_FLOW_DENIED" : "AUTH_INVALID",
|
|
@@ -131177,7 +131385,6 @@ function waitForCallback(opts) {
|
|
|
131177
131385
|
if (!code || !returnedState) {
|
|
131178
131386
|
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
131179
131387
|
res.end(htmlPage("OAuth error", "callback was missing code or state"));
|
|
131180
|
-
clearTimeout(timer);
|
|
131181
131388
|
settle(() => reject(new MoxxyError({
|
|
131182
131389
|
code: "AUTH_INVALID",
|
|
131183
131390
|
message: "OAuth callback was missing code or state \u2014 the upstream redirect is malformed.",
|
|
@@ -131188,7 +131395,6 @@ function waitForCallback(opts) {
|
|
|
131188
131395
|
if (returnedState !== opts.expectedState) {
|
|
131189
131396
|
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
131190
131397
|
res.end(htmlPage("OAuth error", "state mismatch \u2014 possible CSRF, refusing"));
|
|
131191
|
-
clearTimeout(timer);
|
|
131192
131398
|
settle(() => reject(new MoxxyError({
|
|
131193
131399
|
code: "OAUTH_FLOW_STATE_MISMATCH",
|
|
131194
131400
|
message: "OAuth state mismatch \u2014 possible CSRF attempt, refusing to continue.",
|
|
@@ -131246,7 +131452,8 @@ async function exchangeCodeForToken(input, fetchImpl2 = fetch) {
|
|
|
131246
131452
|
const res = await fetchImpl2(input.tokenUrl, {
|
|
131247
131453
|
method: "POST",
|
|
131248
131454
|
headers: { "Content-Type": "application/x-www-form-urlencoded", Accept: "application/json" },
|
|
131249
|
-
body: body.toString()
|
|
131455
|
+
body: body.toString(),
|
|
131456
|
+
...input.signal ? { signal: input.signal } : {}
|
|
131250
131457
|
});
|
|
131251
131458
|
if (!res.ok) {
|
|
131252
131459
|
const text = await res.text().catch(() => "");
|
|
@@ -131362,7 +131569,10 @@ async function runAuthorizationCodeFlow(opts) {
|
|
|
131362
131569
|
});
|
|
131363
131570
|
}
|
|
131364
131571
|
async function pollUntil(fn, opts) {
|
|
131365
|
-
const state = {
|
|
131572
|
+
const state = {
|
|
131573
|
+
intervalMs: opts.intervalMs,
|
|
131574
|
+
...opts.signal ? { signal: opts.signal } : {}
|
|
131575
|
+
};
|
|
131366
131576
|
const leadingWait = opts.leadingWait ?? true;
|
|
131367
131577
|
const deadline = Date.now() + opts.timeoutMs;
|
|
131368
131578
|
const label3 = opts.label ?? "poll";
|
|
@@ -131512,7 +131722,8 @@ async function pollOnce(opts, deviceCode, state) {
|
|
|
131512
131722
|
const pollRes = await fetch(opts.tokenUrl, {
|
|
131513
131723
|
method: "POST",
|
|
131514
131724
|
headers: { "Content-Type": "application/x-www-form-urlencoded", Accept: "application/json" },
|
|
131515
|
-
body: body.toString()
|
|
131725
|
+
body: body.toString(),
|
|
131726
|
+
...state.signal ? { signal: state.signal } : {}
|
|
131516
131727
|
});
|
|
131517
131728
|
const pollJson = await pollRes.json().catch(() => ({}));
|
|
131518
131729
|
return classifyDeviceTokenResponse(pollRes, pollJson, state);
|
|
@@ -132110,12 +132321,13 @@ function openaiDeviceFlow(opts) {
|
|
|
132110
132321
|
}
|
|
132111
132322
|
};
|
|
132112
132323
|
},
|
|
132113
|
-
async poll(init3,
|
|
132324
|
+
async poll(init3, state) {
|
|
132114
132325
|
const { deviceAuthId, userCode, clientId } = init3.providerData;
|
|
132115
132326
|
const res = await fetch(pollUrl, {
|
|
132116
132327
|
method: "POST",
|
|
132117
132328
|
headers: { "Content-Type": "application/json" },
|
|
132118
|
-
body: JSON.stringify({ device_auth_id: deviceAuthId, user_code: userCode })
|
|
132329
|
+
body: JSON.stringify({ device_auth_id: deviceAuthId, user_code: userCode }),
|
|
132330
|
+
...state.signal ? { signal: state.signal } : {}
|
|
132119
132331
|
});
|
|
132120
132332
|
if (res.ok) {
|
|
132121
132333
|
const data = await res.json();
|
|
@@ -132125,7 +132337,8 @@ function openaiDeviceFlow(opts) {
|
|
|
132125
132337
|
code: data.authorization_code,
|
|
132126
132338
|
redirectUri: exchangeRedirectUri,
|
|
132127
132339
|
clientId,
|
|
132128
|
-
codeVerifier: data.code_verifier
|
|
132340
|
+
codeVerifier: data.code_verifier,
|
|
132341
|
+
...state.signal ? { signal: state.signal } : {}
|
|
132129
132342
|
})
|
|
132130
132343
|
};
|
|
132131
132344
|
}
|
|
@@ -132547,9 +132760,16 @@ async function* consumeResponsesSse(body, signal, emitReasoning = false) {
|
|
|
132547
132760
|
if (errored)
|
|
132548
132761
|
return;
|
|
132549
132762
|
for (const entry of pending2.values()) {
|
|
132763
|
+
const outId = entry.callId || entry.id;
|
|
132764
|
+
if (!entry.emittedStart && entry.name) {
|
|
132765
|
+
entry.emittedStart = true;
|
|
132766
|
+
yield { type: "tool_use_start", id: outId, name: entry.name };
|
|
132767
|
+
}
|
|
132550
132768
|
if (entry.emittedStart) {
|
|
132551
132769
|
sawToolCall = true;
|
|
132552
|
-
yield { type: "tool_use_end", id:
|
|
132770
|
+
yield { type: "tool_use_end", id: outId, input: parseToolArgs(entry.args) };
|
|
132771
|
+
} else if (process.env.MOXXY_DEBUG) {
|
|
132772
|
+
console.error(`[openai-codex] dropping a truncated function_call with no name (id=${outId}, args=${entry.args.length}B)`);
|
|
132553
132773
|
}
|
|
132554
132774
|
}
|
|
132555
132775
|
if (stopReason === "end_turn" && sawToolCall) {
|
|
@@ -132629,6 +132849,14 @@ var CodexProvider = class {
|
|
|
132629
132849
|
yield toErrorEvent(err);
|
|
132630
132850
|
return;
|
|
132631
132851
|
}
|
|
132852
|
+
if (response.status === 401) {
|
|
132853
|
+
yield {
|
|
132854
|
+
type: "error",
|
|
132855
|
+
message: "ChatGPT OAuth credentials were rejected after a token refresh. Run `moxxy login openai-codex` to re-authenticate.",
|
|
132856
|
+
retryable: false
|
|
132857
|
+
};
|
|
132858
|
+
return;
|
|
132859
|
+
}
|
|
132632
132860
|
}
|
|
132633
132861
|
if (!response.ok || !response.body) {
|
|
132634
132862
|
const text = await response.text().catch(() => "");
|
|
@@ -134823,6 +135051,18 @@ async function* runGoalMode(ctx) {
|
|
|
134823
135051
|
continue;
|
|
134824
135052
|
}
|
|
134825
135053
|
reactiveCompactions = 0;
|
|
135054
|
+
if (reasoning) {
|
|
135055
|
+
yield await ctx.emit({
|
|
135056
|
+
type: "reasoning_message",
|
|
135057
|
+
sessionId: ctx.sessionId,
|
|
135058
|
+
turnId: ctx.turnId,
|
|
135059
|
+
source: "model",
|
|
135060
|
+
content: reasoning.text,
|
|
135061
|
+
...reasoning.signature ? { signature: reasoning.signature } : {},
|
|
135062
|
+
...reasoning.redacted ? { redacted: true } : {},
|
|
135063
|
+
...reasoning.encrypted ? { encrypted: reasoning.encrypted } : {}
|
|
135064
|
+
});
|
|
135065
|
+
}
|
|
134826
135066
|
if (totalTokens > GOAL_TOKEN_BUDGET) {
|
|
134827
135067
|
yield await ctx.emit({
|
|
134828
135068
|
type: "plugin_event",
|
|
@@ -134843,18 +135083,6 @@ async function* runGoalMode(ctx) {
|
|
|
134843
135083
|
});
|
|
134844
135084
|
return;
|
|
134845
135085
|
}
|
|
134846
|
-
if (reasoning) {
|
|
134847
|
-
yield await ctx.emit({
|
|
134848
|
-
type: "reasoning_message",
|
|
134849
|
-
sessionId: ctx.sessionId,
|
|
134850
|
-
turnId: ctx.turnId,
|
|
134851
|
-
source: "model",
|
|
134852
|
-
content: reasoning.text,
|
|
134853
|
-
...reasoning.signature ? { signature: reasoning.signature } : {},
|
|
134854
|
-
...reasoning.redacted ? { redacted: true } : {},
|
|
134855
|
-
...reasoning.encrypted ? { encrypted: reasoning.encrypted } : {}
|
|
134856
|
-
});
|
|
134857
|
-
}
|
|
134858
135086
|
const stuck = yield* emitRequestsAndDetectStuck(ctx, toolUses, detector, {
|
|
134859
135087
|
abortedResultMessage: "goal mode aborted (stuck pattern) before this call ran",
|
|
134860
135088
|
nearHint: "against the same target (only volatile args varied)",
|
|
@@ -135455,6 +135683,16 @@ async function* runDeepResearchMode(ctx) {
|
|
|
135455
135683
|
const synthesisText = await collectSynthesis(ctx, synthesisInput);
|
|
135456
135684
|
if (synthesisText === null)
|
|
135457
135685
|
return;
|
|
135686
|
+
if (ctx.signal.aborted) {
|
|
135687
|
+
yield await ctx.emit({
|
|
135688
|
+
type: "abort",
|
|
135689
|
+
sessionId: ctx.sessionId,
|
|
135690
|
+
turnId: ctx.turnId,
|
|
135691
|
+
source: "system",
|
|
135692
|
+
reason: "aborted during synthesis"
|
|
135693
|
+
});
|
|
135694
|
+
return;
|
|
135695
|
+
}
|
|
135458
135696
|
yield await ctx.emit({
|
|
135459
135697
|
type: "assistant_message",
|
|
135460
135698
|
sessionId: ctx.sessionId,
|
|
@@ -135907,11 +136145,10 @@ async function createUnixSocketServer(socketPath, logger = stderrLogger) {
|
|
|
135907
136145
|
} else {
|
|
135908
136146
|
warnWindowsPipeAclOnce(logger, socketPath);
|
|
135909
136147
|
}
|
|
135910
|
-
|
|
136148
|
+
let connectionHandler;
|
|
135911
136149
|
const server = net2.createServer((socket) => {
|
|
135912
136150
|
const transport = new NdjsonTransport(socket);
|
|
135913
|
-
|
|
135914
|
-
handler(transport);
|
|
136151
|
+
connectionHandler?.(transport);
|
|
135915
136152
|
});
|
|
135916
136153
|
await new Promise((resolve12, reject) => {
|
|
135917
136154
|
server.once("error", reject);
|
|
@@ -135933,7 +136170,7 @@ async function createUnixSocketServer(socketPath, logger = stderrLogger) {
|
|
|
135933
136170
|
return {
|
|
135934
136171
|
address: socketPath,
|
|
135935
136172
|
onConnection(handler) {
|
|
135936
|
-
|
|
136173
|
+
connectionHandler = handler;
|
|
135937
136174
|
},
|
|
135938
136175
|
close() {
|
|
135939
136176
|
return new Promise((resolve12) => {
|
|
@@ -139655,6 +139892,7 @@ var import_grammy6 = __toESM(require_mod2());
|
|
|
139655
139892
|
|
|
139656
139893
|
// ../plugin-telegram/dist/channel.js
|
|
139657
139894
|
var import_grammy5 = __toESM(require_mod2());
|
|
139895
|
+
init_dist();
|
|
139658
139896
|
|
|
139659
139897
|
// ../plugin-telegram/dist/permission.js
|
|
139660
139898
|
var TelegramPermissionResolver = class {
|
|
@@ -140111,7 +140349,16 @@ function composeFrame(snap) {
|
|
|
140111
140349
|
return parts.join("\n\n");
|
|
140112
140350
|
}
|
|
140113
140351
|
function stripHtml(html) {
|
|
140114
|
-
return html.replace(/<\/?[a-z][^>]*>/gi, "").replace(
|
|
140352
|
+
return html.replace(/<\/?[a-z][^>]*>/gi, "").replace(/&#(\d+);/g, (_2, dec) => safeFromCodePoint(parseInt(dec, 10))).replace(/&#x([0-9a-f]+);/gi, (_2, hex) => safeFromCodePoint(parseInt(hex, 16))).replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/&/g, "&");
|
|
140353
|
+
}
|
|
140354
|
+
function safeFromCodePoint(cp) {
|
|
140355
|
+
if (!Number.isFinite(cp) || cp < 0 || cp > 1114111)
|
|
140356
|
+
return "";
|
|
140357
|
+
try {
|
|
140358
|
+
return String.fromCodePoint(cp);
|
|
140359
|
+
} catch {
|
|
140360
|
+
return "";
|
|
140361
|
+
}
|
|
140115
140362
|
}
|
|
140116
140363
|
function truncate3(s2, n2) {
|
|
140117
140364
|
return s2.length <= n2 ? s2 : s2.slice(0, n2) + "\u2026";
|
|
@@ -140882,13 +141129,11 @@ function mapChoice(choice) {
|
|
|
140882
141129
|
}
|
|
140883
141130
|
|
|
140884
141131
|
// ../plugin-telegram/dist/channel/turn-runner.js
|
|
140885
|
-
init_dist();
|
|
140886
141132
|
async function runUserTurn(ctx, deps, opts) {
|
|
140887
141133
|
const { session, bot, framePump, typing, logger } = deps;
|
|
140888
|
-
const { chatId, text, model, controller } = opts;
|
|
141134
|
+
const { chatId, text, model, controller, turnId } = opts;
|
|
140889
141135
|
framePump.beginTurn(chatId);
|
|
140890
141136
|
typing.start(bot, chatId);
|
|
140891
|
-
const turnId = newTurnId();
|
|
140892
141137
|
const unsubscribe = session.log.subscribe((event) => {
|
|
140893
141138
|
if (event.turnId !== turnId)
|
|
140894
141139
|
return;
|
|
@@ -141089,6 +141334,12 @@ var TelegramChannel = class {
|
|
|
141089
141334
|
// without poisoning the session-level signal (which other channels
|
|
141090
141335
|
// sharing the same Session would also observe).
|
|
141091
141336
|
turnController = null;
|
|
141337
|
+
// turnIds of turns THIS channel initiated. mirrorForeignTurn filters on these
|
|
141338
|
+
// (invariant #8: filter event-log subscribers by turnId when multiplexing
|
|
141339
|
+
// turns on one Session) rather than the coarse `busy` flag alone — so an
|
|
141340
|
+
// assistant_message dispatched for our own turn AFTER `busy` flips false
|
|
141341
|
+
// (async event ordering / RemoteSession replay) isn't re-mirrored as foreign.
|
|
141342
|
+
ownTurnIds = /* @__PURE__ */ new Set();
|
|
141092
141343
|
// When a user clicks an approval option that needs text follow-up
|
|
141093
141344
|
// (e.g. plan-execute "Redraft with feedback"), we stash the
|
|
141094
141345
|
// approval+option pair and capture the user's NEXT message as the
|
|
@@ -141234,6 +141485,13 @@ var TelegramChannel = class {
|
|
|
141234
141485
|
const controller = new AbortController();
|
|
141235
141486
|
this.turnController = controller;
|
|
141236
141487
|
const effectiveModel = this.activeModelOverride ?? this.model;
|
|
141488
|
+
const turnId = newTurnId();
|
|
141489
|
+
this.ownTurnIds.add(turnId);
|
|
141490
|
+
if (this.ownTurnIds.size > 64) {
|
|
141491
|
+
const oldest = this.ownTurnIds.values().next().value;
|
|
141492
|
+
if (oldest !== void 0)
|
|
141493
|
+
this.ownTurnIds.delete(oldest);
|
|
141494
|
+
}
|
|
141237
141495
|
try {
|
|
141238
141496
|
await runUserTurn(ctx, {
|
|
141239
141497
|
session: this.session,
|
|
@@ -141241,7 +141499,7 @@ var TelegramChannel = class {
|
|
|
141241
141499
|
framePump: this.framePump,
|
|
141242
141500
|
typing: this.typing,
|
|
141243
141501
|
...this.opts.logger ? { logger: this.opts.logger } : {}
|
|
141244
|
-
}, { chatId, text, model: effectiveModel, controller });
|
|
141502
|
+
}, { chatId, text, model: effectiveModel, controller, turnId });
|
|
141245
141503
|
} finally {
|
|
141246
141504
|
this.busy = false;
|
|
141247
141505
|
this.turnController = null;
|
|
@@ -141255,7 +141513,11 @@ var TelegramChannel = class {
|
|
|
141255
141513
|
* avoid parse-mode pitfalls; the view itself lives on the web surface.
|
|
141256
141514
|
*/
|
|
141257
141515
|
mirrorForeignTurn(event) {
|
|
141258
|
-
if (event.type !== "assistant_message"
|
|
141516
|
+
if (event.type !== "assistant_message")
|
|
141517
|
+
return;
|
|
141518
|
+
if (this.ownTurnIds.has(event.turnId))
|
|
141519
|
+
return;
|
|
141520
|
+
if (this.busy)
|
|
141259
141521
|
return;
|
|
141260
141522
|
if (!this.bot || this.lastChatId == null)
|
|
141261
141523
|
return;
|
|
@@ -142332,10 +142594,16 @@ async function runPairFlow(ctx) {
|
|
|
142332
142594
|
await session.close("SIGINT").catch(() => void 0);
|
|
142333
142595
|
process.exit(0);
|
|
142334
142596
|
};
|
|
142335
|
-
|
|
142336
|
-
process.
|
|
142337
|
-
|
|
142338
|
-
|
|
142597
|
+
const onSignal = () => void shutdown();
|
|
142598
|
+
process.once("SIGINT", onSignal);
|
|
142599
|
+
process.once("SIGTERM", onSignal);
|
|
142600
|
+
try {
|
|
142601
|
+
await handle2.running;
|
|
142602
|
+
return 0;
|
|
142603
|
+
} finally {
|
|
142604
|
+
process.removeListener("SIGINT", onSignal);
|
|
142605
|
+
process.removeListener("SIGTERM", onSignal);
|
|
142606
|
+
}
|
|
142339
142607
|
}
|
|
142340
142608
|
|
|
142341
142609
|
// ../plugin-telegram/dist/setup-wizard.js
|
|
@@ -142582,8 +142850,8 @@ function buildTelegramPlugin(opts) {
|
|
|
142582
142850
|
if (!targetChat) {
|
|
142583
142851
|
throw new Error("no authorized chat \u2014 run `moxxy channels telegram pair` first or pass `chatId` explicitly");
|
|
142584
142852
|
}
|
|
142585
|
-
const
|
|
142586
|
-
await
|
|
142853
|
+
const api = new import_grammy6.Api(token);
|
|
142854
|
+
await api.sendMessage(targetChat, text, parseMode ? { parse_mode: parseMode } : {});
|
|
142587
142855
|
return { delivered: true, chatId: targetChat, length: text.length };
|
|
142588
142856
|
}
|
|
142589
142857
|
}),
|
|
@@ -142816,6 +143084,9 @@ var HttpChannel = class {
|
|
|
142816
143084
|
this.permissionResolver = opts.allowedTools && opts.allowedTools.length > 0 ? createAllowListResolver([...opts.allowedTools]) : denyByDefaultResolver;
|
|
142817
143085
|
}
|
|
142818
143086
|
async start(startOpts) {
|
|
143087
|
+
if (this.server) {
|
|
143088
|
+
throw new Error("HttpChannel is already started \u2014 call stop() before starting again.");
|
|
143089
|
+
}
|
|
142819
143090
|
const ctx = {
|
|
142820
143091
|
session: startOpts.session,
|
|
142821
143092
|
authToken: this.authToken,
|
|
@@ -142874,11 +143145,16 @@ var HttpChannel = class {
|
|
|
142874
143145
|
return {
|
|
142875
143146
|
running,
|
|
142876
143147
|
stop: async () => {
|
|
143148
|
+
const srv = this.server;
|
|
142877
143149
|
await new Promise((resolve12) => {
|
|
142878
|
-
if (!
|
|
143150
|
+
if (!srv)
|
|
142879
143151
|
return resolve12();
|
|
142880
|
-
|
|
143152
|
+
srv.close(() => resolve12());
|
|
142881
143153
|
});
|
|
143154
|
+
if (this.server === srv) {
|
|
143155
|
+
this.server = null;
|
|
143156
|
+
this.boundPortValue = 0;
|
|
143157
|
+
}
|
|
142882
143158
|
}
|
|
142883
143159
|
};
|
|
142884
143160
|
}
|
|
@@ -143052,13 +143328,19 @@ async function pidCommand2(pid) {
|
|
|
143052
143328
|
function looksLikeMoxxy(command) {
|
|
143053
143329
|
return command.length > 0 && /moxxy/i.test(command);
|
|
143054
143330
|
}
|
|
143055
|
-
|
|
143331
|
+
var realFreePortDeps = {
|
|
143332
|
+
pidsListeningOn,
|
|
143333
|
+
pidCommand: pidCommand2,
|
|
143334
|
+
kill: (pid, signal) => process.kill(pid, signal),
|
|
143335
|
+
graceMs: 400
|
|
143336
|
+
};
|
|
143337
|
+
async function freeTcpPortIfMoxxy(port, logger, deps = realFreePortDeps) {
|
|
143056
143338
|
if (process.platform === "win32")
|
|
143057
143339
|
return false;
|
|
143058
|
-
const pids = (await pidsListeningOn(port)).filter((pid) => pid !== process.pid);
|
|
143340
|
+
const pids = (await deps.pidsListeningOn(port)).filter((pid) => pid !== process.pid);
|
|
143059
143341
|
if (pids.length === 0)
|
|
143060
143342
|
return false;
|
|
143061
|
-
const holders = await Promise.all(pids.map(async (pid) => ({ pid, command: await
|
|
143343
|
+
const holders = await Promise.all(pids.map(async (pid) => ({ pid, command: await deps.pidCommand(pid) })));
|
|
143062
143344
|
const foreign = holders.filter((h3) => !looksLikeMoxxy(h3.command));
|
|
143063
143345
|
if (foreign.length > 0) {
|
|
143064
143346
|
logger?.warn?.(`port ${port} is held by non-moxxy process(es); not killing them`, {
|
|
@@ -143066,17 +143348,29 @@ async function freeTcpPortIfMoxxy(port, logger) {
|
|
|
143066
143348
|
});
|
|
143067
143349
|
return false;
|
|
143068
143350
|
}
|
|
143351
|
+
let attempted = false;
|
|
143069
143352
|
for (const { pid } of holders) {
|
|
143353
|
+
if (!looksLikeMoxxy(await deps.pidCommand(pid)))
|
|
143354
|
+
continue;
|
|
143070
143355
|
try {
|
|
143071
|
-
|
|
143356
|
+
deps.kill(pid, "SIGTERM");
|
|
143357
|
+
attempted = true;
|
|
143072
143358
|
} catch {
|
|
143073
143359
|
}
|
|
143074
143360
|
}
|
|
143075
|
-
|
|
143361
|
+
if (!attempted)
|
|
143362
|
+
return false;
|
|
143363
|
+
await new Promise((r2) => setTimeout(r2, deps.graceMs ?? 400));
|
|
143076
143364
|
for (const { pid } of holders) {
|
|
143077
143365
|
try {
|
|
143078
|
-
|
|
143079
|
-
|
|
143366
|
+
deps.kill(pid, 0);
|
|
143367
|
+
} catch {
|
|
143368
|
+
continue;
|
|
143369
|
+
}
|
|
143370
|
+
if (!looksLikeMoxxy(await deps.pidCommand(pid)))
|
|
143371
|
+
continue;
|
|
143372
|
+
try {
|
|
143373
|
+
deps.kill(pid, "SIGKILL");
|
|
143080
143374
|
} catch {
|
|
143081
143375
|
}
|
|
143082
143376
|
}
|
|
@@ -143634,6 +143928,7 @@ async function createWebSocketTransportServer(opts) {
|
|
|
143634
143928
|
let currentToken = opts.authToken;
|
|
143635
143929
|
let currentAllowedOrigins = opts.allowedOrigins ?? [];
|
|
143636
143930
|
let connections = 0;
|
|
143931
|
+
let pending2 = 0;
|
|
143637
143932
|
const wss = new import_websocket_server.default({
|
|
143638
143933
|
host,
|
|
143639
143934
|
port: opts.port,
|
|
@@ -143643,11 +143938,14 @@ async function createWebSocketTransportServer(opts) {
|
|
|
143643
143938
|
console.warn(`[moxxy] ws bridge: rejected browser-origin upgrade (Origin: ${String(info.req.headers.origin)})`);
|
|
143644
143939
|
return false;
|
|
143645
143940
|
}
|
|
143646
|
-
if (connections >= maxConnections) {
|
|
143941
|
+
if (connections + pending2 >= maxConnections) {
|
|
143647
143942
|
console.warn(`[moxxy] ws bridge: rejected upgrade \u2014 connection cap (${maxConnections}) reached`);
|
|
143648
143943
|
return false;
|
|
143649
143944
|
}
|
|
143650
|
-
|
|
143945
|
+
const ok = checkWsAuth(info.req, currentToken, { allowQueryToken: opts.allowQueryToken });
|
|
143946
|
+
if (ok)
|
|
143947
|
+
pending2 += 1;
|
|
143948
|
+
return ok;
|
|
143651
143949
|
},
|
|
143652
143950
|
// When the client offers subprotocols (the moxxy.bearer.* convention),
|
|
143653
143951
|
// select the moxxy protocol WITHOUT echoing the token-bearing entry back.
|
|
@@ -143655,6 +143953,8 @@ async function createWebSocketTransportServer(opts) {
|
|
|
143655
143953
|
});
|
|
143656
143954
|
const connectionHandlers = [];
|
|
143657
143955
|
wss.on("connection", (ws) => {
|
|
143956
|
+
if (pending2 > 0)
|
|
143957
|
+
pending2 -= 1;
|
|
143658
143958
|
connections += 1;
|
|
143659
143959
|
ws.once("close", () => {
|
|
143660
143960
|
connections -= 1;
|
|
@@ -144105,6 +144405,7 @@ var MobileSessionHost = class {
|
|
|
144105
144405
|
this.bus.handle("session.newSession", async () => {
|
|
144106
144406
|
for (const controller of this.turns.values())
|
|
144107
144407
|
controller.abort();
|
|
144408
|
+
this.autoApprove = false;
|
|
144108
144409
|
if (this.session.reset)
|
|
144109
144410
|
await this.session.reset();
|
|
144110
144411
|
else
|
|
@@ -144251,6 +144552,8 @@ var MobileSessionHost = class {
|
|
|
144251
144552
|
return { turnId };
|
|
144252
144553
|
}
|
|
144253
144554
|
openAsk(req) {
|
|
144555
|
+
if (this.disposed)
|
|
144556
|
+
return Promise.resolve({ mode: "deny" });
|
|
144254
144557
|
const requestId = `ask-${++this.askCounter}`;
|
|
144255
144558
|
return new Promise((resolve12) => {
|
|
144256
144559
|
this.pendingAsks.set(requestId, resolve12);
|
|
@@ -144562,7 +144865,7 @@ function htmlToMarkdown(html, opts = {}) {
|
|
|
144562
144865
|
${"#".repeat(Number(lvl))} ${stripTags(inner).trim()}
|
|
144563
144866
|
|
|
144564
144867
|
`);
|
|
144565
|
-
body = body.replace(/<a\b[^>]*\bhref="([^"]+)"[^>]*>([\s\S]*?)<\/a>/gi, (_2,
|
|
144868
|
+
body = body.replace(/<a\b[^>]*\bhref=(?:"([^"]+)"|'([^']+)'|([^\s>]+))[^>]*>([\s\S]*?)<\/a>/gi, (_2, dq, sq, uq, inner) => `[${stripTags(inner).trim()}](${dq ?? sq ?? uq})`);
|
|
144566
144869
|
body = body.replace(/<pre\b[^>]*>([\s\S]*?)<\/pre>/gi, (_2, inner) => `
|
|
144567
144870
|
|
|
144568
144871
|
\`\`\`
|
|
@@ -145479,6 +145782,8 @@ var TerminalProcessImpl = class {
|
|
|
145479
145782
|
child.stderr.on("data", (b3) => this.emitData(b3.toString("utf8")));
|
|
145480
145783
|
child.on("exit", (code) => this.emitExit(code ?? 0));
|
|
145481
145784
|
child.on("error", () => this.emitExit(1));
|
|
145785
|
+
child.stdin.on("error", () => {
|
|
145786
|
+
});
|
|
145482
145787
|
}
|
|
145483
145788
|
}
|
|
145484
145789
|
emitData(d2) {
|
|
@@ -145518,10 +145823,13 @@ var TerminalProcessImpl = class {
|
|
|
145518
145823
|
write(data) {
|
|
145519
145824
|
if (!this.alive)
|
|
145520
145825
|
return;
|
|
145521
|
-
|
|
145522
|
-
this.pty
|
|
145523
|
-
|
|
145524
|
-
|
|
145826
|
+
try {
|
|
145827
|
+
if (this.pty)
|
|
145828
|
+
this.pty.write(data);
|
|
145829
|
+
else
|
|
145830
|
+
this.child?.stdin.write(data);
|
|
145831
|
+
} catch {
|
|
145832
|
+
}
|
|
145525
145833
|
}
|
|
145526
145834
|
resize(cols, rows) {
|
|
145527
145835
|
if (this.pty && this.alive) {
|
|
@@ -146137,16 +146445,16 @@ function buildProviderAdminPlugin(opts) {
|
|
|
146137
146445
|
// ../plugin-usage-stats/dist/index.js
|
|
146138
146446
|
init_dist();
|
|
146139
146447
|
function buildUsageStatsPlugin(opts = {}) {
|
|
146140
|
-
let
|
|
146448
|
+
let initMaxSeq = null;
|
|
146141
146449
|
return definePlugin({
|
|
146142
146450
|
name: "@moxxy/plugin-usage-stats",
|
|
146143
146451
|
version: "0.0.0",
|
|
146144
146452
|
hooks: {
|
|
146145
146453
|
onInit(ctx) {
|
|
146146
|
-
|
|
146454
|
+
initMaxSeq = maxSeq(ctx.log.slice());
|
|
146147
146455
|
},
|
|
146148
146456
|
async onShutdown(ctx) {
|
|
146149
|
-
const live = ctx.log.slice(
|
|
146457
|
+
const live = initMaxSeq === null ? ctx.log.slice() : ctx.log.slice().filter((e3) => e3.seq > initMaxSeq);
|
|
146150
146458
|
if (live.length === 0)
|
|
146151
146459
|
return;
|
|
146152
146460
|
const delta = summarizeTokensByModel(live);
|
|
@@ -146155,6 +146463,13 @@ function buildUsageStatsPlugin(opts = {}) {
|
|
|
146155
146463
|
}
|
|
146156
146464
|
});
|
|
146157
146465
|
}
|
|
146466
|
+
function maxSeq(events) {
|
|
146467
|
+
let max = null;
|
|
146468
|
+
for (const e3 of events)
|
|
146469
|
+
if (max === null || e3.seq > max)
|
|
146470
|
+
max = e3.seq;
|
|
146471
|
+
return max;
|
|
146472
|
+
}
|
|
146158
146473
|
var infoCmd = {
|
|
146159
146474
|
name: "info",
|
|
146160
146475
|
description: "Show provider \xB7 model \xB7 mode \xB7 plugin/skill counts",
|
|
@@ -146273,7 +146588,8 @@ async function compactSession(session) {
|
|
|
146273
146588
|
...result
|
|
146274
146589
|
};
|
|
146275
146590
|
await s2.log.append(emittable);
|
|
146276
|
-
const
|
|
146591
|
+
const [fromSeq, toSeq] = result.replacedRange;
|
|
146592
|
+
const compactedEvents = events.filter((e3) => e3.seq >= fromSeq && e3.seq <= toSeq).length;
|
|
146277
146593
|
return {
|
|
146278
146594
|
kind: "text",
|
|
146279
146595
|
text: `context compacted: ${formatCount2(compactedEvents)} ${plural2(compactedEvents, "event")}, ~${formatTokenCount2(result.tokensSaved)} tokens saved`
|
|
@@ -146348,15 +146664,26 @@ function buildViewPlugin(opts) {
|
|
|
146348
146664
|
});
|
|
146349
146665
|
}
|
|
146350
146666
|
var IS_DARWIN = process.platform === "darwin";
|
|
146667
|
+
function procFailureCause(proc, timeoutMs) {
|
|
146668
|
+
if (proc.timedOut) {
|
|
146669
|
+
return timeoutMs ? `timed out after ${timeoutMs}ms` : "timed out";
|
|
146670
|
+
}
|
|
146671
|
+
if (proc.aborted)
|
|
146672
|
+
return "aborted (turn cancelled)";
|
|
146673
|
+
return "";
|
|
146674
|
+
}
|
|
146351
146675
|
function runProcess2(cmd, args, opts = {}) {
|
|
146352
146676
|
return new Promise((resolve12, reject) => {
|
|
146353
146677
|
const child = spawn(cmd, [...args], { stdio: ["pipe", "pipe", "pipe"] });
|
|
146354
146678
|
const stdoutChunks = [];
|
|
146355
146679
|
let stderr = "";
|
|
146356
146680
|
let settled = false;
|
|
146681
|
+
let timedOut = false;
|
|
146682
|
+
let aborted = false;
|
|
146357
146683
|
const onAbort = () => {
|
|
146358
146684
|
if (settled)
|
|
146359
146685
|
return;
|
|
146686
|
+
aborted = true;
|
|
146360
146687
|
try {
|
|
146361
146688
|
child.kill("SIGTERM");
|
|
146362
146689
|
} catch {
|
|
@@ -146366,6 +146693,7 @@ function runProcess2(cmd, args, opts = {}) {
|
|
|
146366
146693
|
const timer = opts.timeoutMs ? setTimeout(() => {
|
|
146367
146694
|
if (settled)
|
|
146368
146695
|
return;
|
|
146696
|
+
timedOut = true;
|
|
146369
146697
|
try {
|
|
146370
146698
|
child.kill("SIGTERM");
|
|
146371
146699
|
} catch {
|
|
@@ -146396,7 +146724,9 @@ function runProcess2(cmd, args, opts = {}) {
|
|
|
146396
146724
|
resolve12({
|
|
146397
146725
|
exitCode: code ?? -1,
|
|
146398
146726
|
stdout: Buffer.concat(stdoutChunks).toString("utf8"),
|
|
146399
|
-
stderr
|
|
146727
|
+
stderr,
|
|
146728
|
+
timedOut,
|
|
146729
|
+
aborted
|
|
146400
146730
|
});
|
|
146401
146731
|
});
|
|
146402
146732
|
if (opts.input !== void 0) {
|
|
@@ -146429,10 +146759,11 @@ var applescriptTool = defineTool({
|
|
|
146429
146759
|
timeoutMs: 3e4
|
|
146430
146760
|
});
|
|
146431
146761
|
if (proc.exitCode !== 0) {
|
|
146762
|
+
const cause = procFailureCause(proc, 3e4);
|
|
146432
146763
|
throw new MoxxyError({
|
|
146433
146764
|
code: "TOOL_ERROR",
|
|
146434
|
-
message: `osascript failed (exit ${proc.exitCode}): ${proc.stderr.trim() || "(no error message)"}`,
|
|
146435
|
-
context: { tool: "computer_applescript", exitCode: proc.exitCode }
|
|
146765
|
+
message: cause ? `osascript ${cause}` : `osascript failed (exit ${proc.exitCode}): ${proc.stderr.trim() || "(no error message)"}`,
|
|
146766
|
+
context: { tool: "computer_applescript", exitCode: proc.exitCode, timedOut: proc.timedOut ? 1 : 0 }
|
|
146436
146767
|
});
|
|
146437
146768
|
}
|
|
146438
146769
|
return { ok: true, output: proc.stdout.trim() };
|
|
@@ -146460,10 +146791,11 @@ end tell`;
|
|
|
146460
146791
|
timeoutMs: 1e4
|
|
146461
146792
|
});
|
|
146462
146793
|
if (proc.exitCode !== 0) {
|
|
146794
|
+
const cause = procFailureCause(proc, 1e4);
|
|
146463
146795
|
throw new MoxxyError({
|
|
146464
146796
|
code: "TOOL_ERROR",
|
|
146465
|
-
message: `click failed (exit ${proc.exitCode}): ${proc.stderr.trim() || "(check Accessibility permission in System Settings \u2192 Privacy & Security \u2192 Accessibility)"}`,
|
|
146466
|
-
context: { tool: "computer_click", exitCode: proc.exitCode }
|
|
146797
|
+
message: cause ? `click ${cause}` : `click failed (exit ${proc.exitCode}): ${proc.stderr.trim() || "(check Accessibility permission in System Settings \u2192 Privacy & Security \u2192 Accessibility)"}`,
|
|
146798
|
+
context: { tool: "computer_click", exitCode: proc.exitCode, timedOut: proc.timedOut ? 1 : 0 }
|
|
146467
146799
|
});
|
|
146468
146800
|
}
|
|
146469
146801
|
return { ok: true, x: x4, y: y2, count: n2 };
|
|
@@ -146485,10 +146817,11 @@ var clipboardTool = defineTool({
|
|
|
146485
146817
|
timeoutMs: 5e3
|
|
146486
146818
|
});
|
|
146487
146819
|
if (proc2.exitCode !== 0) {
|
|
146820
|
+
const cause = procFailureCause(proc2, 5e3);
|
|
146488
146821
|
throw new MoxxyError({
|
|
146489
146822
|
code: "TOOL_ERROR",
|
|
146490
|
-
message: `pbpaste failed (exit ${proc2.exitCode}): ${proc2.stderr.trim()}`,
|
|
146491
|
-
context: { tool: "computer_clipboard", exitCode: proc2.exitCode }
|
|
146823
|
+
message: cause ? `pbpaste ${cause}` : `pbpaste failed (exit ${proc2.exitCode}): ${proc2.stderr.trim()}`,
|
|
146824
|
+
context: { tool: "computer_clipboard", exitCode: proc2.exitCode, timedOut: proc2.timedOut ? 1 : 0 }
|
|
146492
146825
|
});
|
|
146493
146826
|
}
|
|
146494
146827
|
return { ok: true, text: proc2.stdout };
|
|
@@ -146506,10 +146839,11 @@ var clipboardTool = defineTool({
|
|
|
146506
146839
|
timeoutMs: 5e3
|
|
146507
146840
|
});
|
|
146508
146841
|
if (proc.exitCode !== 0) {
|
|
146842
|
+
const cause = procFailureCause(proc, 5e3);
|
|
146509
146843
|
throw new MoxxyError({
|
|
146510
146844
|
code: "TOOL_ERROR",
|
|
146511
|
-
message: `pbcopy failed (exit ${proc.exitCode}): ${proc.stderr.trim()}`,
|
|
146512
|
-
context: { tool: "computer_clipboard", exitCode: proc.exitCode }
|
|
146845
|
+
message: cause ? `pbcopy ${cause}` : `pbcopy failed (exit ${proc.exitCode}): ${proc.stderr.trim()}`,
|
|
146846
|
+
context: { tool: "computer_clipboard", exitCode: proc.exitCode, timedOut: proc.timedOut ? 1 : 0 }
|
|
146513
146847
|
});
|
|
146514
146848
|
}
|
|
146515
146849
|
return { ok: true, length: text.length };
|
|
@@ -146547,6 +146881,16 @@ var KEY_CODES = {
|
|
|
146547
146881
|
f11: 103,
|
|
146548
146882
|
f12: 111
|
|
146549
146883
|
};
|
|
146884
|
+
var WHITESPACE_KEY_CODES = {
|
|
146885
|
+
" ": 49,
|
|
146886
|
+
// space
|
|
146887
|
+
" ": 48,
|
|
146888
|
+
// tab
|
|
146889
|
+
"\r": 36,
|
|
146890
|
+
// return
|
|
146891
|
+
"\n": 36
|
|
146892
|
+
// return
|
|
146893
|
+
};
|
|
146550
146894
|
var keyTool = defineTool({
|
|
146551
146895
|
name: "computer_key",
|
|
146552
146896
|
description: "Send a single key chord with optional modifiers. Use this for shortcuts (cmd+c, cmd+tab, cmd+shift+4) and named keys (return, tab, escape, arrows, page_up/down, f1\u2013f12). For typing arbitrary text, use computer_type.",
|
|
@@ -146564,10 +146908,11 @@ var keyTool = defineTool({
|
|
|
146564
146908
|
timeoutMs: 1e4
|
|
146565
146909
|
});
|
|
146566
146910
|
if (proc.exitCode !== 0) {
|
|
146911
|
+
const cause = procFailureCause(proc, 1e4);
|
|
146567
146912
|
throw new MoxxyError({
|
|
146568
146913
|
code: "TOOL_ERROR",
|
|
146569
|
-
message: `key failed (exit ${proc.exitCode}): ${proc.stderr.trim() || "(check Accessibility permission)"}`,
|
|
146570
|
-
context: { tool: "computer_key", exitCode: proc.exitCode }
|
|
146914
|
+
message: cause ? `key ${cause}` : `key failed (exit ${proc.exitCode}): ${proc.stderr.trim() || "(check Accessibility permission)"}`,
|
|
146915
|
+
context: { tool: "computer_key", exitCode: proc.exitCode, timedOut: proc.timedOut ? 1 : 0 }
|
|
146571
146916
|
});
|
|
146572
146917
|
}
|
|
146573
146918
|
return { ok: true, key, modifiers: mods };
|
|
@@ -146579,6 +146924,12 @@ function buildKeyScript(key, modifiers) {
|
|
|
146579
146924
|
if (lower2 in KEY_CODES) {
|
|
146580
146925
|
return `tell application "System Events" to key code ${KEY_CODES[lower2]}${usingClause}`;
|
|
146581
146926
|
}
|
|
146927
|
+
if (key.length === 1) {
|
|
146928
|
+
const wsCode = WHITESPACE_KEY_CODES[key];
|
|
146929
|
+
if (wsCode !== void 0) {
|
|
146930
|
+
return `tell application "System Events" to key code ${wsCode}${usingClause}`;
|
|
146931
|
+
}
|
|
146932
|
+
}
|
|
146582
146933
|
if (key.length === 1) {
|
|
146583
146934
|
const literal3 = `"${key.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
146584
146935
|
return `tell application "System Events" to keystroke ${literal3}${usingClause}`;
|
|
@@ -146630,10 +146981,11 @@ var openTool = defineTool({
|
|
|
146630
146981
|
timeoutMs: 1e4
|
|
146631
146982
|
});
|
|
146632
146983
|
if (proc.exitCode !== 0) {
|
|
146984
|
+
const cause = procFailureCause(proc, 1e4);
|
|
146633
146985
|
throw new MoxxyError({
|
|
146634
146986
|
code: "TOOL_ERROR",
|
|
146635
|
-
message: `open failed (exit ${proc.exitCode}): ${proc.stderr.trim() || "(no error message)"}`,
|
|
146636
|
-
context: { tool: "computer_open", exitCode: proc.exitCode }
|
|
146987
|
+
message: cause ? `open ${cause}` : `open failed (exit ${proc.exitCode}): ${proc.stderr.trim() || "(no error message)"}`,
|
|
146988
|
+
context: { tool: "computer_open", exitCode: proc.exitCode, timedOut: proc.timedOut ? 1 : 0 }
|
|
146637
146989
|
});
|
|
146638
146990
|
}
|
|
146639
146991
|
return { ok: true, app, target };
|
|
@@ -146664,7 +147016,8 @@ var screenshotTool = defineTool({
|
|
|
146664
147016
|
const fmt2 = format ?? DEFAULT_FORMAT;
|
|
146665
147017
|
const dim3 = maxDim ?? DEFAULT_MAX_DIM;
|
|
146666
147018
|
const q3 = quality ?? DEFAULT_JPEG_QUALITY;
|
|
146667
|
-
const
|
|
147019
|
+
const uniq = randomUUID();
|
|
147020
|
+
const captureTmp = path3.join(os5.tmpdir(), `moxxy-screencap-${process.pid}-${Date.now()}-${uniq}.png`);
|
|
146668
147021
|
const captureArgs = ["-x", "-t", "png"];
|
|
146669
147022
|
if (region) {
|
|
146670
147023
|
captureArgs.push("-R", `${region.x},${region.y},${region.width},${region.height}`);
|
|
@@ -146675,14 +147028,15 @@ var screenshotTool = defineTool({
|
|
|
146675
147028
|
timeoutMs: 15e3
|
|
146676
147029
|
});
|
|
146677
147030
|
if (cap.exitCode !== 0) {
|
|
147031
|
+
const cause = procFailureCause(cap, 15e3);
|
|
146678
147032
|
throw new MoxxyError({
|
|
146679
147033
|
code: "TOOL_ERROR",
|
|
146680
|
-
message: `screencapture failed (exit ${cap.exitCode}): ${cap.stderr.trim() || "(no stderr \u2014 likely Screen Recording permission missing \u2014 grant in System Settings \u2192 Privacy & Security)"}`,
|
|
146681
|
-
context: { tool: "computer_screenshot", exitCode: cap.exitCode }
|
|
147034
|
+
message: cause ? `screencapture ${cause}` : `screencapture failed (exit ${cap.exitCode}): ${cap.stderr.trim() || "(no stderr \u2014 likely Screen Recording permission missing \u2014 grant in System Settings \u2192 Privacy & Security)"}`,
|
|
147035
|
+
context: { tool: "computer_screenshot", exitCode: cap.exitCode, timedOut: cap.timedOut ? 1 : 0 }
|
|
146682
147036
|
});
|
|
146683
147037
|
}
|
|
146684
147038
|
const outExt = fmt2 === "jpeg" ? "jpg" : "png";
|
|
146685
|
-
const outTmp = path3.join(os5.tmpdir(), `moxxy-screencap-${process.pid}-${Date.now()}-out.${outExt}`);
|
|
147039
|
+
const outTmp = path3.join(os5.tmpdir(), `moxxy-screencap-${process.pid}-${Date.now()}-${uniq}-out.${outExt}`);
|
|
146686
147040
|
const sipsArgs = [
|
|
146687
147041
|
"-Z",
|
|
146688
147042
|
String(dim3),
|
|
@@ -146701,10 +147055,11 @@ var screenshotTool = defineTool({
|
|
|
146701
147055
|
await promises.rm(captureTmp, { force: true });
|
|
146702
147056
|
if (sip.exitCode !== 0) {
|
|
146703
147057
|
await promises.rm(outTmp, { force: true });
|
|
147058
|
+
const cause = procFailureCause(sip, 15e3);
|
|
146704
147059
|
throw new MoxxyError({
|
|
146705
147060
|
code: "TOOL_ERROR",
|
|
146706
|
-
message: `sips resize/convert failed (exit ${sip.exitCode}): ${sip.stderr.trim() || "(no error message)"}`,
|
|
146707
|
-
context: { tool: "computer_screenshot", exitCode: sip.exitCode }
|
|
147061
|
+
message: cause ? `sips resize/convert ${cause}` : `sips resize/convert failed (exit ${sip.exitCode}): ${sip.stderr.trim() || "(no error message)"}`,
|
|
147062
|
+
context: { tool: "computer_screenshot", exitCode: sip.exitCode, timedOut: sip.timedOut ? 1 : 0 }
|
|
146708
147063
|
});
|
|
146709
147064
|
}
|
|
146710
147065
|
try {
|
|
@@ -146747,10 +147102,11 @@ var typeTool = defineTool({
|
|
|
146747
147102
|
timeoutMs: 3e4
|
|
146748
147103
|
});
|
|
146749
147104
|
if (proc.exitCode !== 0) {
|
|
147105
|
+
const cause = procFailureCause(proc, 3e4);
|
|
146750
147106
|
throw new MoxxyError({
|
|
146751
147107
|
code: "TOOL_ERROR",
|
|
146752
|
-
message: `type failed (exit ${proc.exitCode}): ${proc.stderr.trim() || "(check Accessibility permission)"}`,
|
|
146753
|
-
context: { tool: "computer_type", exitCode: proc.exitCode }
|
|
147108
|
+
message: cause ? `type ${cause}` : `type failed (exit ${proc.exitCode}): ${proc.stderr.trim() || "(check Accessibility permission)"}`,
|
|
147109
|
+
context: { tool: "computer_type", exitCode: proc.exitCode, timedOut: proc.timedOut ? 1 : 0 }
|
|
146754
147110
|
});
|
|
146755
147111
|
}
|
|
146756
147112
|
return { ok: true, length: text.length };
|
|
@@ -147682,7 +148038,16 @@ async function loadDir2(dir, scope, logger) {
|
|
|
147682
148038
|
if (!entry.isFile() || !/\.ya?ml$/i.test(entry.name))
|
|
147683
148039
|
continue;
|
|
147684
148040
|
const full = path3.join(dir, entry.name);
|
|
147685
|
-
|
|
148041
|
+
let raw;
|
|
148042
|
+
try {
|
|
148043
|
+
raw = await promises.readFile(full, "utf8");
|
|
148044
|
+
} catch (err) {
|
|
148045
|
+
logger?.warn?.("workflow: unreadable file, skipping", {
|
|
148046
|
+
path: full,
|
|
148047
|
+
error: err instanceof Error ? err.message : String(err)
|
|
148048
|
+
});
|
|
148049
|
+
continue;
|
|
148050
|
+
}
|
|
147686
148051
|
const result = parseWorkflowYaml(raw);
|
|
147687
148052
|
if (!result.ok || !result.workflow) {
|
|
147688
148053
|
logger?.warn?.("workflow: invalid file, skipping", { path: full, errors: result.errors });
|
|
@@ -147719,6 +148084,12 @@ var WorkflowStore = class {
|
|
|
147719
148084
|
byName = /* @__PURE__ */ new Map();
|
|
147720
148085
|
opts;
|
|
147721
148086
|
loaded = false;
|
|
148087
|
+
// Per-instance lock (invariant: serialize whole-map RMW). A reload
|
|
148088
|
+
// (`load()` clears then refills byName) must never interleave with a save
|
|
148089
|
+
// (read byName → write file → set byName) — e.g. an autonomous onChanged
|
|
148090
|
+
// re-sync racing a user `/workflows enable`, or two concurrent toggles —
|
|
148091
|
+
// or the in-memory registry briefly desyncs from disk.
|
|
148092
|
+
mutex = createMutex();
|
|
147722
148093
|
constructor(opts) {
|
|
147723
148094
|
this.opts = opts;
|
|
147724
148095
|
}
|
|
@@ -147730,6 +148101,14 @@ var WorkflowStore = class {
|
|
|
147730
148101
|
}
|
|
147731
148102
|
/** (Re)scan all sources and rebuild the in-memory map. */
|
|
147732
148103
|
async load() {
|
|
148104
|
+
await this.mutex.run(() => this.loadUnlocked());
|
|
148105
|
+
}
|
|
148106
|
+
/**
|
|
148107
|
+
* Rebuild the map without acquiring the mutex — only call from a context
|
|
148108
|
+
* that already holds it (mutators below), so the clear+refill is atomic
|
|
148109
|
+
* with respect to other mutators.
|
|
148110
|
+
*/
|
|
148111
|
+
async loadUnlocked() {
|
|
147733
148112
|
const discovered = await discoverWorkflows({
|
|
147734
148113
|
userDir: this.userDir(),
|
|
147735
148114
|
projectDir: this.projectDir(),
|
|
@@ -147742,6 +148121,10 @@ var WorkflowStore = class {
|
|
|
147742
148121
|
this.byName.set(wf.workflow.name, wf);
|
|
147743
148122
|
this.loaded = true;
|
|
147744
148123
|
}
|
|
148124
|
+
async ensureLoadedUnlocked() {
|
|
148125
|
+
if (!this.loaded)
|
|
148126
|
+
await this.loadUnlocked();
|
|
148127
|
+
}
|
|
147745
148128
|
async ensureLoaded() {
|
|
147746
148129
|
if (!this.loaded)
|
|
147747
148130
|
await this.load();
|
|
@@ -147760,17 +148143,19 @@ var WorkflowStore = class {
|
|
|
147760
148143
|
}
|
|
147761
148144
|
/** Write a new workflow file and register it. Rejects duplicate names. */
|
|
147762
148145
|
async create(workflow, scope) {
|
|
147763
|
-
|
|
147764
|
-
|
|
147765
|
-
|
|
147766
|
-
|
|
147767
|
-
|
|
147768
|
-
|
|
147769
|
-
|
|
147770
|
-
|
|
147771
|
-
|
|
147772
|
-
|
|
147773
|
-
|
|
148146
|
+
return this.mutex.run(async () => {
|
|
148147
|
+
await this.ensureLoadedUnlocked();
|
|
148148
|
+
if (this.byName.has(workflow.name)) {
|
|
148149
|
+
throw new Error(`workflow "${workflow.name}" already exists \u2014 use update instead`);
|
|
148150
|
+
}
|
|
148151
|
+
const dir = scope === "project" ? this.projectDir() : this.userDir();
|
|
148152
|
+
await promises.mkdir(dir, { recursive: true });
|
|
148153
|
+
const file = await uniqueFilename2(dir, workflow.name);
|
|
148154
|
+
await writeFileAtomic(file, serializeWorkflow(workflow));
|
|
148155
|
+
const entry = { workflow, path: file, scope };
|
|
148156
|
+
this.byName.set(workflow.name, entry);
|
|
148157
|
+
return entry;
|
|
148158
|
+
});
|
|
147774
148159
|
}
|
|
147775
148160
|
/**
|
|
147776
148161
|
* Replace a workflow with a new definition. In-place rewrite for user/project
|
|
@@ -147781,7 +148166,10 @@ var WorkflowStore = class {
|
|
|
147781
148166
|
* rename doesn't leave an orphaned duplicate file + stale entry behind.
|
|
147782
148167
|
*/
|
|
147783
148168
|
async save(workflow, previousName) {
|
|
147784
|
-
|
|
148169
|
+
return this.mutex.run(() => this.saveUnlocked(workflow, previousName));
|
|
148170
|
+
}
|
|
148171
|
+
async saveUnlocked(workflow, previousName) {
|
|
148172
|
+
await this.ensureLoadedUnlocked();
|
|
147785
148173
|
const renamed = previousName != null && previousName !== workflow.name ? this.byName.get(previousName) : void 0;
|
|
147786
148174
|
if (renamed && (renamed.scope === "user" || renamed.scope === "project")) {
|
|
147787
148175
|
await promises.rm(renamed.path, { force: true });
|
|
@@ -147806,24 +148194,28 @@ var WorkflowStore = class {
|
|
|
147806
148194
|
}
|
|
147807
148195
|
/** Toggle a workflow's `enabled` flag, persisting the change. */
|
|
147808
148196
|
async setEnabled(name, enabled) {
|
|
147809
|
-
|
|
147810
|
-
|
|
147811
|
-
|
|
147812
|
-
|
|
147813
|
-
|
|
148197
|
+
return this.mutex.run(async () => {
|
|
148198
|
+
await this.ensureLoadedUnlocked();
|
|
148199
|
+
const existing = this.byName.get(name);
|
|
148200
|
+
if (!existing)
|
|
148201
|
+
return null;
|
|
148202
|
+
return this.saveUnlocked({ ...existing.workflow, enabled });
|
|
148203
|
+
});
|
|
147814
148204
|
}
|
|
147815
148205
|
/** Delete a user/project workflow file. Read-only scopes cannot be deleted. */
|
|
147816
148206
|
async delete(name) {
|
|
147817
|
-
|
|
147818
|
-
|
|
147819
|
-
|
|
147820
|
-
|
|
147821
|
-
|
|
147822
|
-
|
|
147823
|
-
|
|
147824
|
-
|
|
147825
|
-
|
|
147826
|
-
|
|
148207
|
+
return this.mutex.run(async () => {
|
|
148208
|
+
await this.ensureLoadedUnlocked();
|
|
148209
|
+
const existing = this.byName.get(name);
|
|
148210
|
+
if (!existing)
|
|
148211
|
+
return { ok: false, reason: "not found" };
|
|
148212
|
+
if (existing.scope !== "user" && existing.scope !== "project") {
|
|
148213
|
+
return { ok: false, reason: `cannot delete a ${existing.scope} workflow` };
|
|
148214
|
+
}
|
|
148215
|
+
await promises.rm(existing.path, { force: true });
|
|
148216
|
+
this.byName.delete(name);
|
|
148217
|
+
return { ok: true };
|
|
148218
|
+
});
|
|
147827
148219
|
}
|
|
147828
148220
|
};
|
|
147829
148221
|
async function uniqueFilename2(dir, base2) {
|
|
@@ -149501,46 +149893,61 @@ function buildWorkflowRunner(args) {
|
|
|
149501
149893
|
}
|
|
149502
149894
|
async function resumeNow(runId, reply2) {
|
|
149503
149895
|
const checkpoint = await defaultWorkflowRunStore.load(runId);
|
|
149504
|
-
const
|
|
149505
|
-
|
|
149506
|
-
|
|
149507
|
-
|
|
149508
|
-
|
|
149509
|
-
|
|
149510
|
-
|
|
149511
|
-
|
|
149512
|
-
|
|
149513
|
-
|
|
149514
|
-
|
|
149515
|
-
|
|
149516
|
-
|
|
149517
|
-
|
|
149518
|
-
|
|
149519
|
-
|
|
149520
|
-
|
|
149521
|
-
|
|
149522
|
-
now: () => Date.now(),
|
|
149523
|
-
emit: (subtype, payload) => void session.log.append({
|
|
149524
|
-
type: "plugin_event",
|
|
149525
|
-
sessionId: session.id,
|
|
149526
|
-
turnId,
|
|
149527
|
-
source: "plugin",
|
|
149528
|
-
pluginId: PLUGIN_ID3,
|
|
149529
|
-
subtype,
|
|
149530
|
-
payload
|
|
149531
|
-
}),
|
|
149532
|
-
...logger ? { logger } : {}
|
|
149533
|
-
},
|
|
149534
|
-
defaultWorkflowRunStore
|
|
149535
|
-
);
|
|
149536
|
-
if (result.status === "paused") {
|
|
149537
|
-
logger?.warn?.("workflows: run paused again awaiting operator input; not delivering to inbox", {
|
|
149538
|
-
runId: result.runId
|
|
149896
|
+
const name = checkpoint?.workflow?.name;
|
|
149897
|
+
if (name && inFlight.has(name)) {
|
|
149898
|
+
return {
|
|
149899
|
+
ok: false,
|
|
149900
|
+
status: "failed",
|
|
149901
|
+
steps: [],
|
|
149902
|
+
output: "",
|
|
149903
|
+
error: `workflow "${name}" is already running`
|
|
149904
|
+
};
|
|
149905
|
+
}
|
|
149906
|
+
if (name) inFlight.add(name);
|
|
149907
|
+
try {
|
|
149908
|
+
const turnId = session.startTurn().turnId;
|
|
149909
|
+
const spawner = createSubagentSpawner({
|
|
149910
|
+
parentSession: session,
|
|
149911
|
+
parentTurnId: turnId,
|
|
149912
|
+
parentSignal: session.signal,
|
|
149913
|
+
parentModel: activeModel(session)
|
|
149539
149914
|
});
|
|
149915
|
+
const result = await resumeWorkflowRun(
|
|
149916
|
+
runId,
|
|
149917
|
+
reply2,
|
|
149918
|
+
{
|
|
149919
|
+
spawner,
|
|
149920
|
+
tools: session.tools,
|
|
149921
|
+
lookup: {
|
|
149922
|
+
skill: (n2) => session.skills.byName(n2),
|
|
149923
|
+
workflow: (n2) => store.lookup(n2)
|
|
149924
|
+
},
|
|
149925
|
+
signal: session.signal,
|
|
149926
|
+
now: () => Date.now(),
|
|
149927
|
+
emit: (subtype, payload) => void session.log.append({
|
|
149928
|
+
type: "plugin_event",
|
|
149929
|
+
sessionId: session.id,
|
|
149930
|
+
turnId,
|
|
149931
|
+
source: "plugin",
|
|
149932
|
+
pluginId: PLUGIN_ID3,
|
|
149933
|
+
subtype,
|
|
149934
|
+
payload
|
|
149935
|
+
}),
|
|
149936
|
+
...logger ? { logger } : {}
|
|
149937
|
+
},
|
|
149938
|
+
defaultWorkflowRunStore
|
|
149939
|
+
);
|
|
149940
|
+
if (result.status === "paused") {
|
|
149941
|
+
logger?.warn?.("workflows: run paused again awaiting operator input; not delivering to inbox", {
|
|
149942
|
+
runId: result.runId
|
|
149943
|
+
});
|
|
149944
|
+
return result;
|
|
149945
|
+
}
|
|
149946
|
+
if (checkpoint?.workflow) await deliverToInbox(checkpoint.workflow, result, logger);
|
|
149540
149947
|
return result;
|
|
149948
|
+
} finally {
|
|
149949
|
+
if (name) inFlight.delete(name);
|
|
149541
149950
|
}
|
|
149542
|
-
if (checkpoint?.workflow) await deliverToInbox(checkpoint.workflow, result, logger);
|
|
149543
|
-
return result;
|
|
149544
149951
|
}
|
|
149545
149952
|
return { runNow, resumeNow };
|
|
149546
149953
|
}
|
|
@@ -150018,7 +150425,7 @@ function buildSchedulerRunner(session) {
|
|
|
150018
150425
|
for await (const event of runTurn(session, prompt, model ? { model } : {})) {
|
|
150019
150426
|
if (event.type === "assistant_message") {
|
|
150020
150427
|
text = event.content;
|
|
150021
|
-
|
|
150428
|
+
lastError = event.stopReason === "error" ? "turn ended with error stop reason" : null;
|
|
150022
150429
|
} else if (event.type === "error") {
|
|
150023
150430
|
lastError = event.message;
|
|
150024
150431
|
}
|
|
@@ -150043,7 +150450,7 @@ function buildWebhookRunner(session) {
|
|
|
150043
150450
|
for await (const event of runTurn(target, prompt, model ? { model } : {})) {
|
|
150044
150451
|
if (event.type === "assistant_message") {
|
|
150045
150452
|
text = event.content;
|
|
150046
|
-
|
|
150453
|
+
lastError = event.stopReason === "error" ? "turn ended with error stop reason" : null;
|
|
150047
150454
|
} else if (event.type === "error") {
|
|
150048
150455
|
lastError = event.message;
|
|
150049
150456
|
}
|
|
@@ -150910,7 +151317,7 @@ async function fetchLatest(pkg = DEFAULT_PKG, opts = {}) {
|
|
|
150910
151317
|
}
|
|
150911
151318
|
|
|
150912
151319
|
// src/update/check.ts
|
|
150913
|
-
var
|
|
151320
|
+
var CACHE_TTL_MS2 = 12 * 60 * 60 * 1e3;
|
|
150914
151321
|
var PKG = "@moxxy/cli";
|
|
150915
151322
|
function defaultCacheFile() {
|
|
150916
151323
|
return moxxyPath("update-check.json");
|
|
@@ -150965,7 +151372,7 @@ async function checkForCliUpdate(current, opts = {}) {
|
|
|
150965
151372
|
const file = opts.cacheFile ?? defaultCacheFile();
|
|
150966
151373
|
if (!opts.force) {
|
|
150967
151374
|
const cache4 = readCache(file);
|
|
150968
|
-
if (cache4 && now - cache4.checkedAt <
|
|
151375
|
+
if (cache4 && now - cache4.checkedAt < CACHE_TTL_MS2) {
|
|
150969
151376
|
return shape(current, cache4.latest);
|
|
150970
151377
|
}
|
|
150971
151378
|
}
|
|
@@ -151179,12 +151586,14 @@ async function collectKey(providerId, controller) {
|
|
|
151179
151586
|
if (!controller.testKey) return value;
|
|
151180
151587
|
const s2 = ft2();
|
|
151181
151588
|
s2.start(`Validating ${providerId} key`);
|
|
151589
|
+
let rejected = false;
|
|
151182
151590
|
try {
|
|
151183
151591
|
const result = await controller.testKey(providerId, value);
|
|
151184
151592
|
if (result.ok) {
|
|
151185
151593
|
s2.stop(`${colors.bold("\u2713")} ${providerId} key looks good`);
|
|
151186
151594
|
return value;
|
|
151187
151595
|
}
|
|
151596
|
+
rejected = true;
|
|
151188
151597
|
s2.stop(`${colors.red("\u2717")} ${providerId} rejected the key: ${result.message}`);
|
|
151189
151598
|
} catch (err) {
|
|
151190
151599
|
s2.stop(
|
|
@@ -151197,6 +151606,7 @@ async function collectKey(providerId, controller) {
|
|
|
151197
151606
|
});
|
|
151198
151607
|
const retry = guard(retryRaw);
|
|
151199
151608
|
if (!retry) {
|
|
151609
|
+
if (rejected) bail();
|
|
151200
151610
|
return value;
|
|
151201
151611
|
}
|
|
151202
151612
|
}
|
|
@@ -152435,7 +152845,7 @@ ${available}`
|
|
|
152435
152845
|
async function runChannelsCommand(argv) {
|
|
152436
152846
|
const [name, sub, ...rest] = argv.positional;
|
|
152437
152847
|
if (!name || name === "list") {
|
|
152438
|
-
return runList2();
|
|
152848
|
+
return runList2(argv);
|
|
152439
152849
|
}
|
|
152440
152850
|
const outcome = await probeSession(
|
|
152441
152851
|
argvToSetupOptions(argv, {
|
|
@@ -152489,12 +152899,13 @@ ${available}`
|
|
|
152489
152899
|
if (outcome !== "run-channel") return outcome.code;
|
|
152490
152900
|
return runChannelByName(name, argv);
|
|
152491
152901
|
}
|
|
152492
|
-
async function runList2() {
|
|
152902
|
+
async function runList2(argv) {
|
|
152493
152903
|
const { entries, config } = await probeSession(
|
|
152494
|
-
argvToSetupOptions(
|
|
152495
|
-
|
|
152496
|
-
|
|
152497
|
-
|
|
152904
|
+
argvToSetupOptions(argv, {
|
|
152905
|
+
skipKeyPrompt: true,
|
|
152906
|
+
tolerateNoProvider: true,
|
|
152907
|
+
skipProviderActivation: true
|
|
152908
|
+
}),
|
|
152498
152909
|
async ({ session, vault, config: config2 }) => ({
|
|
152499
152910
|
config: config2,
|
|
152500
152911
|
entries: await session.channels.listWithAvailability({
|
|
@@ -153171,7 +153582,7 @@ function unitPath(spec) {
|
|
|
153171
153582
|
}
|
|
153172
153583
|
function renderUnit(spec, ctx) {
|
|
153173
153584
|
const execStart = [ctx.node, ctx.cli, ...spec.execArgs].map(quote).join(" ");
|
|
153174
|
-
const envLines = Object.entries(spec.env ?? {}).map(([k3, v3]) => `Environment=${k3}=${v3}`).join("\n");
|
|
153585
|
+
const envLines = Object.entries(spec.env ?? {}).map(([k3, v3]) => `Environment=${k3}=${envValue(v3)}`).join("\n");
|
|
153175
153586
|
return `[Unit]
|
|
153176
153587
|
Description=${spec.description}
|
|
153177
153588
|
After=network-online.target
|
|
@@ -153195,6 +153606,11 @@ function quote(s2) {
|
|
|
153195
153606
|
if (!/[\s"]/.test(s2)) return s2;
|
|
153196
153607
|
return '"' + s2.replace(/"/g, '\\"') + '"';
|
|
153197
153608
|
}
|
|
153609
|
+
function envValue(v3) {
|
|
153610
|
+
const s2 = v3.replace(/[\r\n]+/g, " ");
|
|
153611
|
+
if (!/[\s"\\]/.test(s2)) return s2;
|
|
153612
|
+
return '"' + s2.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + '"';
|
|
153613
|
+
}
|
|
153198
153614
|
var systemdService = {
|
|
153199
153615
|
platform: "linux",
|
|
153200
153616
|
async getStatus(spec) {
|
|
@@ -153423,21 +153839,23 @@ async function runDaemonBackground() {
|
|
|
153423
153839
|
return result.ok ? 0 : 1;
|
|
153424
153840
|
}
|
|
153425
153841
|
async function runDaemonForeground() {
|
|
153426
|
-
const { session
|
|
153842
|
+
const { session } = await setupSessionWithConfig({ cwd: process.cwd() });
|
|
153427
153843
|
process.stdout.write(
|
|
153428
153844
|
`${colors.bold("scheduler daemon")} ${colors.dim("provider=" + (session.providers.getActiveName() ?? "(none)"))}
|
|
153429
153845
|
` + colors.dim(" ^C to stop. Schedules fire while this process is alive.\n")
|
|
153430
153846
|
);
|
|
153431
153847
|
let stopRequested = false;
|
|
153432
|
-
const shutdown = async () => {
|
|
153848
|
+
const shutdown = async (signal) => {
|
|
153433
153849
|
if (stopRequested) return;
|
|
153434
153850
|
stopRequested = true;
|
|
153851
|
+
const force = setTimeout(() => process.exit(0), 4e3);
|
|
153852
|
+
force.unref?.();
|
|
153435
153853
|
process.stdout.write("\nstopping scheduler\u2026\n");
|
|
153436
|
-
await
|
|
153854
|
+
await session.close(signal).catch(() => void 0);
|
|
153437
153855
|
process.exit(0);
|
|
153438
153856
|
};
|
|
153439
|
-
process.on("SIGINT", () => void shutdown());
|
|
153440
|
-
process.on("SIGTERM", () => void shutdown());
|
|
153857
|
+
process.on("SIGINT", () => void shutdown("SIGINT"));
|
|
153858
|
+
process.on("SIGTERM", () => void shutdown("SIGTERM"));
|
|
153441
153859
|
setInterval(() => {
|
|
153442
153860
|
}, 6e4);
|
|
153443
153861
|
return await new Promise(() => {
|