@moxxy/cli 0.7.2 → 0.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/bin.js +1722 -686
  2. package/dist/bin.js.map +1 -1
  3. package/package.json +2 -2
package/dist/bin.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { z as z$1, defineProvider, definePlugin, defineTool, MoxxyError, writeFileAtomic, asTurnId, defineMode, asPluginId, defineChannel, defineTunnelProvider, createMutex, defineWorkflowExecutor, toFriendlyError, estimateTextTokens, classifyHttpStatus, createStuckLoopDetector, runCompactionIfNeeded, runElisionIfNeeded, collectProviderStream, usageEventFields, isContextOverflowError, emitRequestsAndDetectStuck, executeToolUses, buildSystemPromptWithSkills, projectMessages, defineCompactor, defineCacheStrategy, denyByDefaultResolver, createAllowListResolver, zodToJsonSchema, moxxyPath, runSingleShotTurn, bearerTokenMatches, resolveChannelToken, rotateChannelToken, estimateContextTokens as estimateContextTokens$1, readRequestBody, MOXXY_WS_SUBPROTOCOL, defineEmbedder, bearerGuard, tokenFromWsProtocolHeader, skillFrontmatterSchema, asSkillId, getInstallHint, moxxyHome, defineTranscriber, summarizeTokensByModel, migrateModeName, createDeferredPermissionResolver, classifyNetworkError, addModelTotals, ISOLATION_RANK, moxxyPackageSchema, defineCommand, createCallbackResolver, autoAllowResolver, asSessionId, asToolCallId, defineViewRenderer, DEFAULT_VIEW_TAGS, isSafeViewUrl, evaluateToolRule, summarizeSessionTokensFromEvents, computeElisionState, toolResultStubbed, toolResultStub, toolResultBytes, conversationalStubbed, conversationalStub, asEventId } from '@moxxy/sdk';
3
+ import { z as z$1, defineProvider, definePlugin, defineTool, MoxxyError, writeFileAtomic, asTurnId, defineMode, asPluginId, defineChannel, defineTunnelProvider, spawnCliTunnel, isCliTunnelAvailable, createMutex, defineWorkflowExecutor, toFriendlyError, estimateTextTokens, classifyHttpStatus, createStuckLoopDetector, runCompactionIfNeeded, runElisionIfNeeded, collectProviderStream, usageEventFields, isContextOverflowError, emitRequestsAndDetectStuck, executeToolUses, buildSystemPromptWithSkills, projectMessages, defineCompactor, defineCacheStrategy, denyByDefaultResolver, createAllowListResolver, moxxyPath, zodToJsonSchema, runSingleShotTurn, bearerTokenMatches, resolveChannelToken, rotateChannelToken, estimateContextTokens as estimateContextTokens$1, readRequestBody, MOXXY_WS_SUBPROTOCOL, defineEmbedder, bearerGuard, tokenFromWsProtocolHeader, skillFrontmatterSchema, asSkillId, getInstallHint, moxxyHome, defineTranscriber, summarizeTokensByModel, migrateModeName, createDeferredPermissionResolver, classifyNetworkError, addModelTotals, ISOLATION_RANK, moxxyPackageSchema, defineCommand, createCallbackResolver, autoAllowResolver, asSessionId, asToolCallId, defineViewRenderer, DEFAULT_VIEW_TAGS, isSafeViewUrl, evaluateToolRule, summarizeSessionTokensFromEvents, computeElisionState, toolResultStubbed, toolResultStub, toolResultBytes, conversationalStubbed, conversationalStub, asEventId } from '@moxxy/sdk';
4
4
  import * as fs27 from 'fs';
5
5
  import fs27__default, { existsSync, promises, ReadStream, readFileSync, statSync, readdirSync, mkdirSync, writeFileSync, unlinkSync, renameSync, watch, createReadStream } from 'fs';
6
6
  import * as path3 from 'path';
@@ -20,7 +20,7 @@ import * as z4mini from 'zod/v4-mini';
20
20
  import * as z24 from 'zod/v4';
21
21
  import V3, { stdin, stdout, env, cwd } from 'process';
22
22
  import tty, { ReadStream as ReadStream$1 } from 'tty';
23
- import { once, EventEmitter } from 'events';
23
+ import { EventEmitter } from 'events';
24
24
  import { Buffer as Buffer$1 } from 'buffer';
25
25
  import { readFile, mkdir, open, rm, stat, rename as rename$1, unlink, writeFile } from 'fs/promises';
26
26
  import { spawn, spawnSync } from 'child_process';
@@ -433,18 +433,29 @@ var init_tools = __esm({
433
433
  }
434
434
  });
435
435
 
436
- // ../core/dist/subagents/spawn.js
437
- function createSubagentSpawner(rt3) {
438
- return {
439
- async spawn(spec) {
440
- return runOne(rt3, spec);
441
- },
442
- async spawnAll(specs) {
443
- return Promise.all(specs.map((s2) => runOne(rt3, s2)));
444
- }
445
- };
436
+ // ../core/dist/subagents/registry.js
437
+ function registerRetainedChild(session) {
438
+ retained.set(String(session.childSessionId), session);
439
+ }
440
+ function getRetainedChild(childSessionId) {
441
+ return retained.get(String(childSessionId));
442
+ }
443
+ function releaseRetainedChild(childSessionId) {
444
+ retained.delete(String(childSessionId));
446
445
  }
447
- async function runOne(rt3, spec) {
446
+ function clearRetainedChildren() {
447
+ retained.clear();
448
+ }
449
+ var retained;
450
+ var init_registry = __esm({
451
+ "../core/dist/subagents/registry.js"() {
452
+ retained = /* @__PURE__ */ new Map();
453
+ }
454
+ });
455
+
456
+ // ../core/dist/subagents/run-child.js
457
+ async function runChildTurn(args) {
458
+ const { rt: rt3, spec, retainSession } = args;
448
459
  const { parentSession, parentTurnId } = rt3;
449
460
  const childSessionId = newSessionId();
450
461
  const childTurnId = newTurnId();
@@ -456,6 +467,73 @@ async function runOne(rt3, spec) {
456
467
  const { strategy, strategyName } = resolved;
457
468
  const toolRegistry = spec.allowedTools && spec.allowedTools.length > 0 ? buildFilteredToolRegistry(parentSession.tools, new Set(spec.allowedTools)) : parentSession.tools;
458
469
  const childLog = new EventLog();
470
+ const spawner = createSubagentSpawner(rt3);
471
+ const childCtx = buildChildContext(rt3, spec, childSessionId, childTurnId, toolRegistry, childLog, spawner);
472
+ const capture = await executeChildLoop({
473
+ rt: rt3,
474
+ spec,
475
+ label: label3,
476
+ childSessionId,
477
+ childTurnId,
478
+ childLog,
479
+ childCtx,
480
+ strategy,
481
+ strategyName,
482
+ emitCompleted: !retainSession
483
+ });
484
+ if (retainSession) {
485
+ registerRetainedChild({
486
+ label: label3,
487
+ childSessionId,
488
+ childTurnId,
489
+ childLog,
490
+ childCtx,
491
+ spec,
492
+ strategy,
493
+ strategyName,
494
+ parentSession,
495
+ parentTurnId
496
+ });
497
+ }
498
+ return capture.result;
499
+ }
500
+ async function continueChildTurn(args) {
501
+ const retained2 = getRetainedChild(args.childSessionId);
502
+ if (!retained2) {
503
+ throw new Error(`no retained subagent session for "${String(args.childSessionId)}"`);
504
+ }
505
+ await retained2.childLog.append({
506
+ type: "user_prompt",
507
+ sessionId: retained2.childSessionId,
508
+ turnId: retained2.childTurnId,
509
+ source: "user",
510
+ text: args.prompt
511
+ });
512
+ const rt3 = {
513
+ parentSession: retained2.parentSession,
514
+ parentTurnId: retained2.parentTurnId,
515
+ parentSignal: retained2.childCtx.signal,
516
+ parentModel: retained2.childCtx.model
517
+ };
518
+ const capture = await executeChildLoop({
519
+ rt: rt3,
520
+ spec: retained2.spec,
521
+ label: args.label ?? retained2.label,
522
+ childSessionId: retained2.childSessionId,
523
+ childTurnId: retained2.childTurnId,
524
+ childLog: retained2.childLog,
525
+ childCtx: retained2.childCtx,
526
+ strategy: retained2.strategy,
527
+ strategyName: retained2.strategyName,
528
+ emitCompleted: true,
529
+ skipStartEvent: true
530
+ });
531
+ releaseRetainedChild(args.childSessionId);
532
+ return capture.result;
533
+ }
534
+ async function executeChildLoop(args) {
535
+ const { rt: rt3, spec, label: label3, childSessionId, childTurnId, childLog, childCtx, strategy, strategyName, emitCompleted, skipStartEvent } = args;
536
+ const { parentSession, parentTurnId } = rt3;
459
537
  const capture = { text: "", stopReason: "end_turn", error: null };
460
538
  const unsubCapture = childLog.subscribe((e3) => {
461
539
  if (e3.type === "assistant_message") {
@@ -468,15 +546,16 @@ async function runOne(rt3, spec) {
468
546
  }
469
547
  });
470
548
  const unsubStream = childLog.subscribe((childEvt) => streamChildEventToParent(parentSession, parentTurnId, label3, childSessionId, childEvt));
471
- await emitSubagentStart(parentSession, parentTurnId, label3, childSessionId, spec, strategyName);
472
- await childLog.append({
473
- type: "user_prompt",
474
- sessionId: childSessionId,
475
- turnId: childTurnId,
476
- source: "user",
477
- text: spec.prompt
478
- });
479
- const childCtx = buildChildContext(rt3, spec, childSessionId, childTurnId, toolRegistry, childLog);
549
+ if (!skipStartEvent) {
550
+ await emitSubagentStart(parentSession, parentTurnId, label3, childSessionId, spec, strategyName);
551
+ await childLog.append({
552
+ type: "user_prompt",
553
+ sessionId: childSessionId,
554
+ turnId: childTurnId,
555
+ source: "user",
556
+ text: spec.prompt
557
+ });
558
+ }
480
559
  try {
481
560
  for await (const _2 of strategy.run(childCtx)) {
482
561
  void _2;
@@ -494,8 +573,10 @@ async function runOne(rt3, spec) {
494
573
  stopReason: capture.error ? "error" : capture.stopReason,
495
574
  ...capture.error ? { error: { message: capture.error } } : {}
496
575
  };
497
- await emitSubagentCompleted(parentSession, parentTurnId, label3, childSessionId, capture.text, result.stopReason, capture.error);
498
- return result;
576
+ if (emitCompleted) {
577
+ await emitSubagentCompleted(parentSession, parentTurnId, label3, childSessionId, capture.text, result.stopReason, capture.error);
578
+ }
579
+ return { result };
499
580
  }
500
581
  async function resolveStrategy(parentSession, parentTurnId, label3, childSessionId, spec, requestedStrategy) {
501
582
  const exact = parentSession.modes.list().find((s2) => s2.name === requestedStrategy);
@@ -519,7 +600,7 @@ async function resolveStrategy(parentSession, parentTurnId, label3, childSession
519
600
  }
520
601
  };
521
602
  }
522
- function buildChildContext(rt3, spec, childSessionId, childTurnId, toolRegistry, childLog) {
603
+ function buildChildContext(rt3, spec, childSessionId, childTurnId, toolRegistry, childLog, spawner) {
523
604
  const { parentSession, parentSignal, parentModel } = rt3;
524
605
  return {
525
606
  sessionId: childSessionId,
@@ -543,20 +624,40 @@ function buildChildContext(rt3, spec, childSessionId, childTurnId, toolRegistry,
543
624
  signal: parentSignal,
544
625
  // child cancels when parent cancels
545
626
  maxIterations: spec.maxIterations ?? 50,
546
- subagents: createSubagentSpawner({
547
- ...rt3,
548
- parentTurnId: childTurnId
549
- // grand-children attach to this child's turn
550
- }),
627
+ subagents: spawner,
551
628
  emit: (event) => childLog.append(event)
552
629
  };
553
630
  }
554
- var init_spawn = __esm({
555
- "../core/dist/subagents/spawn.js"() {
631
+ function createSubagentSpawner(rt3) {
632
+ return {
633
+ async spawn(spec) {
634
+ return runChildTurn({ rt: rt3, spec, retainSession: spec.retainSession === true });
635
+ },
636
+ async spawnAll(specs) {
637
+ return Promise.all(specs.map((s2) => runChildTurn({ rt: rt3, spec: s2, retainSession: s2.retainSession === true })));
638
+ },
639
+ async continue(args) {
640
+ return continueChildTurn(args);
641
+ },
642
+ release(childSessionId) {
643
+ releaseRetainedChild(childSessionId);
644
+ }
645
+ };
646
+ }
647
+ var init_run_child = __esm({
648
+ "../core/dist/subagents/run-child.js"() {
556
649
  init_log();
557
650
  init_factory();
558
651
  init_events();
559
652
  init_tools();
653
+ init_registry();
654
+ }
655
+ });
656
+
657
+ // ../core/dist/subagents/spawn.js
658
+ var init_spawn = __esm({
659
+ "../core/dist/subagents/spawn.js"() {
660
+ init_run_child();
560
661
  }
561
662
  });
562
663
 
@@ -564,6 +665,7 @@ var init_spawn = __esm({
564
665
  var init_subagents = __esm({
565
666
  "../core/dist/subagents.js"() {
566
667
  init_spawn();
668
+ init_registry();
567
669
  }
568
670
  });
569
671
 
@@ -2153,8 +2255,8 @@ var init_tools2 = __esm({
2153
2255
  const parseResult = tool.inputSchema.safeParse(input);
2154
2256
  if (!parseResult.success) {
2155
2257
  const issues = parseResult.error.issues.map((iss) => {
2156
- const path60 = iss.path.length ? iss.path.join(".") : "(root)";
2157
- return `${path60}: ${iss.message}`;
2258
+ const path61 = iss.path.length ? iss.path.join(".") : "(root)";
2259
+ return `${path61}: ${iss.message}`;
2158
2260
  }).join("; ");
2159
2261
  throw new Error(`Invalid input for ${name}: ${issues}`);
2160
2262
  }
@@ -2879,6 +2981,7 @@ var init_session = __esm({
2879
2981
  init_engine();
2880
2982
  init_resolvers();
2881
2983
  init_logger();
2984
+ init_registry();
2882
2985
  Session = class {
2883
2986
  id;
2884
2987
  cwd;
@@ -3053,6 +3156,7 @@ var init_session = __esm({
3053
3156
  try {
3054
3157
  await this.dispatcher.dispatchShutdown(this.appContext());
3055
3158
  } finally {
3159
+ clearRetainedChildren();
3056
3160
  this.abort(reason);
3057
3161
  }
3058
3162
  }
@@ -7986,6 +8090,7 @@ __export(dist_exports, {
7986
8090
  autoAllowResolver: () => autoAllowResolver,
7987
8091
  buildSkillIndexPrompt: () => buildSkillIndexPrompt,
7988
8092
  buildSynthesizeSkillPlugin: () => buildSynthesizeSkillPlugin,
8093
+ clearRetainedChildren: () => clearRetainedChildren,
7989
8094
  clearUsageStats: () => clearUsageStats,
7990
8095
  collectTurn: () => collectTurn,
7991
8096
  countNodes: () => countNodes,
@@ -8142,17 +8247,17 @@ var require_visit = __commonJS({
8142
8247
  visit.BREAK = BREAK;
8143
8248
  visit.SKIP = SKIP;
8144
8249
  visit.REMOVE = REMOVE;
8145
- function visit_(key, node, visitor, path60) {
8146
- const ctrl = callVisitor(key, node, visitor, path60);
8250
+ function visit_(key, node, visitor, path61) {
8251
+ const ctrl = callVisitor(key, node, visitor, path61);
8147
8252
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
8148
- replaceNode(key, path60, ctrl);
8149
- return visit_(key, ctrl, visitor, path60);
8253
+ replaceNode(key, path61, ctrl);
8254
+ return visit_(key, ctrl, visitor, path61);
8150
8255
  }
8151
8256
  if (typeof ctrl !== "symbol") {
8152
8257
  if (identity.isCollection(node)) {
8153
- path60 = Object.freeze(path60.concat(node));
8258
+ path61 = Object.freeze(path61.concat(node));
8154
8259
  for (let i2 = 0; i2 < node.items.length; ++i2) {
8155
- const ci = visit_(i2, node.items[i2], visitor, path60);
8260
+ const ci = visit_(i2, node.items[i2], visitor, path61);
8156
8261
  if (typeof ci === "number")
8157
8262
  i2 = ci - 1;
8158
8263
  else if (ci === BREAK)
@@ -8163,13 +8268,13 @@ var require_visit = __commonJS({
8163
8268
  }
8164
8269
  }
8165
8270
  } else if (identity.isPair(node)) {
8166
- path60 = Object.freeze(path60.concat(node));
8167
- const ck = visit_("key", node.key, visitor, path60);
8271
+ path61 = Object.freeze(path61.concat(node));
8272
+ const ck = visit_("key", node.key, visitor, path61);
8168
8273
  if (ck === BREAK)
8169
8274
  return BREAK;
8170
8275
  else if (ck === REMOVE)
8171
8276
  node.key = null;
8172
- const cv = visit_("value", node.value, visitor, path60);
8277
+ const cv = visit_("value", node.value, visitor, path61);
8173
8278
  if (cv === BREAK)
8174
8279
  return BREAK;
8175
8280
  else if (cv === REMOVE)
@@ -8190,17 +8295,17 @@ var require_visit = __commonJS({
8190
8295
  visitAsync.BREAK = BREAK;
8191
8296
  visitAsync.SKIP = SKIP;
8192
8297
  visitAsync.REMOVE = REMOVE;
8193
- async function visitAsync_(key, node, visitor, path60) {
8194
- const ctrl = await callVisitor(key, node, visitor, path60);
8298
+ async function visitAsync_(key, node, visitor, path61) {
8299
+ const ctrl = await callVisitor(key, node, visitor, path61);
8195
8300
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
8196
- replaceNode(key, path60, ctrl);
8197
- return visitAsync_(key, ctrl, visitor, path60);
8301
+ replaceNode(key, path61, ctrl);
8302
+ return visitAsync_(key, ctrl, visitor, path61);
8198
8303
  }
8199
8304
  if (typeof ctrl !== "symbol") {
8200
8305
  if (identity.isCollection(node)) {
8201
- path60 = Object.freeze(path60.concat(node));
8306
+ path61 = Object.freeze(path61.concat(node));
8202
8307
  for (let i2 = 0; i2 < node.items.length; ++i2) {
8203
- const ci = await visitAsync_(i2, node.items[i2], visitor, path60);
8308
+ const ci = await visitAsync_(i2, node.items[i2], visitor, path61);
8204
8309
  if (typeof ci === "number")
8205
8310
  i2 = ci - 1;
8206
8311
  else if (ci === BREAK)
@@ -8211,13 +8316,13 @@ var require_visit = __commonJS({
8211
8316
  }
8212
8317
  }
8213
8318
  } else if (identity.isPair(node)) {
8214
- path60 = Object.freeze(path60.concat(node));
8215
- const ck = await visitAsync_("key", node.key, visitor, path60);
8319
+ path61 = Object.freeze(path61.concat(node));
8320
+ const ck = await visitAsync_("key", node.key, visitor, path61);
8216
8321
  if (ck === BREAK)
8217
8322
  return BREAK;
8218
8323
  else if (ck === REMOVE)
8219
8324
  node.key = null;
8220
- const cv = await visitAsync_("value", node.value, visitor, path60);
8325
+ const cv = await visitAsync_("value", node.value, visitor, path61);
8221
8326
  if (cv === BREAK)
8222
8327
  return BREAK;
8223
8328
  else if (cv === REMOVE)
@@ -8244,23 +8349,23 @@ var require_visit = __commonJS({
8244
8349
  }
8245
8350
  return visitor;
8246
8351
  }
8247
- function callVisitor(key, node, visitor, path60) {
8352
+ function callVisitor(key, node, visitor, path61) {
8248
8353
  if (typeof visitor === "function")
8249
- return visitor(key, node, path60);
8354
+ return visitor(key, node, path61);
8250
8355
  if (identity.isMap(node))
8251
- return visitor.Map?.(key, node, path60);
8356
+ return visitor.Map?.(key, node, path61);
8252
8357
  if (identity.isSeq(node))
8253
- return visitor.Seq?.(key, node, path60);
8358
+ return visitor.Seq?.(key, node, path61);
8254
8359
  if (identity.isPair(node))
8255
- return visitor.Pair?.(key, node, path60);
8360
+ return visitor.Pair?.(key, node, path61);
8256
8361
  if (identity.isScalar(node))
8257
- return visitor.Scalar?.(key, node, path60);
8362
+ return visitor.Scalar?.(key, node, path61);
8258
8363
  if (identity.isAlias(node))
8259
- return visitor.Alias?.(key, node, path60);
8364
+ return visitor.Alias?.(key, node, path61);
8260
8365
  return void 0;
8261
8366
  }
8262
- function replaceNode(key, path60, node) {
8263
- const parent = path60[path60.length - 1];
8367
+ function replaceNode(key, path61, node) {
8368
+ const parent = path61[path61.length - 1];
8264
8369
  if (identity.isCollection(parent)) {
8265
8370
  parent.items[key] = node;
8266
8371
  } else if (identity.isPair(parent)) {
@@ -8861,10 +8966,10 @@ var require_Collection = __commonJS({
8861
8966
  var createNode2 = require_createNode();
8862
8967
  var identity = require_identity();
8863
8968
  var Node = require_Node();
8864
- function collectionFromPath(schema, path60, value) {
8969
+ function collectionFromPath(schema, path61, value) {
8865
8970
  let v3 = value;
8866
- for (let i2 = path60.length - 1; i2 >= 0; --i2) {
8867
- const k3 = path60[i2];
8971
+ for (let i2 = path61.length - 1; i2 >= 0; --i2) {
8972
+ const k3 = path61[i2];
8868
8973
  if (typeof k3 === "number" && Number.isInteger(k3) && k3 >= 0) {
8869
8974
  const a2 = [];
8870
8975
  a2[k3] = v3;
@@ -8883,7 +8988,7 @@ var require_Collection = __commonJS({
8883
8988
  sourceObjects: /* @__PURE__ */ new Map()
8884
8989
  });
8885
8990
  }
8886
- var isEmptyPath = (path60) => path60 == null || typeof path60 === "object" && !!path60[Symbol.iterator]().next().done;
8991
+ var isEmptyPath = (path61) => path61 == null || typeof path61 === "object" && !!path61[Symbol.iterator]().next().done;
8887
8992
  var Collection = class extends Node.NodeBase {
8888
8993
  constructor(type, schema) {
8889
8994
  super(type);
@@ -8913,11 +9018,11 @@ var require_Collection = __commonJS({
8913
9018
  * be a Pair instance or a `{ key, value }` object, which may not have a key
8914
9019
  * that already exists in the map.
8915
9020
  */
8916
- addIn(path60, value) {
8917
- if (isEmptyPath(path60))
9021
+ addIn(path61, value) {
9022
+ if (isEmptyPath(path61))
8918
9023
  this.add(value);
8919
9024
  else {
8920
- const [key, ...rest] = path60;
9025
+ const [key, ...rest] = path61;
8921
9026
  const node = this.get(key, true);
8922
9027
  if (identity.isCollection(node))
8923
9028
  node.addIn(rest, value);
@@ -8931,8 +9036,8 @@ var require_Collection = __commonJS({
8931
9036
  * Removes a value from the collection.
8932
9037
  * @returns `true` if the item was found and removed.
8933
9038
  */
8934
- deleteIn(path60) {
8935
- const [key, ...rest] = path60;
9039
+ deleteIn(path61) {
9040
+ const [key, ...rest] = path61;
8936
9041
  if (rest.length === 0)
8937
9042
  return this.delete(key);
8938
9043
  const node = this.get(key, true);
@@ -8946,8 +9051,8 @@ var require_Collection = __commonJS({
8946
9051
  * scalar values from their surrounding node; to disable set `keepScalar` to
8947
9052
  * `true` (collections are always returned intact).
8948
9053
  */
8949
- getIn(path60, keepScalar) {
8950
- const [key, ...rest] = path60;
9054
+ getIn(path61, keepScalar) {
9055
+ const [key, ...rest] = path61;
8951
9056
  const node = this.get(key, true);
8952
9057
  if (rest.length === 0)
8953
9058
  return !keepScalar && identity.isScalar(node) ? node.value : node;
@@ -8965,8 +9070,8 @@ var require_Collection = __commonJS({
8965
9070
  /**
8966
9071
  * Checks if the collection includes a value with the key `key`.
8967
9072
  */
8968
- hasIn(path60) {
8969
- const [key, ...rest] = path60;
9073
+ hasIn(path61) {
9074
+ const [key, ...rest] = path61;
8970
9075
  if (rest.length === 0)
8971
9076
  return this.has(key);
8972
9077
  const node = this.get(key, true);
@@ -8976,8 +9081,8 @@ var require_Collection = __commonJS({
8976
9081
  * Sets a value in this collection. For `!!set`, `value` needs to be a
8977
9082
  * boolean to add/remove the item from the set.
8978
9083
  */
8979
- setIn(path60, value) {
8980
- const [key, ...rest] = path60;
9084
+ setIn(path61, value) {
9085
+ const [key, ...rest] = path61;
8981
9086
  if (rest.length === 0) {
8982
9087
  this.set(key, value);
8983
9088
  } else {
@@ -11457,9 +11562,9 @@ var require_Document = __commonJS({
11457
11562
  this.contents.add(value);
11458
11563
  }
11459
11564
  /** Adds a value to the document. */
11460
- addIn(path60, value) {
11565
+ addIn(path61, value) {
11461
11566
  if (assertCollection(this.contents))
11462
- this.contents.addIn(path60, value);
11567
+ this.contents.addIn(path61, value);
11463
11568
  }
11464
11569
  /**
11465
11570
  * Create a new `Alias` node, ensuring that the target `node` has the required anchor.
@@ -11534,14 +11639,14 @@ var require_Document = __commonJS({
11534
11639
  * Removes a value from the document.
11535
11640
  * @returns `true` if the item was found and removed.
11536
11641
  */
11537
- deleteIn(path60) {
11538
- if (Collection.isEmptyPath(path60)) {
11642
+ deleteIn(path61) {
11643
+ if (Collection.isEmptyPath(path61)) {
11539
11644
  if (this.contents == null)
11540
11645
  return false;
11541
11646
  this.contents = null;
11542
11647
  return true;
11543
11648
  }
11544
- return assertCollection(this.contents) ? this.contents.deleteIn(path60) : false;
11649
+ return assertCollection(this.contents) ? this.contents.deleteIn(path61) : false;
11545
11650
  }
11546
11651
  /**
11547
11652
  * Returns item at `key`, or `undefined` if not found. By default unwraps
@@ -11556,10 +11661,10 @@ var require_Document = __commonJS({
11556
11661
  * scalar values from their surrounding node; to disable set `keepScalar` to
11557
11662
  * `true` (collections are always returned intact).
11558
11663
  */
11559
- getIn(path60, keepScalar) {
11560
- if (Collection.isEmptyPath(path60))
11664
+ getIn(path61, keepScalar) {
11665
+ if (Collection.isEmptyPath(path61))
11561
11666
  return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
11562
- return identity.isCollection(this.contents) ? this.contents.getIn(path60, keepScalar) : void 0;
11667
+ return identity.isCollection(this.contents) ? this.contents.getIn(path61, keepScalar) : void 0;
11563
11668
  }
11564
11669
  /**
11565
11670
  * Checks if the document includes a value with the key `key`.
@@ -11570,10 +11675,10 @@ var require_Document = __commonJS({
11570
11675
  /**
11571
11676
  * Checks if the document includes a value at `path`.
11572
11677
  */
11573
- hasIn(path60) {
11574
- if (Collection.isEmptyPath(path60))
11678
+ hasIn(path61) {
11679
+ if (Collection.isEmptyPath(path61))
11575
11680
  return this.contents !== void 0;
11576
- return identity.isCollection(this.contents) ? this.contents.hasIn(path60) : false;
11681
+ return identity.isCollection(this.contents) ? this.contents.hasIn(path61) : false;
11577
11682
  }
11578
11683
  /**
11579
11684
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -11590,13 +11695,13 @@ var require_Document = __commonJS({
11590
11695
  * Sets a value in this document. For `!!set`, `value` needs to be a
11591
11696
  * boolean to add/remove the item from the set.
11592
11697
  */
11593
- setIn(path60, value) {
11594
- if (Collection.isEmptyPath(path60)) {
11698
+ setIn(path61, value) {
11699
+ if (Collection.isEmptyPath(path61)) {
11595
11700
  this.contents = value;
11596
11701
  } else if (this.contents == null) {
11597
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path60), value);
11702
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path61), value);
11598
11703
  } else if (assertCollection(this.contents)) {
11599
- this.contents.setIn(path60, value);
11704
+ this.contents.setIn(path61, value);
11600
11705
  }
11601
11706
  }
11602
11707
  /**
@@ -13536,9 +13641,9 @@ var require_cst_visit = __commonJS({
13536
13641
  visit.BREAK = BREAK;
13537
13642
  visit.SKIP = SKIP;
13538
13643
  visit.REMOVE = REMOVE;
13539
- visit.itemAtPath = (cst, path60) => {
13644
+ visit.itemAtPath = (cst, path61) => {
13540
13645
  let item = cst;
13541
- for (const [field, index] of path60) {
13646
+ for (const [field, index] of path61) {
13542
13647
  const tok = item?.[field];
13543
13648
  if (tok && "items" in tok) {
13544
13649
  item = tok.items[index];
@@ -13547,23 +13652,23 @@ var require_cst_visit = __commonJS({
13547
13652
  }
13548
13653
  return item;
13549
13654
  };
13550
- visit.parentCollection = (cst, path60) => {
13551
- const parent = visit.itemAtPath(cst, path60.slice(0, -1));
13552
- const field = path60[path60.length - 1][0];
13655
+ visit.parentCollection = (cst, path61) => {
13656
+ const parent = visit.itemAtPath(cst, path61.slice(0, -1));
13657
+ const field = path61[path61.length - 1][0];
13553
13658
  const coll = parent?.[field];
13554
13659
  if (coll && "items" in coll)
13555
13660
  return coll;
13556
13661
  throw new Error("Parent collection not found");
13557
13662
  };
13558
- function _visit(path60, item, visitor) {
13559
- let ctrl = visitor(item, path60);
13663
+ function _visit(path61, item, visitor) {
13664
+ let ctrl = visitor(item, path61);
13560
13665
  if (typeof ctrl === "symbol")
13561
13666
  return ctrl;
13562
13667
  for (const field of ["key", "value"]) {
13563
13668
  const token = item[field];
13564
13669
  if (token && "items" in token) {
13565
13670
  for (let i2 = 0; i2 < token.items.length; ++i2) {
13566
- const ci = _visit(Object.freeze(path60.concat([[field, i2]])), token.items[i2], visitor);
13671
+ const ci = _visit(Object.freeze(path61.concat([[field, i2]])), token.items[i2], visitor);
13567
13672
  if (typeof ci === "number")
13568
13673
  i2 = ci - 1;
13569
13674
  else if (ci === BREAK)
@@ -13574,10 +13679,10 @@ var require_cst_visit = __commonJS({
13574
13679
  }
13575
13680
  }
13576
13681
  if (typeof ctrl === "function" && field === "key")
13577
- ctrl = ctrl(item, path60);
13682
+ ctrl = ctrl(item, path61);
13578
13683
  }
13579
13684
  }
13580
- return typeof ctrl === "function" ? ctrl(item, path60) : ctrl;
13685
+ return typeof ctrl === "function" ? ctrl(item, path61) : ctrl;
13581
13686
  }
13582
13687
  exports.visit = visit;
13583
13688
  }
@@ -14875,14 +14980,14 @@ var require_parser = __commonJS({
14875
14980
  case "scalar":
14876
14981
  case "single-quoted-scalar":
14877
14982
  case "double-quoted-scalar": {
14878
- const fs43 = this.flowScalar(this.type);
14983
+ const fs44 = this.flowScalar(this.type);
14879
14984
  if (atNextItem || it4.value) {
14880
- map2.items.push({ start, key: fs43, sep: [] });
14985
+ map2.items.push({ start, key: fs44, sep: [] });
14881
14986
  this.onKeyLine = true;
14882
14987
  } else if (it4.sep) {
14883
- this.stack.push(fs43);
14988
+ this.stack.push(fs44);
14884
14989
  } else {
14885
- Object.assign(it4, { key: fs43, sep: [] });
14990
+ Object.assign(it4, { key: fs44, sep: [] });
14886
14991
  this.onKeyLine = true;
14887
14992
  }
14888
14993
  return;
@@ -15010,13 +15115,13 @@ var require_parser = __commonJS({
15010
15115
  case "scalar":
15011
15116
  case "single-quoted-scalar":
15012
15117
  case "double-quoted-scalar": {
15013
- const fs43 = this.flowScalar(this.type);
15118
+ const fs44 = this.flowScalar(this.type);
15014
15119
  if (!it4 || it4.value)
15015
- fc.items.push({ start: [], key: fs43, sep: [] });
15120
+ fc.items.push({ start: [], key: fs44, sep: [] });
15016
15121
  else if (it4.sep)
15017
- this.stack.push(fs43);
15122
+ this.stack.push(fs44);
15018
15123
  else
15019
- Object.assign(it4, { key: fs43, sep: [] });
15124
+ Object.assign(it4, { key: fs44, sep: [] });
15020
15125
  return;
15021
15126
  }
15022
15127
  case "flow-map-end":
@@ -16299,14 +16404,14 @@ var require_url_state_machine = __commonJS({
16299
16404
  return url2.replace(/\u0009|\u000A|\u000D/g, "");
16300
16405
  }
16301
16406
  function shortenPath(url2) {
16302
- const path60 = url2.path;
16303
- if (path60.length === 0) {
16407
+ const path61 = url2.path;
16408
+ if (path61.length === 0) {
16304
16409
  return;
16305
16410
  }
16306
- if (url2.scheme === "file" && path60.length === 1 && isNormalizedWindowsDriveLetter(path60[0])) {
16411
+ if (url2.scheme === "file" && path61.length === 1 && isNormalizedWindowsDriveLetter(path61[0])) {
16307
16412
  return;
16308
16413
  }
16309
- path60.pop();
16414
+ path61.pop();
16310
16415
  }
16311
16416
  function includesCredentials(url2) {
16312
16417
  return url2.username !== "" || url2.password !== "";
@@ -25529,14 +25634,14 @@ __export(fileFromPath_exports, {
25529
25634
  fileFromPathSync: () => fileFromPathSync,
25530
25635
  isFile: () => isFile
25531
25636
  });
25532
- function createFileFromPath(path60, { mtimeMs, size }, filenameOrOptions, options = {}) {
25637
+ function createFileFromPath(path61, { mtimeMs, size }, filenameOrOptions, options = {}) {
25533
25638
  let filename;
25534
25639
  if (isPlainObject_default2(filenameOrOptions)) {
25535
25640
  [options, filename] = [filenameOrOptions, void 0];
25536
25641
  } else {
25537
25642
  filename = filenameOrOptions;
25538
25643
  }
25539
- const file = new FileFromPath({ path: path60, size, lastModified: mtimeMs });
25644
+ const file = new FileFromPath({ path: path61, size, lastModified: mtimeMs });
25540
25645
  if (!filename) {
25541
25646
  filename = file.name;
25542
25647
  }
@@ -25545,13 +25650,13 @@ function createFileFromPath(path60, { mtimeMs, size }, filenameOrOptions, option
25545
25650
  lastModified: file.lastModified
25546
25651
  });
25547
25652
  }
25548
- function fileFromPathSync(path60, filenameOrOptions, options = {}) {
25549
- const stats = statSync(path60);
25550
- return createFileFromPath(path60, stats, filenameOrOptions, options);
25653
+ function fileFromPathSync(path61, filenameOrOptions, options = {}) {
25654
+ const stats = statSync(path61);
25655
+ return createFileFromPath(path61, stats, filenameOrOptions, options);
25551
25656
  }
25552
- async function fileFromPath2(path60, filenameOrOptions, options) {
25553
- const stats = await promises.stat(path60);
25554
- return createFileFromPath(path60, stats, filenameOrOptions, options);
25657
+ async function fileFromPath2(path61, filenameOrOptions, options) {
25658
+ const stats = await promises.stat(path61);
25659
+ return createFileFromPath(path61, stats, filenameOrOptions, options);
25555
25660
  }
25556
25661
  var import_node_domexception, __classPrivateFieldSet4, __classPrivateFieldGet5, _FileFromPath_path, _FileFromPath_start, MESSAGE, FileFromPath;
25557
25662
  var init_fileFromPath = __esm({
@@ -41683,8 +41788,8 @@ var require_utils2 = __commonJS({
41683
41788
  }
41684
41789
  return ind;
41685
41790
  }
41686
- function removeDotSegments(path60) {
41687
- let input = path60;
41791
+ function removeDotSegments(path61) {
41792
+ let input = path61;
41688
41793
  const output = [];
41689
41794
  let nextSlash = -1;
41690
41795
  let len = 0;
@@ -41935,8 +42040,8 @@ var require_schemes = __commonJS({
41935
42040
  wsComponent.secure = void 0;
41936
42041
  }
41937
42042
  if (wsComponent.resourceName) {
41938
- const [path60, query] = wsComponent.resourceName.split("?");
41939
- wsComponent.path = path60 && path60 !== "/" ? path60 : void 0;
42043
+ const [path61, query] = wsComponent.resourceName.split("?");
42044
+ wsComponent.path = path61 && path61 !== "/" ? path61 : void 0;
41940
42045
  wsComponent.query = query;
41941
42046
  wsComponent.resourceName = void 0;
41942
42047
  }
@@ -45283,12 +45388,12 @@ var require_dist2 = __commonJS({
45283
45388
  throw new Error(`Unknown format "${name}"`);
45284
45389
  return f3;
45285
45390
  };
45286
- function addFormats(ajv, list, fs43, exportName) {
45391
+ function addFormats(ajv, list, fs44, exportName) {
45287
45392
  var _a3;
45288
45393
  var _b;
45289
45394
  (_a3 = (_b = ajv.opts.code).formats) !== null && _a3 !== void 0 ? _a3 : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
45290
45395
  for (const f3 of list)
45291
- ajv.addFormat(f3, fs43[f3]);
45396
+ ajv.addFormat(f3, fs44[f3]);
45292
45397
  }
45293
45398
  module.exports = exports = formatsPlugin;
45294
45399
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -46093,8 +46198,8 @@ var require_windows = __commonJS({
46093
46198
  "../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/windows.js"(exports, module) {
46094
46199
  module.exports = isexe;
46095
46200
  isexe.sync = sync;
46096
- var fs43 = __require("fs");
46097
- function checkPathExt(path60, options) {
46201
+ var fs44 = __require("fs");
46202
+ function checkPathExt(path61, options) {
46098
46203
  var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
46099
46204
  if (!pathext) {
46100
46205
  return true;
@@ -46105,25 +46210,25 @@ var require_windows = __commonJS({
46105
46210
  }
46106
46211
  for (var i2 = 0; i2 < pathext.length; i2++) {
46107
46212
  var p3 = pathext[i2].toLowerCase();
46108
- if (p3 && path60.substr(-p3.length).toLowerCase() === p3) {
46213
+ if (p3 && path61.substr(-p3.length).toLowerCase() === p3) {
46109
46214
  return true;
46110
46215
  }
46111
46216
  }
46112
46217
  return false;
46113
46218
  }
46114
- function checkStat(stat2, path60, options) {
46219
+ function checkStat(stat2, path61, options) {
46115
46220
  if (!stat2.isSymbolicLink() && !stat2.isFile()) {
46116
46221
  return false;
46117
46222
  }
46118
- return checkPathExt(path60, options);
46223
+ return checkPathExt(path61, options);
46119
46224
  }
46120
- function isexe(path60, options, cb) {
46121
- fs43.stat(path60, function(er2, stat2) {
46122
- cb(er2, er2 ? false : checkStat(stat2, path60, options));
46225
+ function isexe(path61, options, cb) {
46226
+ fs44.stat(path61, function(er2, stat2) {
46227
+ cb(er2, er2 ? false : checkStat(stat2, path61, options));
46123
46228
  });
46124
46229
  }
46125
- function sync(path60, options) {
46126
- return checkStat(fs43.statSync(path60), path60, options);
46230
+ function sync(path61, options) {
46231
+ return checkStat(fs44.statSync(path61), path61, options);
46127
46232
  }
46128
46233
  }
46129
46234
  });
@@ -46133,14 +46238,14 @@ var require_mode = __commonJS({
46133
46238
  "../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/mode.js"(exports, module) {
46134
46239
  module.exports = isexe;
46135
46240
  isexe.sync = sync;
46136
- var fs43 = __require("fs");
46137
- function isexe(path60, options, cb) {
46138
- fs43.stat(path60, function(er2, stat2) {
46241
+ var fs44 = __require("fs");
46242
+ function isexe(path61, options, cb) {
46243
+ fs44.stat(path61, function(er2, stat2) {
46139
46244
  cb(er2, er2 ? false : checkStat(stat2, options));
46140
46245
  });
46141
46246
  }
46142
- function sync(path60, options) {
46143
- return checkStat(fs43.statSync(path60), options);
46247
+ function sync(path61, options) {
46248
+ return checkStat(fs44.statSync(path61), options);
46144
46249
  }
46145
46250
  function checkStat(stat2, options) {
46146
46251
  return stat2.isFile() && checkMode(stat2, options);
@@ -46173,7 +46278,7 @@ var require_isexe = __commonJS({
46173
46278
  }
46174
46279
  module.exports = isexe;
46175
46280
  isexe.sync = sync;
46176
- function isexe(path60, options, cb) {
46281
+ function isexe(path61, options, cb) {
46177
46282
  if (typeof options === "function") {
46178
46283
  cb = options;
46179
46284
  options = {};
@@ -46183,7 +46288,7 @@ var require_isexe = __commonJS({
46183
46288
  throw new TypeError("callback not provided");
46184
46289
  }
46185
46290
  return new Promise(function(resolve12, reject) {
46186
- isexe(path60, options || {}, function(er2, is) {
46291
+ isexe(path61, options || {}, function(er2, is) {
46187
46292
  if (er2) {
46188
46293
  reject(er2);
46189
46294
  } else {
@@ -46192,7 +46297,7 @@ var require_isexe = __commonJS({
46192
46297
  });
46193
46298
  });
46194
46299
  }
46195
- core(path60, options || {}, function(er2, is) {
46300
+ core(path61, options || {}, function(er2, is) {
46196
46301
  if (er2) {
46197
46302
  if (er2.code === "EACCES" || options && options.ignoreErrors) {
46198
46303
  er2 = null;
@@ -46202,9 +46307,9 @@ var require_isexe = __commonJS({
46202
46307
  cb(er2, is);
46203
46308
  });
46204
46309
  }
46205
- function sync(path60, options) {
46310
+ function sync(path61, options) {
46206
46311
  try {
46207
- return core.sync(path60, options || {});
46312
+ return core.sync(path61, options || {});
46208
46313
  } catch (er2) {
46209
46314
  if (options && options.ignoreErrors || er2.code === "EACCES") {
46210
46315
  return false;
@@ -46220,7 +46325,7 @@ var require_isexe = __commonJS({
46220
46325
  var require_which = __commonJS({
46221
46326
  "../../node_modules/.pnpm/which@2.0.2/node_modules/which/which.js"(exports, module) {
46222
46327
  var isWindows3 = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
46223
- var path60 = __require("path");
46328
+ var path61 = __require("path");
46224
46329
  var COLON = isWindows3 ? ";" : ":";
46225
46330
  var isexe = require_isexe();
46226
46331
  var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
@@ -46258,7 +46363,7 @@ var require_which = __commonJS({
46258
46363
  return opt.all && found.length ? resolve12(found) : reject(getNotFoundError(cmd));
46259
46364
  const ppRaw = pathEnv[i2];
46260
46365
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
46261
- const pCmd = path60.join(pathPart, cmd);
46366
+ const pCmd = path61.join(pathPart, cmd);
46262
46367
  const p3 = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
46263
46368
  resolve12(subStep(p3, i2, 0));
46264
46369
  });
@@ -46285,7 +46390,7 @@ var require_which = __commonJS({
46285
46390
  for (let i2 = 0; i2 < pathEnv.length; i2++) {
46286
46391
  const ppRaw = pathEnv[i2];
46287
46392
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
46288
- const pCmd = path60.join(pathPart, cmd);
46393
+ const pCmd = path61.join(pathPart, cmd);
46289
46394
  const p3 = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
46290
46395
  for (let j3 = 0; j3 < pathExt.length; j3++) {
46291
46396
  const cur = p3 + pathExt[j3];
@@ -46331,7 +46436,7 @@ var require_path_key = __commonJS({
46331
46436
  // ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.js
46332
46437
  var require_resolveCommand = __commonJS({
46333
46438
  "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.js"(exports, module) {
46334
- var path60 = __require("path");
46439
+ var path61 = __require("path");
46335
46440
  var which = require_which();
46336
46441
  var getPathKey = require_path_key();
46337
46442
  function resolveCommandAttempt(parsed, withoutPathExt) {
@@ -46349,7 +46454,7 @@ var require_resolveCommand = __commonJS({
46349
46454
  try {
46350
46455
  resolved = which.sync(parsed.command, {
46351
46456
  path: env3[getPathKey({ env: env3 })],
46352
- pathExt: withoutPathExt ? path60.delimiter : void 0
46457
+ pathExt: withoutPathExt ? path61.delimiter : void 0
46353
46458
  });
46354
46459
  } catch (e3) {
46355
46460
  } finally {
@@ -46358,7 +46463,7 @@ var require_resolveCommand = __commonJS({
46358
46463
  }
46359
46464
  }
46360
46465
  if (resolved) {
46361
- resolved = path60.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
46466
+ resolved = path61.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
46362
46467
  }
46363
46468
  return resolved;
46364
46469
  }
@@ -46409,8 +46514,8 @@ var require_shebang_command = __commonJS({
46409
46514
  if (!match) {
46410
46515
  return null;
46411
46516
  }
46412
- const [path60, argument] = match[0].replace(/#! ?/, "").split(" ");
46413
- const binary = path60.split("/").pop();
46517
+ const [path61, argument] = match[0].replace(/#! ?/, "").split(" ");
46518
+ const binary = path61.split("/").pop();
46414
46519
  if (binary === "env") {
46415
46520
  return argument;
46416
46521
  }
@@ -46422,16 +46527,16 @@ var require_shebang_command = __commonJS({
46422
46527
  // ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js
46423
46528
  var require_readShebang = __commonJS({
46424
46529
  "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js"(exports, module) {
46425
- var fs43 = __require("fs");
46530
+ var fs44 = __require("fs");
46426
46531
  var shebangCommand = require_shebang_command();
46427
46532
  function readShebang(command) {
46428
46533
  const size = 150;
46429
46534
  const buffer = Buffer.alloc(size);
46430
46535
  let fd;
46431
46536
  try {
46432
- fd = fs43.openSync(command, "r");
46433
- fs43.readSync(fd, buffer, 0, size, 0);
46434
- fs43.closeSync(fd);
46537
+ fd = fs44.openSync(command, "r");
46538
+ fs44.readSync(fd, buffer, 0, size, 0);
46539
+ fs44.closeSync(fd);
46435
46540
  } catch (e3) {
46436
46541
  }
46437
46542
  return shebangCommand(buffer.toString());
@@ -46443,7 +46548,7 @@ var require_readShebang = __commonJS({
46443
46548
  // ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/parse.js
46444
46549
  var require_parse = __commonJS({
46445
46550
  "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/parse.js"(exports, module) {
46446
- var path60 = __require("path");
46551
+ var path61 = __require("path");
46447
46552
  var resolveCommand = require_resolveCommand();
46448
46553
  var escape4 = require_escape();
46449
46554
  var readShebang = require_readShebang();
@@ -46468,7 +46573,7 @@ var require_parse = __commonJS({
46468
46573
  const needsShell = !isExecutableRegExp.test(commandFile);
46469
46574
  if (parsed.options.forceShell || needsShell) {
46470
46575
  const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
46471
- parsed.command = path60.normalize(parsed.command);
46576
+ parsed.command = path61.normalize(parsed.command);
46472
46577
  parsed.command = escape4.command(parsed.command);
46473
46578
  parsed.args = parsed.args.map((arg) => escape4.argument(arg, needsDoubleEscapeMetaChars));
46474
46579
  const shellCommand = [parsed.command].concat(parsed.args).join(" ");
@@ -46556,7 +46661,7 @@ var require_cross_spawn = __commonJS({
46556
46661
  var cp = __require("child_process");
46557
46662
  var parse2 = require_parse();
46558
46663
  var enoent = require_enoent();
46559
- function spawn17(command, args, options) {
46664
+ function spawn14(command, args, options) {
46560
46665
  const parsed = parse2(command, args, options);
46561
46666
  const spawned = cp.spawn(parsed.command, parsed.args, parsed.options);
46562
46667
  enoent.hookChildProcess(spawned, parsed);
@@ -46568,8 +46673,8 @@ var require_cross_spawn = __commonJS({
46568
46673
  result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
46569
46674
  return result;
46570
46675
  }
46571
- module.exports = spawn17;
46572
- module.exports.spawn = spawn17;
46676
+ module.exports = spawn14;
46677
+ module.exports.spawn = spawn14;
46573
46678
  module.exports.sync = spawnSync5;
46574
46679
  module.exports._parse = parse2;
46575
46680
  module.exports._enoent = enoent;
@@ -74297,10 +74402,10 @@ var require_react_reconciler_development = __commonJS({
74297
74402
  var setErrorHandler = null;
74298
74403
  var setSuspenseHandler = null;
74299
74404
  {
74300
- var copyWithDeleteImpl = function(obj, path60, index2) {
74301
- var key = path60[index2];
74405
+ var copyWithDeleteImpl = function(obj, path61, index2) {
74406
+ var key = path61[index2];
74302
74407
  var updated = isArray(obj) ? obj.slice() : assign({}, obj);
74303
- if (index2 + 1 === path60.length) {
74408
+ if (index2 + 1 === path61.length) {
74304
74409
  if (isArray(updated)) {
74305
74410
  updated.splice(key, 1);
74306
74411
  } else {
@@ -74308,11 +74413,11 @@ var require_react_reconciler_development = __commonJS({
74308
74413
  }
74309
74414
  return updated;
74310
74415
  }
74311
- updated[key] = copyWithDeleteImpl(obj[key], path60, index2 + 1);
74416
+ updated[key] = copyWithDeleteImpl(obj[key], path61, index2 + 1);
74312
74417
  return updated;
74313
74418
  };
74314
- var copyWithDelete = function(obj, path60) {
74315
- return copyWithDeleteImpl(obj, path60, 0);
74419
+ var copyWithDelete = function(obj, path61) {
74420
+ return copyWithDeleteImpl(obj, path61, 0);
74316
74421
  };
74317
74422
  var copyWithRenameImpl = function(obj, oldPath, newPath, index2) {
74318
74423
  var oldKey = oldPath[index2];
@@ -74350,17 +74455,17 @@ var require_react_reconciler_development = __commonJS({
74350
74455
  }
74351
74456
  return copyWithRenameImpl(obj, oldPath, newPath, 0);
74352
74457
  };
74353
- var copyWithSetImpl = function(obj, path60, index2, value) {
74354
- if (index2 >= path60.length) {
74458
+ var copyWithSetImpl = function(obj, path61, index2, value) {
74459
+ if (index2 >= path61.length) {
74355
74460
  return value;
74356
74461
  }
74357
- var key = path60[index2];
74462
+ var key = path61[index2];
74358
74463
  var updated = isArray(obj) ? obj.slice() : assign({}, obj);
74359
- updated[key] = copyWithSetImpl(obj[key], path60, index2 + 1, value);
74464
+ updated[key] = copyWithSetImpl(obj[key], path61, index2 + 1, value);
74360
74465
  return updated;
74361
74466
  };
74362
- var copyWithSet = function(obj, path60, value) {
74363
- return copyWithSetImpl(obj, path60, 0, value);
74467
+ var copyWithSet = function(obj, path61, value) {
74468
+ return copyWithSetImpl(obj, path61, 0, value);
74364
74469
  };
74365
74470
  var findHook = function(fiber, id) {
74366
74471
  var currentHook2 = fiber.memoizedState;
@@ -74370,10 +74475,10 @@ var require_react_reconciler_development = __commonJS({
74370
74475
  }
74371
74476
  return currentHook2;
74372
74477
  };
74373
- overrideHookState = function(fiber, id, path60, value) {
74478
+ overrideHookState = function(fiber, id, path61, value) {
74374
74479
  var hook = findHook(fiber, id);
74375
74480
  if (hook !== null) {
74376
- var newState = copyWithSet(hook.memoizedState, path60, value);
74481
+ var newState = copyWithSet(hook.memoizedState, path61, value);
74377
74482
  hook.memoizedState = newState;
74378
74483
  hook.baseState = newState;
74379
74484
  fiber.memoizedProps = assign({}, fiber.memoizedProps);
@@ -74383,10 +74488,10 @@ var require_react_reconciler_development = __commonJS({
74383
74488
  }
74384
74489
  }
74385
74490
  };
74386
- overrideHookStateDeletePath = function(fiber, id, path60) {
74491
+ overrideHookStateDeletePath = function(fiber, id, path61) {
74387
74492
  var hook = findHook(fiber, id);
74388
74493
  if (hook !== null) {
74389
- var newState = copyWithDelete(hook.memoizedState, path60);
74494
+ var newState = copyWithDelete(hook.memoizedState, path61);
74390
74495
  hook.memoizedState = newState;
74391
74496
  hook.baseState = newState;
74392
74497
  fiber.memoizedProps = assign({}, fiber.memoizedProps);
@@ -74409,8 +74514,8 @@ var require_react_reconciler_development = __commonJS({
74409
74514
  }
74410
74515
  }
74411
74516
  };
74412
- overrideProps = function(fiber, path60, value) {
74413
- fiber.pendingProps = copyWithSet(fiber.memoizedProps, path60, value);
74517
+ overrideProps = function(fiber, path61, value) {
74518
+ fiber.pendingProps = copyWithSet(fiber.memoizedProps, path61, value);
74414
74519
  if (fiber.alternate) {
74415
74520
  fiber.alternate.pendingProps = fiber.pendingProps;
74416
74521
  }
@@ -74419,8 +74524,8 @@ var require_react_reconciler_development = __commonJS({
74419
74524
  scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp);
74420
74525
  }
74421
74526
  };
74422
- overridePropsDeletePath = function(fiber, path60) {
74423
- fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path60);
74527
+ overridePropsDeletePath = function(fiber, path61) {
74528
+ fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path61);
74424
74529
  if (fiber.alternate) {
74425
74530
  fiber.alternate.pendingProps = fiber.pendingProps;
74426
74531
  }
@@ -81862,8 +81967,8 @@ var init_ErrorOverview = __esm({
81862
81967
  init_dist7();
81863
81968
  init_Box();
81864
81969
  init_Text();
81865
- cleanupPath = (path60) => {
81866
- return path60?.replace(`file://${cwd()}/`, "");
81970
+ cleanupPath = (path61) => {
81971
+ return path61?.replace(`file://${cwd()}/`, "");
81867
81972
  };
81868
81973
  stackUtils = new import_stack_utils.default({
81869
81974
  cwd: cwd(),
@@ -86352,8 +86457,8 @@ function readClipboardImageLinux() {
86352
86457
  if (result.status === 0 && result.stdout && result.stdout.length > 0) {
86353
86458
  const target = nextCachePath();
86354
86459
  try {
86355
- const fs43 = __require("fs");
86356
- fs43.writeFileSync(target, result.stdout);
86460
+ const fs44 = __require("fs");
86461
+ fs44.writeFileSync(target, result.stdout);
86357
86462
  } catch {
86358
86463
  return null;
86359
86464
  }
@@ -90717,10 +90822,10 @@ var require_segments = __commonJS({
90717
90822
  const segs = getSegmentsFromString(data, Utils.isKanjiModeEnabled());
90718
90823
  const nodes = buildNodes(segs);
90719
90824
  const graph = buildGraph(nodes, version);
90720
- const path60 = dijkstra.find_path(graph.map, "start", "end");
90825
+ const path61 = dijkstra.find_path(graph.map, "start", "end");
90721
90826
  const optimizedSegs = [];
90722
- for (let i2 = 1; i2 < path60.length - 1; i2++) {
90723
- optimizedSegs.push(graph.table[path60[i2]].node);
90827
+ for (let i2 = 1; i2 < path61.length - 1; i2++) {
90828
+ optimizedSegs.push(graph.table[path61[i2]].node);
90724
90829
  }
90725
90830
  return exports.fromArray(mergeSegments(optimizedSegs));
90726
90831
  };
@@ -93131,7 +93236,7 @@ var require_utils4 = __commonJS({
93131
93236
  // ../../node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/png.js
93132
93237
  var require_png2 = __commonJS({
93133
93238
  "../../node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/png.js"(exports) {
93134
- var fs43 = __require("fs");
93239
+ var fs44 = __require("fs");
93135
93240
  var PNG = require_png().PNG;
93136
93241
  var Utils = require_utils4();
93137
93242
  exports.render = function render2(qrData, options) {
@@ -93172,7 +93277,7 @@ var require_png2 = __commonJS({
93172
93277
  });
93173
93278
  png.pack();
93174
93279
  };
93175
- exports.renderToFile = function renderToFile(path60, qrData, options, cb) {
93280
+ exports.renderToFile = function renderToFile(path61, qrData, options, cb) {
93176
93281
  if (typeof cb === "undefined") {
93177
93282
  cb = options;
93178
93283
  options = void 0;
@@ -93183,7 +93288,7 @@ var require_png2 = __commonJS({
93183
93288
  called = true;
93184
93289
  cb.apply(null, args);
93185
93290
  };
93186
- const stream = fs43.createWriteStream(path60);
93291
+ const stream = fs44.createWriteStream(path61);
93187
93292
  stream.on("error", done);
93188
93293
  stream.on("close", done);
93189
93294
  exports.renderToFileStream(stream, qrData, options);
@@ -93245,14 +93350,14 @@ var require_utf8 = __commonJS({
93245
93350
  }
93246
93351
  return output;
93247
93352
  };
93248
- exports.renderToFile = function renderToFile(path60, qrData, options, cb) {
93353
+ exports.renderToFile = function renderToFile(path61, qrData, options, cb) {
93249
93354
  if (typeof cb === "undefined") {
93250
93355
  cb = options;
93251
93356
  options = void 0;
93252
93357
  }
93253
- const fs43 = __require("fs");
93358
+ const fs44 = __require("fs");
93254
93359
  const utf8 = exports.render(qrData, options);
93255
- fs43.writeFile(path60, utf8, cb);
93360
+ fs44.writeFile(path61, utf8, cb);
93256
93361
  };
93257
93362
  }
93258
93363
  });
@@ -93373,7 +93478,7 @@ var require_svg_tag = __commonJS({
93373
93478
  return str2;
93374
93479
  }
93375
93480
  function qrToPath(data, size, margin) {
93376
- let path60 = "";
93481
+ let path61 = "";
93377
93482
  let moveBy = 0;
93378
93483
  let newRow = false;
93379
93484
  let lineLength = 0;
@@ -93384,19 +93489,19 @@ var require_svg_tag = __commonJS({
93384
93489
  if (data[i2]) {
93385
93490
  lineLength++;
93386
93491
  if (!(i2 > 0 && col > 0 && data[i2 - 1])) {
93387
- path60 += newRow ? svgCmd("M", col + margin, 0.5 + row + margin) : svgCmd("m", moveBy, 0);
93492
+ path61 += newRow ? svgCmd("M", col + margin, 0.5 + row + margin) : svgCmd("m", moveBy, 0);
93388
93493
  moveBy = 0;
93389
93494
  newRow = false;
93390
93495
  }
93391
93496
  if (!(col + 1 < size && data[i2 + 1])) {
93392
- path60 += svgCmd("h", lineLength);
93497
+ path61 += svgCmd("h", lineLength);
93393
93498
  lineLength = 0;
93394
93499
  }
93395
93500
  } else {
93396
93501
  moveBy++;
93397
93502
  }
93398
93503
  }
93399
- return path60;
93504
+ return path61;
93400
93505
  }
93401
93506
  exports.render = function render2(qrData, options, cb) {
93402
93507
  const opts = Utils.getOptions(options);
@@ -93404,10 +93509,10 @@ var require_svg_tag = __commonJS({
93404
93509
  const data = qrData.modules.data;
93405
93510
  const qrcodesize = size + opts.margin * 2;
93406
93511
  const bg = !opts.color.light.a ? "" : "<path " + getColorAttrib(opts.color.light, "fill") + ' d="M0 0h' + qrcodesize + "v" + qrcodesize + 'H0z"/>';
93407
- const path60 = "<path " + getColorAttrib(opts.color.dark, "stroke") + ' d="' + qrToPath(data, size, opts.margin) + '"/>';
93512
+ const path61 = "<path " + getColorAttrib(opts.color.dark, "stroke") + ' d="' + qrToPath(data, size, opts.margin) + '"/>';
93408
93513
  const viewBox = 'viewBox="0 0 ' + qrcodesize + " " + qrcodesize + '"';
93409
93514
  const width = !opts.width ? "" : 'width="' + opts.width + '" height="' + opts.width + '" ';
93410
- const svgTag = '<svg xmlns="http://www.w3.org/2000/svg" ' + width + viewBox + ' shape-rendering="crispEdges">' + bg + path60 + "</svg>\n";
93515
+ const svgTag = '<svg xmlns="http://www.w3.org/2000/svg" ' + width + viewBox + ' shape-rendering="crispEdges">' + bg + path61 + "</svg>\n";
93411
93516
  if (typeof cb === "function") {
93412
93517
  cb(null, svgTag);
93413
93518
  }
@@ -93421,15 +93526,15 @@ var require_svg = __commonJS({
93421
93526
  "../../node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/svg.js"(exports) {
93422
93527
  var svgTagRenderer = require_svg_tag();
93423
93528
  exports.render = svgTagRenderer.render;
93424
- exports.renderToFile = function renderToFile(path60, qrData, options, cb) {
93529
+ exports.renderToFile = function renderToFile(path61, qrData, options, cb) {
93425
93530
  if (typeof cb === "undefined") {
93426
93531
  cb = options;
93427
93532
  options = void 0;
93428
93533
  }
93429
- const fs43 = __require("fs");
93534
+ const fs44 = __require("fs");
93430
93535
  const svgTag = exports.render(qrData, options);
93431
93536
  const xmlStr = '<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' + svgTag;
93432
- fs43.writeFile(path60, xmlStr, cb);
93537
+ fs44.writeFile(path61, xmlStr, cb);
93433
93538
  };
93434
93539
  }
93435
93540
  });
@@ -93587,8 +93692,8 @@ var require_server = __commonJS({
93587
93692
  cb
93588
93693
  };
93589
93694
  }
93590
- function getTypeFromFilename(path60) {
93591
- return path60.slice((path60.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
93695
+ function getTypeFromFilename(path61) {
93696
+ return path61.slice((path61.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
93592
93697
  }
93593
93698
  function getRendererFromType(type) {
93594
93699
  switch (type) {
@@ -93652,17 +93757,17 @@ var require_server = __commonJS({
93652
93757
  const renderer2 = getRendererFromType(params.opts.type);
93653
93758
  return render2(renderer2.renderToBuffer, text, params);
93654
93759
  };
93655
- exports.toFile = function toFile3(path60, text, opts, cb) {
93656
- if (typeof path60 !== "string" || !(typeof text === "string" || typeof text === "object")) {
93760
+ exports.toFile = function toFile3(path61, text, opts, cb) {
93761
+ if (typeof path61 !== "string" || !(typeof text === "string" || typeof text === "object")) {
93657
93762
  throw new Error("Invalid argument");
93658
93763
  }
93659
93764
  if (arguments.length < 3 && !canPromise()) {
93660
93765
  throw new Error("Too few arguments provided");
93661
93766
  }
93662
93767
  const params = checkParams(text, opts, cb);
93663
- const type = params.opts.type || getTypeFromFilename(path60);
93768
+ const type = params.opts.type || getTypeFromFilename(path61);
93664
93769
  const renderer2 = getRendererFromType(type);
93665
- const renderToFile = renderer2.renderToFile.bind(null, path60);
93770
+ const renderToFile = renderer2.renderToFile.bind(null, path61);
93666
93771
  return render2(renderToFile, text, params);
93667
93772
  };
93668
93773
  exports.toFileStream = function toFileStream(stream, text, opts) {
@@ -94482,14 +94587,14 @@ var require_util2 = __commonJS({
94482
94587
  }
94483
94588
  const port = url2.port != null ? url2.port : url2.protocol === "https:" ? 443 : 80;
94484
94589
  let origin = url2.origin != null ? url2.origin : `${url2.protocol || ""}//${url2.hostname || ""}:${port}`;
94485
- let path60 = url2.path != null ? url2.path : `${url2.pathname || ""}${url2.search || ""}`;
94590
+ let path61 = url2.path != null ? url2.path : `${url2.pathname || ""}${url2.search || ""}`;
94486
94591
  if (origin[origin.length - 1] === "/") {
94487
94592
  origin = origin.slice(0, origin.length - 1);
94488
94593
  }
94489
- if (path60 && path60[0] !== "/") {
94490
- path60 = `/${path60}`;
94594
+ if (path61 && path61[0] !== "/") {
94595
+ path61 = `/${path61}`;
94491
94596
  }
94492
- return new URL(`${origin}${path60}`);
94597
+ return new URL(`${origin}${path61}`);
94493
94598
  }
94494
94599
  if (!isHttpOrHttpsPrefixed(url2.origin || url2.protocol)) {
94495
94600
  throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
@@ -94939,39 +95044,39 @@ var require_diagnostics = __commonJS({
94939
95044
  });
94940
95045
  diagnosticsChannel.channel("undici:client:sendHeaders").subscribe((evt) => {
94941
95046
  const {
94942
- request: { method, path: path60, origin }
95047
+ request: { method, path: path61, origin }
94943
95048
  } = evt;
94944
- debuglog("sending request to %s %s/%s", method, origin, path60);
95049
+ debuglog("sending request to %s %s/%s", method, origin, path61);
94945
95050
  });
94946
95051
  diagnosticsChannel.channel("undici:request:headers").subscribe((evt) => {
94947
95052
  const {
94948
- request: { method, path: path60, origin },
95053
+ request: { method, path: path61, origin },
94949
95054
  response: { statusCode }
94950
95055
  } = evt;
94951
95056
  debuglog(
94952
95057
  "received response to %s %s/%s - HTTP %d",
94953
95058
  method,
94954
95059
  origin,
94955
- path60,
95060
+ path61,
94956
95061
  statusCode
94957
95062
  );
94958
95063
  });
94959
95064
  diagnosticsChannel.channel("undici:request:trailers").subscribe((evt) => {
94960
95065
  const {
94961
- request: { method, path: path60, origin }
95066
+ request: { method, path: path61, origin }
94962
95067
  } = evt;
94963
- debuglog("trailers received from %s %s/%s", method, origin, path60);
95068
+ debuglog("trailers received from %s %s/%s", method, origin, path61);
94964
95069
  });
94965
95070
  diagnosticsChannel.channel("undici:request:error").subscribe((evt) => {
94966
95071
  const {
94967
- request: { method, path: path60, origin },
95072
+ request: { method, path: path61, origin },
94968
95073
  error: error2
94969
95074
  } = evt;
94970
95075
  debuglog(
94971
95076
  "request to %s %s/%s errored - %s",
94972
95077
  method,
94973
95078
  origin,
94974
- path60,
95079
+ path61,
94975
95080
  error2.message
94976
95081
  );
94977
95082
  });
@@ -95020,9 +95125,9 @@ var require_diagnostics = __commonJS({
95020
95125
  });
95021
95126
  diagnosticsChannel.channel("undici:client:sendHeaders").subscribe((evt) => {
95022
95127
  const {
95023
- request: { method, path: path60, origin }
95128
+ request: { method, path: path61, origin }
95024
95129
  } = evt;
95025
- debuglog("sending request to %s %s/%s", method, origin, path60);
95130
+ debuglog("sending request to %s %s/%s", method, origin, path61);
95026
95131
  });
95027
95132
  }
95028
95133
  diagnosticsChannel.channel("undici:websocket:open").subscribe((evt) => {
@@ -95084,7 +95189,7 @@ var require_request = __commonJS({
95084
95189
  var kHandler = /* @__PURE__ */ Symbol("handler");
95085
95190
  var Request4 = class {
95086
95191
  constructor(origin, {
95087
- path: path60,
95192
+ path: path61,
95088
95193
  method,
95089
95194
  body,
95090
95195
  headers,
@@ -95099,11 +95204,11 @@ var require_request = __commonJS({
95099
95204
  expectContinue,
95100
95205
  servername
95101
95206
  }, handler) {
95102
- if (typeof path60 !== "string") {
95207
+ if (typeof path61 !== "string") {
95103
95208
  throw new InvalidArgumentError("path must be a string");
95104
- } else if (path60[0] !== "/" && !(path60.startsWith("http://") || path60.startsWith("https://")) && method !== "CONNECT") {
95209
+ } else if (path61[0] !== "/" && !(path61.startsWith("http://") || path61.startsWith("https://")) && method !== "CONNECT") {
95105
95210
  throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
95106
- } else if (invalidPathRegex.test(path60)) {
95211
+ } else if (invalidPathRegex.test(path61)) {
95107
95212
  throw new InvalidArgumentError("invalid request path");
95108
95213
  }
95109
95214
  if (typeof method !== "string") {
@@ -95169,7 +95274,7 @@ var require_request = __commonJS({
95169
95274
  this.completed = false;
95170
95275
  this.aborted = false;
95171
95276
  this.upgrade = upgrade || null;
95172
- this.path = query ? buildURL(path60, query) : path60;
95277
+ this.path = query ? buildURL(path61, query) : path61;
95173
95278
  this.origin = origin;
95174
95279
  this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
95175
95280
  this.blocking = blocking == null ? false : blocking;
@@ -99707,7 +99812,7 @@ var require_client_h1 = __commonJS({
99707
99812
  return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT";
99708
99813
  }
99709
99814
  function writeH1(client, request) {
99710
- const { method, path: path60, host, upgrade, blocking, reset } = request;
99815
+ const { method, path: path61, host, upgrade, blocking, reset } = request;
99711
99816
  let { body, headers, contentLength } = request;
99712
99817
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
99713
99818
  if (util.isFormDataLike(body)) {
@@ -99773,7 +99878,7 @@ var require_client_h1 = __commonJS({
99773
99878
  if (blocking) {
99774
99879
  socket[kBlocking] = true;
99775
99880
  }
99776
- let header = `${method} ${path60} HTTP/1.1\r
99881
+ let header = `${method} ${path61} HTTP/1.1\r
99777
99882
  `;
99778
99883
  if (typeof host === "string") {
99779
99884
  header += `host: ${host}\r
@@ -100298,7 +100403,7 @@ var require_client_h2 = __commonJS({
100298
100403
  }
100299
100404
  function writeH2(client, request) {
100300
100405
  const session = client[kHTTP2Session];
100301
- const { method, path: path60, host, upgrade, expectContinue, signal, headers: reqHeaders } = request;
100406
+ const { method, path: path61, host, upgrade, expectContinue, signal, headers: reqHeaders } = request;
100302
100407
  let { body } = request;
100303
100408
  if (upgrade) {
100304
100409
  util.errorRequest(client, request, new Error("Upgrade not supported for H2"));
@@ -100365,7 +100470,7 @@ var require_client_h2 = __commonJS({
100365
100470
  });
100366
100471
  return true;
100367
100472
  }
100368
- headers[HTTP2_HEADER_PATH] = path60;
100473
+ headers[HTTP2_HEADER_PATH] = path61;
100369
100474
  headers[HTTP2_HEADER_SCHEME] = "https";
100370
100475
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
100371
100476
  if (body && typeof body.read === "function") {
@@ -100717,9 +100822,9 @@ var require_redirect_handler = __commonJS({
100717
100822
  return this.handler.onHeaders(statusCode, headers, resume, statusText);
100718
100823
  }
100719
100824
  const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
100720
- const path60 = search ? `${pathname}${search}` : pathname;
100825
+ const path61 = search ? `${pathname}${search}` : pathname;
100721
100826
  this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
100722
- this.opts.path = path60;
100827
+ this.opts.path = path61;
100723
100828
  this.opts.origin = origin;
100724
100829
  this.opts.maxRedirections = 0;
100725
100830
  this.opts.query = null;
@@ -101944,10 +102049,10 @@ var require_proxy_agent = __commonJS({
101944
102049
  };
101945
102050
  const {
101946
102051
  origin,
101947
- path: path60 = "/",
102052
+ path: path61 = "/",
101948
102053
  headers = {}
101949
102054
  } = opts;
101950
- opts.path = origin + path60;
102055
+ opts.path = origin + path61;
101951
102056
  if (!("host" in headers) && !("Host" in headers)) {
101952
102057
  const { host } = new URL3(origin);
101953
102058
  headers.host = host;
@@ -103855,20 +103960,20 @@ var require_mock_utils = __commonJS({
103855
103960
  }
103856
103961
  return true;
103857
103962
  }
103858
- function safeUrl(path60) {
103859
- if (typeof path60 !== "string") {
103860
- return path60;
103963
+ function safeUrl(path61) {
103964
+ if (typeof path61 !== "string") {
103965
+ return path61;
103861
103966
  }
103862
- const pathSegments = path60.split("?");
103967
+ const pathSegments = path61.split("?");
103863
103968
  if (pathSegments.length !== 2) {
103864
- return path60;
103969
+ return path61;
103865
103970
  }
103866
103971
  const qp = new URLSearchParams(pathSegments.pop());
103867
103972
  qp.sort();
103868
103973
  return [...pathSegments, qp.toString()].join("?");
103869
103974
  }
103870
- function matchKey(mockDispatch2, { path: path60, method, body, headers }) {
103871
- const pathMatch = matchValue(mockDispatch2.path, path60);
103975
+ function matchKey(mockDispatch2, { path: path61, method, body, headers }) {
103976
+ const pathMatch = matchValue(mockDispatch2.path, path61);
103872
103977
  const methodMatch = matchValue(mockDispatch2.method, method);
103873
103978
  const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
103874
103979
  const headersMatch = matchHeaders(mockDispatch2, headers);
@@ -103890,7 +103995,7 @@ var require_mock_utils = __commonJS({
103890
103995
  function getMockDispatch(mockDispatches, key) {
103891
103996
  const basePath = key.query ? buildURL(key.path, key.query) : key.path;
103892
103997
  const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
103893
- let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path60 }) => matchValue(safeUrl(path60), resolvedPath));
103998
+ let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path61 }) => matchValue(safeUrl(path61), resolvedPath));
103894
103999
  if (matchedMockDispatches.length === 0) {
103895
104000
  throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
103896
104001
  }
@@ -103928,9 +104033,9 @@ var require_mock_utils = __commonJS({
103928
104033
  }
103929
104034
  }
103930
104035
  function buildKey(opts) {
103931
- const { path: path60, method, body, headers, query } = opts;
104036
+ const { path: path61, method, body, headers, query } = opts;
103932
104037
  return {
103933
- path: path60,
104038
+ path: path61,
103934
104039
  method,
103935
104040
  body,
103936
104041
  headers,
@@ -104388,10 +104493,10 @@ var require_pending_interceptors_formatter = __commonJS({
104388
104493
  }
104389
104494
  format(pendingInterceptors) {
104390
104495
  const withPrettyHeaders = pendingInterceptors.map(
104391
- ({ method, path: path60, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
104496
+ ({ method, path: path61, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
104392
104497
  Method: method,
104393
104498
  Origin: origin,
104394
- Path: path60,
104499
+ Path: path61,
104395
104500
  "Status code": statusCode,
104396
104501
  Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
104397
104502
  Invocations: timesInvoked,
@@ -109230,9 +109335,9 @@ var require_util7 = __commonJS({
109230
109335
  }
109231
109336
  }
109232
109337
  }
109233
- function validateCookiePath(path60) {
109234
- for (let i2 = 0; i2 < path60.length; ++i2) {
109235
- const code = path60.charCodeAt(i2);
109338
+ function validateCookiePath(path61) {
109339
+ for (let i2 = 0; i2 < path61.length; ++i2) {
109340
+ const code = path61.charCodeAt(i2);
109236
109341
  if (code < 32 || // exclude CTLs (0-31)
109237
109342
  code === 127 || // DEL
109238
109343
  code === 59) {
@@ -111892,11 +111997,11 @@ var require_undici = __commonJS({
111892
111997
  if (typeof opts.path !== "string") {
111893
111998
  throw new InvalidArgumentError("invalid opts.path");
111894
111999
  }
111895
- let path60 = opts.path;
112000
+ let path61 = opts.path;
111896
112001
  if (!opts.path.startsWith("/")) {
111897
- path60 = `/${path60}`;
112002
+ path61 = `/${path61}`;
111898
112003
  }
111899
- url2 = new URL(util.parseOrigin(url2).origin + path60);
112004
+ url2 = new URL(util.parseOrigin(url2).origin + path61);
111900
112005
  } else {
111901
112006
  if (!opts) {
111902
112007
  opts = typeof url2 === "object" ? url2 : {};
@@ -113793,7 +113898,12 @@ var VaultStore = class {
113793
113898
  }
113794
113899
  const parsed = JSON.parse(raw);
113795
113900
  if (parsed.version !== 1 || parsed.kdf !== "scrypt") {
113796
- throw new Error(`Unsupported vault file: version=${parsed.version} kdf=${parsed.kdf}`);
113901
+ throw new MoxxyError({
113902
+ code: "VAULT_CORRUPT",
113903
+ message: `Unsupported vault file: version=${parsed.version} kdf=${parsed.kdf}`,
113904
+ hint: `This vault was written by an incompatible version. Back up and remove ${this.filePath} to re-initialize.`,
113905
+ context: { filePath: this.filePath }
113906
+ });
113797
113907
  }
113798
113908
  this.file = parsed;
113799
113909
  const salt = Buffer.from(parsed.salt, "base64");
@@ -113977,8 +114087,6 @@ function firstEntry(entries) {
113977
114087
  }
113978
114088
  return void 0;
113979
114089
  }
113980
-
113981
- // ../plugin-vault/dist/placeholder.js
113982
114090
  var PLACEHOLDER_RE = /\$\{vault:([A-Za-z0-9_.-]+)\}/g;
113983
114091
  async function resolveString(input, vault) {
113984
114092
  PLACEHOLDER_RE.lastIndex = 0;
@@ -113992,8 +114100,14 @@ async function resolveString(input, vault) {
113992
114100
  const values = /* @__PURE__ */ new Map();
113993
114101
  for (const name of names) {
113994
114102
  const value = await vault.get(name);
113995
- if (value === null)
113996
- throw new Error(`vault: missing required entry '${name}' referenced in config`);
114103
+ if (value === null) {
114104
+ throw new MoxxyError({
114105
+ code: "CONFIG_INVALID",
114106
+ message: `vault: missing required entry '${name}' referenced in config`,
114107
+ hint: `Add it with \`/vault set ${name} <value>\` (or the \`vault_set\` tool), then retry.`,
114108
+ context: { name }
114109
+ });
114110
+ }
113997
114111
  values.set(name, value);
113998
114112
  }
113999
114113
  return input.replace(PLACEHOLDER_RE, (_match, name) => values.get(name) ?? "");
@@ -114118,8 +114232,14 @@ ${vaultCommandUsage()}` };
114118
114232
  permission: { action: "prompt" },
114119
114233
  handler: async ({ name }) => {
114120
114234
  const value = await vault.get(name);
114121
- if (value === null)
114122
- throw new Error(`vault: '${name}' not found`);
114235
+ if (value === null) {
114236
+ throw new MoxxyError({
114237
+ code: "TOOL_ERROR",
114238
+ message: `vault: '${name}' not found`,
114239
+ hint: "Use `vault_list` to see stored entry names.",
114240
+ context: { name }
114241
+ });
114242
+ }
114123
114243
  return value;
114124
114244
  }
114125
114245
  }),
@@ -115826,13 +115946,13 @@ var MultipartBody = class {
115826
115946
  }
115827
115947
  };
115828
115948
  var fileFromPathWarned = false;
115829
- async function fileFromPath3(path60, ...args) {
115949
+ async function fileFromPath3(path61, ...args) {
115830
115950
  const { fileFromPath: _fileFromPath } = await Promise.resolve().then(() => (init_fileFromPath(), fileFromPath_exports));
115831
115951
  if (!fileFromPathWarned) {
115832
- console.warn(`fileFromPath is deprecated; use fs.createReadStream(${JSON.stringify(path60)}) instead`);
115952
+ console.warn(`fileFromPath is deprecated; use fs.createReadStream(${JSON.stringify(path61)}) instead`);
115833
115953
  fileFromPathWarned = true;
115834
115954
  }
115835
- return await _fileFromPath(path60, ...args);
115955
+ return await _fileFromPath(path61, ...args);
115836
115956
  }
115837
115957
  var defaultHttpAgent = new import_agentkeepalive.default({ keepAlive: true, timeout: 5 * 60 * 1e3 });
115838
115958
  var defaultHttpsAgent = new import_agentkeepalive.default.HttpsAgent({ keepAlive: true, timeout: 5 * 60 * 1e3 });
@@ -116555,29 +116675,29 @@ var APIClient = class {
116555
116675
  defaultIdempotencyKey() {
116556
116676
  return `stainless-node-retry-${uuid4()}`;
116557
116677
  }
116558
- get(path60, opts) {
116559
- return this.methodRequest("get", path60, opts);
116678
+ get(path61, opts) {
116679
+ return this.methodRequest("get", path61, opts);
116560
116680
  }
116561
- post(path60, opts) {
116562
- return this.methodRequest("post", path60, opts);
116681
+ post(path61, opts) {
116682
+ return this.methodRequest("post", path61, opts);
116563
116683
  }
116564
- patch(path60, opts) {
116565
- return this.methodRequest("patch", path60, opts);
116684
+ patch(path61, opts) {
116685
+ return this.methodRequest("patch", path61, opts);
116566
116686
  }
116567
- put(path60, opts) {
116568
- return this.methodRequest("put", path60, opts);
116687
+ put(path61, opts) {
116688
+ return this.methodRequest("put", path61, opts);
116569
116689
  }
116570
- delete(path60, opts) {
116571
- return this.methodRequest("delete", path60, opts);
116690
+ delete(path61, opts) {
116691
+ return this.methodRequest("delete", path61, opts);
116572
116692
  }
116573
- methodRequest(method, path60, opts) {
116693
+ methodRequest(method, path61, opts) {
116574
116694
  return this.request(Promise.resolve(opts).then(async (opts2) => {
116575
116695
  const body = opts2 && isBlobLike(opts2?.body) ? new DataView(await opts2.body.arrayBuffer()) : opts2?.body instanceof DataView ? opts2.body : opts2?.body instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2?.body) ? new DataView(opts2.body.buffer) : opts2?.body;
116576
- return { method, path: path60, ...opts2, body };
116696
+ return { method, path: path61, ...opts2, body };
116577
116697
  }));
116578
116698
  }
116579
- getAPIList(path60, Page3, opts) {
116580
- return this.requestAPIList(Page3, { method: "get", path: path60, ...opts });
116699
+ getAPIList(path61, Page3, opts) {
116700
+ return this.requestAPIList(Page3, { method: "get", path: path61, ...opts });
116581
116701
  }
116582
116702
  calculateContentLength(body) {
116583
116703
  if (typeof body === "string") {
@@ -116596,10 +116716,10 @@ var APIClient = class {
116596
116716
  }
116597
116717
  buildRequest(inputOptions, { retryCount = 0 } = {}) {
116598
116718
  const options = { ...inputOptions };
116599
- const { method, path: path60, query, headers = {} } = options;
116719
+ const { method, path: path61, query, headers = {} } = options;
116600
116720
  const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === "string" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;
116601
116721
  const contentLength = this.calculateContentLength(body);
116602
- const url2 = this.buildURL(path60, query);
116722
+ const url2 = this.buildURL(path61, query);
116603
116723
  if ("timeout" in options)
116604
116724
  validatePositiveInteger("timeout", options.timeout);
116605
116725
  options.timeout = options.timeout ?? this.timeout;
@@ -116723,8 +116843,8 @@ var APIClient = class {
116723
116843
  const request = this.makeRequest(options, null);
116724
116844
  return new PagePromise(this, request, Page3);
116725
116845
  }
116726
- buildURL(path60, query) {
116727
- const url2 = isAbsoluteURL(path60) ? new URL(path60) : new URL(this.baseURL + (this.baseURL.endsWith("/") && path60.startsWith("/") ? path60.slice(1) : path60));
116846
+ buildURL(path61, query) {
116847
+ const url2 = isAbsoluteURL(path61) ? new URL(path61) : new URL(this.baseURL + (this.baseURL.endsWith("/") && path61.startsWith("/") ? path61.slice(1) : path61));
116728
116848
  const defaultQuery = this.defaultQuery();
116729
116849
  if (!isEmptyObj(defaultQuery)) {
116730
116850
  query = { ...defaultQuery, ...query };
@@ -119135,9 +119255,9 @@ function toAnthropicTools(tools, opts = {}) {
119135
119255
 
119136
119256
  // ../plugin-provider-anthropic/dist/provider.js
119137
119257
  var anthropicModels = [
119138
- { id: "claude-opus-4-7", contextWindow: 8e5, maxOutputTokens: 8e3, supportsTools: true, supportsStreaming: true, supportsImages: true, supportsDocuments: true },
119139
- { id: "claude-sonnet-4-6", contextWindow: 2e5, maxOutputTokens: 8e3, supportsTools: true, supportsStreaming: true, supportsImages: true, supportsDocuments: true },
119140
- { id: "claude-haiku-4-5-20251001", contextWindow: 2e5, maxOutputTokens: 8e3, supportsTools: true, supportsStreaming: true, supportsImages: true, supportsDocuments: true }
119258
+ { id: "claude-opus-4-7", contextWindow: 1e6, maxOutputTokens: 128e3, supportsTools: true, supportsStreaming: true, supportsImages: true, supportsDocuments: true },
119259
+ { id: "claude-sonnet-4-6", contextWindow: 1e6, maxOutputTokens: 64e3, supportsTools: true, supportsStreaming: true, supportsImages: true, supportsDocuments: true },
119260
+ { id: "claude-haiku-4-5-20251001", contextWindow: 2e5, maxOutputTokens: 64e3, supportsTools: true, supportsStreaming: true, supportsImages: true, supportsDocuments: true }
119141
119261
  ];
119142
119262
  var AnthropicProvider = class {
119143
119263
  name;
@@ -119396,9 +119516,13 @@ var AnthropicProvider = class {
119396
119516
  try {
119397
119517
  const result = await this.client.messages.countTokens({
119398
119518
  model: req.model || this.defaultModel,
119399
- system: systemForCount,
119519
+ ...systemForCount !== void 0 ? { system: systemForCount } : {},
119520
+ // NARROW cast: our hand-rolled message/tool shapes carry `media_type:
119521
+ // string`, which the SDK narrows to a literal union it can't see we
119522
+ // never violate. The method itself is fully typed (no `as unknown` on
119523
+ // the resource anymore); only these two args need the structural cast.
119400
119524
  messages,
119401
- tools
119525
+ ...tools !== void 0 ? { tools } : {}
119402
119526
  });
119403
119527
  return result.input_tokens;
119404
119528
  } catch {
@@ -119883,13 +120007,13 @@ var MultipartBody2 = class {
119883
120007
  }
119884
120008
  };
119885
120009
  var fileFromPathWarned2 = false;
119886
- async function fileFromPath5(path60, ...args) {
120010
+ async function fileFromPath5(path61, ...args) {
119887
120011
  const { fileFromPath: _fileFromPath } = await Promise.resolve().then(() => (init_fileFromPath(), fileFromPath_exports));
119888
120012
  if (!fileFromPathWarned2) {
119889
- console.warn(`fileFromPath is deprecated; use fs.createReadStream(${JSON.stringify(path60)}) instead`);
120013
+ console.warn(`fileFromPath is deprecated; use fs.createReadStream(${JSON.stringify(path61)}) instead`);
119890
120014
  fileFromPathWarned2 = true;
119891
120015
  }
119892
- return await _fileFromPath(path60, ...args);
120016
+ return await _fileFromPath(path61, ...args);
119893
120017
  }
119894
120018
  var defaultHttpAgent2 = new import_agentkeepalive2.default({ keepAlive: true, timeout: 5 * 60 * 1e3 });
119895
120019
  var defaultHttpsAgent2 = new import_agentkeepalive2.default.HttpsAgent({ keepAlive: true, timeout: 5 * 60 * 1e3 });
@@ -120667,29 +120791,29 @@ var APIClient2 = class {
120667
120791
  defaultIdempotencyKey() {
120668
120792
  return `stainless-node-retry-${uuid42()}`;
120669
120793
  }
120670
- get(path60, opts) {
120671
- return this.methodRequest("get", path60, opts);
120794
+ get(path61, opts) {
120795
+ return this.methodRequest("get", path61, opts);
120672
120796
  }
120673
- post(path60, opts) {
120674
- return this.methodRequest("post", path60, opts);
120797
+ post(path61, opts) {
120798
+ return this.methodRequest("post", path61, opts);
120675
120799
  }
120676
- patch(path60, opts) {
120677
- return this.methodRequest("patch", path60, opts);
120800
+ patch(path61, opts) {
120801
+ return this.methodRequest("patch", path61, opts);
120678
120802
  }
120679
- put(path60, opts) {
120680
- return this.methodRequest("put", path60, opts);
120803
+ put(path61, opts) {
120804
+ return this.methodRequest("put", path61, opts);
120681
120805
  }
120682
- delete(path60, opts) {
120683
- return this.methodRequest("delete", path60, opts);
120806
+ delete(path61, opts) {
120807
+ return this.methodRequest("delete", path61, opts);
120684
120808
  }
120685
- methodRequest(method, path60, opts) {
120809
+ methodRequest(method, path61, opts) {
120686
120810
  return this.request(Promise.resolve(opts).then(async (opts2) => {
120687
120811
  const body = opts2 && isBlobLike2(opts2?.body) ? new DataView(await opts2.body.arrayBuffer()) : opts2?.body instanceof DataView ? opts2.body : opts2?.body instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2?.body) ? new DataView(opts2.body.buffer) : opts2?.body;
120688
- return { method, path: path60, ...opts2, body };
120812
+ return { method, path: path61, ...opts2, body };
120689
120813
  }));
120690
120814
  }
120691
- getAPIList(path60, Page3, opts) {
120692
- return this.requestAPIList(Page3, { method: "get", path: path60, ...opts });
120815
+ getAPIList(path61, Page3, opts) {
120816
+ return this.requestAPIList(Page3, { method: "get", path: path61, ...opts });
120693
120817
  }
120694
120818
  calculateContentLength(body) {
120695
120819
  if (typeof body === "string") {
@@ -120708,10 +120832,10 @@ var APIClient2 = class {
120708
120832
  }
120709
120833
  buildRequest(inputOptions, { retryCount = 0 } = {}) {
120710
120834
  const options = { ...inputOptions };
120711
- const { method, path: path60, query, headers = {} } = options;
120835
+ const { method, path: path61, query, headers = {} } = options;
120712
120836
  const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === "string" ? options.body : isMultipartBody2(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;
120713
120837
  const contentLength = this.calculateContentLength(body);
120714
- const url2 = this.buildURL(path60, query);
120838
+ const url2 = this.buildURL(path61, query);
120715
120839
  if ("timeout" in options)
120716
120840
  validatePositiveInteger2("timeout", options.timeout);
120717
120841
  options.timeout = options.timeout ?? this.timeout;
@@ -120827,8 +120951,8 @@ var APIClient2 = class {
120827
120951
  const request = this.makeRequest(options, null);
120828
120952
  return new PagePromise2(this, request, Page3);
120829
120953
  }
120830
- buildURL(path60, query) {
120831
- const url2 = isAbsoluteURL2(path60) ? new URL(path60) : new URL(this.baseURL + (this.baseURL.endsWith("/") && path60.startsWith("/") ? path60.slice(1) : path60));
120954
+ buildURL(path61, query) {
120955
+ const url2 = isAbsoluteURL2(path61) ? new URL(path61) : new URL(this.baseURL + (this.baseURL.endsWith("/") && path61.startsWith("/") ? path61.slice(1) : path61));
120832
120956
  const defaultQuery = this.defaultQuery();
120833
120957
  if (!isEmptyObj2(defaultQuery)) {
120834
120958
  query = { ...defaultQuery, ...query };
@@ -126216,11 +126340,11 @@ function buildAuthUrl(input) {
126216
126340
  }
126217
126341
  async function runAuthorizationCodeFlow(opts) {
126218
126342
  const port = opts.redirectPort ?? 8765;
126219
- const path60 = opts.redirectPath ?? "/callback";
126343
+ const path61 = opts.redirectPath ?? "/callback";
126220
126344
  const codeVerifier = generateCodeVerifier();
126221
126345
  const codeChallenge = computeCodeChallenge(codeVerifier);
126222
126346
  const state = generateState();
126223
- const redirectUri = `http://localhost:${port}${path60}`;
126347
+ const redirectUri = `http://localhost:${port}${path61}`;
126224
126348
  const authUrl = buildAuthUrl({
126225
126349
  authUrl: opts.authUrl,
126226
126350
  clientId: opts.clientId,
@@ -126232,7 +126356,7 @@ async function runAuthorizationCodeFlow(opts) {
126232
126356
  });
126233
126357
  const codePromise = waitForCallback({
126234
126358
  port,
126235
- path: path60,
126359
+ path: path61,
126236
126360
  expectedState: state,
126237
126361
  timeoutMs: opts.timeoutMs ?? 3e5,
126238
126362
  ...opts.signal ? { signal: opts.signal } : {}
@@ -126546,7 +126670,10 @@ function buildOauthAuthorizeTool(deps) {
126546
126670
  let tokens;
126547
126671
  if (mode === "device") {
126548
126672
  if (!input.deviceUrl) {
126549
- throw new Error('mode="device" requires `deviceUrl` (the provider\'s device-authorization endpoint)');
126673
+ throw new MoxxyError({
126674
+ code: "TOOL_ERROR",
126675
+ message: 'mode="device" requires `deviceUrl` (the provider\'s device-authorization endpoint)'
126676
+ });
126550
126677
  }
126551
126678
  tokens = await runDeviceCodeFlow({
126552
126679
  deviceUrl: input.deviceUrl,
@@ -126572,7 +126699,10 @@ function buildOauthAuthorizeTool(deps) {
126572
126699
  });
126573
126700
  } else {
126574
126701
  if (!input.authUrl) {
126575
- throw new Error('mode="loopback" requires `authUrl` (the provider\'s authorization endpoint)');
126702
+ throw new MoxxyError({
126703
+ code: "TOOL_ERROR",
126704
+ message: 'mode="loopback" requires `authUrl` (the provider\'s authorization endpoint)'
126705
+ });
126576
126706
  }
126577
126707
  if (input.noOpen) {
126578
126708
  const verifier = generateCodeVerifier();
@@ -126580,11 +126710,11 @@ function buildOauthAuthorizeTool(deps) {
126580
126710
  const { computeCodeChallenge: computeCodeChallenge2 } = await Promise.resolve().then(() => (init_pkce(), pkce_exports));
126581
126711
  const challenge = computeCodeChallenge2(verifier);
126582
126712
  const port = input.redirectPort ?? 8765;
126583
- const path60 = input.redirectPath ?? "/callback";
126713
+ const path61 = input.redirectPath ?? "/callback";
126584
126714
  const url2 = buildAuthUrl({
126585
126715
  authUrl: input.authUrl,
126586
126716
  clientId: input.clientId,
126587
- redirectUri: `http://localhost:${port}${path60}`,
126717
+ redirectUri: `http://localhost:${port}${path61}`,
126588
126718
  scopes: input.scopes,
126589
126719
  codeChallenge: challenge,
126590
126720
  state,
@@ -126726,7 +126856,7 @@ async function runOauthLogin(profile, ctx) {
126726
126856
  }
126727
126857
  async function runBrowserFlow(profile, ctx) {
126728
126858
  const port = profile.redirect?.port ?? 8765;
126729
- const path60 = profile.redirect?.path ?? "/callback";
126859
+ const path61 = profile.redirect?.path ?? "/callback";
126730
126860
  const serviceName = profile.displayName ?? profile.id;
126731
126861
  return runAuthorizationCodeFlow({
126732
126862
  authUrl: profile.authUrl,
@@ -126735,7 +126865,7 @@ async function runBrowserFlow(profile, ctx) {
126735
126865
  ...profile.clientSecret ? { clientSecret: profile.clientSecret } : {},
126736
126866
  scopes: profile.scopes,
126737
126867
  redirectPort: port,
126738
- redirectPath: path60,
126868
+ redirectPath: path61,
126739
126869
  ...profile.extraAuthParams ? { extraAuthParams: profile.extraAuthParams } : {},
126740
126870
  timeoutMs: DEFAULT_BROWSER_TIMEOUT_MS,
126741
126871
  ...ctx.signal ? { signal: ctx.signal } : {},
@@ -126747,7 +126877,7 @@ If your browser doesn't open automatically, paste this URL:
126747
126877
 
126748
126878
  ${url2}
126749
126879
 
126750
- Waiting for callback on http://localhost:${port}${path60} (5 min timeout)\u2026
126880
+ Waiting for callback on http://localhost:${port}${path61} (5 min timeout)\u2026
126751
126881
 
126752
126882
  `);
126753
126883
  }
@@ -133523,11 +133653,11 @@ function isAddrInUse(err) {
133523
133653
  return !!err && typeof err === "object" && err.code === "EADDRINUSE";
133524
133654
  }
133525
133655
  async function captureStdout(cmd, args) {
133526
- const { spawn: spawn17 } = await import('child_process');
133656
+ const { spawn: spawn14 } = await import('child_process');
133527
133657
  return await new Promise((resolve12) => {
133528
133658
  let out = "";
133529
133659
  try {
133530
- const child = spawn17(cmd, [...args], { stdio: ["ignore", "pipe", "ignore"] });
133660
+ const child = spawn14(cmd, [...args], { stdio: ["ignore", "pipe", "ignore"] });
133531
133661
  child.stdout.on("data", (b3) => {
133532
133662
  out += b3.toString();
133533
133663
  });
@@ -133903,161 +134033,30 @@ var WebChannel = class {
133903
134033
  }
133904
134034
  }
133905
134035
  };
133906
-
133907
- // ../plugin-channel-web/dist/child-cleanup.js
133908
- var live = /* @__PURE__ */ new Set();
133909
- var hooked = false;
133910
- function killChild(child) {
133911
- if (child.exitCode != null || child.signalCode != null)
133912
- return;
133913
- try {
133914
- child.kill("SIGTERM");
133915
- } catch {
133916
- }
133917
- const t2 = setTimeout(() => {
133918
- try {
133919
- child.kill("SIGKILL");
133920
- } catch {
133921
- }
133922
- }, 2e3);
133923
- t2.unref?.();
133924
- child.once("exit", () => clearTimeout(t2));
133925
- }
133926
- function ensureHook() {
133927
- if (hooked)
133928
- return;
133929
- hooked = true;
133930
- const killAll = () => {
133931
- for (const child of live) {
133932
- try {
133933
- child.kill("SIGKILL");
133934
- } catch {
133935
- }
133936
- }
133937
- live.clear();
133938
- };
133939
- process.once("exit", killAll);
133940
- process.once("SIGINT", killAll);
133941
- process.once("SIGTERM", killAll);
133942
- }
133943
- function trackChild(child) {
133944
- ensureHook();
133945
- live.add(child);
133946
- child.once("exit", () => live.delete(child));
133947
- return () => new Promise((resolve12) => {
133948
- live.delete(child);
133949
- if (child.exitCode != null || child.signalCode != null)
133950
- return resolve12();
133951
- child.once("exit", () => resolve12());
133952
- killChild(child);
133953
- });
133954
- }
133955
-
133956
- // ../plugin-channel-web/dist/cloudflared.js
133957
134036
  var TRYCLOUDFLARE_RE = /https:\/\/[a-z0-9-]+\.trycloudflare\.com/i;
133958
134037
  var URL_TIMEOUT_MS = 3e4;
133959
- function parseTrycloudflareUrl(chunk) {
133960
- return TRYCLOUDFLARE_RE.exec(chunk)?.[0] ?? null;
133961
- }
133962
134038
  var cloudflaredTunnel = defineTunnelProvider({
133963
134039
  name: "cloudflared",
133964
- isAvailable: () => new Promise((resolve12) => {
133965
- const child = spawn("cloudflared", ["--version"]);
133966
- child.on("error", () => resolve12(false));
133967
- child.on("exit", (code) => resolve12(code === 0));
133968
- }),
133969
- open: ({ port, host }) => new Promise((resolve12, reject) => {
133970
- const child = spawn("cloudflared", ["tunnel", "--no-autoupdate", "--url", `http://${host}:${port}`]);
133971
- const untrack = trackChild(child);
133972
- let settled = false;
133973
- const timer = setTimeout(() => {
133974
- if (settled)
133975
- return;
133976
- settled = true;
133977
- void untrack();
133978
- reject(new Error("cloudflared: timed out waiting for the tunnel URL"));
133979
- }, URL_TIMEOUT_MS);
133980
- timer.unref?.();
133981
- const onData = (buf) => {
133982
- if (settled)
133983
- return;
133984
- const url2 = parseTrycloudflareUrl(buf.toString("utf8"));
133985
- if (!url2)
133986
- return;
133987
- settled = true;
133988
- clearTimeout(timer);
133989
- resolve12({ url: url2, close: untrack });
133990
- };
133991
- child.stderr?.on("data", onData);
133992
- child.stdout?.on("data", onData);
133993
- child.on("error", (err) => {
133994
- if (settled)
133995
- return;
133996
- settled = true;
133997
- clearTimeout(timer);
133998
- void untrack();
133999
- reject(err);
134000
- });
134001
- child.on("exit", (code) => {
134002
- if (settled)
134003
- return;
134004
- settled = true;
134005
- clearTimeout(timer);
134006
- reject(new Error(`cloudflared exited (code ${code}) before emitting a URL`));
134007
- });
134040
+ isAvailable: () => isCliTunnelAvailable("cloudflared"),
134041
+ open: ({ port, host }) => spawnCliTunnel({
134042
+ cmd: "cloudflared",
134043
+ args: ["tunnel", "--no-autoupdate", "--url", `http://${host}:${port}`],
134044
+ urlRegex: TRYCLOUDFLARE_RE,
134045
+ timeoutMs: URL_TIMEOUT_MS,
134046
+ name: "cloudflared"
134008
134047
  })
134009
134048
  });
134010
134049
  var NGROK_URL_RE = /https:\/\/[a-z0-9-]+\.ngrok(?:-free)?\.(?:app|io|dev)/i;
134011
134050
  var URL_TIMEOUT_MS2 = 3e4;
134012
- function parseNgrokUrl(chunk) {
134013
- return NGROK_URL_RE.exec(chunk)?.[0] ?? null;
134014
- }
134015
134051
  var ngrokTunnel = defineTunnelProvider({
134016
134052
  name: "ngrok",
134017
- isAvailable: () => new Promise((resolve12) => {
134018
- const child = spawn("ngrok", ["--version"]);
134019
- child.on("error", () => resolve12(false));
134020
- child.on("exit", (code) => resolve12(code === 0));
134021
- }),
134022
- open: ({ port }) => new Promise((resolve12, reject) => {
134023
- const child = spawn("ngrok", ["http", String(port), "--log", "stdout", "--log-format", "json"]);
134024
- const untrack = trackChild(child);
134025
- let settled = false;
134026
- const timer = setTimeout(() => {
134027
- if (settled)
134028
- return;
134029
- settled = true;
134030
- void untrack();
134031
- reject(new Error("ngrok: timed out waiting for the tunnel URL"));
134032
- }, URL_TIMEOUT_MS2);
134033
- timer.unref?.();
134034
- const onData = (buf) => {
134035
- if (settled)
134036
- return;
134037
- const url2 = parseNgrokUrl(buf.toString("utf8"));
134038
- if (!url2)
134039
- return;
134040
- settled = true;
134041
- clearTimeout(timer);
134042
- resolve12({ url: url2, close: untrack });
134043
- };
134044
- child.stdout?.on("data", onData);
134045
- child.stderr?.on("data", onData);
134046
- child.on("error", (err) => {
134047
- if (settled)
134048
- return;
134049
- settled = true;
134050
- clearTimeout(timer);
134051
- void untrack();
134052
- reject(err);
134053
- });
134054
- child.on("exit", (code) => {
134055
- if (settled)
134056
- return;
134057
- settled = true;
134058
- clearTimeout(timer);
134059
- reject(new Error(`ngrok exited (code ${code}) before emitting a URL`));
134060
- });
134053
+ isAvailable: () => isCliTunnelAvailable("ngrok"),
134054
+ open: ({ port }) => spawnCliTunnel({
134055
+ cmd: "ngrok",
134056
+ args: ["http", String(port), "--log", "stdout", "--log-format", "json"],
134057
+ urlRegex: NGROK_URL_RE,
134058
+ timeoutMs: URL_TIMEOUT_MS2,
134059
+ name: "ngrok"
134061
134060
  })
134062
134061
  });
134063
134062
  var webSettingsSchema = z$1.object({ tunnel: z$1.string().optional() });
@@ -134310,6 +134309,9 @@ async function createWebSocketTransportServer(opts) {
134310
134309
  for (const client of wss.clients)
134311
134310
  client.terminate();
134312
134311
  },
134312
+ clientCount() {
134313
+ return connections;
134314
+ },
134313
134315
  close() {
134314
134316
  return new Promise((resolve12) => {
134315
134317
  for (const client of wss.clients)
@@ -134640,7 +134642,7 @@ function isRunnerUp(socketPath = runnerSocketPath()) {
134640
134642
 
134641
134643
  // ../runner/dist/server.js
134642
134644
  init_dist();
134643
- var RUNNER_PROTOCOL_VERSION = 3;
134645
+ var RUNNER_PROTOCOL_VERSION = 4;
134644
134646
  var RunnerMethod = {
134645
134647
  /** client->server: handshake; returns the initial info snapshot. */
134646
134648
  Attach: "attach",
@@ -134684,6 +134686,12 @@ var RunnerMethod = {
134684
134686
  WorkflowSetEnabled: "workflow.setEnabled",
134685
134687
  /** client->server: run a workflow now. */
134686
134688
  WorkflowRun: "workflow.run",
134689
+ /** client->server: validate a draft workflow YAML (builder). */
134690
+ WorkflowValidateDraft: "workflow.validateDraft",
134691
+ /** client->server: persist a workflow from full YAML (builder). */
134692
+ WorkflowSave: "workflow.save",
134693
+ /** client->server: fetch one saved workflow as canonical YAML (builder). */
134694
+ WorkflowGetRun: "workflow.getRun",
134687
134695
  /** server->client: ask this client to decide a tool-call permission. */
134688
134696
  PermissionCheck: "permission.check",
134689
134697
  /** server->client: ask this client to confirm an approval checkpoint. */
@@ -134760,6 +134768,14 @@ var workflowSetEnabledParamsSchema = z.object({
134760
134768
  enabled: z.boolean()
134761
134769
  });
134762
134770
  var workflowRunParamsSchema = z.object({ name: z.string() });
134771
+ var workflowValidateDraftParamsSchema = z.object({
134772
+ yaml: z.string().min(1).max(1e6)
134773
+ });
134774
+ var workflowSaveParamsSchema = z.object({
134775
+ yaml: z.string().min(1).max(1e6),
134776
+ previousName: z.string().min(1).max(120).optional()
134777
+ });
134778
+ var workflowGetRunParamsSchema = z.object({ name: z.string().min(1).max(120) });
134763
134779
 
134764
134780
  // ../runner/dist/server.js
134765
134781
  var RunnerServer = class {
@@ -134836,6 +134852,9 @@ var RunnerServer = class {
134836
134852
  peer.handle(RunnerMethod.WorkflowList, () => this.handleWorkflowList());
134837
134853
  peer.handle(RunnerMethod.WorkflowSetEnabled, (raw) => this.handleWorkflowSetEnabled(raw));
134838
134854
  peer.handle(RunnerMethod.WorkflowRun, (raw) => this.handleWorkflowRun(raw));
134855
+ peer.handle(RunnerMethod.WorkflowValidateDraft, (raw) => this.handleWorkflowValidateDraft(raw));
134856
+ peer.handle(RunnerMethod.WorkflowSave, (raw) => this.handleWorkflowSave(raw));
134857
+ peer.handle(RunnerMethod.WorkflowGetRun, (raw) => this.handleWorkflowGetRun(raw));
134839
134858
  peer.onClose(() => this.onDisconnect(client));
134840
134859
  }
134841
134860
  onDisconnect(client) {
@@ -135066,6 +135085,30 @@ var RunnerServer = class {
135066
135085
  throw new Error("workflows plugin not loaded");
135067
135086
  return view.run(params.name);
135068
135087
  }
135088
+ // --- Workflows builder (validate / save / getRun) ------------------------
135089
+ // Optional on the view (older hosts / pre-builder plugins lack them), so
135090
+ // feature-check and throw a clear error rather than calling undefined.
135091
+ async handleWorkflowValidateDraft(raw) {
135092
+ const params = workflowValidateDraftParamsSchema.parse(raw);
135093
+ const view = this.session.workflows;
135094
+ if (!view?.validateDraft)
135095
+ throw new Error("workflows builder not supported on this runner");
135096
+ return view.validateDraft(params.yaml);
135097
+ }
135098
+ async handleWorkflowSave(raw) {
135099
+ const params = workflowSaveParamsSchema.parse(raw);
135100
+ const view = this.session.workflows;
135101
+ if (!view?.save)
135102
+ throw new Error("workflows builder not supported on this runner");
135103
+ return view.save(params.yaml, params.previousName);
135104
+ }
135105
+ async handleWorkflowGetRun(raw) {
135106
+ const params = workflowGetRunParamsSchema.parse(raw);
135107
+ const view = this.session.workflows;
135108
+ if (!view?.getRun)
135109
+ throw new Error("workflows builder not supported on this runner");
135110
+ return await view.getRun(params.name) ?? null;
135111
+ }
135069
135112
  broadcastInfo() {
135070
135113
  this.broadcast(RunnerNotification.InfoChanged, { info: this.session.getInfo() });
135071
135114
  }
@@ -135508,7 +135551,15 @@ var RemoteSession = class {
135508
135551
  enabled
135509
135552
  });
135510
135553
  },
135511
- run: (name) => this.peer.request(RunnerMethod.WorkflowRun, { name })
135554
+ run: (name) => this.peer.request(RunnerMethod.WorkflowRun, { name }),
135555
+ // Builder methods (protocol v4): forward to the runner so the desktop's
135556
+ // RemoteSession-backed visual builder can validate/save/load drafts.
135557
+ validateDraft: (yaml) => this.peer.request(RunnerMethod.WorkflowValidateDraft, { yaml }),
135558
+ save: (yaml, previousName) => this.peer.request(RunnerMethod.WorkflowSave, {
135559
+ yaml,
135560
+ ...previousName ? { previousName } : {}
135561
+ }),
135562
+ getRun: (name) => this.peer.request(RunnerMethod.WorkflowGetRun, { name })
135512
135563
  };
135513
135564
  }
135514
135565
  };
@@ -135614,11 +135665,11 @@ async function isMoxxyProcess(pid) {
135614
135665
  return command.length > 0 && /moxxy/i.test(command);
135615
135666
  }
135616
135667
  async function pidCommand2(pid) {
135617
- const { spawn: spawn17 } = await import('child_process');
135668
+ const { spawn: spawn14 } = await import('child_process');
135618
135669
  return await new Promise((resolve12) => {
135619
135670
  let out = "";
135620
135671
  try {
135621
- const child = spawn17("ps", ["-p", String(pid), "-o", "command="], {
135672
+ const child = spawn14("ps", ["-p", String(pid), "-o", "command="], {
135622
135673
  stdio: ["ignore", "pipe", "ignore"]
135623
135674
  });
135624
135675
  child.stdout.on("data", (b3) => {
@@ -135656,11 +135707,11 @@ async function pidsListeningOnPort(port) {
135656
135707
  return await runLsof(["-t", `-iTCP:${port}`, "-sTCP:LISTEN"]);
135657
135708
  }
135658
135709
  async function runLsof(args) {
135659
- const { spawn: spawn17 } = await import('child_process');
135710
+ const { spawn: spawn14 } = await import('child_process');
135660
135711
  return await new Promise((resolve12) => {
135661
135712
  let out = "";
135662
135713
  try {
135663
- const child = spawn17("lsof", [...args], {
135714
+ const child = spawn14("lsof", [...args], {
135664
135715
  stdio: ["ignore", "pipe", "ignore"]
135665
135716
  });
135666
135717
  child.stdout.on("data", (b3) => {
@@ -135684,8 +135735,8 @@ function parsePids(out) {
135684
135735
  }
135685
135736
  async function unlinkSocket(socketPath) {
135686
135737
  try {
135687
- const fs43 = await import('fs');
135688
- fs43.unlinkSync(socketPath);
135738
+ const fs44 = await import('fs');
135739
+ fs44.unlinkSync(socketPath);
135689
135740
  } catch {
135690
135741
  }
135691
135742
  }
@@ -135704,13 +135755,38 @@ async function connectWithRetry(socketPath, retries) {
135704
135755
  }
135705
135756
 
135706
135757
  // ../desktop-ipc-contract/dist/index.js
135707
- var REMOTE_DISALLOWED_COMMANDS = /* @__PURE__ */ new Set([
135708
- "desks.pickFolder",
135709
- "session.pickAttachment",
135710
- "focus.close",
135711
- "focus.restoreMain",
135712
- "focus.resize",
135713
- "app.relaunch"
135758
+ var REMOTE_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
135759
+ // Answer a permission/approval prompt — RESPOND only. Note that
135760
+ // `session.setAutoApprove` (turn the prompt OFF entirely) is deliberately NOT
135761
+ // here: a remote client may answer the desktop user's prompts, never disable
135762
+ // them and run tools unattended.
135763
+ "ask.respond",
135764
+ // Workspace discovery + reconnect (read-only / non-mutating).
135765
+ "connection.snapshotAll",
135766
+ "connection.activeWorkspace",
135767
+ "connection.retry",
135768
+ // The conversation itself.
135769
+ "session.info",
135770
+ "session.runTurn",
135771
+ "session.abortTurn",
135772
+ "session.setMode",
135773
+ "session.newSession",
135774
+ "session.runCommand",
135775
+ // Voice input (capability-probed; transcribe fails coded without a transcriber).
135776
+ "session.hasTranscriber",
135777
+ "session.transcribe",
135778
+ // Per-workspace transcript log (the mobile ChatStoreBridge persists through
135779
+ // these; they're scoped to a workspace's NDJSON log, not host config).
135780
+ "chat.append",
135781
+ "chat.loadSegment",
135782
+ "chat.clearLog",
135783
+ "chat.migrate",
135784
+ // Workflows: READ + run an existing one only. Authoring (`workflows.save`,
135785
+ // `workflows.validateDraft`, `workflows.setEnabled`) is host-only — a paired
135786
+ // phone must not rewrite or re-enable the host's workflows.
135787
+ "workflows.list",
135788
+ "workflows.run",
135789
+ "workflows.getRun"
135714
135790
  ]);
135715
135791
  var providerName = z.string().regex(/^[a-z][a-z0-9-]{0,63}$/, "invalid provider name");
135716
135792
  var httpUrl = z.string().refine((s2) => {
@@ -135725,6 +135801,9 @@ var skillName = z.string().min(1).max(200).regex(/^[A-Za-z0-9][A-Za-z0-9 ._/-]*$
135725
135801
  var vaultKeyName = z.string().min(1).max(200).regex(/^[A-Za-z0-9][A-Za-z0-9._/-]*$/, "invalid vault key name").refine((s2) => !s2.includes(".."), 'vault key name may not contain ".."');
135726
135802
  var optionalWorkspace = z.string().min(1).max(256).optional();
135727
135803
  var MAX_AUDIO_BASE64 = 4e7;
135804
+ var MAX_INLINE_ATTACHMENT_CONTENT = 12e6;
135805
+ var commandName = z.string().min(1).max(64).regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/, "invalid command name");
135806
+ var workflowName = z.string().min(1).max(200).refine((s2) => !s2.includes("..") && !s2.includes("/") && !s2.includes("\\"), "invalid workflow name");
135728
135807
  var ipcInputSchemas = {
135729
135808
  // No-arg, but spawns a child process (npm install) — pin the payload to
135730
135809
  // "nothing" so a hostile renderer can't smuggle args across.
@@ -135769,8 +135848,35 @@ var ipcInputSchemas = {
135769
135848
  attachments: z.array(z.object({
135770
135849
  path: z.string().min(1).max(4096),
135771
135850
  name: z.string().min(1).max(1024)
135772
- })).max(64).optional()
135851
+ })).max(64).optional(),
135852
+ // Inline attachments cross the wire as payload (remote/mobile clients) —
135853
+ // bound both the entry count and per-entry content size.
135854
+ inlineAttachments: z.array(z.object({
135855
+ kind: z.enum(["stdin", "file", "image", "document", "audio"]),
135856
+ content: z.string().max(MAX_INLINE_ATTACHMENT_CONTENT),
135857
+ name: z.string().max(1024).optional(),
135858
+ mediaType: z.string().max(128).optional()
135859
+ })).max(8).optional()
135773
135860
  }),
135861
+ // Runs an arbitrary registered slash command — the audit flagged this as the
135862
+ // one mutating session command without a schema, so lock the name to a
135863
+ // registry slug and bound the free-text args.
135864
+ "session.runCommand": z.object({
135865
+ workspaceId: optionalWorkspace,
135866
+ name: commandName,
135867
+ args: z.string().max(1e4)
135868
+ }),
135869
+ "workflows.run": z.object({ name: workflowName }),
135870
+ "workflows.setEnabled": z.object({ name: workflowName, enabled: z.boolean() }),
135871
+ // Builder commands. validateDraft/save take full YAML — bound the size so a
135872
+ // hostile renderer can't OOM the host; save writes to disk so it's
135873
+ // filesystem-touching and gets a boundary check like the other writers.
135874
+ "workflows.validateDraft": z.object({ yaml: z.string().min(1).max(1e6) }),
135875
+ "workflows.save": z.object({
135876
+ yaml: z.string().min(1).max(1e6),
135877
+ previousName: workflowName.optional()
135878
+ }),
135879
+ "workflows.getRun": z.object({ name: workflowName }),
135774
135880
  // Security-sensitive: this bypasses the approval sheet, so validate it at
135775
135881
  // the boundary like the other dangerous commands.
135776
135882
  "session.setAutoApprove": z.object({ workspaceId: optionalWorkspace, enabled: z.boolean() }),
@@ -135795,8 +135901,14 @@ var ipcInputSchemas = {
135795
135901
  onboardingComplete: z.boolean().optional(),
135796
135902
  clerkUserId: z.string().max(256).nullable().optional(),
135797
135903
  clerkDisplayName: z.string().max(256).nullable().optional(),
135798
- signedInAt: z.number().nullable().optional()
135904
+ signedInAt: z.number().nullable().optional(),
135905
+ mobileGatewayEnabled: z.boolean().optional()
135799
135906
  }).strict(),
135907
+ // Mobile-gateway control. Both no-arg variants pin the payload to "nothing"
135908
+ // so a hostile caller can't smuggle args; setEnabled is a strict boolean.
135909
+ "mobileGateway.status": z.undefined(),
135910
+ "mobileGateway.rotateToken": z.undefined(),
135911
+ "mobileGateway.setEnabled": z.object({ enabled: z.boolean() }).strict(),
135800
135912
  "chat.append": z.object({
135801
135913
  workspaceId: z.string().min(1).max(256),
135802
135914
  events: z.array(z.unknown()).max(1e4)
@@ -135877,6 +135989,11 @@ async function dispatch(channel, args, fn) {
135877
135989
  var WebSocketCommandBus = class {
135878
135990
  methods = /* @__PURE__ */ new Map();
135879
135991
  peers = /* @__PURE__ */ new Set();
135992
+ /** Deny-by-default allow-list (null ⇒ no filter; see the constructor). */
135993
+ allowedCommands;
135994
+ constructor(opts = {}) {
135995
+ this.allowedCommands = opts.allowedCommands === void 0 ? REMOTE_ALLOWED_COMMANDS : opts.allowedCommands;
135996
+ }
135880
135997
  handle(channel, fn) {
135881
135998
  this.methods.set(channel, fn);
135882
135999
  }
@@ -135889,7 +136006,7 @@ var WebSocketCommandBus = class {
135889
136006
  const peer = new JsonRpcPeer(transport);
135890
136007
  for (const [channel, fn] of this.methods) {
135891
136008
  peer.handle(channel, async (params) => {
135892
- if (REMOTE_DISALLOWED_COMMANDS.has(channel)) {
136009
+ if (this.allowedCommands && !this.allowedCommands.has(channel)) {
135893
136010
  const message = `command "${channel}" is not available over a remote transport`;
135894
136011
  throw new RpcError(message, { code: "runner-error", message });
135895
136012
  }
@@ -135983,7 +136100,68 @@ var MobileSessionHost = class {
135983
136100
  this.bus.handle("session.setAutoApprove", async ({ enabled }) => {
135984
136101
  this.autoApprove = enabled;
135985
136102
  });
135986
- this.bus.handle("session.hasTranscriber", async () => false);
136103
+ this.bus.handle("session.setMode", async ({ mode }) => {
136104
+ this.session.modes.setActive(mode);
136105
+ this.bus.broadcast("connection.changed", { workspaceId: ws, phase: this.snapshot().phase });
136106
+ });
136107
+ this.bus.handle("session.newSession", async () => {
136108
+ for (const controller of this.turns.values())
136109
+ controller.abort();
136110
+ if (this.session.reset)
136111
+ await this.session.reset();
136112
+ else
136113
+ this.session.log.clear();
136114
+ });
136115
+ this.bus.handle("session.runCommand", async ({ name, args }) => {
136116
+ const def = this.session.commands.get(name);
136117
+ if (!def)
136118
+ return { kind: "error", message: `unknown command: /${name}` };
136119
+ return await def.handler({
136120
+ channel: "mobile",
136121
+ sessionId: this.session.getInfo().sessionId,
136122
+ args,
136123
+ session: this.session
136124
+ });
136125
+ });
136126
+ this.bus.handle("session.hasTranscriber", async () => this.activeTranscriber() != null);
136127
+ this.bus.handle("session.transcribe", async ({ audioBase64, mimeType }) => {
136128
+ const transcriber = this.activeTranscriber();
136129
+ if (!transcriber) {
136130
+ throw new IpcError("not-supported", "no transcriber is active on this session");
136131
+ }
136132
+ const audio = Buffer.from(audioBase64, "base64");
136133
+ const result = await transcriber.transcribe(audio, mimeType ? { mimeType } : void 0);
136134
+ return result.text;
136135
+ });
136136
+ this.bus.handle("workflows.list", async () => this.session.workflows?.list() ?? []);
136137
+ this.bus.handle("workflows.setEnabled", async ({ name, enabled }) => {
136138
+ if (this.session.workflows)
136139
+ await this.session.workflows.setEnabled(name, enabled);
136140
+ });
136141
+ this.bus.handle("workflows.run", async ({ name }) => {
136142
+ if (!this.session.workflows) {
136143
+ throw new IpcError("not-supported", "workflows plugin not loaded on this session");
136144
+ }
136145
+ return await this.session.workflows.run(name);
136146
+ });
136147
+ this.bus.handle("workflows.validateDraft", async ({ yaml }) => {
136148
+ if (!this.session.workflows?.validateDraft) {
136149
+ throw new IpcError("not-supported", "workflows builder not supported on this session");
136150
+ }
136151
+ return await this.session.workflows.validateDraft(yaml);
136152
+ });
136153
+ this.bus.handle("workflows.save", async ({ yaml }) => {
136154
+ if (!this.session.workflows?.save) {
136155
+ throw new IpcError("not-supported", "workflows builder not supported on this session");
136156
+ }
136157
+ return await this.session.workflows.save(yaml);
136158
+ });
136159
+ this.bus.handle("workflows.getRun", async ({ name }) => {
136160
+ if (!this.session.workflows?.getRun) {
136161
+ throw new IpcError("not-supported", "workflows builder not supported on this session");
136162
+ }
136163
+ return await this.session.workflows.getRun(name);
136164
+ });
135987
136165
  this.bus.handle("ask.respond", async ({ requestId, response }) => {
135988
136166
  this.answerAsk(requestId, response);
135989
136167
  });
@@ -136025,6 +136203,15 @@ var MobileSessionHost = class {
136025
136203
  this.session.setApprovalResolver(null);
136026
136204
  }
136027
136205
  // ---- internals ----------------------------------------------------------
136206
+ /** Active transcriber, or null. Guarded access — a thin/remote session may
136207
+ * leave the registry view undefined (capability-absent ≠ crash). */
136208
+ activeTranscriber() {
136209
+ try {
136210
+ return this.session.transcribers?.tryGetActive() ?? null;
136211
+ } catch {
136212
+ return null;
136213
+ }
136214
+ }
136028
136215
  snapshot() {
136029
136216
  const info = this.session.getInfo();
136030
136217
  const phase = {
@@ -136045,7 +136232,8 @@ var MobileSessionHost = class {
136045
136232
  try {
136046
136233
  for await (const _event of this.session.runTurn(args.prompt, {
136047
136234
  signal: controller.signal,
136048
- ...args.model ? { model: args.model } : {}
136235
+ ...args.model ? { model: args.model } : {},
136236
+ ...args.inlineAttachments && args.inlineAttachments.length > 0 ? { attachments: args.inlineAttachments } : {}
136049
136237
  })) {
136050
136238
  void _event;
136051
136239
  }
@@ -136084,19 +136272,6 @@ function resolveMobileToken(configured) {
136084
136272
  function rotateMobileToken() {
136085
136273
  return rotateChannelToken({ fileName: TOKEN_FILE });
136086
136274
  }
136087
- function normalizeTunnelChoice(raw) {
136088
- const v3 = (process.env.MOXXY_MOBILE_TUNNEL ?? raw ?? "localhost").trim().toLowerCase();
136089
- if (v3 === "cloudflared" || v3 === "ngrok")
136090
- return v3;
136091
- return "localhost";
136092
- }
136093
- function tunnelProviderFor(choice) {
136094
- if (choice === "cloudflared")
136095
- return cloudflaredTunnel;
136096
- if (choice === "ngrok")
136097
- return ngrokTunnel;
136098
- return null;
136099
- }
136100
136275
  function resolveBindHost(configured) {
136101
136276
  const v3 = (process.env.MOXXY_MOBILE_HOST ?? configured ?? "").trim();
136102
136277
  return v3.length > 0 ? v3 : "127.0.0.1";
@@ -136133,6 +136308,21 @@ function buildConnectUrl(opts) {
136133
136308
  return `ws://${opts.localHost}:${opts.port}/?t=${t2}`;
136134
136309
  }
136135
136310
 
136311
+ // ../plugin-channel-mobile/dist/tunnel.js
136312
+ function normalizeTunnelChoice(raw) {
136313
+ const v3 = (process.env.MOXXY_MOBILE_TUNNEL ?? raw ?? "localhost").trim().toLowerCase();
136314
+ if (v3 === "cloudflared" || v3 === "ngrok")
136315
+ return v3;
136316
+ return "localhost";
136317
+ }
136318
+ function tunnelProviderFor(choice) {
136319
+ if (choice === "cloudflared")
136320
+ return cloudflaredTunnel;
136321
+ if (choice === "ngrok")
136322
+ return ngrokTunnel;
136323
+ return null;
136324
+ }
136325
+
136136
136326
  // ../plugin-channel-mobile/dist/qr.js
136137
136327
  var import_qrcode = __toESM(require_lib3());
136138
136328
  async function printConnectInfo(url2, token, hint) {
@@ -136196,7 +136386,7 @@ var MobileChannel = class {
136196
136386
  return this.token;
136197
136387
  }
136198
136388
  async start(startOpts) {
136199
- const bus = new WebSocketCommandBus();
136389
+ const bus = new WebSocketCommandBus({ allowedCommands: null });
136200
136390
  const host = new MobileSessionHost(bus, startOpts.session);
136201
136391
  this.host = host;
136202
136392
  host.register();
@@ -137691,10 +137881,10 @@ function buildUsageStatsPlugin(opts = {}) {
137691
137881
  cursor = ctx.log.length;
137692
137882
  },
137693
137883
  async onShutdown(ctx) {
137694
- const live2 = ctx.log.slice(cursor);
137695
- if (live2.length === 0)
137884
+ const live = ctx.log.slice(cursor);
137885
+ if (live.length === 0)
137696
137886
  return;
137697
- const delta = summarizeTokensByModel(live2);
137887
+ const delta = summarizeTokensByModel(live);
137698
137888
  await mergeUsageStats(delta, opts.statsPath);
137699
137889
  }
137700
137890
  }
@@ -138835,11 +139025,11 @@ var ScheduleStore = class {
138835
139025
  * Used by the workflows integration to mirror a workflow's `on.schedule`
138836
139026
  * into the shared poller without a separate timer.
138837
139027
  */
138838
- async syncWorkflowSchedule(workflowName, entry) {
139028
+ async syncWorkflowSchedule(workflowName2, entry) {
138839
139029
  await this.mutate((schedules) => {
138840
- const filtered = schedules.filter((s2) => !(s2.source === "workflow" && s2.workflowName === workflowName));
139030
+ const filtered = schedules.filter((s2) => !(s2.source === "workflow" && s2.workflowName === workflowName2));
138841
139031
  if (entry) {
138842
- filtered.push(scheduleEntrySchema.parse({ ...entry, source: "workflow", workflowName }));
139032
+ filtered.push(scheduleEntrySchema.parse({ ...entry, source: "workflow", workflowName: workflowName2 }));
138843
139033
  }
138844
139034
  return filtered;
138845
139035
  });
@@ -139282,7 +139472,7 @@ function readHeader(headers, name) {
139282
139472
  return v3[0] ?? null;
139283
139473
  return v3 ?? null;
139284
139474
  }
139285
- function readJsonPath(body, path60) {
139475
+ function readJsonPath(body, path61) {
139286
139476
  let parsed;
139287
139477
  try {
139288
139478
  parsed = JSON.parse(body.toString("utf8"));
@@ -139290,7 +139480,7 @@ function readJsonPath(body, path60) {
139290
139480
  return null;
139291
139481
  }
139292
139482
  let cur = parsed;
139293
- for (const seg of path60.split(".")) {
139483
+ for (const seg of path61.split(".")) {
139294
139484
  if (cur === null || cur === void 0 || typeof cur !== "object")
139295
139485
  return null;
139296
139486
  cur = cur[seg];
@@ -139905,88 +140095,52 @@ function redactVerification(v3) {
139905
140095
  }
139906
140096
  var CLOUDFLARED_URL_RE = /https:\/\/[A-Za-z0-9.-]+\.trycloudflare\.com/;
139907
140097
  var NGROK_URL_RE2 = /https:\/\/[A-Za-z0-9.-]+\.ngrok[a-z.-]*\.app/;
139908
- async function isTunnelCliAvailable(kind3) {
139909
- return new Promise((resolve12) => {
139910
- const child = spawn(kind3, ["--version"], { stdio: "ignore" });
139911
- child.once("error", () => resolve12(false));
139912
- child.once("exit", (code) => resolve12(code === 0));
140098
+ var SPAWN_CONFIG = {
140099
+ cloudflared: {
140100
+ cmd: "cloudflared",
140101
+ urlRegex: CLOUDFLARED_URL_RE,
140102
+ args: (port, host) => ["tunnel", "--no-autoupdate", "--url", `http://${host}:${port}`]
140103
+ },
140104
+ ngrok: {
140105
+ cmd: "ngrok",
140106
+ urlRegex: NGROK_URL_RE2,
140107
+ args: (port) => ["http", String(port), "--log=stdout"]
140108
+ }
140109
+ };
140110
+ function openCliTunnel(kind3, port, host, timeoutMs) {
140111
+ const cfg = SPAWN_CONFIG[kind3];
140112
+ return spawnCliTunnel({
140113
+ cmd: cfg.cmd,
140114
+ args: cfg.args(port, host),
140115
+ urlRegex: cfg.urlRegex,
140116
+ name: kind3,
140117
+ ...timeoutMs !== void 0 ? { timeoutMs } : {}
139913
140118
  });
139914
140119
  }
140120
+ var webhookTunnelProviders = {
140121
+ cloudflared: defineTunnelProvider({
140122
+ name: "cloudflared",
140123
+ isAvailable: () => isCliTunnelAvailable("cloudflared"),
140124
+ open: ({ port, host }) => openCliTunnel("cloudflared", port, host)
140125
+ }),
140126
+ ngrok: defineTunnelProvider({
140127
+ name: "ngrok",
140128
+ isAvailable: () => isCliTunnelAvailable("ngrok"),
140129
+ open: ({ port, host }) => openCliTunnel("ngrok", port, host)
140130
+ })
140131
+ };
140132
+ function isTunnelCliAvailable(kind3) {
140133
+ const provider = webhookTunnelProviders[kind3];
140134
+ return provider.isAvailable ? provider.isAvailable() : Promise.resolve(false);
140135
+ }
139915
140136
  async function startTunnel(opts) {
139916
140137
  const host = opts.host ?? "127.0.0.1";
139917
- const target = `http://${host}:${opts.port}`;
139918
- const args = opts.kind === "cloudflared" ? ["tunnel", "--no-autoupdate", "--url", target, ...opts.extraArgs ?? []] : ["http", `${opts.port}`, "--log=stdout", ...opts.extraArgs ?? []];
139919
- const timeoutMs = opts.urlTimeoutMs ?? 3e4;
139920
- let child;
139921
- try {
139922
- child = spawn(opts.kind, args, { stdio: ["ignore", "pipe", "pipe"] });
139923
- } catch (err) {
139924
- throw new Error(`failed to spawn ${opts.kind} \u2014 is it installed? (${err instanceof Error ? err.message : String(err)})`);
139925
- }
139926
- const urlRe = opts.kind === "cloudflared" ? CLOUDFLARED_URL_RE : NGROK_URL_RE2;
139927
- const urlPromise = new Promise((resolve12, reject) => {
139928
- let settled = false;
139929
- const onChunk = (buf) => {
139930
- const match = urlRe.exec(buf.toString("utf8"));
139931
- if (match && !settled) {
139932
- settled = true;
139933
- resolve12(match[0]);
139934
- }
139935
- };
139936
- child.stdout?.on("data", onChunk);
139937
- child.stderr?.on("data", onChunk);
139938
- child.once("error", (err) => {
139939
- if (!settled) {
139940
- settled = true;
139941
- reject(err);
139942
- }
139943
- });
139944
- child.once("exit", (code) => {
139945
- if (!settled) {
139946
- settled = true;
139947
- reject(new Error(`${opts.kind} exited before printing a URL (code=${code ?? "null"})`));
139948
- }
139949
- });
139950
- setTimeout(() => {
139951
- if (!settled) {
139952
- settled = true;
139953
- reject(new Error(`timed out waiting ${timeoutMs}ms for ${opts.kind} URL`));
139954
- }
139955
- }, timeoutMs).unref?.();
139956
- });
139957
- let url2;
139958
- try {
139959
- url2 = await urlPromise;
139960
- } catch (err) {
139961
- try {
139962
- child.kill("SIGTERM");
139963
- } catch {
139964
- }
139965
- throw err;
139966
- }
139967
- const pid = child.pid ?? -1;
140138
+ const handle2 = await openCliTunnel(opts.kind, opts.port, host, opts.urlTimeoutMs);
139968
140139
  return {
139969
140140
  kind: opts.kind,
139970
- url: url2,
139971
- pid,
139972
- stop: async () => {
139973
- if (!child.killed && child.exitCode === null) {
139974
- child.kill("SIGTERM");
139975
- try {
139976
- await Promise.race([
139977
- once(child, "exit"),
139978
- new Promise((r2) => setTimeout(r2, 2e3).unref?.())
139979
- ]);
139980
- } catch {
139981
- }
139982
- if (!child.killed && child.exitCode === null) {
139983
- try {
139984
- child.kill("SIGKILL");
139985
- } catch {
139986
- }
139987
- }
139988
- }
139989
- }
140141
+ url: handle2.url,
140142
+ pid: handle2.pid,
140143
+ stop: () => handle2.close()
139990
140144
  };
139991
140145
  }
139992
140146
  function defaultWebhookSecretsDir() {
@@ -141926,23 +142080,122 @@ function validateCondition(expr) {
141926
142080
  }
141927
142081
 
141928
142082
  // ../plugin-workflows/dist/schema.js
141929
- var ACTION_KEYS = ["skill", "prompt", "tool", "workflow"];
142083
+ var ACTION_KEYS = [
142084
+ "skill",
142085
+ "prompt",
142086
+ "tool",
142087
+ "workflow",
142088
+ "bridge",
142089
+ "condition",
142090
+ "switch",
142091
+ "loop"
142092
+ ];
141930
142093
  var SLUG_RE = /^[a-z0-9][a-z0-9-]*$/i;
141931
142094
  var STEP_ID_RE = /^[a-z0-9][a-z0-9_-]*$/i;
142095
+ var loopActionSchema = z.object({
142096
+ body: z.array(z.string().min(1)).min(1),
142097
+ condition: z.string().min(1),
142098
+ maxIterations: z.number().int().min(1).max(50).default(10)
142099
+ });
141932
142100
  var stepSchema = z.object({
141933
142101
  id: z.string().min(1).max(80).regex(STEP_ID_RE, "step id must be slug-like"),
141934
142102
  skill: z.string().min(1).optional(),
141935
142103
  prompt: z.string().min(1).optional(),
141936
142104
  tool: z.string().min(1).optional(),
141937
142105
  workflow: z.string().min(1).optional(),
142106
+ bridge: z.string().min(1).optional(),
142107
+ condition: z.string().min(1).optional(),
142108
+ then: z.array(z.string().min(1)).optional(),
142109
+ else: z.array(z.string().min(1)).optional(),
142110
+ switch: z.string().min(1).optional(),
142111
+ cases: z.record(z.array(z.string().min(1))).optional(),
142112
+ default: z.array(z.string().min(1)).optional(),
142113
+ loop: loopActionSchema.optional(),
141938
142114
  input: z.string().optional(),
141939
142115
  args: z.record(z.unknown()).optional(),
141940
142116
  needs: z.array(z.string().min(1)).default([]),
141941
142117
  when: z.string().min(1).optional(),
141942
142118
  onError: z.enum(["fail", "continue", "retry"]).default("fail"),
141943
142119
  retries: z.number().int().min(0).max(3).default(0),
141944
- label: z.string().max(60).optional()
142120
+ label: z.string().max(60).optional(),
142121
+ format: z.enum(["json", "plain"]).optional(),
142122
+ awaitInput: z.boolean().optional()
141945
142123
  }).superRefine((step, ctx) => {
142124
+ if (step.awaitInput) {
142125
+ ctx.addIssue({
142126
+ code: z.ZodIssueCode.custom,
142127
+ message: `step "${step.id}": awaitInput requires the resume channel, which is not available in this build \u2014 a paused run would hang forever. Remove awaitInput (gather the input via an \`inputs\` field or a normal prompt step instead).`,
142128
+ path: ["awaitInput"]
142129
+ });
142130
+ }
142131
+ if (step.format === "plain" && step.bridge == null) {
142132
+ ctx.addIssue({
142133
+ code: z.ZodIssueCode.custom,
142134
+ message: `step "${step.id}": format plain is only allowed on bridge steps`,
142135
+ path: ["format"]
142136
+ });
142137
+ }
142138
+ if (step.condition != null) {
142139
+ if (step.then == null) {
142140
+ ctx.addIssue({
142141
+ code: z.ZodIssueCode.custom,
142142
+ message: `step "${step.id}": condition requires then`,
142143
+ path: ["then"]
142144
+ });
142145
+ }
142146
+ if (step.else == null) {
142147
+ ctx.addIssue({
142148
+ code: z.ZodIssueCode.custom,
142149
+ message: `step "${step.id}": condition requires else`,
142150
+ path: ["else"]
142151
+ });
142152
+ }
142153
+ }
142154
+ if (step.switch != null) {
142155
+ const caseKeys = Object.keys(step.cases ?? {});
142156
+ if (caseKeys.length === 0) {
142157
+ ctx.addIssue({
142158
+ code: z.ZodIssueCode.custom,
142159
+ message: `step "${step.id}": switch requires at least one case`,
142160
+ path: ["cases"]
142161
+ });
142162
+ }
142163
+ }
142164
+ if (step.loop != null && (step.then != null || step.else != null || step.cases != null || step.default != null)) {
142165
+ ctx.addIssue({
142166
+ code: z.ZodIssueCode.custom,
142167
+ message: `step "${step.id}": loop cannot be combined with then/else/cases/default`,
142168
+ path: ["loop"]
142169
+ });
142170
+ }
142171
+ if (step.then != null && step.condition == null) {
142172
+ ctx.addIssue({
142173
+ code: z.ZodIssueCode.custom,
142174
+ message: `step "${step.id}": then is only valid with condition`,
142175
+ path: ["then"]
142176
+ });
142177
+ }
142178
+ if (step.else != null && step.condition == null) {
142179
+ ctx.addIssue({
142180
+ code: z.ZodIssueCode.custom,
142181
+ message: `step "${step.id}": else is only valid with condition`,
142182
+ path: ["else"]
142183
+ });
142184
+ }
142185
+ if (step.cases != null && step.switch == null) {
142186
+ ctx.addIssue({
142187
+ code: z.ZodIssueCode.custom,
142188
+ message: `step "${step.id}": cases is only valid with switch`,
142189
+ path: ["cases"]
142190
+ });
142191
+ }
142192
+ if (step.default != null && step.switch == null) {
142193
+ ctx.addIssue({
142194
+ code: z.ZodIssueCode.custom,
142195
+ message: `step "${step.id}": default branch list is only valid with switch`,
142196
+ path: ["default"]
142197
+ });
142198
+ }
141946
142199
  const present2 = ACTION_KEYS.filter((k3) => step[k3] != null);
141947
142200
  if (present2.length === 0) {
141948
142201
  ctx.addIssue({
@@ -141972,6 +142225,17 @@ var inputSpecSchema = z.object({
141972
142225
  default: z.unknown().optional(),
141973
142226
  description: z.string().optional()
141974
142227
  });
142228
+ var uiLayoutSchema = z.object({
142229
+ nodes: z.record(z.object({
142230
+ x: z.number(),
142231
+ y: z.number()
142232
+ })).default({}),
142233
+ viewport: z.object({
142234
+ x: z.number(),
142235
+ y: z.number(),
142236
+ zoom: z.number().positive()
142237
+ }).optional()
142238
+ });
141975
142239
  var workflowSchema = z.object({
141976
142240
  name: z.string().min(1).max(120).regex(SLUG_RE, "name must be slug-like"),
141977
142241
  description: z.string().min(1),
@@ -141983,6 +142247,9 @@ var workflowSchema = z.object({
141983
142247
  channel: z.string().optional(),
141984
142248
  inbox: z.boolean().default(true)
141985
142249
  }).optional(),
142250
+ ui: z.object({
142251
+ layout: uiLayoutSchema.optional()
142252
+ }).optional(),
141986
142253
  concurrency: z.number().int().min(1).max(8).default(4),
141987
142254
  steps: z.array(stepSchema).min(1).max(40)
141988
142255
  }).superRefine((wf, ctx) => {
@@ -142028,6 +142295,112 @@ var workflowSchema = z.object({
142028
142295
  });
142029
142296
  }
142030
142297
  }
142298
+ for (const step of wf.steps) {
142299
+ const branchIds = [];
142300
+ if (step.then)
142301
+ branchIds.push(...step.then);
142302
+ if (step.else)
142303
+ branchIds.push(...step.else);
142304
+ if (step.cases)
142305
+ for (const list of Object.values(step.cases))
142306
+ branchIds.push(...list);
142307
+ if (step.default)
142308
+ branchIds.push(...step.default);
142309
+ for (const ref of branchIds) {
142310
+ if (!ids.has(ref)) {
142311
+ ctx.addIssue({
142312
+ code: z.ZodIssueCode.custom,
142313
+ message: `step "${step.id}" references unknown branch step "${ref}"`,
142314
+ path: ["steps"]
142315
+ });
142316
+ }
142317
+ if (ref === step.id) {
142318
+ ctx.addIssue({
142319
+ code: z.ZodIssueCode.custom,
142320
+ message: `step "${step.id}" cannot reference itself in then/else/cases/default`,
142321
+ path: ["steps"]
142322
+ });
142323
+ }
142324
+ }
142325
+ }
142326
+ for (const step of wf.steps) {
142327
+ if (step.loop == null)
142328
+ continue;
142329
+ for (const ref of step.loop.body) {
142330
+ if (!ids.has(ref)) {
142331
+ ctx.addIssue({
142332
+ code: z.ZodIssueCode.custom,
142333
+ message: `step "${step.id}" loop references unknown body step "${ref}"`,
142334
+ path: ["steps"]
142335
+ });
142336
+ }
142337
+ }
142338
+ }
142339
+ const stepById = new Map(wf.steps.map((s2) => [s2.id, s2]));
142340
+ const bodyOwner = /* @__PURE__ */ new Map();
142341
+ for (const step of wf.steps) {
142342
+ if (step.loop == null)
142343
+ continue;
142344
+ for (const ref of step.loop.body)
142345
+ bodyOwner.set(ref, step.id);
142346
+ }
142347
+ for (const step of wf.steps) {
142348
+ const owner = bodyOwner.get(step.id);
142349
+ if (owner == null)
142350
+ continue;
142351
+ const body = stepById.get(step.id);
142352
+ if (body.condition != null || body.switch != null) {
142353
+ ctx.addIssue({
142354
+ code: z.ZodIssueCode.custom,
142355
+ message: `step "${step.id}" is a loop body of "${owner}" and cannot be a condition/switch step \u2014 branch routing is not honored inside a loop body. Use a bridge step to set vars and drive the loop's own exit condition instead.`,
142356
+ path: ["steps"]
142357
+ });
142358
+ }
142359
+ if (body.when != null) {
142360
+ ctx.addIssue({
142361
+ code: z.ZodIssueCode.custom,
142362
+ message: `step "${step.id}" is a loop body of "${owner}" and cannot have a \`when\` guard \u2014 loop body steps run unconditionally each iteration. Gate the loop via its \`condition\` (exit) instead.`,
142363
+ path: ["steps"]
142364
+ });
142365
+ }
142366
+ for (const dep of body.needs) {
142367
+ if (dep === owner)
142368
+ continue;
142369
+ if (bodyOwner.get(dep) === owner)
142370
+ continue;
142371
+ ctx.addIssue({
142372
+ code: z.ZodIssueCode.custom,
142373
+ message: `step "${step.id}" is a loop body of "${owner}" and may only \`needs\` its loop step ("${owner}") or a sibling body step of the same loop \u2014 "${dep}" is outside the loop and would never settle for it.`,
142374
+ path: ["steps"]
142375
+ });
142376
+ }
142377
+ }
142378
+ for (const step of wf.steps) {
142379
+ if (bodyOwner.has(step.id))
142380
+ continue;
142381
+ if (step.loop != null) {
142382
+ const ownBody = new Set(step.loop.body);
142383
+ for (const dep of step.needs) {
142384
+ if (bodyOwner.has(dep) && !ownBody.has(dep)) {
142385
+ ctx.addIssue({
142386
+ code: z.ZodIssueCode.custom,
142387
+ message: `step "${step.id}" needs "${dep}", which is a loop body of "${bodyOwner.get(dep)}" \u2014 depend on the loop step "${bodyOwner.get(dep)}" instead.`,
142388
+ path: ["steps"]
142389
+ });
142390
+ }
142391
+ }
142392
+ continue;
142393
+ }
142394
+ for (const dep of step.needs) {
142395
+ if (bodyOwner.has(dep)) {
142396
+ ctx.addIssue({
142397
+ code: z.ZodIssueCode.custom,
142398
+ message: `step "${step.id}" needs "${dep}", which is a loop body of "${bodyOwner.get(dep)}" \u2014 depend on the loop step "${bodyOwner.get(dep)}" instead (loop body steps are owned by their loop and never scheduled in the main DAG).`,
142399
+ path: ["steps"]
142400
+ });
142401
+ }
142402
+ }
142403
+ }
142031
142404
  });
142032
142405
  function findCycle(steps) {
142033
142406
  const byId = new Map(steps.map((s2) => [s2.id, s2]));
@@ -142064,8 +142437,8 @@ function findCycle(steps) {
142064
142437
  }
142065
142438
  function formatIssues(error2) {
142066
142439
  return error2.issues.map((iss) => {
142067
- const path60 = iss.path.join(".") || "(root)";
142068
- return `${path60}: ${iss.message}`;
142440
+ const path61 = iss.path.join(".") || "(root)";
142441
+ return `${path61}: ${iss.message}`;
142069
142442
  });
142070
142443
  }
142071
142444
  function validateWorkflow(raw) {
@@ -142195,9 +142568,18 @@ var WorkflowStore = class {
142195
142568
  /**
142196
142569
  * Replace a workflow with a new definition. In-place rewrite for user/project
142197
142570
  * workflows; a user-scope override for builtin/plugin ones.
142571
+ *
142572
+ * `previousName` supports rename from the builder: when the workflow's name
142573
+ * changed, the old user/project file and its registry entry are removed so a
142574
+ * rename doesn't leave an orphaned duplicate file + stale entry behind.
142198
142575
  */
142199
- async save(workflow) {
142576
+ async save(workflow, previousName) {
142200
142577
  await this.ensureLoaded();
142578
+ const renamed = previousName != null && previousName !== workflow.name ? this.byName.get(previousName) : void 0;
142579
+ if (renamed && (renamed.scope === "user" || renamed.scope === "project")) {
142580
+ await promises.rm(renamed.path, { force: true });
142581
+ this.byName.delete(previousName);
142582
+ }
142201
142583
  const existing = this.byName.get(workflow.name);
142202
142584
  const editable = existing && (existing.scope === "user" || existing.scope === "project");
142203
142585
  if (existing && editable) {
@@ -142206,11 +142588,12 @@ var WorkflowStore = class {
142206
142588
  this.byName.set(workflow.name, entry2);
142207
142589
  return entry2;
142208
142590
  }
142209
- const dir = this.userDir();
142591
+ const scope = renamed?.scope === "project" ? "project" : "user";
142592
+ const dir = scope === "project" ? this.projectDir() : this.userDir();
142210
142593
  await promises.mkdir(dir, { recursive: true });
142211
142594
  const file = await uniqueFilename2(dir, workflow.name);
142212
142595
  await writeFileAtomic(file, serializeWorkflow(workflow));
142213
- const entry = { workflow, path: file, scope: "user" };
142596
+ const entry = { workflow, path: file, scope };
142214
142597
  this.byName.set(workflow.name, entry);
142215
142598
  return entry;
142216
142599
  }
@@ -142257,8 +142640,175 @@ async function exists3(p3) {
142257
142640
  return false;
142258
142641
  }
142259
142642
  }
142643
+
142644
+ // ../plugin-workflows/dist/run-store.js
142645
+ init_index_esm();
142646
+ var WorkflowRunStore = class {
142647
+ dir;
142648
+ constructor(dir = moxxyPath("workflow-runs", "active")) {
142649
+ this.dir = dir;
142650
+ }
142651
+ async save(checkpoint) {
142652
+ const runId = ulid();
142653
+ await promises.mkdir(this.dir, { recursive: true });
142654
+ const file = path3.join(this.dir, `${runId}.json`);
142655
+ const payload = { ...checkpoint, runId };
142656
+ const tmp = `${file}.tmp`;
142657
+ await promises.writeFile(tmp, JSON.stringify(payload), "utf8");
142658
+ await promises.rename(tmp, file);
142659
+ return runId;
142660
+ }
142661
+ async load(runId) {
142662
+ const file = path3.join(this.dir, `${runId}.json`);
142663
+ try {
142664
+ const raw = await promises.readFile(file, "utf8");
142665
+ return JSON.parse(raw);
142666
+ } catch {
142667
+ return null;
142668
+ }
142669
+ }
142670
+ async remove(runId) {
142671
+ const file = path3.join(this.dir, `${runId}.json`);
142672
+ try {
142673
+ await promises.unlink(file);
142674
+ } catch {
142675
+ }
142676
+ }
142677
+ /**
142678
+ * Delete checkpoint files older than `maxAgeMs` (by mtime). Paused runs that
142679
+ * are never resumed (the common case while `awaitInput` is gated — see
142680
+ * schema.ts — and in general after a crash) would otherwise accumulate
142681
+ * `<ulid>.json` files under `active/` forever. Returns the count removed.
142682
+ * Best-effort: a missing dir or an unreadable entry is skipped, not thrown.
142683
+ */
142684
+ async sweepStale(maxAgeMs = DEFAULT_CHECKPOINT_TTL_MS, now = Date.now()) {
142685
+ let removed = 0;
142686
+ let entries;
142687
+ try {
142688
+ entries = await promises.readdir(this.dir);
142689
+ } catch {
142690
+ return 0;
142691
+ }
142692
+ for (const name of entries) {
142693
+ if (!name.endsWith(".json"))
142694
+ continue;
142695
+ const file = path3.join(this.dir, name);
142696
+ try {
142697
+ const st3 = await promises.stat(file);
142698
+ if (now - st3.mtimeMs > maxAgeMs) {
142699
+ await promises.unlink(file);
142700
+ removed += 1;
142701
+ }
142702
+ } catch {
142703
+ }
142704
+ }
142705
+ return removed;
142706
+ }
142707
+ };
142708
+ var DEFAULT_CHECKPOINT_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
142709
+ var defaultWorkflowRunStore = new WorkflowRunStore();
142710
+
142711
+ // ../plugin-workflows/dist/logic-response.js
142712
+ var PLAIN_PROMPT_MARKERS = [
142713
+ "odpowiedz wy\u0142\u0105cznie zwyk\u0142ym tekstem",
142714
+ "odpowiedz tylko zwyk\u0142ym tekstem",
142715
+ "without json",
142716
+ "no json",
142717
+ "plain text only"
142718
+ ];
142719
+ var LOGIC_SYSTEM_PROMPT = 'You are a workflow logic step. Do not use tools. Reply with exactly one JSON object. Use keys as needed: "vars" (object, data for downstream templates), "branch" (string, routing decision), "text" (optional human-readable summary). No markdown fences or commentary outside the JSON.';
142720
+ function logicSystemPrompt() {
142721
+ return LOGIC_SYSTEM_PROMPT;
142722
+ }
142723
+ function wantsPlainResponse(step) {
142724
+ if (step.format === "plain")
142725
+ return true;
142726
+ if (step.format === "json")
142727
+ return false;
142728
+ const text = (step.bridge ?? step.condition ?? step.switch ?? "").toLowerCase();
142729
+ return PLAIN_PROMPT_MARKERS.some((m3) => text.includes(m3));
142730
+ }
142731
+ function stripJsonFence(raw) {
142732
+ const trimmed = raw.trim();
142733
+ const fence = /^```(?:json)?\s*([\s\S]*?)```$/i.exec(trimmed);
142734
+ return fence ? fence[1].trim() : trimmed;
142735
+ }
142736
+ function parseJsonObject(raw) {
142737
+ const parsed = JSON.parse(stripJsonFence(raw));
142738
+ if (parsed == null || typeof parsed !== "object" || Array.isArray(parsed)) {
142739
+ throw new Error("logic step response must be a JSON object");
142740
+ }
142741
+ return parsed;
142742
+ }
142743
+ function parseLogicResponse(raw, _step, format) {
142744
+ if (format === "plain") {
142745
+ return { output: raw.trim() };
142746
+ }
142747
+ const obj = parseJsonObject(raw);
142748
+ const vars = obj.vars != null && typeof obj.vars === "object" && !Array.isArray(obj.vars) ? obj.vars : void 0;
142749
+ const branch = typeof obj.branch === "string" ? obj.branch.trim() : void 0;
142750
+ const text = typeof obj.text === "string" ? obj.text : void 0;
142751
+ const output = text ?? JSON.stringify(obj);
142752
+ return { output, ...vars ? { vars } : {}, ...branch ? { branch } : {} };
142753
+ }
142754
+ function resolveBranchForCondition(_step, branch) {
142755
+ if (!branch)
142756
+ return void 0;
142757
+ const b3 = branch.toLowerCase();
142758
+ if (b3 === "then")
142759
+ return "then";
142760
+ if (b3 === "else")
142761
+ return "else";
142762
+ return void 0;
142763
+ }
142764
+ function resolveBranchForSwitch(step, branch) {
142765
+ if (!branch)
142766
+ return void 0;
142767
+ const cases = step.cases ?? {};
142768
+ if (branch in cases)
142769
+ return branch;
142770
+ if (step.default && step.default.length > 0)
142771
+ return "__default__";
142772
+ return void 0;
142773
+ }
142774
+ function stepsToSkipForBranch(step, selected) {
142775
+ if (step.condition != null) {
142776
+ const then = step.then ?? [];
142777
+ const els = step.else ?? [];
142778
+ const active = selected === "then" ? then : els;
142779
+ const all = [...then, ...els];
142780
+ return all.filter((id) => !active.includes(id));
142781
+ }
142782
+ if (step.switch != null) {
142783
+ const cases = step.cases ?? {};
142784
+ const all = /* @__PURE__ */ new Set();
142785
+ for (const ids of Object.values(cases))
142786
+ for (const id of ids)
142787
+ all.add(id);
142788
+ for (const id of step.default ?? [])
142789
+ all.add(id);
142790
+ if (selected === "__default__") {
142791
+ const keep2 = new Set(step.default ?? []);
142792
+ return [...all].filter((id) => !keep2.has(id));
142793
+ }
142794
+ const keep = new Set(cases[selected] ?? []);
142795
+ return [...all].filter((id) => !keep.has(id));
142796
+ }
142797
+ return [];
142798
+ }
142799
+
142800
+ // ../plugin-workflows/dist/executor/dag.js
142260
142801
  var DAG_EXECUTOR_NAME = "dag";
142261
142802
  var MAX_NESTING_DEPTH = 5;
142803
+ function collectLoopBodyIds(workflow) {
142804
+ const ids = /* @__PURE__ */ new Set();
142805
+ for (const step of workflow.steps) {
142806
+ if (step.loop)
142807
+ for (const id of step.loop.body)
142808
+ ids.add(id);
142809
+ }
142810
+ return ids;
142811
+ }
142262
142812
  function nowFn(deps) {
142263
142813
  return deps.now ?? (() => Date.now());
142264
142814
  }
@@ -142274,27 +142824,87 @@ function resolveInputs(workflow, deps) {
142274
142824
  }
142275
142825
  return out;
142276
142826
  }
142277
- function buildScope(states, inputs, deps, nowIso) {
142827
+ function buildScope(ctx, nowIso) {
142278
142828
  const steps = {};
142279
- for (const [id, st3] of states)
142829
+ for (const [id, st3] of ctx.states)
142280
142830
  steps[id] = { output: st3.output };
142281
142831
  return {
142282
142832
  steps,
142283
- inputs,
142284
- ...deps.trigger != null ? { trigger: deps.trigger } : {},
142833
+ inputs: ctx.inputs,
142834
+ vars: ctx.vars,
142835
+ ...ctx.deps.trigger != null ? { trigger: ctx.deps.trigger } : {},
142285
142836
  now: nowIso
142286
142837
  };
142287
142838
  }
142288
- async function runExecutor(workflow, deps) {
142289
- const now = nowFn(deps);
142290
- const inputs = resolveInputs(workflow, deps);
142291
- const states = /* @__PURE__ */ new Map();
142292
- for (const step of workflow.steps) {
142293
- states.set(step.id, { status: "pending", output: "", startedAt: 0, endedAt: 0 });
142839
+ var UNSAFE_VAR_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
142840
+ function mergeVars(ctx, vars) {
142841
+ if (!vars)
142842
+ return;
142843
+ for (const [key, value] of Object.entries(vars)) {
142844
+ if (UNSAFE_VAR_KEYS.has(key)) {
142845
+ ctx.deps.logger?.warn?.("workflow vars: dropping prototype-pollution key", { key });
142846
+ continue;
142847
+ }
142848
+ Object.defineProperty(ctx.vars, key, {
142849
+ value,
142850
+ writable: true,
142851
+ enumerable: true,
142852
+ configurable: true
142853
+ });
142854
+ }
142855
+ }
142856
+ async function applyBranchSkips(ctx, gate, selected) {
142857
+ for (const id of stepsToSkipForBranch(gate, selected)) {
142858
+ const st3 = ctx.states.get(id);
142859
+ if (!st3 || st3.status !== "pending")
142860
+ continue;
142861
+ st3.status = "skipped";
142862
+ st3.startedAt = st3.endedAt = ctx.now();
142863
+ await ctx.deps.emit?.("workflow_step_skipped", { id, reason: `branch:${gate.id}` });
142864
+ }
142865
+ }
142866
+ function serializeStates(states) {
142867
+ const out = {};
142868
+ for (const [id, st3] of states) {
142869
+ out[id] = {
142870
+ status: st3.status === "pending" ? "pending" : st3.status,
142871
+ output: st3.output,
142872
+ ...st3.error ? { error: st3.error } : {},
142873
+ startedAt: st3.startedAt,
142874
+ endedAt: st3.endedAt
142875
+ };
142294
142876
  }
142877
+ return out;
142878
+ }
142879
+ function buildStepResults(workflow, states) {
142880
+ return workflow.steps.map((step) => {
142881
+ const st3 = states.get(step.id);
142882
+ const status = st3.status === "pending" ? "skipped" : st3.status;
142883
+ return {
142884
+ id: step.id,
142885
+ status,
142886
+ output: st3.output,
142887
+ ...st3.error ? { error: st3.error } : {},
142888
+ startedAt: st3.startedAt,
142889
+ endedAt: st3.endedAt
142890
+ };
142891
+ });
142892
+ }
142893
+ function buildRunResult(ctx, status, ok, extra) {
142894
+ const output = status === "completed" ? sinkOutput(ctx.workflow, ctx.states) : "";
142895
+ return {
142896
+ ok,
142897
+ status,
142898
+ steps: buildStepResults(ctx.workflow, ctx.states),
142899
+ output,
142900
+ ...extra
142901
+ };
142902
+ }
142903
+ async function runExecutorLoop(ctx) {
142904
+ const { workflow, deps } = ctx;
142295
142905
  await deps.emit?.("workflow_started", { name: workflow.name, steps: workflow.steps.length });
142296
142906
  const settled = (id) => {
142297
- const s2 = states.get(id)?.status;
142907
+ const s2 = ctx.states.get(id)?.status;
142298
142908
  return s2 === "completed" || s2 === "skipped" || s2 === "failed";
142299
142909
  };
142300
142910
  let aborted = false;
@@ -142308,21 +142918,23 @@ async function runExecutor(workflow, deps) {
142308
142918
  while (skippedSomething) {
142309
142919
  skippedSomething = false;
142310
142920
  for (const step of workflow.steps) {
142311
- const st3 = states.get(step.id);
142921
+ if (ctx.loopBodyIds.has(step.id))
142922
+ continue;
142923
+ const st3 = ctx.states.get(step.id);
142312
142924
  if (st3.status !== "pending")
142313
142925
  continue;
142314
142926
  if (!step.needs.every(settled))
142315
142927
  continue;
142316
142928
  if (step.when == null)
142317
142929
  continue;
142318
- const scope2 = buildScope(states, inputs, deps, new Date(now()).toISOString());
142930
+ const scope2 = buildScope(ctx, new Date(ctx.now()).toISOString());
142319
142931
  let keep;
142320
142932
  try {
142321
142933
  keep = evalCondition(step.when, scope2);
142322
142934
  } catch (err) {
142323
142935
  st3.status = "failed";
142324
142936
  st3.error = `when: ${err instanceof Error ? err.message : String(err)}`;
142325
- st3.startedAt = st3.endedAt = now();
142937
+ st3.startedAt = st3.endedAt = ctx.now();
142326
142938
  await deps.emit?.("workflow_step_failed", { id: step.id, error: st3.error });
142327
142939
  if (step.onError !== "continue") {
142328
142940
  aborted = true;
@@ -142333,7 +142945,7 @@ async function runExecutor(workflow, deps) {
142333
142945
  }
142334
142946
  if (!keep) {
142335
142947
  st3.status = "skipped";
142336
- st3.startedAt = st3.endedAt = now();
142948
+ st3.startedAt = st3.endedAt = ctx.now();
142337
142949
  await deps.emit?.("workflow_step_skipped", { id: step.id });
142338
142950
  skippedSomething = true;
142339
142951
  }
@@ -142344,11 +142956,13 @@ async function runExecutor(workflow, deps) {
142344
142956
  if (aborted)
142345
142957
  break;
142346
142958
  const ready = workflow.steps.filter((step) => {
142347
- const st3 = states.get(step.id);
142959
+ if (ctx.loopBodyIds.has(step.id))
142960
+ return false;
142961
+ const st3 = ctx.states.get(step.id);
142348
142962
  return st3.status === "pending" && step.needs.every(settled);
142349
142963
  });
142350
142964
  if (ready.length === 0) {
142351
- const anyPending = [...states.values()].some((s2) => s2.status === "pending");
142965
+ const anyPending = [...ctx.states.values()].some((s2) => s2.status === "pending");
142352
142966
  if (anyPending) {
142353
142967
  abortReason = "workflow stalled \u2014 no runnable steps (check needs/when)";
142354
142968
  aborted = true;
@@ -142356,19 +142970,56 @@ async function runExecutor(workflow, deps) {
142356
142970
  break;
142357
142971
  }
142358
142972
  const wave = ready.slice(0, Math.max(1, workflow.concurrency));
142359
- const scope = buildScope(states, inputs, deps, new Date(now()).toISOString());
142360
- await Promise.all(wave.map(async (step) => {
142361
- const st3 = states.get(step.id);
142362
- st3.startedAt = now();
142973
+ const scope = buildScope(ctx, new Date(ctx.now()).toISOString());
142974
+ for (const step of wave) {
142975
+ const st3 = ctx.states.get(step.id);
142976
+ st3.startedAt = ctx.now();
142363
142977
  await deps.emit?.("workflow_step_started", {
142364
142978
  id: step.id,
142365
142979
  label: step.label ?? step.id
142366
142980
  });
142367
- const outcome = await runStep(step, scope, deps);
142368
- st3.endedAt = now();
142981
+ const outcome = await runStep(step, scope, ctx);
142982
+ st3.endedAt = ctx.now();
142983
+ if (outcome.paused) {
142984
+ st3.status = "awaiting_input";
142985
+ st3.output = outcome.output;
142986
+ await deps.emit?.("workflow_step_awaiting_input", {
142987
+ id: step.id,
142988
+ label: step.label ?? step.id,
142989
+ preview: outcome.output.slice(0, 280),
142990
+ childSessionId: outcome.interactionAgentId
142991
+ });
142992
+ const store = deps.runStore ?? defaultWorkflowRunStore;
142993
+ const runId = await store.save({
142994
+ workflow,
142995
+ trigger: deps.trigger ?? "manual",
142996
+ inputs: ctx.inputs,
142997
+ states: serializeStates(ctx.states),
142998
+ // Persist vars set by logic steps that ran before this pause so a
142999
+ // resume restores them (otherwise downstream `{{ vars.x }}` is lost).
143000
+ vars: ctx.vars,
143001
+ pendingStepId: step.id,
143002
+ interactionAgentId: outcome.interactionAgentId,
143003
+ startedAt: ctx.now()
143004
+ });
143005
+ await deps.emit?.("workflow_paused", {
143006
+ runId,
143007
+ stepId: step.id,
143008
+ childSessionId: outcome.interactionAgentId
143009
+ });
143010
+ return buildRunResult(ctx, "paused", true, {
143011
+ runId,
143012
+ pendingStepId: step.id,
143013
+ ...outcome.interactionAgentId ? { interactionAgentId: outcome.interactionAgentId } : {}
143014
+ });
143015
+ }
142369
143016
  if (outcome.ok) {
142370
143017
  st3.status = "completed";
142371
143018
  st3.output = outcome.output;
143019
+ mergeVars(ctx, outcome.vars);
143020
+ if (outcome.branchRoute != null) {
143021
+ await applyBranchSkips(ctx, step, outcome.branchRoute);
143022
+ }
142372
143023
  await deps.emit?.("workflow_step_completed", {
142373
143024
  id: step.id,
142374
143025
  preview: outcome.output.slice(0, 280)
@@ -142382,32 +143033,34 @@ async function runExecutor(workflow, deps) {
142382
143033
  abortReason = `step "${step.id}" failed: ${outcome.error}`;
142383
143034
  }
142384
143035
  }
142385
- }));
143036
+ }
142386
143037
  }
142387
- const stepResults = workflow.steps.map((step) => {
142388
- const st3 = states.get(step.id);
142389
- return {
142390
- id: step.id,
142391
- status: st3.status === "pending" ? "skipped" : st3.status,
142392
- output: st3.output,
142393
- ...st3.error ? { error: st3.error } : {},
142394
- startedAt: st3.startedAt,
142395
- endedAt: st3.endedAt
142396
- };
142397
- });
142398
143038
  const ok = !aborted;
142399
- const output = sinkOutput(workflow, states);
143039
+ const output = sinkOutput(workflow, ctx.states);
142400
143040
  if (ok) {
142401
143041
  await deps.emit?.("workflow_completed", { name: workflow.name, output: output.slice(0, 280) });
142402
- } else {
142403
- await deps.emit?.("workflow_failed", { name: workflow.name, error: abortReason });
143042
+ return buildRunResult(ctx, "completed", true, { output });
142404
143043
  }
142405
- return {
142406
- ok,
142407
- steps: stepResults,
143044
+ await deps.emit?.("workflow_failed", { name: workflow.name, error: abortReason });
143045
+ return buildRunResult(ctx, "failed", false, {
142408
143046
  output,
142409
- ...ok ? {} : { error: abortReason ?? "workflow failed" }
143047
+ error: abortReason ?? "workflow failed"
143048
+ });
143049
+ }
143050
+ async function runExecutor(workflow, deps) {
143051
+ const ctx = {
143052
+ workflow,
143053
+ deps,
143054
+ inputs: resolveInputs(workflow, deps),
143055
+ vars: {},
143056
+ states: /* @__PURE__ */ new Map(),
143057
+ now: nowFn(deps),
143058
+ loopBodyIds: collectLoopBodyIds(workflow)
142410
143059
  };
143060
+ for (const step of workflow.steps) {
143061
+ ctx.states.set(step.id, { status: "pending", output: "", startedAt: 0, endedAt: 0 });
143062
+ }
143063
+ return runExecutorLoop(ctx);
142411
143064
  }
142412
143065
  function sinkOutput(workflow, states) {
142413
143066
  const needed = /* @__PURE__ */ new Set();
@@ -142421,18 +143074,17 @@ function sinkOutput(workflow, states) {
142421
143074
  const lastCompleted = [...states.values()].filter((s2) => s2.status === "completed").pop();
142422
143075
  return lastCompleted?.output ?? "";
142423
143076
  }
142424
- async function runStep(step, scope, deps) {
143077
+ async function runStep(step, scope, ctx) {
142425
143078
  const attempts = 1 + Math.max(0, step.retries);
142426
143079
  let lastError = "";
142427
143080
  for (let attempt = 0; attempt < attempts; attempt++) {
142428
- if (deps.signal.aborted)
143081
+ if (ctx.deps.signal.aborted)
142429
143082
  return { ok: false, output: "", error: "aborted" };
142430
143083
  try {
142431
- const output = await runStepOnce(step, scope, deps);
142432
- return { ok: true, output };
143084
+ return await runStepOnce(step, scope, ctx);
142433
143085
  } catch (err) {
142434
143086
  lastError = err instanceof Error ? err.message : String(err);
142435
- deps.logger?.warn?.("workflow step attempt failed", {
143087
+ ctx.deps.logger?.warn?.("workflow step attempt failed", {
142436
143088
  step: step.id,
142437
143089
  attempt: attempt + 1,
142438
143090
  error: lastError
@@ -142441,39 +143093,237 @@ async function runStep(step, scope, deps) {
142441
143093
  }
142442
143094
  return { ok: false, output: "", error: lastError };
142443
143095
  }
142444
- async function runStepOnce(step, scope, deps) {
143096
+ async function runStepOnce(step, scope, ctx) {
143097
+ const { deps } = ctx;
142445
143098
  const opts = deps.logger ? { logger: deps.logger } : {};
143099
+ if (step.loop != null) {
143100
+ return runLoopStep(step, ctx, opts);
143101
+ }
143102
+ if (step.bridge != null || step.condition != null || step.switch != null) {
143103
+ return runLogicStep(step, scope, ctx, opts);
143104
+ }
142446
143105
  if (step.tool) {
142447
143106
  const args = renderArgs(step.args ?? {}, scope, opts);
142448
143107
  const result = await deps.tools.execute(step.tool, args, deps.signal);
142449
- return typeof result === "string" ? result : JSON.stringify(result ?? "");
143108
+ const output = typeof result === "string" ? result : JSON.stringify(result ?? "");
143109
+ return { ok: true, output };
142450
143110
  }
142451
143111
  if (step.workflow) {
142452
- const nested = deps.lookup.workflow(step.workflow);
142453
- if (!nested)
142454
- throw new Error(`nested workflow "${step.workflow}" not found`);
142455
- const depth = (deps.depth ?? 0) + 1;
142456
- if (depth > MAX_NESTING_DEPTH) {
142457
- throw new Error(`nested workflow depth exceeded ${MAX_NESTING_DEPTH}`);
142458
- }
142459
- const nestedInputs = renderArgs(step.args ?? {}, scope, opts);
142460
- const result = await runExecutor(nested, {
142461
- ...deps,
142462
- inputs: nestedInputs,
142463
- depth,
142464
- trigger: `workflow:${step.workflow}`
142465
- });
142466
- if (!result.ok)
142467
- throw new Error(result.error ?? `nested workflow "${step.workflow}" failed`);
142468
- return result.output;
142469
- }
142470
- const spec = buildSubagentSpec(step, scope, deps, opts);
143112
+ return runNestedWorkflow(step, scope, ctx, opts);
143113
+ }
143114
+ const spec = buildSubagentSpecWithDeps(step, scope, deps, opts);
143115
+ if (step.awaitInput) {
143116
+ const child2 = await deps.spawner.spawn({ ...spec, retainSession: true });
143117
+ if (child2.error)
143118
+ throw new Error(child2.error.message);
143119
+ return {
143120
+ ok: false,
143121
+ output: child2.text,
143122
+ paused: true,
143123
+ interactionAgentId: String(child2.childSessionId)
143124
+ };
143125
+ }
142471
143126
  const child = await deps.spawner.spawn(spec);
142472
143127
  if (child.error)
142473
143128
  throw new Error(child.error.message);
142474
- return child.text;
143129
+ return { ok: true, output: child.text };
143130
+ }
143131
+ async function runNestedWorkflow(step, scope, ctx, opts) {
143132
+ const { deps } = ctx;
143133
+ const nested = deps.lookup.workflow(step.workflow);
143134
+ if (!nested)
143135
+ throw new Error(`nested workflow "${step.workflow}" not found`);
143136
+ const depth = (deps.depth ?? 0) + 1;
143137
+ if (depth > MAX_NESTING_DEPTH) {
143138
+ throw new Error(`nested workflow depth exceeded ${MAX_NESTING_DEPTH}`);
143139
+ }
143140
+ const nestedInputs = renderArgs(step.args ?? {}, scope, opts);
143141
+ const result = await runExecutor(nested, {
143142
+ ...deps,
143143
+ inputs: nestedInputs,
143144
+ depth,
143145
+ trigger: `workflow:${step.workflow}`
143146
+ });
143147
+ if (result.status === "paused") {
143148
+ return {
143149
+ ok: false,
143150
+ output: result.output,
143151
+ paused: true,
143152
+ ...result.interactionAgentId ? { interactionAgentId: result.interactionAgentId } : {}
143153
+ };
143154
+ }
143155
+ if (!result.ok)
143156
+ throw new Error(result.error ?? `nested workflow "${step.workflow}" failed`);
143157
+ return { ok: true, output: result.output };
142475
143158
  }
142476
- function buildSubagentSpec(step, scope, deps, opts) {
143159
+ function buildUpstreamBlock(step, scope) {
143160
+ if (step.needs.length === 0)
143161
+ return "";
143162
+ const parts = step.needs.map((id) => `### ${id}
143163
+ ${scope.steps?.[id]?.output ?? ""}`);
143164
+ return `
143165
+
143166
+ ## Upstream
143167
+ ${parts.join("\n\n")}`;
143168
+ }
143169
+ async function runLogicStep(step, scope, ctx, opts) {
143170
+ const instruction = step.bridge ?? step.condition ?? step.switch ?? "";
143171
+ const format = wantsPlainResponse(step) ? "plain" : "json";
143172
+ if ((step.condition != null || step.switch != null) && format === "plain") {
143173
+ return { ok: false, output: "", error: "condition/switch steps require JSON responses" };
143174
+ }
143175
+ const userPrompt = renderTemplate(instruction, scope, opts) + buildUpstreamBlock(step, scope);
143176
+ const spec = {
143177
+ prompt: userPrompt,
143178
+ ...format === "json" ? { systemPrompt: logicSystemPrompt() } : {},
143179
+ label: step.label ?? step.id,
143180
+ allowedTools: []
143181
+ };
143182
+ const child = await ctx.deps.spawner.spawn(spec);
143183
+ if (child.error)
143184
+ return { ok: false, output: "", error: child.error.message };
143185
+ try {
143186
+ const parsed = parseLogicResponse(child.text, step, format);
143187
+ let branchRoute;
143188
+ if (step.condition != null) {
143189
+ const route = resolveBranchForCondition(step, parsed.branch);
143190
+ if (!route) {
143191
+ return {
143192
+ ok: false,
143193
+ output: child.text,
143194
+ error: `condition step "${step.id}": expected branch "then" or "else", got ${JSON.stringify(parsed.branch)}`
143195
+ };
143196
+ }
143197
+ branchRoute = route;
143198
+ }
143199
+ if (step.switch != null) {
143200
+ const route = resolveBranchForSwitch(step, parsed.branch);
143201
+ if (!route) {
143202
+ return {
143203
+ ok: false,
143204
+ output: child.text,
143205
+ error: `switch step "${step.id}": unknown branch ${JSON.stringify(parsed.branch)}`
143206
+ };
143207
+ }
143208
+ branchRoute = route;
143209
+ }
143210
+ return {
143211
+ ok: true,
143212
+ output: parsed.output,
143213
+ ...parsed.vars ? { vars: parsed.vars } : {},
143214
+ ...branchRoute != null ? { branchRoute } : {}
143215
+ };
143216
+ } catch (err) {
143217
+ const message = err instanceof Error ? err.message : String(err);
143218
+ return { ok: false, output: child.text, error: message };
143219
+ }
143220
+ }
143221
+ async function runLoopStep(step, ctx, opts) {
143222
+ const loop = step.loop;
143223
+ const max = loop.maxIterations;
143224
+ const bodySteps = loop.body.map((id) => ctx.workflow.steps.find((s2) => s2.id === id)).filter((s2) => s2 != null);
143225
+ let iteration = 0;
143226
+ let lastBodyOutput = "";
143227
+ for (; iteration < max; iteration++) {
143228
+ await ctx.deps.emit?.("workflow_step_started", {
143229
+ id: step.id,
143230
+ label: `${step.label ?? step.id} (iteration ${iteration + 1})`
143231
+ });
143232
+ for (const body of bodySteps) {
143233
+ const bst = ctx.states.get(body.id);
143234
+ bst.status = "pending";
143235
+ bst.output = "";
143236
+ delete bst.error;
143237
+ }
143238
+ for (const body of bodySteps) {
143239
+ if (ctx.deps.signal.aborted)
143240
+ return { ok: false, output: lastBodyOutput, error: "aborted" };
143241
+ const bodyScope = buildScope(ctx, new Date(ctx.now()).toISOString());
143242
+ const bst = ctx.states.get(body.id);
143243
+ bst.startedAt = ctx.now();
143244
+ const outcome = await runStep(body, bodyScope, ctx);
143245
+ bst.endedAt = ctx.now();
143246
+ if (outcome.paused) {
143247
+ return {
143248
+ ok: false,
143249
+ output: lastBodyOutput,
143250
+ error: `loop "${step.id}": body step "${body.id}" cannot pause for input`
143251
+ };
143252
+ }
143253
+ if (outcome.ok) {
143254
+ bst.status = "completed";
143255
+ bst.output = outcome.output;
143256
+ lastBodyOutput = outcome.output;
143257
+ mergeVars(ctx, outcome.vars);
143258
+ } else {
143259
+ bst.status = "failed";
143260
+ bst.error = outcome.error;
143261
+ if (body.onError !== "continue") {
143262
+ ctx.deps.logger?.warn?.("workflow loop broke on body error", {
143263
+ step: step.id,
143264
+ body: body.id,
143265
+ error: outcome.error
143266
+ });
143267
+ return {
143268
+ ok: true,
143269
+ output: `loop "${step.id}" broke on error in body step "${body.id}" after ${iteration + 1} iteration(s): ${outcome.error}` + (lastBodyOutput ? `
143270
+
143271
+ ${lastBodyOutput}` : "")
143272
+ };
143273
+ }
143274
+ }
143275
+ }
143276
+ const decision = await evaluateLoopCondition(step, loop.condition, ctx, opts);
143277
+ if (!decision.ok) {
143278
+ return { ok: false, output: lastBodyOutput, error: decision.error };
143279
+ }
143280
+ if (decision.route === "then") {
143281
+ return {
143282
+ ok: true,
143283
+ output: `loop "${step.id}" stopped after ${iteration + 1} iteration(s).
143284
+
143285
+ ${lastBodyOutput}`.trim()
143286
+ };
143287
+ }
143288
+ }
143289
+ ctx.deps.logger?.warn?.("workflow loop hit max iterations", { step: step.id, maxIterations: max });
143290
+ return {
143291
+ ok: true,
143292
+ output: `loop "${step.id}" reached max iterations (${max}); stopping.` + (lastBodyOutput ? `
143293
+
143294
+ ${lastBodyOutput}` : "")
143295
+ };
143296
+ }
143297
+ async function evaluateLoopCondition(step, condition, ctx, opts) {
143298
+ const scope = buildScope(ctx, new Date(ctx.now()).toISOString());
143299
+ const userPrompt = renderTemplate(condition, scope, opts) + `
143300
+
143301
+ This is the loop's EXIT condition. Evaluate whether it is now met. Reply with {"branch":"then"} if the condition IS met (stop the loop and continue to the next step), or {"branch":"else"} if it is NOT yet met (run another iteration).`;
143302
+ const spec = {
143303
+ prompt: userPrompt,
143304
+ systemPrompt: logicSystemPrompt(),
143305
+ label: `${step.label ?? step.id} (condition)`,
143306
+ allowedTools: []
143307
+ };
143308
+ const child = await ctx.deps.spawner.spawn(spec);
143309
+ if (child.error)
143310
+ return { ok: false, error: child.error.message };
143311
+ try {
143312
+ const parsed = parseLogicResponse(child.text, step, "json");
143313
+ const route = resolveBranchForCondition(step, parsed.branch);
143314
+ if (!route) {
143315
+ return {
143316
+ ok: false,
143317
+ error: `loop "${step.id}" condition: expected branch "then" or "else", got ${JSON.stringify(parsed.branch)}`
143318
+ };
143319
+ }
143320
+ mergeVars(ctx, parsed.vars);
143321
+ return { ok: true, route };
143322
+ } catch (err) {
143323
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
143324
+ }
143325
+ }
143326
+ function buildSubagentSpecWithDeps(step, scope, deps, opts) {
142477
143327
  const label3 = step.label ?? step.id;
142478
143328
  const renderedInput = step.input ? renderTemplate(step.input, scope, opts) : "";
142479
143329
  if (step.skill) {
@@ -142536,33 +143386,167 @@ async function writeRunRecord(workflow, result, startedAt, executorName, deps, d
142536
143386
  }
142537
143387
 
142538
143388
  // ../plugin-workflows/dist/draft.js
143389
+ var DEFAULT_MAX_TOKENS = 4096;
142539
143390
  function buildSystemPrompt(opts) {
142540
- const skills = opts.availableSkills?.length ? opts.availableSkills.join(", ") : "(none registered \u2014 prefer `prompt` steps)";
142541
- const tools = opts.availableTools?.length ? opts.availableTools.join(", ") : "(none)";
142542
- return `You are a workflow author for the "moxxy" agent. Output ONLY a YAML document (optionally inside a \`\`\`yaml fence) \u2014 no prose.
143391
+ const skills = formatCatalog(opts.availableSkills, "(none registered \u2014 use `prompt` steps with clear instructions)");
143392
+ const tools = formatCatalog(opts.availableTools, "(none \u2014 use `delivery: { channel: inbox }` for notifications)");
143393
+ return `You are a workflow author for the "moxxy" agent. Output ONLY a YAML document (optionally inside a \`\`\`yaml fence) \u2014 no prose before or after.
142543
143394
 
142544
143395
  A workflow is a DAG of steps. Schema:
142545
143396
  - name: kebab-case slug (lowercase letters/numbers/hyphens, starts with a letter)
142546
- - description: one sentence
143397
+ - description: one clear sentence matching the user's goal (never "A simple Moxxy workflow.")
143398
+ - enabled: true
142547
143399
  - on (optional triggers): { schedule: { cron: "m h dom mon dow", timeZone? }, afterWorkflow?, fileChanged?, webhook? }
142548
- - inputs (optional): { <name>: { default: <value>, description? } }
143400
+ - inputs (optional): { <name>: { default: <value>, description: "..." } } \u2014 use for values the operator supplies at run time (e.g. recipient email, image brief)
142549
143401
  - delivery (optional): { channel?: "inbox", inbox?: true }
142550
143402
  - steps: array of steps, each with:
142551
143403
  - id: slug, unique
142552
- - EXACTLY ONE action: skill: <name> | prompt: <text> | tool: <name> | workflow: <name>
142553
- - input: templated prompt for skill/prompt steps
143404
+ - label: short human title (match the user's language when possible)
143405
+ - EXACTLY ONE action: skill | prompt | tool | workflow | bridge | condition | switch | loop
143406
+ - bridge: instruction \u2014 logic step; agent returns JSON with vars (extract/transform data); optional format: plain
143407
+ - condition: instruction + then: [step ids] + else: [step ids] \u2014 agent returns JSON branch then|else
143408
+ - switch: instruction + cases: { <caseId>: [step ids], ... } + optional default: [step ids] \u2014 agent returns JSON branch matching a case id
143409
+ - loop: { body: [step ids], condition: "<prompt>", maxIterations: 1..50 } \u2014 repeats body in order each iteration. \`condition\` is the loop's EXIT/GOAL condition: after each iteration the agent returns JSON branch then (condition met \u2192 STOP, continue to the next step) | else (not yet met \u2192 run body again). A body step error BREAKS the loop to the next step (use onError: continue on a body step to swallow its error and keep iterating). Always stops at maxIterations (default 10). Body step ids must be real steps; do NOT combine loop with then/else/cases/default.
143410
+ - input: templated instruction for skill steps
143411
+ - prompt: templated instruction for prompt steps (multiline allowed with |)
142554
143412
  - args: templated args object for tool/workflow steps
142555
- - needs: [ <upstream step ids> ] (defines the DAG; omit for sources)
142556
- - when (optional): a condition like '{{ steps.x.output }} is not empty' or '{{ inputs.r }} == "US"' or '... contains "text"', joined by and/or
143413
+ - needs: [ <upstream step ids> ] (defines the DAG; omit only for true sources)
143414
+ - when (optional, legacy): simple guards only \u2014 '{{ steps.x.output }} is not empty'. Do NOT use when for semantic decisions (use condition/switch).
142557
143415
  - onError (optional): fail | continue | retry ; retries (optional, 0-3)
142558
143416
 
142559
- Templating: reference earlier results with {{ steps.<id>.output }}, inputs with {{ inputs.<name> }}, plus {{ trigger }} and {{ now }}.
143417
+ IMPORTANT \u2014 no mid-run questions: this build has NO chat-resume channel, so a workflow CANNOT pause to ask the operator something mid-run (\`awaitInput\` is rejected at save time). For any value the operator must supply, declare it as an \`inputs\` field (the operator fills it in before Run); never try to "ask in chat".
143418
+
143419
+ Templating: {{ steps.<id>.output }}, {{ inputs.<name> }}, {{ vars.<name> }}, {{ trigger }}, {{ now }}.
143420
+
143421
+ Logic steps: default response is one JSON object (vars, branch, optional text). Describe semantics in the instruction; do not repeat JSON syntax unless needed.
143422
+
143423
+ Ordering: steps whose \`needs\` are all satisfied run in parallel \u2014 chain with \`needs\` for sequential pipelines. A loop's body steps run only inside the loop (each iteration), so give them \`needs: [<loop step id>]\` and never schedule them elsewhere. A loop body step runs unconditionally each iteration: do NOT put \`when\` on it, do NOT make it a condition/switch step, and only \`needs\` its loop step or a sibling body step of the same loop. No NON-loop step may \`needs\` a loop body step \u2014 depend on the loop step instead.
143424
+
143425
+ Authoring rules:
143426
+ 1. Decompose the intent into concrete steps. Multi-phase requests (collect \u2192 act \u2192 summarize \u2192 deliver) need at least 4 steps with a linear or fan-in \`needs\` chain.
143427
+ 2. Values the operator must supply (search topic, recipient email, brief): declare each as an \`inputs\` field with a clear \`description\` (and a \`default\` when sensible). The operator fills them in before Run; reference them downstream via \`{{ inputs.<name> }}\`. There is NO way to pause and ask mid-run.
143428
+ 3. Never use \`awaitInput\` \u2014 it is rejected at save time in this build (no resume channel). Do NOT add a prompt/skill step that only says "ask the operator"; that finishes in one turn and just stores the question as output. Use \`inputs\` instead.
143429
+ 4. Research + report + email intents: typical chain \u2014 \`web-research\` skill (over \`{{ inputs.topic }}\`) \u2192 \`write_report\` \u2192 \`send_email\` tool (to \`{{ inputs.recipient }}\`). Put \`topic\` and \`recipient\` in \`inputs\`.
143430
+ 5. Use ONLY skill/tool names from the catalogs below \u2014 never placeholders like "<< skill-name >>", "TBD", or empty skill/tool fields.
143431
+ 6. Prefer a listed skill when its description fits; otherwise use a detailed \`prompt\` step.
143432
+ 7. For email/notify: use a listed mail/MCP tool if available; else \`delivery: { channel: inbox }\`.
143433
+ 8. For image generation: use a listed image/generation tool if available; else a \`prompt\` step that describes producing the image artifact in text.
143434
+ 9. Later steps must read prior results via \`{{ steps.<id>.output }}\`, extracted fields via \`{{ vars.<name> }}\`, and operator data via \`{{ inputs.<name> }}\` \u2014 never invent example emails or briefs in prompts.
143435
+ 10. Between incompatible steps insert \`bridge\` to extract fields into vars (e.g. an email address from text). Use \`condition\` for if/else routing, \`switch\` for multi-way (e.g. value > 100 \u2192 pies, < 0 \u2192 kot, else nieokreslony).
143436
+ 11. Use \`loop\` for "keep refining until good enough" / "retry up to N times" / "iterate while X holds" intents \u2014 set a sane maxIterations so it always terminates. Prefer bridge + vars over passing raw output to tools.
143437
+
143438
+ Available skills (name \u2014 description):
143439
+ ${skills}
142560
143440
 
142561
- Steps with all their \`needs\` satisfied run in parallel, so use \`needs\` to express ordering and fan-out/fan-in.
143441
+ Available tools (name \u2014 description):
143442
+ ${tools}
142562
143443
 
142563
- Available skills: ${skills}
142564
- Available tools: ${tools}
142565
- Prefer a named skill when one fits; otherwise use a \`prompt\` step. For "send/email/notify me" use a connected tool if available, else rely on delivery: { channel: inbox }.`;
143444
+ Example shape for internet research \u2192 report \u2192 email (operator data via inputs):
143445
+ \`\`\`yaml
143446
+ name: internet-research-report-email
143447
+ description: Research a topic, write a report, and email it to the recipient.
143448
+ enabled: true
143449
+ inputs:
143450
+ topic:
143451
+ description: Temat/zakres wyszukiwania w internecie.
143452
+ recipient:
143453
+ description: Adres e-mail odbiorcy raportu.
143454
+ steps:
143455
+ - id: search_web
143456
+ label: Wyszukaj w internecie
143457
+ skill: web-research
143458
+ input: |
143459
+ Przeprowad\u017A research na temat:
143460
+ {{ inputs.topic }}
143461
+ - id: write_report
143462
+ needs: [search_web]
143463
+ label: Przygotuj raport
143464
+ prompt: |
143465
+ Napisz raport po polsku z wynik\xF3w researchu.
143466
+ Temat: {{ inputs.topic }}
143467
+ Research: {{ steps.search_web.output }}
143468
+ - id: send_email
143469
+ needs: [write_report]
143470
+ label: Wy\u015Blij e-mail
143471
+ tool: gmail_send
143472
+ args:
143473
+ to: ["{{ inputs.recipient }}"]
143474
+ subject: "Raport z researchu"
143475
+ body: "{{ steps.write_report.output }}"
143476
+ \`\`\`
143477
+
143478
+ Example shape for image brief \u2192 generate \u2192 report \u2192 email (operator data via inputs):
143479
+ \`\`\`yaml
143480
+ name: image-report-email
143481
+ description: Generate an image from a brief, write a report, and email it.
143482
+ enabled: true
143483
+ inputs:
143484
+ brief:
143485
+ description: What image to generate (subject, style, format, mood, colors).
143486
+ recipient:
143487
+ description: Recipient email for the report.
143488
+ steps:
143489
+ - id: generate_image
143490
+ label: Generate image
143491
+ prompt: |
143492
+ Generate the image from this brief:
143493
+ {{ inputs.brief }}
143494
+ Return the artifact path or id and short generation notes.
143495
+ - id: write_report
143496
+ needs: [generate_image]
143497
+ label: Write report
143498
+ prompt: |
143499
+ Write a concise report in the operator's language.
143500
+ Brief: {{ inputs.brief }}
143501
+ Generation: {{ steps.generate_image.output }}
143502
+ - id: send_report
143503
+ needs: [write_report]
143504
+ label: Send report
143505
+ tool: gmail_send
143506
+ args:
143507
+ to: ["{{ inputs.recipient }}"]
143508
+ subject: "Image workflow report"
143509
+ body: "{{ steps.write_report.output }}"
143510
+ \`\`\`
143511
+
143512
+ Example shape for an iterative refine-until-good loop:
143513
+ \`\`\`yaml
143514
+ name: refine-draft
143515
+ description: Draft a paragraph, then refine it until it is good enough or 5 tries are used.
143516
+ enabled: true
143517
+ inputs:
143518
+ topic:
143519
+ default: "release notes"
143520
+ steps:
143521
+ - id: first_draft
143522
+ label: First draft
143523
+ prompt: |
143524
+ Write a first draft about {{ inputs.topic }}.
143525
+ - id: refine
143526
+ needs: [first_draft]
143527
+ label: Refine loop
143528
+ loop:
143529
+ # condition is the EXIT/GOAL condition \u2014 describe the goal that ENDS the
143530
+ # loop. Met (then) \u2192 stop and continue to the next step; not met (else) \u2192
143531
+ # run the body again. A body step error breaks the loop to the next step.
143532
+ body: [improve]
143533
+ condition: |
143534
+ Is the latest draft in {{ vars.draft }} good enough \u2014 clear, accurate, and well-structured?
143535
+ If yes, the goal is reached and the loop stops; if not, keep refining.
143536
+ maxIterations: 5
143537
+ - id: improve
143538
+ needs: [refine]
143539
+ label: Improve draft
143540
+ bridge: |
143541
+ Improve the current draft (start from {{ steps.first_draft.output }} or {{ vars.draft }}).
143542
+ Return JSON with vars.draft set to the improved text.
143543
+ \`\`\`
143544
+ (Replace skill/tool names with ones from the catalog when drafting.)`;
143545
+ }
143546
+ function formatCatalog(entries, emptyLabel) {
143547
+ if (!entries?.length)
143548
+ return emptyLabel;
143549
+ return entries.map((entry) => `- ${entry.name}${entry.description ? ` \u2014 ${entry.description}` : ""}`).join("\n");
142566
143550
  }
142567
143551
  async function draftWorkflow(provider, model, intent, signal, opts = {}) {
142568
143552
  let accumulated = "";
@@ -142570,7 +143554,7 @@ async function draftWorkflow(provider, model, intent, signal, opts = {}) {
142570
143554
  model,
142571
143555
  system: buildSystemPrompt(opts),
142572
143556
  messages: [{ role: "user", content: [{ type: "text", text: `Build a workflow for: ${intent}` }] }],
142573
- maxTokens: opts.maxTokens ?? 1500,
143557
+ maxTokens: opts.maxTokens ?? DEFAULT_MAX_TOKENS,
142574
143558
  signal
142575
143559
  })) {
142576
143560
  if (event.type === "text_delta")
@@ -142652,7 +143636,8 @@ function createTool(deps) {
142652
143636
  const model = deps.draftModel ?? provider.models[0]?.id ?? "claude-sonnet-4-6";
142653
143637
  const drafted = await draftWorkflow(provider, model, intent, ctx.signal, {
142654
143638
  ...deps.listSkills ? { availableSkills: deps.listSkills() } : {},
142655
- ...deps.listTools ? { availableTools: deps.listTools() } : {}
143639
+ ...deps.listTools ? { availableTools: deps.listTools() } : {},
143640
+ maxTokens: 4096
142656
143641
  });
142657
143642
  if (!drafted.parse.ok || !drafted.parse.workflow) {
142658
143643
  throw new MoxxyError({
@@ -143148,9 +144133,17 @@ function buildWorkflowsIntegration(args) {
143148
144133
  const warnedCycles = /* @__PURE__ */ new Set();
143149
144134
  async function runNow(input) {
143150
144135
  const entry = await store.get(input.name);
143151
- if (!entry) return { ok: false, steps: [], output: "", error: `no workflow named "${input.name}"` };
144136
+ if (!entry) {
144137
+ return { ok: false, status: "failed", steps: [], output: "", error: `no workflow named "${input.name}"` };
144138
+ }
143152
144139
  if (inFlight.has(input.name)) {
143153
- return { ok: false, steps: [], output: "", error: `workflow "${input.name}" is already running` };
144140
+ return {
144141
+ ok: false,
144142
+ status: "failed",
144143
+ steps: [],
144144
+ output: "",
144145
+ error: `workflow "${input.name}" is already running`
144146
+ };
143154
144147
  }
143155
144148
  inFlight.add(input.name);
143156
144149
  try {
@@ -143189,6 +144182,13 @@ function buildWorkflowsIntegration(args) {
143189
144182
  },
143190
144183
  { executor: session.workflowExecutors.getActive() }
143191
144184
  );
144185
+ if (result.status === "paused") {
144186
+ logger?.warn?.("workflows: run paused awaiting operator input; not delivering to inbox", {
144187
+ workflow: input.name,
144188
+ runId: result.runId
144189
+ });
144190
+ return result;
144191
+ }
143192
144192
  await deliverToInbox(entry.workflow, result, logger);
143193
144193
  return result;
143194
144194
  } finally {
@@ -143216,6 +144216,32 @@ function buildWorkflowsIntegration(args) {
143216
144216
  ...r2.error ? { error: r2.error } : {},
143217
144217
  steps: r2.steps.map((s2) => ({ id: s2.id, status: s2.status, ...s2.error ? { error: s2.error } : {} }))
143218
144218
  };
144219
+ },
144220
+ // Builder-facing additions (phase 2 GUI): validate a draft YAML, persist a
144221
+ // workflow, and fetch one as canonical YAML. Keep them on the same store so
144222
+ // the modal and the builder share one source of truth.
144223
+ validateDraft: async (yaml) => {
144224
+ const r2 = parseWorkflowYaml(yaml);
144225
+ return { ok: r2.ok, errors: r2.errors };
144226
+ },
144227
+ save: async (yaml, previousName) => {
144228
+ const parsed = parseWorkflowYaml(yaml);
144229
+ if (!parsed.ok || !parsed.workflow) {
144230
+ throw new Error(`invalid workflow YAML \u2014 ${parsed.errors.join("; ")}`);
144231
+ }
144232
+ const saved = await store.save(parsed.workflow, previousName);
144233
+ await syncSchedules();
144234
+ return { name: saved.workflow.name, scope: saved.scope, path: saved.path };
144235
+ },
144236
+ getRun: async (name) => {
144237
+ const entry = await store.get(name);
144238
+ if (!entry) return null;
144239
+ return {
144240
+ name: entry.workflow.name,
144241
+ scope: entry.scope,
144242
+ path: entry.path,
144243
+ yaml: serializeWorkflow(entry.workflow)
144244
+ };
143219
144245
  }
143220
144246
  };
143221
144247
  async function syncSchedules() {
@@ -143312,8 +144338,11 @@ function buildWorkflowsIntegration(args) {
143312
144338
  appendEvent: (e3) => session.log.append(e3),
143313
144339
  ...logger ? { logger } : {},
143314
144340
  provider: () => safeActiveProvider(session),
143315
- listSkills: () => session.skills.list().map((s2) => s2.frontmatter.name),
143316
- listTools: () => session.tools.list().map((t2) => t2.name),
144341
+ listSkills: () => session.skills.list().map((s2) => ({
144342
+ name: s2.frontmatter.name,
144343
+ description: s2.frontmatter.description ?? ""
144344
+ })),
144345
+ listTools: () => session.tools.list().map((t2) => ({ name: t2.name, description: t2.description ?? "" })),
143317
144346
  onChanged: syncSchedules,
143318
144347
  runNow,
143319
144348
  userDir: defaultUserWorkflowsDir(),
@@ -143321,6 +144350,13 @@ function buildWorkflowsIntegration(args) {
143321
144350
  session.workflows = view;
143322
144351
  await syncSchedules();
143323
144352
  await startFileWatchers();
144353
+ void defaultWorkflowRunStore.sweepStale().then((n2) => {
144354
+ if (n2 > 0) logger?.info?.("workflows: swept stale paused-run checkpoints", { count: n2 });
144355
+ }).catch(
144356
+ (err) => logger?.warn?.("workflows: checkpoint sweep failed", {
144357
+ err: err instanceof Error ? err.message : String(err)
144358
+ })
144359
+ );
143324
144360
  }
143325
144361
  });
143326
144362
  return {
@@ -148864,9 +149900,9 @@ ${HELP12}`);
148864
149900
  function formatCapabilities(caps) {
148865
149901
  if (!caps) return "";
148866
149902
  const bits = [];
148867
- const fs43 = caps.fs;
148868
- if (fs43?.read?.length) bits.push(`fs:read(${fs43.read.length})`);
148869
- if (fs43?.write?.length) bits.push(`fs:write(${fs43.write.length})`);
149903
+ const fs44 = caps.fs;
149904
+ if (fs44?.read?.length) bits.push(`fs:read(${fs44.read.length})`);
149905
+ if (fs44?.write?.length) bits.push(`fs:write(${fs44.write.length})`);
148870
149906
  const net3 = caps.net;
148871
149907
  if (net3?.mode) bits.push(`net:${net3.mode}`);
148872
149908
  const env3 = caps.env;