@moxxy/cli 0.8.1 → 0.8.2
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 +114 -25
- 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 });
|
|
@@ -134704,7 +134753,7 @@ function isRunnerUp(socketPath = runnerSocketPath()) {
|
|
|
134704
134753
|
|
|
134705
134754
|
// ../runner/dist/server.js
|
|
134706
134755
|
init_dist();
|
|
134707
|
-
var RUNNER_PROTOCOL_VERSION =
|
|
134756
|
+
var RUNNER_PROTOCOL_VERSION = 6;
|
|
134708
134757
|
var MIN_COMPATIBLE_PROTOCOL_VERSION = 1;
|
|
134709
134758
|
var RunnerMethod = {
|
|
134710
134759
|
/** client->server: handshake; returns the initial info snapshot. */
|
|
@@ -134779,7 +134828,14 @@ var RunnerNotification = {
|
|
|
134779
134828
|
* clear: post-reset events restart at seq 0, which a seq-contiguous
|
|
134780
134829
|
* mirror only accepts from an empty log.
|
|
134781
134830
|
*/
|
|
134782
|
-
SessionReset: "session.reset"
|
|
134831
|
+
SessionReset: "session.reset",
|
|
134832
|
+
/**
|
|
134833
|
+
* Sent once, immediately before the attach-time replay loop (v6): the
|
|
134834
|
+
* first seq this connection will replay/stream. The client rebases its
|
|
134835
|
+
* (empty) mirror to `fromSeq` so a partial replay (`replay: 'none'` /
|
|
134836
|
+
* `{ tail }`) ingests contiguously instead of dropping every event.
|
|
134837
|
+
*/
|
|
134838
|
+
ReplayStart: "replay.start"
|
|
134783
134839
|
};
|
|
134784
134840
|
var attachmentSchema = z.object({
|
|
134785
134841
|
kind: z.string(),
|
|
@@ -134790,14 +134846,22 @@ var attachmentSchema = z.object({
|
|
|
134790
134846
|
var attachParamsSchema = z.object({
|
|
134791
134847
|
protocolVersion: z.number(),
|
|
134792
134848
|
role: z.string(),
|
|
134793
|
-
sinceSeq: z.number().int().nonnegative().optional()
|
|
134849
|
+
sinceSeq: z.number().int().nonnegative().optional(),
|
|
134850
|
+
replay: z.union([
|
|
134851
|
+
z.literal("full"),
|
|
134852
|
+
z.literal("none"),
|
|
134853
|
+
z.object({ tail: z.number().int().positive() })
|
|
134854
|
+
]).optional()
|
|
134794
134855
|
});
|
|
134795
134856
|
var runTurnParamsSchema = z.object({
|
|
134796
134857
|
prompt: z.string(),
|
|
134797
134858
|
model: z.string().optional(),
|
|
134798
134859
|
systemPrompt: z.string().optional(),
|
|
134799
134860
|
maxIterations: z.number().int().positive().optional(),
|
|
134800
|
-
attachments: z.array(attachmentSchema).optional()
|
|
134861
|
+
attachments: z.array(attachmentSchema).optional(),
|
|
134862
|
+
// Bounded like the other id-bearing params so a hostile client can't stuff
|
|
134863
|
+
// an arbitrary blob into every event of the turn.
|
|
134864
|
+
turnId: z.string().min(1).max(120).optional()
|
|
134801
134865
|
});
|
|
134802
134866
|
var abortParamsSchema = z.object({ turnId: z.string() });
|
|
134803
134867
|
var setResolverParamsSchema = z.object({
|
|
@@ -134945,7 +135009,11 @@ var RunnerServer = class {
|
|
|
134945
135009
|
}
|
|
134946
135010
|
client.role = params.role;
|
|
134947
135011
|
client.attached = true;
|
|
134948
|
-
|
|
135012
|
+
const replay = params.replay ?? "full";
|
|
135013
|
+
const total = this.session.log.length;
|
|
135014
|
+
const start = replay === "full" ? 0 : replay === "none" ? total : Math.max(0, total - replay.tail);
|
|
135015
|
+
client.peer.notify(RunnerNotification.ReplayStart, { fromSeq: start });
|
|
135016
|
+
for (const event of this.session.log.slice(start)) {
|
|
134949
135017
|
client.peer.notify(RunnerNotification.Event, { event });
|
|
134950
135018
|
}
|
|
134951
135019
|
return {
|
|
@@ -134956,7 +135024,10 @@ var RunnerServer = class {
|
|
|
134956
135024
|
}
|
|
134957
135025
|
handleRunTurn(client, raw) {
|
|
134958
135026
|
const params = runTurnParamsSchema.parse(raw);
|
|
134959
|
-
const turnId = newTurnId();
|
|
135027
|
+
const turnId = params.turnId ? asTurnId(params.turnId) : newTurnId();
|
|
135028
|
+
if (this.turnControllers.has(turnId)) {
|
|
135029
|
+
throw new Error(`turn id ${turnId} is already in flight \u2014 client-supplied turn ids must be unique`);
|
|
135030
|
+
}
|
|
134960
135031
|
const controller = new AbortController();
|
|
134961
135032
|
this.turnControllers.set(turnId, { controller, owner: client });
|
|
134962
135033
|
client.turns.add(turnId);
|
|
@@ -135361,6 +135432,10 @@ var RemoteSession = class {
|
|
|
135361
135432
|
this.peer.on(RunnerNotification.InfoChanged, (params) => {
|
|
135362
135433
|
this.info = params.info;
|
|
135363
135434
|
});
|
|
135435
|
+
this.peer.on(RunnerNotification.ReplayStart, (params) => {
|
|
135436
|
+
const { fromSeq } = params;
|
|
135437
|
+
this.mirror.rebase(fromSeq);
|
|
135438
|
+
});
|
|
135364
135439
|
this.peer.on(RunnerNotification.SessionReset, () => {
|
|
135365
135440
|
this.mirror.clear();
|
|
135366
135441
|
});
|
|
@@ -135404,11 +135479,12 @@ var RemoteSession = class {
|
|
|
135404
135479
|
return new Set(this.info?.readyProviders ?? []);
|
|
135405
135480
|
}
|
|
135406
135481
|
/** Handshake. Resolves once history has been replayed into the mirror. */
|
|
135407
|
-
async attach(role, sinceSeq) {
|
|
135482
|
+
async attach(role, sinceSeq, replay) {
|
|
135408
135483
|
const result = await this.peer.request(RunnerMethod.Attach, {
|
|
135409
135484
|
protocolVersion: RUNNER_PROTOCOL_VERSION,
|
|
135410
135485
|
role,
|
|
135411
|
-
sinceSeq
|
|
135486
|
+
sinceSeq,
|
|
135487
|
+
...replay ? { replay } : {}
|
|
135412
135488
|
});
|
|
135413
135489
|
this.info = result.info;
|
|
135414
135490
|
this.serverProtocolVersion = typeof result.protocolVersion === "number" ? result.protocolVersion : RUNNER_PROTOCOL_VERSION;
|
|
@@ -135463,7 +135539,11 @@ var RemoteSession = class {
|
|
|
135463
135539
|
...opts.model ? { model: opts.model } : {},
|
|
135464
135540
|
...opts.systemPrompt ? { systemPrompt: opts.systemPrompt } : {},
|
|
135465
135541
|
...opts.maxIterations ? { maxIterations: opts.maxIterations } : {},
|
|
135466
|
-
...opts.attachments && opts.attachments.length > 0 ? { attachments: opts.attachments } : {}
|
|
135542
|
+
...opts.attachments && opts.attachments.length > 0 ? { attachments: opts.attachments } : {},
|
|
135543
|
+
// Pre-minted client turn id (v6) so per-turn event filters match. The
|
|
135544
|
+
// reply's turnId stays authoritative: an older server ignores ours and
|
|
135545
|
+
// mints its own.
|
|
135546
|
+
...opts.turnId ? { turnId: opts.turnId } : {}
|
|
135467
135547
|
});
|
|
135468
135548
|
const turnId = result.turnId;
|
|
135469
135549
|
const stream = new TurnStream();
|
|
@@ -135758,7 +135838,7 @@ async function connectRemoteSession(opts = {}) {
|
|
|
135758
135838
|
const transport = opts.transport ?? await connectWithRetry(socketPath, opts.connectRetries ?? 5);
|
|
135759
135839
|
const session = new RemoteSession(transport);
|
|
135760
135840
|
try {
|
|
135761
|
-
await session.attach(opts.role ?? "client", opts.sinceSeq ?? 0);
|
|
135841
|
+
await session.attach(opts.role ?? "client", opts.sinceSeq ?? 0, opts.replay);
|
|
135762
135842
|
return session;
|
|
135763
135843
|
} catch (err) {
|
|
135764
135844
|
await maybeRecoverFromMismatch(err, socketPath, opts);
|
|
@@ -137300,7 +137380,7 @@ var agentSpecSchema = z$1.object({
|
|
|
137300
137380
|
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
137381
|
label: z$1.string().max(60).optional().describe('Short label shown in progress events (e.g. "research-deps", "lint-fix-A").'),
|
|
137302
137382
|
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."),
|
|
137383
|
+
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
137384
|
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
137385
|
allowedTools: z$1.array(z$1.string()).optional().describe("Restrict the child to these tool names. Overrides the kind's allowlist if set.")
|
|
137306
137386
|
});
|
|
@@ -143956,7 +144036,7 @@ function createTool(deps) {
|
|
|
143956
144036
|
if (!provider) {
|
|
143957
144037
|
throw new MoxxyError({ code: "PROVIDER_NOT_CONFIGURED", message: "workflow_create: no active provider to draft with." });
|
|
143958
144038
|
}
|
|
143959
|
-
const model = deps.draftModel ?? provider.models[0]?.id ?? "
|
|
144039
|
+
const model = deps.draftModel ?? provider.models[0]?.id ?? "default";
|
|
143960
144040
|
const drafted = await draftWorkflow(provider, model, intent, ctx.signal, {
|
|
143961
144041
|
...deps.listSkills ? { availableSkills: deps.listSkills() } : {},
|
|
143962
144042
|
...deps.listTools ? { availableTools: deps.listTools() } : {},
|
|
@@ -144847,7 +144927,7 @@ async function fireAfterWorkflowDependents(args) {
|
|
|
144847
144927
|
}
|
|
144848
144928
|
}
|
|
144849
144929
|
function activeModel(session) {
|
|
144850
|
-
return safeActiveProvider(session)?.models[0]?.id ?? "
|
|
144930
|
+
return session.lastResolvedModel ?? safeActiveProvider(session)?.models[0]?.id ?? "default";
|
|
144851
144931
|
}
|
|
144852
144932
|
function safeActiveProvider(session) {
|
|
144853
144933
|
try {
|
|
@@ -145356,6 +145436,15 @@ function scopedSessionView(session, allowedTools, triggerName) {
|
|
|
145356
145436
|
get pluginHost() {
|
|
145357
145437
|
return session.pluginHost;
|
|
145358
145438
|
},
|
|
145439
|
+
// Read-through AND write-through: runTurn records the resolved model on
|
|
145440
|
+
// the session it was handed, and that must land on the real session, not
|
|
145441
|
+
// this per-fire view.
|
|
145442
|
+
get lastResolvedModel() {
|
|
145443
|
+
return session.lastResolvedModel;
|
|
145444
|
+
},
|
|
145445
|
+
set lastResolvedModel(model) {
|
|
145446
|
+
session.lastResolvedModel = model;
|
|
145447
|
+
},
|
|
145359
145448
|
startTurn: () => session.startTurn(),
|
|
145360
145449
|
appContext: () => session.appContext()
|
|
145361
145450
|
};
|