@moxxy/cli 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +194 -31
- package/dist/bin.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -194,6 +194,14 @@ var init_log = __esm({
|
|
|
194
194
|
listeners = /* @__PURE__ */ new Set();
|
|
195
195
|
clearListeners = /* @__PURE__ */ new Set();
|
|
196
196
|
now;
|
|
197
|
+
/**
|
|
198
|
+
* Seq of the FIRST event this log holds. 0 for an authoring log; a mirror
|
|
199
|
+
* primed by a partial attach replay (runner protocol v6 `replay.start`)
|
|
200
|
+
* rebases to the first replayed seq so `ingest`'s contiguity gate lines up
|
|
201
|
+
* with the runner's stream instead of expecting history we never received.
|
|
202
|
+
* `seq === base + index` for every held event.
|
|
203
|
+
*/
|
|
204
|
+
base = 0;
|
|
197
205
|
constructor(seed = [], opts = {}) {
|
|
198
206
|
this.now = opts.now ?? Date.now;
|
|
199
207
|
for (const e3 of seed)
|
|
@@ -202,13 +210,18 @@ var init_log = __esm({
|
|
|
202
210
|
get length() {
|
|
203
211
|
return this.events.length;
|
|
204
212
|
}
|
|
213
|
+
/** Seq of the first held event (see {@link rebase}). */
|
|
214
|
+
get baseSeq() {
|
|
215
|
+
return this.base;
|
|
216
|
+
}
|
|
205
217
|
at(seq) {
|
|
206
|
-
|
|
218
|
+
const index = seq - this.base;
|
|
219
|
+
if (index < 0 || index >= this.events.length)
|
|
207
220
|
return void 0;
|
|
208
|
-
return this.events[
|
|
221
|
+
return this.events[index];
|
|
209
222
|
}
|
|
210
|
-
slice(from = 0, to = this.events.length) {
|
|
211
|
-
return this.events.slice(from, to);
|
|
223
|
+
slice(from = 0, to = this.base + this.events.length) {
|
|
224
|
+
return this.events.slice(Math.max(0, from - this.base), Math.max(0, to - this.base));
|
|
212
225
|
}
|
|
213
226
|
ofType(type) {
|
|
214
227
|
return this.events.filter((e3) => e3.type === type);
|
|
@@ -220,7 +233,7 @@ var init_log = __esm({
|
|
|
220
233
|
return [...this.events];
|
|
221
234
|
}
|
|
222
235
|
async append(partial) {
|
|
223
|
-
const event = materializeEvent(partial, this.events.length, this.now);
|
|
236
|
+
const event = materializeEvent(partial, this.base + this.events.length, this.now);
|
|
224
237
|
this.events.push(event);
|
|
225
238
|
const snapshot = [...this.listeners];
|
|
226
239
|
for (const fn of snapshot) {
|
|
@@ -245,7 +258,7 @@ var init_log = __esm({
|
|
|
245
258
|
* Not for normal authoring; use {@link append} for that.
|
|
246
259
|
*/
|
|
247
260
|
ingest(event) {
|
|
248
|
-
if (event.seq !== this.events.length)
|
|
261
|
+
if (event.seq !== this.base + this.events.length)
|
|
249
262
|
return;
|
|
250
263
|
this.events.push(event);
|
|
251
264
|
const snapshot = [...this.listeners];
|
|
@@ -271,8 +284,25 @@ var init_log = __esm({
|
|
|
271
284
|
* Safe to call only when no turn is in flight — callers should abort
|
|
272
285
|
* their AbortController and await any pending runTurn() first.
|
|
273
286
|
*/
|
|
287
|
+
/**
|
|
288
|
+
* Start this (empty) log at `seq` instead of 0. A mirror primed by a
|
|
289
|
+
* PARTIAL attach replay (`replay: 'none'` / `{ tail }`) calls this with the
|
|
290
|
+
* runner's announced first seq so {@link ingest}'s contiguity gate accepts
|
|
291
|
+
* the stream. Only valid while empty — rebasing held events would detach
|
|
292
|
+
* their seqs from their indices.
|
|
293
|
+
*/
|
|
294
|
+
rebase(seq) {
|
|
295
|
+
if (this.events.length > 0) {
|
|
296
|
+
throw new Error(`EventLog.rebase(${seq}): log already holds ${this.events.length} events`);
|
|
297
|
+
}
|
|
298
|
+
if (!Number.isInteger(seq) || seq < 0) {
|
|
299
|
+
throw new Error(`EventLog.rebase(${seq}): seq must be a non-negative integer`);
|
|
300
|
+
}
|
|
301
|
+
this.base = seq;
|
|
302
|
+
}
|
|
274
303
|
clear() {
|
|
275
304
|
this.events.length = 0;
|
|
305
|
+
this.base = 0;
|
|
276
306
|
const snapshot = [...this.clearListeners];
|
|
277
307
|
for (const fn of snapshot) {
|
|
278
308
|
try {
|
|
@@ -466,9 +496,10 @@ async function runChildTurn(args) {
|
|
|
466
496
|
return resolved.failure;
|
|
467
497
|
const { strategy, strategyName } = resolved;
|
|
468
498
|
const toolRegistry = spec.allowedTools && spec.allowedTools.length > 0 ? buildFilteredToolRegistry(parentSession.tools, new Set(spec.allowedTools)) : parentSession.tools;
|
|
499
|
+
const childModel = await resolveChildModel(rt3, spec, label3, childSessionId);
|
|
469
500
|
const childLog = new EventLog();
|
|
470
|
-
const spawner = createSubagentSpawner(rt3);
|
|
471
|
-
const childCtx = buildChildContext(rt3, spec, childSessionId, childTurnId, toolRegistry, childLog, spawner);
|
|
501
|
+
const spawner = createSubagentSpawner({ ...rt3, parentModel: childModel });
|
|
502
|
+
const childCtx = buildChildContext(rt3, spec, childModel, childSessionId, childTurnId, toolRegistry, childLog, spawner);
|
|
472
503
|
const capture = await executeChildLoop({
|
|
473
504
|
rt: rt3,
|
|
474
505
|
spec,
|
|
@@ -600,12 +631,24 @@ async function resolveStrategy(parentSession, parentTurnId, label3, childSession
|
|
|
600
631
|
}
|
|
601
632
|
};
|
|
602
633
|
}
|
|
603
|
-
function
|
|
604
|
-
const { parentSession,
|
|
634
|
+
async function resolveChildModel(rt3, spec, label3, childSessionId) {
|
|
635
|
+
const { parentSession, parentTurnId, parentModel } = rt3;
|
|
636
|
+
const requested = spec.model;
|
|
637
|
+
if (requested === void 0 || requested === parentModel)
|
|
638
|
+
return parentModel;
|
|
639
|
+
const models = parentSession.providers.getActive().models;
|
|
640
|
+
if (models.length > 0 && !models.some((m3) => m3.id === requested)) {
|
|
641
|
+
await emitSubagentWarning(parentSession, parentTurnId, label3, childSessionId, `unknown model "${requested}" \u2014 falling back to parent model "${parentModel}"`);
|
|
642
|
+
return parentModel;
|
|
643
|
+
}
|
|
644
|
+
return requested;
|
|
645
|
+
}
|
|
646
|
+
function buildChildContext(rt3, spec, model, childSessionId, childTurnId, toolRegistry, childLog, spawner) {
|
|
647
|
+
const { parentSession, parentSignal } = rt3;
|
|
605
648
|
return {
|
|
606
649
|
sessionId: childSessionId,
|
|
607
650
|
turnId: childTurnId,
|
|
608
|
-
model
|
|
651
|
+
model,
|
|
609
652
|
...spec.systemPrompt !== void 0 ? { systemPrompt: spec.systemPrompt } : {},
|
|
610
653
|
provider: parentSession.providers.getActive(),
|
|
611
654
|
tools: toolRegistry,
|
|
@@ -674,6 +717,7 @@ async function* runTurn(session, prompt, opts = {}) {
|
|
|
674
717
|
const turnId = opts.turnId ?? session.startTurn().turnId;
|
|
675
718
|
const provider = session.providers.getActive();
|
|
676
719
|
const model = opts.model ?? provider.models[0]?.id ?? "default";
|
|
720
|
+
session.lastResolvedModel = model;
|
|
677
721
|
const queue = [];
|
|
678
722
|
const waiters = [];
|
|
679
723
|
let done = false;
|
|
@@ -3023,6 +3067,11 @@ var init_session = __esm({
|
|
|
3023
3067
|
elisionSettings = null;
|
|
3024
3068
|
/** Lazy tool loading toggle, from `config.context.lazyTools`. Default off. */
|
|
3025
3069
|
lazyTools = false;
|
|
3070
|
+
/**
|
|
3071
|
+
* Model id resolved by the most recent `runTurn()` (see SessionRuntime).
|
|
3072
|
+
* Last-writer-wins for concurrent turns; null until the first turn runs.
|
|
3073
|
+
*/
|
|
3074
|
+
lastResolvedModel = null;
|
|
3026
3075
|
/**
|
|
3027
3076
|
* Live runtime capabilities the host installs on a local Session (see
|
|
3028
3077
|
* SessionLike). A RemoteSession leaves them undefined. Declared here — rather
|
|
@@ -3638,7 +3687,7 @@ The body is the instructions for future invocations. Keep it under 30 lines. Num
|
|
|
3638
3687
|
});
|
|
3639
3688
|
async function synthesizeSkill(session, intent, scope, opts = {}) {
|
|
3640
3689
|
const provider = session.providers.getActive();
|
|
3641
|
-
const model = opts.model ?? provider.models[0]?.id ?? "
|
|
3690
|
+
const model = opts.model ?? session.lastResolvedModel ?? provider.models[0]?.id ?? "default";
|
|
3642
3691
|
const draft = await draftSkill(provider, model, intent, session.signal);
|
|
3643
3692
|
const baseDir = scope === "project" ? opts.projectDir ?? defaultProjectSkillsDir(session.cwd) : opts.userDir ?? defaultUserSkillsDir();
|
|
3644
3693
|
await promises.mkdir(baseDir, { recursive: true });
|
|
@@ -134325,13 +134374,14 @@ async function createWebSocketTransportServer(opts) {
|
|
|
134325
134374
|
const host = opts.host ?? "127.0.0.1";
|
|
134326
134375
|
const maxConnections = opts.maxConnections ?? DEFAULT_MAX_CONNECTIONS;
|
|
134327
134376
|
let currentToken = opts.authToken;
|
|
134377
|
+
let currentAllowedOrigins = opts.allowedOrigins ?? [];
|
|
134328
134378
|
let connections = 0;
|
|
134329
134379
|
const wss = new import_websocket_server.default({
|
|
134330
134380
|
host,
|
|
134331
134381
|
port: opts.port,
|
|
134332
134382
|
maxPayload: opts.maxPayloadBytes ?? 64 * 1024 * 1024,
|
|
134333
134383
|
verifyClient: (info) => {
|
|
134334
|
-
if (!checkWsOrigin(info.req,
|
|
134384
|
+
if (!checkWsOrigin(info.req, currentAllowedOrigins)) {
|
|
134335
134385
|
console.warn(`[moxxy] ws bridge: rejected browser-origin upgrade (Origin: ${String(info.req.headers.origin)})`);
|
|
134336
134386
|
return false;
|
|
134337
134387
|
}
|
|
@@ -134371,6 +134421,9 @@ async function createWebSocketTransportServer(opts) {
|
|
|
134371
134421
|
for (const client of wss.clients)
|
|
134372
134422
|
client.terminate();
|
|
134373
134423
|
},
|
|
134424
|
+
setAllowedOrigins(origins) {
|
|
134425
|
+
currentAllowedOrigins = [...origins];
|
|
134426
|
+
},
|
|
134374
134427
|
clientCount() {
|
|
134375
134428
|
return connections;
|
|
134376
134429
|
},
|
|
@@ -134704,7 +134757,7 @@ function isRunnerUp(socketPath = runnerSocketPath()) {
|
|
|
134704
134757
|
|
|
134705
134758
|
// ../runner/dist/server.js
|
|
134706
134759
|
init_dist();
|
|
134707
|
-
var RUNNER_PROTOCOL_VERSION =
|
|
134760
|
+
var RUNNER_PROTOCOL_VERSION = 6;
|
|
134708
134761
|
var MIN_COMPATIBLE_PROTOCOL_VERSION = 1;
|
|
134709
134762
|
var RunnerMethod = {
|
|
134710
134763
|
/** client->server: handshake; returns the initial info snapshot. */
|
|
@@ -134779,7 +134832,14 @@ var RunnerNotification = {
|
|
|
134779
134832
|
* clear: post-reset events restart at seq 0, which a seq-contiguous
|
|
134780
134833
|
* mirror only accepts from an empty log.
|
|
134781
134834
|
*/
|
|
134782
|
-
SessionReset: "session.reset"
|
|
134835
|
+
SessionReset: "session.reset",
|
|
134836
|
+
/**
|
|
134837
|
+
* Sent once, immediately before the attach-time replay loop (v6): the
|
|
134838
|
+
* first seq this connection will replay/stream. The client rebases its
|
|
134839
|
+
* (empty) mirror to `fromSeq` so a partial replay (`replay: 'none'` /
|
|
134840
|
+
* `{ tail }`) ingests contiguously instead of dropping every event.
|
|
134841
|
+
*/
|
|
134842
|
+
ReplayStart: "replay.start"
|
|
134783
134843
|
};
|
|
134784
134844
|
var attachmentSchema = z.object({
|
|
134785
134845
|
kind: z.string(),
|
|
@@ -134790,14 +134850,22 @@ var attachmentSchema = z.object({
|
|
|
134790
134850
|
var attachParamsSchema = z.object({
|
|
134791
134851
|
protocolVersion: z.number(),
|
|
134792
134852
|
role: z.string(),
|
|
134793
|
-
sinceSeq: z.number().int().nonnegative().optional()
|
|
134853
|
+
sinceSeq: z.number().int().nonnegative().optional(),
|
|
134854
|
+
replay: z.union([
|
|
134855
|
+
z.literal("full"),
|
|
134856
|
+
z.literal("none"),
|
|
134857
|
+
z.object({ tail: z.number().int().positive() })
|
|
134858
|
+
]).optional()
|
|
134794
134859
|
});
|
|
134795
134860
|
var runTurnParamsSchema = z.object({
|
|
134796
134861
|
prompt: z.string(),
|
|
134797
134862
|
model: z.string().optional(),
|
|
134798
134863
|
systemPrompt: z.string().optional(),
|
|
134799
134864
|
maxIterations: z.number().int().positive().optional(),
|
|
134800
|
-
attachments: z.array(attachmentSchema).optional()
|
|
134865
|
+
attachments: z.array(attachmentSchema).optional(),
|
|
134866
|
+
// Bounded like the other id-bearing params so a hostile client can't stuff
|
|
134867
|
+
// an arbitrary blob into every event of the turn.
|
|
134868
|
+
turnId: z.string().min(1).max(120).optional()
|
|
134801
134869
|
});
|
|
134802
134870
|
var abortParamsSchema = z.object({ turnId: z.string() });
|
|
134803
134871
|
var setResolverParamsSchema = z.object({
|
|
@@ -134945,7 +135013,11 @@ var RunnerServer = class {
|
|
|
134945
135013
|
}
|
|
134946
135014
|
client.role = params.role;
|
|
134947
135015
|
client.attached = true;
|
|
134948
|
-
|
|
135016
|
+
const replay = params.replay ?? "full";
|
|
135017
|
+
const total = this.session.log.length;
|
|
135018
|
+
const start = replay === "full" ? 0 : replay === "none" ? total : Math.max(0, total - replay.tail);
|
|
135019
|
+
client.peer.notify(RunnerNotification.ReplayStart, { fromSeq: start });
|
|
135020
|
+
for (const event of this.session.log.slice(start)) {
|
|
134949
135021
|
client.peer.notify(RunnerNotification.Event, { event });
|
|
134950
135022
|
}
|
|
134951
135023
|
return {
|
|
@@ -134956,7 +135028,10 @@ var RunnerServer = class {
|
|
|
134956
135028
|
}
|
|
134957
135029
|
handleRunTurn(client, raw) {
|
|
134958
135030
|
const params = runTurnParamsSchema.parse(raw);
|
|
134959
|
-
const turnId = newTurnId();
|
|
135031
|
+
const turnId = params.turnId ? asTurnId(params.turnId) : newTurnId();
|
|
135032
|
+
if (this.turnControllers.has(turnId)) {
|
|
135033
|
+
throw new Error(`turn id ${turnId} is already in flight \u2014 client-supplied turn ids must be unique`);
|
|
135034
|
+
}
|
|
134960
135035
|
const controller = new AbortController();
|
|
134961
135036
|
this.turnControllers.set(turnId, { controller, owner: client });
|
|
134962
135037
|
client.turns.add(turnId);
|
|
@@ -135361,6 +135436,10 @@ var RemoteSession = class {
|
|
|
135361
135436
|
this.peer.on(RunnerNotification.InfoChanged, (params) => {
|
|
135362
135437
|
this.info = params.info;
|
|
135363
135438
|
});
|
|
135439
|
+
this.peer.on(RunnerNotification.ReplayStart, (params) => {
|
|
135440
|
+
const { fromSeq } = params;
|
|
135441
|
+
this.mirror.rebase(fromSeq);
|
|
135442
|
+
});
|
|
135364
135443
|
this.peer.on(RunnerNotification.SessionReset, () => {
|
|
135365
135444
|
this.mirror.clear();
|
|
135366
135445
|
});
|
|
@@ -135404,11 +135483,12 @@ var RemoteSession = class {
|
|
|
135404
135483
|
return new Set(this.info?.readyProviders ?? []);
|
|
135405
135484
|
}
|
|
135406
135485
|
/** Handshake. Resolves once history has been replayed into the mirror. */
|
|
135407
|
-
async attach(role, sinceSeq) {
|
|
135486
|
+
async attach(role, sinceSeq, replay) {
|
|
135408
135487
|
const result = await this.peer.request(RunnerMethod.Attach, {
|
|
135409
135488
|
protocolVersion: RUNNER_PROTOCOL_VERSION,
|
|
135410
135489
|
role,
|
|
135411
|
-
sinceSeq
|
|
135490
|
+
sinceSeq,
|
|
135491
|
+
...replay ? { replay } : {}
|
|
135412
135492
|
});
|
|
135413
135493
|
this.info = result.info;
|
|
135414
135494
|
this.serverProtocolVersion = typeof result.protocolVersion === "number" ? result.protocolVersion : RUNNER_PROTOCOL_VERSION;
|
|
@@ -135463,7 +135543,11 @@ var RemoteSession = class {
|
|
|
135463
135543
|
...opts.model ? { model: opts.model } : {},
|
|
135464
135544
|
...opts.systemPrompt ? { systemPrompt: opts.systemPrompt } : {},
|
|
135465
135545
|
...opts.maxIterations ? { maxIterations: opts.maxIterations } : {},
|
|
135466
|
-
...opts.attachments && opts.attachments.length > 0 ? { attachments: opts.attachments } : {}
|
|
135546
|
+
...opts.attachments && opts.attachments.length > 0 ? { attachments: opts.attachments } : {},
|
|
135547
|
+
// Pre-minted client turn id (v6) so per-turn event filters match. The
|
|
135548
|
+
// reply's turnId stays authoritative: an older server ignores ours and
|
|
135549
|
+
// mints its own.
|
|
135550
|
+
...opts.turnId ? { turnId: opts.turnId } : {}
|
|
135467
135551
|
});
|
|
135468
135552
|
const turnId = result.turnId;
|
|
135469
135553
|
const stream = new TurnStream();
|
|
@@ -135758,7 +135842,7 @@ async function connectRemoteSession(opts = {}) {
|
|
|
135758
135842
|
const transport = opts.transport ?? await connectWithRetry(socketPath, opts.connectRetries ?? 5);
|
|
135759
135843
|
const session = new RemoteSession(transport);
|
|
135760
135844
|
try {
|
|
135761
|
-
await session.attach(opts.role ?? "client", opts.sinceSeq ?? 0);
|
|
135845
|
+
await session.attach(opts.role ?? "client", opts.sinceSeq ?? 0, opts.replay);
|
|
135762
135846
|
return session;
|
|
135763
135847
|
} catch (err) {
|
|
135764
135848
|
await maybeRecoverFromMismatch(err, socketPath, opts);
|
|
@@ -135914,6 +135998,17 @@ var REMOTE_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
135914
135998
|
"session.setMode",
|
|
135915
135999
|
"session.newSession",
|
|
135916
136000
|
"session.runCommand",
|
|
136001
|
+
// Multi-session conversations: list/create/switch/rename are conversation-
|
|
136002
|
+
// scoped — the same trust class as `session.newSession` (already allowed),
|
|
136003
|
+
// and what a paired phone needs to mirror the desktop's session list.
|
|
136004
|
+
// `sessions.remove` is deliberately NOT here: it deletes on-disk state
|
|
136005
|
+
// (the runner's session JSONL + the chat NDJSON transcript), a destructive
|
|
136006
|
+
// host mutation in the same class as `desks.remove`, which is also
|
|
136007
|
+
// host-only.
|
|
136008
|
+
"sessions.list",
|
|
136009
|
+
"sessions.create",
|
|
136010
|
+
"sessions.setActive",
|
|
136011
|
+
"sessions.rename",
|
|
135917
136012
|
// Voice input (capability-probed; transcribe fails coded without a transcriber).
|
|
135918
136013
|
"session.hasTranscriber",
|
|
135919
136014
|
"session.transcribe",
|
|
@@ -136049,6 +136144,20 @@ var ipcInputSchemas = {
|
|
|
136049
136144
|
id: z.string().min(1).max(256),
|
|
136050
136145
|
name: z.string().min(1).max(200)
|
|
136051
136146
|
}),
|
|
136147
|
+
// Sessions: create/rename persist the name into the desks JSON (bound it
|
|
136148
|
+
// like desks.create/rename); setActive spawns a runner and remove deletes
|
|
136149
|
+
// the session's on-disk logs, so their ids are bounded too. These commands
|
|
136150
|
+
// are also served to remote (WS) clients, so the bounds are load-bearing.
|
|
136151
|
+
"sessions.create": z.object({
|
|
136152
|
+
deskId: z.string().min(1).max(256).optional(),
|
|
136153
|
+
name: z.string().min(1).max(200).optional()
|
|
136154
|
+
}).optional(),
|
|
136155
|
+
"sessions.setActive": z.object({ id: z.string().min(1).max(256) }),
|
|
136156
|
+
"sessions.remove": z.object({ id: z.string().min(1).max(256) }),
|
|
136157
|
+
"sessions.rename": z.object({
|
|
136158
|
+
id: z.string().min(1).max(256),
|
|
136159
|
+
name: z.string().min(1).max(200)
|
|
136160
|
+
}),
|
|
136052
136161
|
// Whitelist the fields a renderer may write — `version` is managed by
|
|
136053
136162
|
// the main process; unknown keys are rejected (.strict()).
|
|
136054
136163
|
"prefs.update": z.object({
|
|
@@ -136056,7 +136165,8 @@ var ipcInputSchemas = {
|
|
|
136056
136165
|
clerkUserId: z.string().max(256).nullable().optional(),
|
|
136057
136166
|
clerkDisplayName: z.string().max(256).nullable().optional(),
|
|
136058
136167
|
signedInAt: z.number().nullable().optional(),
|
|
136059
|
-
mobileGatewayEnabled: z.boolean().optional()
|
|
136168
|
+
mobileGatewayEnabled: z.boolean().optional(),
|
|
136169
|
+
theme: z.enum(["light", "dark", "system"]).optional()
|
|
136060
136170
|
}).strict(),
|
|
136061
136171
|
// Mobile-gateway control. Both no-arg variants pin the payload to "nothing"
|
|
136062
136172
|
// so a hostile caller can't smuggle args; setEnabled is a strict boolean.
|
|
@@ -136444,14 +136554,41 @@ function isWildcardHost(host) {
|
|
|
136444
136554
|
const h3 = host.trim().toLowerCase();
|
|
136445
136555
|
return h3 === "0.0.0.0" || h3 === "::" || h3 === "[::]";
|
|
136446
136556
|
}
|
|
136557
|
+
var VIRTUAL_IFACE = /^(?:utun|tun|tap|ppp|ipsec|wg|zt|ts|tailscale|vmnet|vnic|bridge|docker|veth|awdl|llw|ap|anpi)\d*$/i;
|
|
136558
|
+
function isLinkLocalV4(ip) {
|
|
136559
|
+
return ip.startsWith("169.254.");
|
|
136560
|
+
}
|
|
136561
|
+
function isRfc1918(ip) {
|
|
136562
|
+
if (ip.startsWith("10.") || ip.startsWith("192.168."))
|
|
136563
|
+
return true;
|
|
136564
|
+
const m3 = /^172\.(\d{1,3})\./.exec(ip);
|
|
136565
|
+
return m3 !== null && Number(m3[1]) >= 16 && Number(m3[1]) <= 31;
|
|
136566
|
+
}
|
|
136567
|
+
function isCgnat(ip) {
|
|
136568
|
+
const m3 = /^100\.(\d{1,3})\./.exec(ip);
|
|
136569
|
+
return m3 !== null && Number(m3[1]) >= 64 && Number(m3[1]) <= 127;
|
|
136570
|
+
}
|
|
136447
136571
|
function lanHost(fallback) {
|
|
136448
|
-
|
|
136572
|
+
let best = null;
|
|
136573
|
+
for (const [name, list] of Object.entries(os5__default.networkInterfaces())) {
|
|
136449
136574
|
for (const ni of list ?? []) {
|
|
136450
|
-
if (ni.family
|
|
136451
|
-
|
|
136575
|
+
if (ni.family !== "IPv4" || ni.internal)
|
|
136576
|
+
continue;
|
|
136577
|
+
const virtual = VIRTUAL_IFACE.test(name);
|
|
136578
|
+
let rank;
|
|
136579
|
+
if (isLinkLocalV4(ni.address))
|
|
136580
|
+
rank = 5;
|
|
136581
|
+
else if (isRfc1918(ni.address))
|
|
136582
|
+
rank = virtual ? 3 : 1;
|
|
136583
|
+
else if (isCgnat(ni.address))
|
|
136584
|
+
rank = 4;
|
|
136585
|
+
else
|
|
136586
|
+
rank = virtual ? 4 : 2;
|
|
136587
|
+
if (!best || rank < best.rank)
|
|
136588
|
+
best = { address: ni.address, rank };
|
|
136452
136589
|
}
|
|
136453
136590
|
}
|
|
136454
|
-
return fallback;
|
|
136591
|
+
return best?.address ?? fallback;
|
|
136455
136592
|
}
|
|
136456
136593
|
function advertisedHost(bindHost) {
|
|
136457
136594
|
if (isWildcardHost(bindHost))
|
|
@@ -136467,6 +136604,20 @@ function buildConnectUrl(opts) {
|
|
|
136467
136604
|
}
|
|
136468
136605
|
return `ws://${opts.localHost}:${opts.port}/?t=${t2}`;
|
|
136469
136606
|
}
|
|
136607
|
+
function connectUrlOrigin(url2) {
|
|
136608
|
+
const u2 = new URL(url2);
|
|
136609
|
+
const secure = u2.protocol === "wss:" || u2.protocol === "https:";
|
|
136610
|
+
return `${secure ? "https" : "http"}://${u2.host}`;
|
|
136611
|
+
}
|
|
136612
|
+
function advertisedOrigins(bindHost, port) {
|
|
136613
|
+
return [
|
|
136614
|
+
.../* @__PURE__ */ new Set([
|
|
136615
|
+
connectUrlOrigin(`ws://${advertisedHost(bindHost)}:${port}`),
|
|
136616
|
+
`http://127.0.0.1:${port}`,
|
|
136617
|
+
`http://localhost:${port}`
|
|
136618
|
+
])
|
|
136619
|
+
];
|
|
136620
|
+
}
|
|
136470
136621
|
|
|
136471
136622
|
// ../plugin-channel-mobile/dist/tunnel.js
|
|
136472
136623
|
function normalizeTunnelChoice(raw) {
|
|
@@ -136551,10 +136702,12 @@ var MobileChannel = class {
|
|
|
136551
136702
|
this.host = host;
|
|
136552
136703
|
host.register();
|
|
136553
136704
|
host.wire();
|
|
136705
|
+
const localOrigins = advertisedOrigins(this.bindHost, this.port);
|
|
136554
136706
|
const server = await startWsBridge(bus, {
|
|
136555
136707
|
port: this.port,
|
|
136556
136708
|
host: this.bindHost,
|
|
136557
136709
|
authToken: this.token,
|
|
136710
|
+
allowedOrigins: localOrigins,
|
|
136558
136711
|
// Back-compat ONLY: the QR this channel prints embeds the token as `?t=`
|
|
136559
136712
|
// (pairing payload); current apps strip it and authenticate via the
|
|
136560
136713
|
// Sec-WebSocket-Protocol bearer entry, but older installed builds still
|
|
@@ -136569,6 +136722,7 @@ var MobileChannel = class {
|
|
|
136569
136722
|
try {
|
|
136570
136723
|
this.tunnel = await provider.open({ port: this.port, host: this.bindHost });
|
|
136571
136724
|
tunnelUrl = this.tunnel.url;
|
|
136725
|
+
server.setAllowedOrigins([...localOrigins, connectUrlOrigin(tunnelUrl)]);
|
|
136572
136726
|
this.logger?.info?.("mobile tunnel open", { provider: provider.name, url: tunnelUrl });
|
|
136573
136727
|
} catch (err) {
|
|
136574
136728
|
this.logger?.warn?.("mobile tunnel failed; using the local URL", {
|
|
@@ -137300,7 +137454,7 @@ var agentSpecSchema = z$1.object({
|
|
|
137300
137454
|
agentType: z$1.string().optional().describe('Named agent kind to spawn (e.g. "researcher", "code-reviewer"). Looked up in the agent registry contributed by installed plugins. Omit, or pass "default", for a generic tool-use agent. Unknown types fall back to default \u2014 the request never fails over a missing kind. List of currently-registered kinds is visible via the /agents command.'),
|
|
137301
137455
|
label: z$1.string().max(60).optional().describe('Short label shown in progress events (e.g. "research-deps", "lint-fix-A").'),
|
|
137302
137456
|
systemPrompt: z$1.string().optional().describe("Override the kind's system prompt. Use to set persona, constraints, or hand off upstream artifacts the child needs as context."),
|
|
137303
|
-
model: z$1.string().optional().describe("Model id override; defaults to the kind's model, then the parent's."),
|
|
137457
|
+
model: z$1.string().optional().describe("Model id override; defaults to the kind's model, then the parent's. Omit unless the user explicitly requested a specific model \u2014 do NOT invent model ids. Unknown ids fall back to the parent's model with a warning."),
|
|
137304
137458
|
mode: z$1.string().optional().describe(`Loop strategy override. Valid values: "default", "goal", "research". OMIT for the kind's default \u2014 do NOT invent names.`),
|
|
137305
137459
|
allowedTools: z$1.array(z$1.string()).optional().describe("Restrict the child to these tool names. Overrides the kind's allowlist if set.")
|
|
137306
137460
|
});
|
|
@@ -143956,7 +144110,7 @@ function createTool(deps) {
|
|
|
143956
144110
|
if (!provider) {
|
|
143957
144111
|
throw new MoxxyError({ code: "PROVIDER_NOT_CONFIGURED", message: "workflow_create: no active provider to draft with." });
|
|
143958
144112
|
}
|
|
143959
|
-
const model = deps.draftModel ?? provider.models[0]?.id ?? "
|
|
144113
|
+
const model = deps.draftModel ?? provider.models[0]?.id ?? "default";
|
|
143960
144114
|
const drafted = await draftWorkflow(provider, model, intent, ctx.signal, {
|
|
143961
144115
|
...deps.listSkills ? { availableSkills: deps.listSkills() } : {},
|
|
143962
144116
|
...deps.listTools ? { availableTools: deps.listTools() } : {},
|
|
@@ -144847,7 +145001,7 @@ async function fireAfterWorkflowDependents(args) {
|
|
|
144847
145001
|
}
|
|
144848
145002
|
}
|
|
144849
145003
|
function activeModel(session) {
|
|
144850
|
-
return safeActiveProvider(session)?.models[0]?.id ?? "
|
|
145004
|
+
return session.lastResolvedModel ?? safeActiveProvider(session)?.models[0]?.id ?? "default";
|
|
144851
145005
|
}
|
|
144852
145006
|
function safeActiveProvider(session) {
|
|
144853
145007
|
try {
|
|
@@ -145356,6 +145510,15 @@ function scopedSessionView(session, allowedTools, triggerName) {
|
|
|
145356
145510
|
get pluginHost() {
|
|
145357
145511
|
return session.pluginHost;
|
|
145358
145512
|
},
|
|
145513
|
+
// Read-through AND write-through: runTurn records the resolved model on
|
|
145514
|
+
// the session it was handed, and that must land on the real session, not
|
|
145515
|
+
// this per-fire view.
|
|
145516
|
+
get lastResolvedModel() {
|
|
145517
|
+
return session.lastResolvedModel;
|
|
145518
|
+
},
|
|
145519
|
+
set lastResolvedModel(model) {
|
|
145520
|
+
session.lastResolvedModel = model;
|
|
145521
|
+
},
|
|
145359
145522
|
startTurn: () => session.startTurn(),
|
|
145360
145523
|
appContext: () => session.appContext()
|
|
145361
145524
|
};
|