webmux 0.18.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/webmux.js CHANGED
@@ -169,6 +169,14 @@ function listLocalGitBranches(cwd) {
169
169
  return output.split(`
170
170
  `).map((line) => line.trim()).filter((line) => line.length > 0);
171
171
  }
172
+ function listRemoteGitBranches(cwd) {
173
+ try {
174
+ runGit(["fetch", "--prune", "origin"], cwd);
175
+ } catch {}
176
+ const output = runGit(["for-each-ref", "--format=%(refname:short)", "refs/remotes/origin"], cwd);
177
+ return output.split(`
178
+ `).map((line) => line.trim()).filter((line) => line.length > 0).map((line) => line.replace(/^origin\//, "")).filter((name) => name !== "HEAD");
179
+ }
172
180
  function readGitWorktreeStatus(cwd) {
173
181
  const dirtyOutput = runGit(["status", "--porcelain"], cwd);
174
182
  const commit = tryRunGit(["rev-parse", "HEAD"], cwd);
@@ -216,6 +224,9 @@ class BunGitGateway {
216
224
  listLocalBranches(cwd) {
217
225
  return listLocalGitBranches(cwd);
218
226
  }
227
+ listRemoteBranches(cwd) {
228
+ return listRemoteGitBranches(cwd);
229
+ }
219
230
  readWorktreeStatus(cwd) {
220
231
  return readGitWorktreeStatus(cwd);
221
232
  }
@@ -290,6 +301,15 @@ class BunGitGateway {
290
301
  };
291
302
  });
292
303
  }
304
+ fetchBranch(repoRoot, remote, branch) {
305
+ return tryRunGit(["fetch", remote, branch], repoRoot);
306
+ }
307
+ fastForwardMerge(repoRoot, ref) {
308
+ return tryRunGit(["merge", "--ff-only", ref], repoRoot);
309
+ }
310
+ hardReset(repoRoot, ref) {
311
+ return tryRunGit(["reset", "--hard", ref], repoRoot);
312
+ }
293
313
  }
294
314
  var init_git = () => {};
295
315
 
@@ -386,6 +406,7 @@ _webmux() {
386
406
  'close:Close a worktree session'
387
407
  'remove:Remove a worktree'
388
408
  'merge:Merge a worktree into main'
409
+ 'send:Send a prompt to a running worktree agent'
389
410
  'prune:Remove all worktrees in the current project'
390
411
  'completion:Generate shell completion script'
391
412
  )
@@ -396,7 +417,7 @@ _webmux() {
396
417
  fi
397
418
 
398
419
  case "\${words[2]}" in
399
- open|close|remove|merge)
420
+ open|close|remove|merge|send)
400
421
  if (( CURRENT == 3 )); then
401
422
  local -a branches
402
423
  branches=(\${(f)"$(webmux --completions "\${words[2]}" 2>/dev/null)"})
@@ -434,12 +455,12 @@ compdef _webmux webmux`, BASH_SCRIPT = `_webmux() {
434
455
  prev="\${COMP_WORDS[COMP_CWORD-1]}"
435
456
 
436
457
  if [[ \${COMP_CWORD} -eq 1 ]]; then
437
- COMPREPLY=($(compgen -W "serve init service update add list open close remove merge prune completion" -- "\${cur}"))
458
+ COMPREPLY=($(compgen -W "serve init service update add list open close remove merge send prune completion" -- "\${cur}"))
438
459
  return
439
460
  fi
440
461
 
441
462
  case "\${COMP_WORDS[1]}" in
442
- open|close|remove|merge)
463
+ open|close|remove|merge|send)
443
464
  if [[ \${COMP_CWORD} -eq 2 ]]; then
444
465
  local branches
445
466
  branches=$(webmux --completions "\${COMP_WORDS[1]}" 2>/dev/null)
@@ -462,7 +483,7 @@ compdef _webmux webmux`, BASH_SCRIPT = `_webmux() {
462
483
  complete -F _webmux webmux`;
463
484
  var init_completions = __esm(() => {
464
485
  init_git();
465
- BRANCH_SUBCOMMANDS = new Set(["open", "close", "remove", "merge"]);
486
+ BRANCH_SUBCOMMANDS = new Set(["open", "close", "remove", "merge", "send"]);
466
487
  });
467
488
 
468
489
  // node_modules/.bun/sisteransi@1.0.5/node_modules/sisteransi/src/index.js
@@ -2584,7 +2605,7 @@ function isPrComment(raw) {
2584
2605
  function isCiCheck(raw) {
2585
2606
  if (!isRecord2(raw))
2586
2607
  return false;
2587
- return typeof raw.name === "string" && (raw.status === "pending" || raw.status === "success" || raw.status === "failed" || raw.status === "skipped") && typeof raw.url === "string" && (raw.runId === null || typeof raw.runId === "number");
2608
+ return typeof raw.name === "string" && (raw.status === "pending" || raw.status === "success" || raw.status === "failed" || raw.status === "skipped") && (raw.url === null || typeof raw.url === "string") && (raw.runId === null || typeof raw.runId === "number");
2588
2609
  }
2589
2610
  function isPrEntry(raw) {
2590
2611
  if (!isRecord2(raw))
@@ -2760,7 +2781,7 @@ var init_policies = __esm(() => {
2760
2781
  VALID_WORKTREE_NAME_RE = /^[a-z0-9][a-z0-9\-_./]*$/;
2761
2782
  });
2762
2783
 
2763
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/nodes/identity.js
2784
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/identity.js
2764
2785
  var require_identity = __commonJS((exports) => {
2765
2786
  var ALIAS = Symbol.for("yaml.alias");
2766
2787
  var DOC = Symbol.for("yaml.document");
@@ -2814,7 +2835,7 @@ var require_identity = __commonJS((exports) => {
2814
2835
  exports.isSeq = isSeq;
2815
2836
  });
2816
2837
 
2817
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/visit.js
2838
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/visit.js
2818
2839
  var require_visit = __commonJS((exports) => {
2819
2840
  var identity = require_identity();
2820
2841
  var BREAK = Symbol("break visit");
@@ -2969,7 +2990,7 @@ var require_visit = __commonJS((exports) => {
2969
2990
  exports.visitAsync = visitAsync;
2970
2991
  });
2971
2992
 
2972
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/doc/directives.js
2993
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/doc/directives.js
2973
2994
  var require_directives = __commonJS((exports) => {
2974
2995
  var identity = require_identity();
2975
2996
  var visit = require_visit();
@@ -3121,7 +3142,7 @@ var require_directives = __commonJS((exports) => {
3121
3142
  exports.Directives = Directives;
3122
3143
  });
3123
3144
 
3124
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/doc/anchors.js
3145
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/doc/anchors.js
3125
3146
  var require_anchors = __commonJS((exports) => {
3126
3147
  var identity = require_identity();
3127
3148
  var visit = require_visit();
@@ -3183,7 +3204,7 @@ var require_anchors = __commonJS((exports) => {
3183
3204
  exports.findNewAnchor = findNewAnchor;
3184
3205
  });
3185
3206
 
3186
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/doc/applyReviver.js
3207
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/doc/applyReviver.js
3187
3208
  var require_applyReviver = __commonJS((exports) => {
3188
3209
  function applyReviver(reviver, obj, key, val) {
3189
3210
  if (val && typeof val === "object") {
@@ -3230,7 +3251,7 @@ var require_applyReviver = __commonJS((exports) => {
3230
3251
  exports.applyReviver = applyReviver;
3231
3252
  });
3232
3253
 
3233
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/nodes/toJS.js
3254
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/toJS.js
3234
3255
  var require_toJS = __commonJS((exports) => {
3235
3256
  var identity = require_identity();
3236
3257
  function toJS(value, arg, ctx) {
@@ -3257,7 +3278,7 @@ var require_toJS = __commonJS((exports) => {
3257
3278
  exports.toJS = toJS;
3258
3279
  });
3259
3280
 
3260
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/nodes/Node.js
3281
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/Node.js
3261
3282
  var require_Node = __commonJS((exports) => {
3262
3283
  var applyReviver = require_applyReviver();
3263
3284
  var identity = require_identity();
@@ -3294,7 +3315,7 @@ var require_Node = __commonJS((exports) => {
3294
3315
  exports.NodeBase = NodeBase;
3295
3316
  });
3296
3317
 
3297
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/nodes/Alias.js
3318
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/Alias.js
3298
3319
  var require_Alias = __commonJS((exports) => {
3299
3320
  var anchors = require_anchors();
3300
3321
  var visit = require_visit();
@@ -3402,7 +3423,7 @@ var require_Alias = __commonJS((exports) => {
3402
3423
  exports.Alias = Alias;
3403
3424
  });
3404
3425
 
3405
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/nodes/Scalar.js
3426
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/Scalar.js
3406
3427
  var require_Scalar = __commonJS((exports) => {
3407
3428
  var identity = require_identity();
3408
3429
  var Node = require_Node();
@@ -3430,7 +3451,7 @@ var require_Scalar = __commonJS((exports) => {
3430
3451
  exports.isScalarValue = isScalarValue;
3431
3452
  });
3432
3453
 
3433
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/doc/createNode.js
3454
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/doc/createNode.js
3434
3455
  var require_createNode = __commonJS((exports) => {
3435
3456
  var Alias = require_Alias();
3436
3457
  var identity = require_identity();
@@ -3502,7 +3523,7 @@ var require_createNode = __commonJS((exports) => {
3502
3523
  exports.createNode = createNode;
3503
3524
  });
3504
3525
 
3505
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/nodes/Collection.js
3526
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/Collection.js
3506
3527
  var require_Collection = __commonJS((exports) => {
3507
3528
  var createNode = require_createNode();
3508
3529
  var identity = require_identity();
@@ -3617,7 +3638,7 @@ var require_Collection = __commonJS((exports) => {
3617
3638
  exports.isEmptyPath = isEmptyPath;
3618
3639
  });
3619
3640
 
3620
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/stringify/stringifyComment.js
3641
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringifyComment.js
3621
3642
  var require_stringifyComment = __commonJS((exports) => {
3622
3643
  var stringifyComment = (str) => str.replace(/^(?!$)(?: $)?/gm, "#");
3623
3644
  function indentComment(comment, indent) {
@@ -3634,7 +3655,7 @@ var require_stringifyComment = __commonJS((exports) => {
3634
3655
  exports.stringifyComment = stringifyComment;
3635
3656
  });
3636
3657
 
3637
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/stringify/foldFlowLines.js
3658
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/foldFlowLines.js
3638
3659
  var require_foldFlowLines = __commonJS((exports) => {
3639
3660
  var FOLD_FLOW = "flow";
3640
3661
  var FOLD_BLOCK = "block";
@@ -3771,7 +3792,7 @@ ${indent}${text.slice(fold + 1, end2)}`;
3771
3792
  exports.foldFlowLines = foldFlowLines;
3772
3793
  });
3773
3794
 
3774
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/stringify/stringifyString.js
3795
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringifyString.js
3775
3796
  var require_stringifyString = __commonJS((exports) => {
3776
3797
  var Scalar = require_Scalar();
3777
3798
  var foldFlowLines = require_foldFlowLines();
@@ -4069,7 +4090,7 @@ ${indent}`);
4069
4090
  exports.stringifyString = stringifyString;
4070
4091
  });
4071
4092
 
4072
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/stringify/stringify.js
4093
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringify.js
4073
4094
  var require_stringify = __commonJS((exports) => {
4074
4095
  var anchors = require_anchors();
4075
4096
  var identity = require_identity();
@@ -4092,6 +4113,7 @@ var require_stringify = __commonJS((exports) => {
4092
4113
  nullStr: "null",
4093
4114
  simpleKeys: false,
4094
4115
  singleQuote: null,
4116
+ trailingComma: false,
4095
4117
  trueStr: "true",
4096
4118
  verifyAliasOrder: true
4097
4119
  }, doc.schema.toStringOptions, options);
@@ -4189,7 +4211,7 @@ ${ctx.indent}${str}`;
4189
4211
  exports.stringify = stringify;
4190
4212
  });
4191
4213
 
4192
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/stringify/stringifyPair.js
4214
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringifyPair.js
4193
4215
  var require_stringifyPair = __commonJS((exports) => {
4194
4216
  var identity = require_identity();
4195
4217
  var Scalar = require_Scalar();
@@ -4325,7 +4347,7 @@ ${ctx.indent}`;
4325
4347
  exports.stringifyPair = stringifyPair;
4326
4348
  });
4327
4349
 
4328
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/log.js
4350
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/log.js
4329
4351
  var require_log = __commonJS((exports) => {
4330
4352
  var node_process = __require("process");
4331
4353
  function debug(logLevel, ...messages) {
@@ -4344,7 +4366,7 @@ var require_log = __commonJS((exports) => {
4344
4366
  exports.warn = warn;
4345
4367
  });
4346
4368
 
4347
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/yaml-1.1/merge.js
4369
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/merge.js
4348
4370
  var require_merge = __commonJS((exports) => {
4349
4371
  var identity = require_identity();
4350
4372
  var Scalar = require_Scalar();
@@ -4398,7 +4420,7 @@ var require_merge = __commonJS((exports) => {
4398
4420
  exports.merge = merge;
4399
4421
  });
4400
4422
 
4401
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/nodes/addPairToJSMap.js
4423
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/addPairToJSMap.js
4402
4424
  var require_addPairToJSMap = __commonJS((exports) => {
4403
4425
  var log = require_log();
4404
4426
  var merge = require_merge();
@@ -4459,7 +4481,7 @@ var require_addPairToJSMap = __commonJS((exports) => {
4459
4481
  exports.addPairToJSMap = addPairToJSMap;
4460
4482
  });
4461
4483
 
4462
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/nodes/Pair.js
4484
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/Pair.js
4463
4485
  var require_Pair = __commonJS((exports) => {
4464
4486
  var createNode = require_createNode();
4465
4487
  var stringifyPair = require_stringifyPair();
@@ -4497,7 +4519,7 @@ var require_Pair = __commonJS((exports) => {
4497
4519
  exports.createPair = createPair;
4498
4520
  });
4499
4521
 
4500
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/stringify/stringifyCollection.js
4522
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringifyCollection.js
4501
4523
  var require_stringifyCollection = __commonJS((exports) => {
4502
4524
  var identity = require_identity();
4503
4525
  var stringify = require_stringify();
@@ -4600,13 +4622,20 @@ ${indent}${line}` : `
4600
4622
  if (comment)
4601
4623
  reqNewline = true;
4602
4624
  let str = stringify.stringify(item, itemCtx, () => comment = null);
4603
- if (i < items.length - 1)
4625
+ reqNewline || (reqNewline = lines.length > linesAtValue || str.includes(`
4626
+ `));
4627
+ if (i < items.length - 1) {
4604
4628
  str += ",";
4629
+ } else if (ctx.options.trailingComma) {
4630
+ if (ctx.options.lineWidth > 0) {
4631
+ reqNewline || (reqNewline = lines.reduce((sum, line) => sum + line.length + 2, 2) + (str.length + 2) > ctx.options.lineWidth);
4632
+ }
4633
+ if (reqNewline) {
4634
+ str += ",";
4635
+ }
4636
+ }
4605
4637
  if (comment)
4606
4638
  str += stringifyComment.lineComment(str, itemIndent, commentString(comment));
4607
- if (!reqNewline && (lines.length > linesAtValue || str.includes(`
4608
- `)))
4609
- reqNewline = true;
4610
4639
  lines.push(str);
4611
4640
  linesAtValue = lines.length;
4612
4641
  }
@@ -4642,7 +4671,7 @@ ${indent}${end}`;
4642
4671
  exports.stringifyCollection = stringifyCollection;
4643
4672
  });
4644
4673
 
4645
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/nodes/YAMLMap.js
4674
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/YAMLMap.js
4646
4675
  var require_YAMLMap = __commonJS((exports) => {
4647
4676
  var stringifyCollection = require_stringifyCollection();
4648
4677
  var addPairToJSMap = require_addPairToJSMap();
@@ -4769,7 +4798,7 @@ var require_YAMLMap = __commonJS((exports) => {
4769
4798
  exports.findPair = findPair;
4770
4799
  });
4771
4800
 
4772
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/common/map.js
4801
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/common/map.js
4773
4802
  var require_map = __commonJS((exports) => {
4774
4803
  var identity = require_identity();
4775
4804
  var YAMLMap = require_YAMLMap();
@@ -4788,7 +4817,7 @@ var require_map = __commonJS((exports) => {
4788
4817
  exports.map = map;
4789
4818
  });
4790
4819
 
4791
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/nodes/YAMLSeq.js
4820
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/YAMLSeq.js
4792
4821
  var require_YAMLSeq = __commonJS((exports) => {
4793
4822
  var createNode = require_createNode();
4794
4823
  var stringifyCollection = require_stringifyCollection();
@@ -4881,7 +4910,7 @@ var require_YAMLSeq = __commonJS((exports) => {
4881
4910
  exports.YAMLSeq = YAMLSeq;
4882
4911
  });
4883
4912
 
4884
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/common/seq.js
4913
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/common/seq.js
4885
4914
  var require_seq = __commonJS((exports) => {
4886
4915
  var identity = require_identity();
4887
4916
  var YAMLSeq = require_YAMLSeq();
@@ -4900,7 +4929,7 @@ var require_seq = __commonJS((exports) => {
4900
4929
  exports.seq = seq;
4901
4930
  });
4902
4931
 
4903
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/common/string.js
4932
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/common/string.js
4904
4933
  var require_string = __commonJS((exports) => {
4905
4934
  var stringifyString = require_stringifyString();
4906
4935
  var string = {
@@ -4916,7 +4945,7 @@ var require_string = __commonJS((exports) => {
4916
4945
  exports.string = string;
4917
4946
  });
4918
4947
 
4919
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/common/null.js
4948
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/common/null.js
4920
4949
  var require_null = __commonJS((exports) => {
4921
4950
  var Scalar = require_Scalar();
4922
4951
  var nullTag = {
@@ -4931,7 +4960,7 @@ var require_null = __commonJS((exports) => {
4931
4960
  exports.nullTag = nullTag;
4932
4961
  });
4933
4962
 
4934
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/core/bool.js
4963
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/core/bool.js
4935
4964
  var require_bool = __commonJS((exports) => {
4936
4965
  var Scalar = require_Scalar();
4937
4966
  var boolTag = {
@@ -4952,7 +4981,7 @@ var require_bool = __commonJS((exports) => {
4952
4981
  exports.boolTag = boolTag;
4953
4982
  });
4954
4983
 
4955
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/stringify/stringifyNumber.js
4984
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringifyNumber.js
4956
4985
  var require_stringifyNumber = __commonJS((exports) => {
4957
4986
  function stringifyNumber({ format, minFractionDigits, tag, value }) {
4958
4987
  if (typeof value === "bigint")
@@ -4976,7 +5005,7 @@ var require_stringifyNumber = __commonJS((exports) => {
4976
5005
  exports.stringifyNumber = stringifyNumber;
4977
5006
  });
4978
5007
 
4979
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/core/float.js
5008
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/core/float.js
4980
5009
  var require_float = __commonJS((exports) => {
4981
5010
  var Scalar = require_Scalar();
4982
5011
  var stringifyNumber = require_stringifyNumber();
@@ -5019,7 +5048,7 @@ var require_float = __commonJS((exports) => {
5019
5048
  exports.floatNaN = floatNaN;
5020
5049
  });
5021
5050
 
5022
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/core/int.js
5051
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/core/int.js
5023
5052
  var require_int = __commonJS((exports) => {
5024
5053
  var stringifyNumber = require_stringifyNumber();
5025
5054
  var intIdentify = (value) => typeof value === "bigint" || Number.isInteger(value);
@@ -5061,7 +5090,7 @@ var require_int = __commonJS((exports) => {
5061
5090
  exports.intOct = intOct;
5062
5091
  });
5063
5092
 
5064
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/core/schema.js
5093
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/core/schema.js
5065
5094
  var require_schema = __commonJS((exports) => {
5066
5095
  var map = require_map();
5067
5096
  var _null = require_null();
@@ -5086,7 +5115,7 @@ var require_schema = __commonJS((exports) => {
5086
5115
  exports.schema = schema;
5087
5116
  });
5088
5117
 
5089
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/json/schema.js
5118
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/json/schema.js
5090
5119
  var require_schema2 = __commonJS((exports) => {
5091
5120
  var Scalar = require_Scalar();
5092
5121
  var map = require_map();
@@ -5150,7 +5179,7 @@ var require_schema2 = __commonJS((exports) => {
5150
5179
  exports.schema = schema;
5151
5180
  });
5152
5181
 
5153
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/yaml-1.1/binary.js
5182
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/binary.js
5154
5183
  var require_binary = __commonJS((exports) => {
5155
5184
  var node_buffer = __require("buffer");
5156
5185
  var Scalar = require_Scalar();
@@ -5205,7 +5234,7 @@ var require_binary = __commonJS((exports) => {
5205
5234
  exports.binary = binary;
5206
5235
  });
5207
5236
 
5208
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/yaml-1.1/pairs.js
5237
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/pairs.js
5209
5238
  var require_pairs = __commonJS((exports) => {
5210
5239
  var identity = require_identity();
5211
5240
  var Pair = require_Pair();
@@ -5280,7 +5309,7 @@ ${cn.comment}` : item.comment;
5280
5309
  exports.resolvePairs = resolvePairs;
5281
5310
  });
5282
5311
 
5283
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/yaml-1.1/omap.js
5312
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/omap.js
5284
5313
  var require_omap = __commonJS((exports) => {
5285
5314
  var identity = require_identity();
5286
5315
  var toJS = require_toJS();
@@ -5352,7 +5381,7 @@ var require_omap = __commonJS((exports) => {
5352
5381
  exports.omap = omap;
5353
5382
  });
5354
5383
 
5355
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/yaml-1.1/bool.js
5384
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/bool.js
5356
5385
  var require_bool2 = __commonJS((exports) => {
5357
5386
  var Scalar = require_Scalar();
5358
5387
  function boolStringify({ value, source }, ctx) {
@@ -5381,7 +5410,7 @@ var require_bool2 = __commonJS((exports) => {
5381
5410
  exports.trueTag = trueTag;
5382
5411
  });
5383
5412
 
5384
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/yaml-1.1/float.js
5413
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/float.js
5385
5414
  var require_float2 = __commonJS((exports) => {
5386
5415
  var Scalar = require_Scalar();
5387
5416
  var stringifyNumber = require_stringifyNumber();
@@ -5427,7 +5456,7 @@ var require_float2 = __commonJS((exports) => {
5427
5456
  exports.floatNaN = floatNaN;
5428
5457
  });
5429
5458
 
5430
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/yaml-1.1/int.js
5459
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/int.js
5431
5460
  var require_int2 = __commonJS((exports) => {
5432
5461
  var stringifyNumber = require_stringifyNumber();
5433
5462
  var intIdentify = (value) => typeof value === "bigint" || Number.isInteger(value);
@@ -5503,7 +5532,7 @@ var require_int2 = __commonJS((exports) => {
5503
5532
  exports.intOct = intOct;
5504
5533
  });
5505
5534
 
5506
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/yaml-1.1/set.js
5535
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/set.js
5507
5536
  var require_set = __commonJS((exports) => {
5508
5537
  var identity = require_identity();
5509
5538
  var Pair = require_Pair();
@@ -5586,7 +5615,7 @@ var require_set = __commonJS((exports) => {
5586
5615
  exports.set = set;
5587
5616
  });
5588
5617
 
5589
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/yaml-1.1/timestamp.js
5618
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/timestamp.js
5590
5619
  var require_timestamp = __commonJS((exports) => {
5591
5620
  var stringifyNumber = require_stringifyNumber();
5592
5621
  function parseSexagesimal(str, asBigInt) {
@@ -5668,7 +5697,7 @@ var require_timestamp = __commonJS((exports) => {
5668
5697
  exports.timestamp = timestamp;
5669
5698
  });
5670
5699
 
5671
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/yaml-1.1/schema.js
5700
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/schema.js
5672
5701
  var require_schema3 = __commonJS((exports) => {
5673
5702
  var map = require_map();
5674
5703
  var _null = require_null();
@@ -5709,7 +5738,7 @@ var require_schema3 = __commonJS((exports) => {
5709
5738
  exports.schema = schema;
5710
5739
  });
5711
5740
 
5712
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/tags.js
5741
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/tags.js
5713
5742
  var require_tags = __commonJS((exports) => {
5714
5743
  var map = require_map();
5715
5744
  var _null = require_null();
@@ -5800,7 +5829,7 @@ var require_tags = __commonJS((exports) => {
5800
5829
  exports.getTags = getTags;
5801
5830
  });
5802
5831
 
5803
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/schema/Schema.js
5832
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/Schema.js
5804
5833
  var require_Schema = __commonJS((exports) => {
5805
5834
  var identity = require_identity();
5806
5835
  var map = require_map();
@@ -5830,7 +5859,7 @@ var require_Schema = __commonJS((exports) => {
5830
5859
  exports.Schema = Schema;
5831
5860
  });
5832
5861
 
5833
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/stringify/stringifyDocument.js
5862
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringifyDocument.js
5834
5863
  var require_stringifyDocument = __commonJS((exports) => {
5835
5864
  var identity = require_identity();
5836
5865
  var stringify = require_stringify();
@@ -5910,7 +5939,7 @@ var require_stringifyDocument = __commonJS((exports) => {
5910
5939
  exports.stringifyDocument = stringifyDocument;
5911
5940
  });
5912
5941
 
5913
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/doc/Document.js
5942
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/doc/Document.js
5914
5943
  var require_Document = __commonJS((exports) => {
5915
5944
  var Alias = require_Alias();
5916
5945
  var Collection = require_Collection();
@@ -6145,7 +6174,7 @@ var require_Document = __commonJS((exports) => {
6145
6174
  exports.Document = Document;
6146
6175
  });
6147
6176
 
6148
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/errors.js
6177
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/errors.js
6149
6178
  var require_errors = __commonJS((exports) => {
6150
6179
  class YAMLError extends Error {
6151
6180
  constructor(name, pos, code, message) {
@@ -6210,7 +6239,7 @@ ${pointer}
6210
6239
  exports.prettifyError = prettifyError;
6211
6240
  });
6212
6241
 
6213
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/compose/resolve-props.js
6242
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-props.js
6214
6243
  var require_resolve_props = __commonJS((exports) => {
6215
6244
  function resolveProps(tokens, { flow, indicator, next, offset, onError, parentIndent, startOnNewline }) {
6216
6245
  let spaceBefore = false;
@@ -6340,7 +6369,7 @@ var require_resolve_props = __commonJS((exports) => {
6340
6369
  exports.resolveProps = resolveProps;
6341
6370
  });
6342
6371
 
6343
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/compose/util-contains-newline.js
6372
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/util-contains-newline.js
6344
6373
  var require_util_contains_newline = __commonJS((exports) => {
6345
6374
  function containsNewline(key) {
6346
6375
  if (!key)
@@ -6380,7 +6409,7 @@ var require_util_contains_newline = __commonJS((exports) => {
6380
6409
  exports.containsNewline = containsNewline;
6381
6410
  });
6382
6411
 
6383
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/compose/util-flow-indent-check.js
6412
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/util-flow-indent-check.js
6384
6413
  var require_util_flow_indent_check = __commonJS((exports) => {
6385
6414
  var utilContainsNewline = require_util_contains_newline();
6386
6415
  function flowIndentCheck(indent, fc, onError) {
@@ -6395,7 +6424,7 @@ var require_util_flow_indent_check = __commonJS((exports) => {
6395
6424
  exports.flowIndentCheck = flowIndentCheck;
6396
6425
  });
6397
6426
 
6398
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/compose/util-map-includes.js
6427
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/util-map-includes.js
6399
6428
  var require_util_map_includes = __commonJS((exports) => {
6400
6429
  var identity = require_identity();
6401
6430
  function mapIncludes(ctx, items, search) {
@@ -6408,7 +6437,7 @@ var require_util_map_includes = __commonJS((exports) => {
6408
6437
  exports.mapIncludes = mapIncludes;
6409
6438
  });
6410
6439
 
6411
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/compose/resolve-block-map.js
6440
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-block-map.js
6412
6441
  var require_resolve_block_map = __commonJS((exports) => {
6413
6442
  var Pair = require_Pair();
6414
6443
  var YAMLMap = require_YAMLMap();
@@ -6515,7 +6544,7 @@ var require_resolve_block_map = __commonJS((exports) => {
6515
6544
  exports.resolveBlockMap = resolveBlockMap;
6516
6545
  });
6517
6546
 
6518
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/compose/resolve-block-seq.js
6547
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-block-seq.js
6519
6548
  var require_resolve_block_seq = __commonJS((exports) => {
6520
6549
  var YAMLSeq = require_YAMLSeq();
6521
6550
  var resolveProps = require_resolve_props();
@@ -6563,7 +6592,7 @@ var require_resolve_block_seq = __commonJS((exports) => {
6563
6592
  exports.resolveBlockSeq = resolveBlockSeq;
6564
6593
  });
6565
6594
 
6566
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/compose/resolve-end.js
6595
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-end.js
6567
6596
  var require_resolve_end = __commonJS((exports) => {
6568
6597
  function resolveEnd(end, offset, reqSpace, onError) {
6569
6598
  let comment = "";
@@ -6603,7 +6632,7 @@ var require_resolve_end = __commonJS((exports) => {
6603
6632
  exports.resolveEnd = resolveEnd;
6604
6633
  });
6605
6634
 
6606
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/compose/resolve-flow-collection.js
6635
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-flow-collection.js
6607
6636
  var require_resolve_flow_collection = __commonJS((exports) => {
6608
6637
  var identity = require_identity();
6609
6638
  var Pair = require_Pair();
@@ -6794,7 +6823,7 @@ var require_resolve_flow_collection = __commonJS((exports) => {
6794
6823
  exports.resolveFlowCollection = resolveFlowCollection;
6795
6824
  });
6796
6825
 
6797
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/compose/compose-collection.js
6826
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/compose-collection.js
6798
6827
  var require_compose_collection = __commonJS((exports) => {
6799
6828
  var identity = require_identity();
6800
6829
  var Scalar = require_Scalar();
@@ -6856,7 +6885,7 @@ var require_compose_collection = __commonJS((exports) => {
6856
6885
  exports.composeCollection = composeCollection;
6857
6886
  });
6858
6887
 
6859
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/compose/resolve-block-scalar.js
6888
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-block-scalar.js
6860
6889
  var require_resolve_block_scalar = __commonJS((exports) => {
6861
6890
  var Scalar = require_Scalar();
6862
6891
  function resolveBlockScalar(ctx, scalar, onError) {
@@ -7049,7 +7078,7 @@ var require_resolve_block_scalar = __commonJS((exports) => {
7049
7078
  exports.resolveBlockScalar = resolveBlockScalar;
7050
7079
  });
7051
7080
 
7052
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/compose/resolve-flow-scalar.js
7081
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-flow-scalar.js
7053
7082
  var require_resolve_flow_scalar = __commonJS((exports) => {
7054
7083
  var Scalar = require_Scalar();
7055
7084
  var resolveEnd = require_resolve_end();
@@ -7265,7 +7294,7 @@ var require_resolve_flow_scalar = __commonJS((exports) => {
7265
7294
  exports.resolveFlowScalar = resolveFlowScalar;
7266
7295
  });
7267
7296
 
7268
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/compose/compose-scalar.js
7297
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/compose-scalar.js
7269
7298
  var require_compose_scalar = __commonJS((exports) => {
7270
7299
  var identity = require_identity();
7271
7300
  var Scalar = require_Scalar();
@@ -7343,7 +7372,7 @@ var require_compose_scalar = __commonJS((exports) => {
7343
7372
  exports.composeScalar = composeScalar;
7344
7373
  });
7345
7374
 
7346
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/compose/util-empty-scalar-position.js
7375
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/util-empty-scalar-position.js
7347
7376
  var require_util_empty_scalar_position = __commonJS((exports) => {
7348
7377
  function emptyScalarPosition(offset, before, pos) {
7349
7378
  if (before) {
@@ -7370,7 +7399,7 @@ var require_util_empty_scalar_position = __commonJS((exports) => {
7370
7399
  exports.emptyScalarPosition = emptyScalarPosition;
7371
7400
  });
7372
7401
 
7373
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/compose/compose-node.js
7402
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/compose-node.js
7374
7403
  var require_compose_node = __commonJS((exports) => {
7375
7404
  var Alias = require_Alias();
7376
7405
  var identity = require_identity();
@@ -7401,17 +7430,22 @@ var require_compose_node = __commonJS((exports) => {
7401
7430
  case "block-map":
7402
7431
  case "block-seq":
7403
7432
  case "flow-collection":
7404
- node = composeCollection.composeCollection(CN, ctx, token, props, onError);
7405
- if (anchor)
7406
- node.anchor = anchor.source.substring(1);
7433
+ try {
7434
+ node = composeCollection.composeCollection(CN, ctx, token, props, onError);
7435
+ if (anchor)
7436
+ node.anchor = anchor.source.substring(1);
7437
+ } catch (error) {
7438
+ const message = error instanceof Error ? error.message : String(error);
7439
+ onError(token, "RESOURCE_EXHAUSTION", message);
7440
+ }
7407
7441
  break;
7408
7442
  default: {
7409
7443
  const message = token.type === "error" ? token.message : `Unsupported token (type: ${token.type})`;
7410
7444
  onError(token, "UNEXPECTED_TOKEN", message);
7411
- node = composeEmptyNode(ctx, token.offset, undefined, null, props, onError);
7412
7445
  isSrcToken = false;
7413
7446
  }
7414
7447
  }
7448
+ node ?? (node = composeEmptyNode(ctx, token.offset, undefined, null, props, onError));
7415
7449
  if (anchor && node.anchor === "")
7416
7450
  onError(anchor, "BAD_ALIAS", "Anchor cannot be an empty string");
7417
7451
  if (atKey && ctx.options.stringKeys && (!identity.isScalar(node) || typeof node.value !== "string" || node.tag && node.tag !== "tag:yaml.org,2002:str")) {
@@ -7468,7 +7502,7 @@ var require_compose_node = __commonJS((exports) => {
7468
7502
  exports.composeNode = composeNode;
7469
7503
  });
7470
7504
 
7471
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/compose/compose-doc.js
7505
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/compose-doc.js
7472
7506
  var require_compose_doc = __commonJS((exports) => {
7473
7507
  var Document = require_Document();
7474
7508
  var composeNode = require_compose_node();
@@ -7508,7 +7542,7 @@ var require_compose_doc = __commonJS((exports) => {
7508
7542
  exports.composeDoc = composeDoc;
7509
7543
  });
7510
7544
 
7511
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/compose/composer.js
7545
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/composer.js
7512
7546
  var require_composer = __commonJS((exports) => {
7513
7547
  var node_process = __require("process");
7514
7548
  var directives = require_directives();
@@ -7697,7 +7731,7 @@ ${end.comment}` : end.comment;
7697
7731
  exports.Composer = Composer;
7698
7732
  });
7699
7733
 
7700
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/parse/cst-scalar.js
7734
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/cst-scalar.js
7701
7735
  var require_cst_scalar = __commonJS((exports) => {
7702
7736
  var resolveBlockScalar = require_resolve_block_scalar();
7703
7737
  var resolveFlowScalar = require_resolve_flow_scalar();
@@ -7887,7 +7921,7 @@ var require_cst_scalar = __commonJS((exports) => {
7887
7921
  exports.setScalarValue = setScalarValue;
7888
7922
  });
7889
7923
 
7890
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/parse/cst-stringify.js
7924
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/cst-stringify.js
7891
7925
  var require_cst_stringify = __commonJS((exports) => {
7892
7926
  var stringify = (cst) => ("type" in cst) ? stringifyToken(cst) : stringifyItem(cst);
7893
7927
  function stringifyToken(token) {
@@ -7945,7 +7979,7 @@ var require_cst_stringify = __commonJS((exports) => {
7945
7979
  exports.stringify = stringify;
7946
7980
  });
7947
7981
 
7948
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/parse/cst-visit.js
7982
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/cst-visit.js
7949
7983
  var require_cst_visit = __commonJS((exports) => {
7950
7984
  var BREAK = Symbol("break visit");
7951
7985
  var SKIP = Symbol("skip children");
@@ -8004,7 +8038,7 @@ var require_cst_visit = __commonJS((exports) => {
8004
8038
  exports.visit = visit;
8005
8039
  });
8006
8040
 
8007
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/parse/cst.js
8041
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/cst.js
8008
8042
  var require_cst = __commonJS((exports) => {
8009
8043
  var cstScalar = require_cst_scalar();
8010
8044
  var cstStringify = require_cst_stringify();
@@ -8105,7 +8139,7 @@ var require_cst = __commonJS((exports) => {
8105
8139
  exports.tokenType = tokenType;
8106
8140
  });
8107
8141
 
8108
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/parse/lexer.js
8142
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/lexer.js
8109
8143
  var require_lexer = __commonJS((exports) => {
8110
8144
  var cst = require_cst();
8111
8145
  function isEmpty(ch) {
@@ -8691,7 +8725,7 @@ var require_lexer = __commonJS((exports) => {
8691
8725
  exports.Lexer = Lexer;
8692
8726
  });
8693
8727
 
8694
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/parse/line-counter.js
8728
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/line-counter.js
8695
8729
  var require_line_counter = __commonJS((exports) => {
8696
8730
  class LineCounter {
8697
8731
  constructor() {
@@ -8719,7 +8753,7 @@ var require_line_counter = __commonJS((exports) => {
8719
8753
  exports.LineCounter = LineCounter;
8720
8754
  });
8721
8755
 
8722
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/parse/parser.js
8756
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/parser.js
8723
8757
  var require_parser = __commonJS((exports) => {
8724
8758
  var node_process = __require("process");
8725
8759
  var cst = require_cst();
@@ -9568,7 +9602,7 @@ var require_parser = __commonJS((exports) => {
9568
9602
  exports.Parser = Parser;
9569
9603
  });
9570
9604
 
9571
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/public-api.js
9605
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/public-api.js
9572
9606
  var require_public_api = __commonJS((exports) => {
9573
9607
  var composer = require_composer();
9574
9608
  var Document = require_Document();
@@ -9662,7 +9696,7 @@ var require_public_api = __commonJS((exports) => {
9662
9696
  exports.stringify = stringify;
9663
9697
  });
9664
9698
 
9665
- // node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/index.js
9699
+ // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/index.js
9666
9700
  var composer, Document, Schema, errors, Alias, identity, Pair, Scalar, YAMLMap, YAMLSeq, cst, lexer, lineCounter, parser, publicApi, visit, $Composer, $Document, $Schema, $YAMLError, $YAMLParseError, $YAMLWarning, $Alias, $isAlias, $isCollection, $isDocument, $isMap, $isNode, $isPair, $isScalar, $isSeq, $Pair, $Scalar, $YAMLMap, $YAMLSeq, $Lexer, $LineCounter, $Parser, $parse, $parseAllDocuments, $parseDocument, $stringify, $visit, $visitAsync;
9667
9701
  var init_dist3 = __esm(() => {
9668
9702
  composer = require_composer();
@@ -9770,6 +9804,9 @@ function parsePane(raw, index) {
9770
9804
  if (typeof raw.command !== "string" || !raw.command.trim())
9771
9805
  return null;
9772
9806
  pane.command = raw.command.trim();
9807
+ if (typeof raw.workingDir === "string" && raw.workingDir.trim()) {
9808
+ pane.workingDir = raw.workingDir.trim();
9809
+ }
9773
9810
  }
9774
9811
  return pane;
9775
9812
  }
@@ -9867,6 +9904,13 @@ function parseAutoName(raw) {
9867
9904
  ...typeof raw.system_prompt === "string" && raw.system_prompt.trim() ? { systemPrompt: raw.system_prompt.trim() } : {}
9868
9905
  };
9869
9906
  }
9907
+ function parseAutoPull(raw) {
9908
+ if (!isRecord3(raw))
9909
+ return DEFAULT_CONFIG.workspace.autoPull;
9910
+ const enabled = typeof raw.enabled === "boolean" ? raw.enabled : false;
9911
+ const interval = typeof raw.intervalSeconds === "number" && Number.isFinite(raw.intervalSeconds) && raw.intervalSeconds >= 30 ? raw.intervalSeconds : 300;
9912
+ return { enabled, intervalSeconds: interval };
9913
+ }
9870
9914
  function parseLinkedRepos(raw) {
9871
9915
  if (!Array.isArray(raw))
9872
9916
  return [];
@@ -9900,17 +9944,22 @@ function parseProjectConfig(parsed) {
9900
9944
  workspace: {
9901
9945
  mainBranch: isRecord3(parsed.workspace) && typeof parsed.workspace.mainBranch === "string" ? parsed.workspace.mainBranch : DEFAULT_CONFIG.workspace.mainBranch,
9902
9946
  worktreeRoot: isRecord3(parsed.workspace) && typeof parsed.workspace.worktreeRoot === "string" ? parsed.workspace.worktreeRoot : DEFAULT_CONFIG.workspace.worktreeRoot,
9903
- defaultAgent: isRecord3(parsed.workspace) ? parseAgentKind(parsed.workspace.defaultAgent) : DEFAULT_CONFIG.workspace.defaultAgent
9947
+ defaultAgent: isRecord3(parsed.workspace) ? parseAgentKind(parsed.workspace.defaultAgent) : DEFAULT_CONFIG.workspace.defaultAgent,
9948
+ autoPull: isRecord3(parsed.workspace) ? parseAutoPull(parsed.workspace.autoPull) : DEFAULT_CONFIG.workspace.autoPull
9904
9949
  },
9905
9950
  profiles: parseProfiles(parsed.profiles, true),
9906
9951
  services: parseServices(parsed.services),
9907
9952
  startupEnvs: parseStartupEnvs(parsed.startupEnvs),
9908
9953
  integrations: {
9909
9954
  github: {
9910
- linkedRepos: isRecord3(parsed.integrations) && isRecord3(parsed.integrations.github) ? parseLinkedRepos(parsed.integrations.github.linkedRepos) : isRecord3(parsed.integrations) && Array.isArray(parsed.integrations.github) ? parseLinkedRepos(parsed.integrations.github) : []
9955
+ linkedRepos: isRecord3(parsed.integrations) && isRecord3(parsed.integrations.github) ? parseLinkedRepos(parsed.integrations.github.linkedRepos) : isRecord3(parsed.integrations) && Array.isArray(parsed.integrations.github) ? parseLinkedRepos(parsed.integrations.github) : [],
9956
+ autoRemoveOnMerge: isRecord3(parsed.integrations) && isRecord3(parsed.integrations.github) && typeof parsed.integrations.github.autoRemoveOnMerge === "boolean" ? parsed.integrations.github.autoRemoveOnMerge : DEFAULT_CONFIG.integrations.github.autoRemoveOnMerge
9911
9957
  },
9912
9958
  linear: {
9913
- enabled: isRecord3(parsed.integrations) && isRecord3(parsed.integrations.linear) && typeof parsed.integrations.linear.enabled === "boolean" ? parsed.integrations.linear.enabled : DEFAULT_CONFIG.integrations.linear.enabled
9959
+ enabled: isRecord3(parsed.integrations) && isRecord3(parsed.integrations.linear) && typeof parsed.integrations.linear.enabled === "boolean" ? parsed.integrations.linear.enabled : DEFAULT_CONFIG.integrations.linear.enabled,
9960
+ autoCreateWorktrees: isRecord3(parsed.integrations) && isRecord3(parsed.integrations.linear) && typeof parsed.integrations.linear.autoCreateWorktrees === "boolean" ? parsed.integrations.linear.autoCreateWorktrees : DEFAULT_CONFIG.integrations.linear.autoCreateWorktrees,
9961
+ createTicketOption: isRecord3(parsed.integrations) && isRecord3(parsed.integrations.linear) && typeof parsed.integrations.linear.createTicketOption === "boolean" ? parsed.integrations.linear.createTicketOption : DEFAULT_CONFIG.integrations.linear.createTicketOption,
9962
+ ...isRecord3(parsed.integrations) && isRecord3(parsed.integrations.linear) && typeof parsed.integrations.linear.teamId === "string" && parsed.integrations.linear.teamId.trim() ? { teamId: parsed.integrations.linear.teamId.trim() } : {}
9914
9963
  }
9915
9964
  },
9916
9965
  lifecycleHooks: parseLifecycleHooks(parsed.lifecycleHooks),
@@ -9920,21 +9969,66 @@ function parseProjectConfig(parsed) {
9920
9969
  function defaultConfig() {
9921
9970
  return parseProjectConfig({});
9922
9971
  }
9972
+ function parseLocalLinearOverlay(parsed) {
9973
+ if (!isRecord3(parsed.integrations))
9974
+ return null;
9975
+ const linear = parsed.integrations.linear;
9976
+ if (!isRecord3(linear))
9977
+ return null;
9978
+ const overlay = {};
9979
+ if (typeof linear.enabled === "boolean")
9980
+ overlay.enabled = linear.enabled;
9981
+ if (typeof linear.autoCreateWorktrees === "boolean")
9982
+ overlay.autoCreateWorktrees = linear.autoCreateWorktrees;
9983
+ if (typeof linear.createTicketOption === "boolean")
9984
+ overlay.createTicketOption = linear.createTicketOption;
9985
+ if (typeof linear.teamId === "string" && linear.teamId.trim())
9986
+ overlay.teamId = linear.teamId.trim();
9987
+ return Object.keys(overlay).length > 0 ? overlay : null;
9988
+ }
9989
+ function parseLocalGitHubOverlay(parsed) {
9990
+ if (!isRecord3(parsed.integrations))
9991
+ return null;
9992
+ const github = parsed.integrations.github;
9993
+ if (!isRecord3(github))
9994
+ return null;
9995
+ const overlay = {};
9996
+ if (typeof github.autoRemoveOnMerge === "boolean")
9997
+ overlay.autoRemoveOnMerge = github.autoRemoveOnMerge;
9998
+ return Object.keys(overlay).length > 0 ? overlay : null;
9999
+ }
10000
+ function parseLocalAutoPullOverlay(parsed) {
10001
+ if (!isRecord3(parsed.workspace))
10002
+ return null;
10003
+ const autoPull = parsed.workspace.autoPull;
10004
+ if (!isRecord3(autoPull))
10005
+ return null;
10006
+ const overlay = {};
10007
+ if (typeof autoPull.enabled === "boolean")
10008
+ overlay.enabled = autoPull.enabled;
10009
+ if (typeof autoPull.intervalSeconds === "number" && Number.isFinite(autoPull.intervalSeconds) && autoPull.intervalSeconds >= 30) {
10010
+ overlay.intervalSeconds = autoPull.intervalSeconds;
10011
+ }
10012
+ return Object.keys(overlay).length > 0 ? overlay : null;
10013
+ }
9923
10014
  function loadLocalProjectConfigOverlay(root) {
9924
10015
  try {
9925
10016
  const text = readLocalConfigFile(root).trim();
9926
10017
  if (!text) {
9927
- return { worktreeRoot: null, profiles: {}, lifecycleHooks: {} };
10018
+ return { worktreeRoot: null, profiles: {}, lifecycleHooks: {}, linear: null, github: null, autoPull: null };
9928
10019
  }
9929
10020
  const parsed = parseConfigDocument(text);
9930
10021
  const ws = isRecord3(parsed.workspace) ? parsed.workspace : null;
9931
10022
  return {
9932
10023
  worktreeRoot: ws && typeof ws.worktreeRoot === "string" ? ws.worktreeRoot : null,
9933
10024
  profiles: parseProfiles(parsed.profiles, false),
9934
- lifecycleHooks: parseLifecycleHooks(parsed.lifecycleHooks)
10025
+ lifecycleHooks: parseLifecycleHooks(parsed.lifecycleHooks),
10026
+ linear: parseLocalLinearOverlay(parsed),
10027
+ github: parseLocalGitHubOverlay(parsed),
10028
+ autoPull: parseLocalAutoPullOverlay(parsed)
9935
10029
  };
9936
10030
  } catch {
9937
- return { worktreeRoot: null, profiles: {}, lifecycleHooks: {} };
10031
+ return { worktreeRoot: null, profiles: {}, lifecycleHooks: {}, linear: null, github: null, autoPull: null };
9938
10032
  }
9939
10033
  }
9940
10034
  function mergeHookCommand(projectCommand, localCommand) {
@@ -9976,16 +10070,26 @@ function loadConfig(dir, options = {}) {
9976
10070
  projectConfig = defaultConfig();
9977
10071
  }
9978
10072
  const localOverlay = loadLocalProjectConfigOverlay(root);
10073
+ const workspace = localOverlay.worktreeRoot !== null || localOverlay.autoPull ? {
10074
+ ...projectConfig.workspace,
10075
+ ...localOverlay.worktreeRoot !== null ? { worktreeRoot: localOverlay.worktreeRoot } : {},
10076
+ ...localOverlay.autoPull ? { autoPull: { ...projectConfig.workspace.autoPull, ...localOverlay.autoPull } } : {}
10077
+ } : projectConfig.workspace;
10078
+ const hasIntegrationOverlay = localOverlay.linear || localOverlay.github;
10079
+ const integrations = hasIntegrationOverlay ? {
10080
+ ...projectConfig.integrations,
10081
+ ...localOverlay.linear ? { linear: { ...projectConfig.integrations.linear, ...localOverlay.linear } } : {},
10082
+ ...localOverlay.github ? { github: { ...projectConfig.integrations.github, ...localOverlay.github } } : {}
10083
+ } : projectConfig.integrations;
9979
10084
  return {
9980
10085
  ...projectConfig,
9981
- ...localOverlay.worktreeRoot !== null ? {
9982
- workspace: { ...projectConfig.workspace, worktreeRoot: localOverlay.worktreeRoot }
9983
- } : {},
10086
+ workspace,
9984
10087
  profiles: {
9985
10088
  ...cloneProfiles(projectConfig.profiles),
9986
10089
  ...cloneProfiles(localOverlay.profiles)
9987
10090
  },
9988
- lifecycleHooks: mergeLifecycleHooks(projectConfig.lifecycleHooks, localOverlay.lifecycleHooks)
10091
+ lifecycleHooks: mergeLifecycleHooks(projectConfig.lifecycleHooks, localOverlay.lifecycleHooks),
10092
+ integrations
9989
10093
  };
9990
10094
  }
9991
10095
  function expandTemplate(template, env) {
@@ -10003,7 +10107,8 @@ var init_config = __esm(() => {
10003
10107
  workspace: {
10004
10108
  mainBranch: "main",
10005
10109
  worktreeRoot: "../worktrees",
10006
- defaultAgent: "claude"
10110
+ defaultAgent: "claude",
10111
+ autoPull: { enabled: false, intervalSeconds: 300 }
10007
10112
  },
10008
10113
  profiles: {
10009
10114
  default: {
@@ -10015,8 +10120,8 @@ var init_config = __esm(() => {
10015
10120
  services: [],
10016
10121
  startupEnvs: {},
10017
10122
  integrations: {
10018
- github: { linkedRepos: [] },
10019
- linear: { enabled: true }
10123
+ github: { linkedRepos: [], autoRemoveOnMerge: false },
10124
+ linear: { enabled: true, autoCreateWorktrees: false, createTicketOption: false }
10020
10125
  },
10021
10126
  lifecycleHooks: {},
10022
10127
  autoName: null
@@ -10360,8 +10465,8 @@ class BunLifecycleHookRunner {
10360
10465
  }
10361
10466
  async run(input) {
10362
10467
  const cmd = await this.buildCommand(input.cwd, input.command);
10363
- console.debug(`[hook-runner] Spawning: ${cmd.join(" ")} cwd=${input.cwd}`);
10364
- console.debug(`[hook-runner] Env keys: ${Object.keys(input.env).join(", ")}`);
10468
+ log.debug(`[hook-runner] Spawning: ${cmd.join(" ")} cwd=${input.cwd}`);
10469
+ log.debug(`[hook-runner] envKeys=${Object.keys(input.env).length}`);
10365
10470
  const proc = Bun.spawn(cmd, {
10366
10471
  cwd: input.cwd,
10367
10472
  env: {
@@ -10376,17 +10481,19 @@ class BunLifecycleHookRunner {
10376
10481
  new Response(proc.stdout).text(),
10377
10482
  new Response(proc.stderr).text()
10378
10483
  ]);
10379
- console.debug(`[hook-runner] ${input.name} exitCode=${exitCode}`);
10484
+ log.debug(`[hook-runner] ${input.name} exitCode=${exitCode}`);
10380
10485
  if (stdout.trim())
10381
- console.debug(`[hook-runner] stdout: ${stdout.trim()}`);
10486
+ log.debug(`[hook-runner] stdout: ${stdout.trim()}`);
10382
10487
  if (stderr.trim())
10383
- console.debug(`[hook-runner] stderr: ${stderr.trim()}`);
10488
+ log.debug(`[hook-runner] stderr: ${stderr.trim()}`);
10384
10489
  if (exitCode !== 0) {
10385
10490
  throw new Error(buildErrorMessage(input.name, exitCode, stdout, stderr));
10386
10491
  }
10387
10492
  }
10388
10493
  }
10389
- var init_hooks = () => {};
10494
+ var init_hooks = __esm(() => {
10495
+ init_log();
10496
+ });
10390
10497
 
10391
10498
  // backend/src/adapters/port-probe.ts
10392
10499
  class BunPortProbe {
@@ -10891,20 +10998,31 @@ function buildDockerAgentPaneCommand(input) {
10891
10998
  }
10892
10999
 
10893
11000
  // backend/src/services/session-service.ts
11001
+ import { resolve as resolve5 } from "path";
11002
+ function quoteShell2(value) {
11003
+ return `'${value.replaceAll("'", "'\\''")}'`;
11004
+ }
10894
11005
  function resolvePaneCwd(template, ctx) {
10895
11006
  return template.cwd === "repo" ? ctx.repoRoot : ctx.worktreePath;
10896
11007
  }
10897
- function resolvePaneStartupCommand(template, commands) {
11008
+ function buildCommandPaneStartupCommand(template, ctx) {
11009
+ if (!template.command) {
11010
+ throw new Error(`Pane "${template.id}" is kind=command but has no command`);
11011
+ }
11012
+ if (!template.workingDir) {
11013
+ return template.command;
11014
+ }
11015
+ const workingDir = resolve5(resolvePaneCwd(template, ctx), template.workingDir);
11016
+ return `cd -- ${quoteShell2(workingDir)} && ${template.command}`;
11017
+ }
11018
+ function resolvePaneStartupCommand(template, ctx) {
10898
11019
  switch (template.kind) {
10899
11020
  case "agent":
10900
- return commands.agent;
11021
+ return ctx.paneCommands.agent;
10901
11022
  case "shell":
10902
11023
  return;
10903
11024
  case "command":
10904
- if (!template.command) {
10905
- throw new Error(`Pane "${template.id}" is kind=command but has no command`);
10906
- }
10907
- return template.command;
11025
+ return buildCommandPaneStartupCommand(template, ctx);
10908
11026
  }
10909
11027
  }
10910
11028
  function planSessionLayout(projectRoot2, branch, templates, ctx) {
@@ -10912,7 +11030,7 @@ function planSessionLayout(projectRoot2, branch, templates, ctx) {
10912
11030
  throw new Error("At least one pane template is required");
10913
11031
  }
10914
11032
  const panes = templates.map((template, index) => {
10915
- const startupCommand = resolvePaneStartupCommand(template, ctx.paneCommands);
11033
+ const startupCommand = resolvePaneStartupCommand(template, ctx);
10916
11034
  return {
10917
11035
  id: template.id,
10918
11036
  index,
@@ -11025,6 +11143,7 @@ async function initializeManagedWorktree(opts) {
11025
11143
  schemaVersion: WORKTREE_META_SCHEMA_VERSION,
11026
11144
  worktreeId: opts.worktreeId ?? randomUUID(),
11027
11145
  branch: opts.branch,
11146
+ ...opts.baseBranch ? { baseBranch: opts.baseBranch } : {},
11028
11147
  createdAt,
11029
11148
  profile: opts.profile,
11030
11149
  agent: opts.agent,
@@ -11071,6 +11190,7 @@ async function createManagedWorktree(opts, deps2 = {}) {
11071
11190
  const initialized = await initializeManagedWorktree({
11072
11191
  gitDir,
11073
11192
  branch: opts.branch,
11193
+ baseBranch: opts.baseBranch,
11074
11194
  profile: opts.profile,
11075
11195
  agent: opts.agent,
11076
11196
  runtime: opts.runtime,
@@ -11125,7 +11245,7 @@ var init_worktree_service = __esm(() => {
11125
11245
  // backend/src/services/lifecycle-service.ts
11126
11246
  import { randomUUID as randomUUID2 } from "crypto";
11127
11247
  import { mkdir as mkdir4 } from "fs/promises";
11128
- import { dirname as dirname5, resolve as resolve5 } from "path";
11248
+ import { dirname as dirname5, resolve as resolve6 } from "path";
11129
11249
  function generateBranchName() {
11130
11250
  return `change-${randomUUID2().slice(0, 8)}`;
11131
11251
  }
@@ -11143,19 +11263,34 @@ class LifecycleService {
11143
11263
  }
11144
11264
  async createWorktree(input) {
11145
11265
  const mode = input.mode ?? "new";
11266
+ const requestedBaseBranch = input.baseBranch?.trim();
11267
+ if (requestedBaseBranch && !isValidBranchName(requestedBaseBranch)) {
11268
+ throw new LifecycleError("Invalid base branch name", 400);
11269
+ }
11270
+ if (requestedBaseBranch && mode === "existing") {
11271
+ throw new LifecycleError("Base branch is only supported for new worktrees", 400);
11272
+ }
11146
11273
  const branch = await this.resolveBranch(input.branch, input.prompt, mode);
11274
+ if (requestedBaseBranch && requestedBaseBranch === branch) {
11275
+ throw new LifecycleError("Base branch must differ from branch name", 400);
11276
+ }
11277
+ const baseBranch = mode === "new" ? requestedBaseBranch || this.deps.config.workspace.mainBranch : undefined;
11147
11278
  this.ensureBranchAvailable(branch, mode);
11148
11279
  const { profileName, profile } = this.resolveProfile(input.profile);
11149
11280
  const agent = this.resolveAgent(input.agent);
11150
11281
  const worktreePath = this.resolveWorktreePath(branch);
11282
+ const createProgressBase = {
11283
+ branch,
11284
+ ...baseBranch ? { baseBranch } : {},
11285
+ path: worktreePath,
11286
+ profile: profileName,
11287
+ agent
11288
+ };
11151
11289
  const deleteBranchOnRollback = mode === "new";
11152
11290
  let initialized = null;
11153
11291
  try {
11154
11292
  await this.reportCreateProgress({
11155
- branch,
11156
- path: worktreePath,
11157
- profile: profileName,
11158
- agent,
11293
+ ...createProgressBase,
11159
11294
  phase: "creating_worktree"
11160
11295
  });
11161
11296
  await mkdir4(dirname5(worktreePath), { recursive: true });
@@ -11164,7 +11299,7 @@ class LifecycleService {
11164
11299
  worktreePath,
11165
11300
  branch,
11166
11301
  mode,
11167
- ...mode === "new" ? { baseBranch: this.deps.config.workspace.mainBranch } : {},
11302
+ ...baseBranch ? { baseBranch } : {},
11168
11303
  profile: profileName,
11169
11304
  agent,
11170
11305
  runtime: profile.runtime,
@@ -11178,10 +11313,7 @@ class LifecycleService {
11178
11313
  git: this.deps.git
11179
11314
  });
11180
11315
  await this.reportCreateProgress({
11181
- branch,
11182
- path: worktreePath,
11183
- profile: profileName,
11184
- agent,
11316
+ ...createProgressBase,
11185
11317
  phase: "running_post_create_hook"
11186
11318
  });
11187
11319
  await this.runLifecycleHook({
@@ -11196,10 +11328,7 @@ class LifecycleService {
11196
11328
  worktreePath
11197
11329
  });
11198
11330
  await this.reportCreateProgress({
11199
- branch,
11200
- path: worktreePath,
11201
- profile: profileName,
11202
- agent,
11331
+ ...createProgressBase,
11203
11332
  phase: "preparing_runtime"
11204
11333
  });
11205
11334
  await ensureAgentRuntimeArtifacts({
@@ -11207,10 +11336,7 @@ class LifecycleService {
11207
11336
  worktreePath
11208
11337
  });
11209
11338
  await this.reportCreateProgress({
11210
- branch,
11211
- path: worktreePath,
11212
- profile: profileName,
11213
- agent,
11339
+ ...createProgressBase,
11214
11340
  phase: "starting_session"
11215
11341
  });
11216
11342
  await this.materializeRuntimeSession({
@@ -11223,13 +11349,10 @@ class LifecycleService {
11223
11349
  launchMode: "fresh"
11224
11350
  });
11225
11351
  await this.reportCreateProgress({
11226
- branch,
11227
- path: worktreePath,
11228
- profile: profileName,
11229
- agent,
11352
+ ...createProgressBase,
11230
11353
  phase: "reconciling"
11231
11354
  });
11232
- await this.deps.reconciliation.reconcile(this.deps.projectRoot);
11355
+ await this.deps.reconciliation.reconcile(this.deps.projectRoot, { force: true });
11233
11356
  return {
11234
11357
  branch,
11235
11358
  worktreeId: initialized.meta.worktreeId
@@ -11264,7 +11387,7 @@ class LifecycleService {
11264
11387
  worktreePath: resolved.entry.path,
11265
11388
  launchMode
11266
11389
  });
11267
- await this.deps.reconciliation.reconcile(this.deps.projectRoot);
11390
+ await this.deps.reconciliation.reconcile(this.deps.projectRoot, { force: true });
11268
11391
  return {
11269
11392
  branch,
11270
11393
  worktreeId: initialized.meta.worktreeId
@@ -11277,7 +11400,7 @@ class LifecycleService {
11277
11400
  try {
11278
11401
  const resolved = await this.resolveExistingWorktree(branch);
11279
11402
  this.deps.tmux.killWindow(buildProjectSessionName(this.deps.projectRoot), buildWorktreeWindowName(branch));
11280
- await this.deps.reconciliation.reconcile(this.deps.projectRoot);
11403
+ await this.deps.reconciliation.reconcile(this.deps.projectRoot, { force: true });
11281
11404
  } catch (error) {
11282
11405
  throw this.wrapOperationError(error);
11283
11406
  }
@@ -11324,8 +11447,13 @@ class LifecycleService {
11324
11447
  }
11325
11448
  listAvailableBranches() {
11326
11449
  const localBranches = this.listLocalBranches().filter((branch) => isValidBranchName(branch));
11450
+ const remoteBranches = this.listRemoteBranches().filter((branch) => isValidBranchName(branch));
11327
11451
  const checkedOutBranches = this.listCheckedOutBranches();
11328
- return localBranches.filter((branch) => !checkedOutBranches.has(branch)).sort((left, right) => left.localeCompare(right)).map((name) => ({ name }));
11452
+ const allBranches = [...new Set([...localBranches, ...remoteBranches])];
11453
+ return allBranches.filter((branch) => !checkedOutBranches.has(branch)).sort((left, right) => left.localeCompare(right)).map((name) => ({ name }));
11454
+ }
11455
+ listBaseBranches() {
11456
+ return this.listLocalBranches().filter((branch) => isValidBranchName(branch)).sort((left, right) => left.localeCompare(right)).map((name) => ({ name }));
11329
11457
  }
11330
11458
  async resolveBranch(rawBranch, prompt, mode) {
11331
11459
  const explicitBranch = rawBranch?.trim();
@@ -11393,17 +11521,20 @@ class LifecycleService {
11393
11521
  return allocateServicePorts(metas, this.deps.config.services);
11394
11522
  }
11395
11523
  resolveWorktreePath(branch) {
11396
- return resolve5(this.deps.projectRoot, this.deps.config.workspace.worktreeRoot, branch);
11524
+ return resolve6(this.deps.projectRoot, this.deps.config.workspace.worktreeRoot, branch);
11397
11525
  }
11398
11526
  listLocalBranches() {
11399
- return this.deps.git.listLocalBranches(resolve5(this.deps.projectRoot));
11527
+ return this.deps.git.listLocalBranches(resolve6(this.deps.projectRoot));
11528
+ }
11529
+ listRemoteBranches() {
11530
+ return this.deps.git.listRemoteBranches(resolve6(this.deps.projectRoot));
11400
11531
  }
11401
11532
  listCheckedOutBranches() {
11402
- return new Set(this.deps.git.listWorktrees(resolve5(this.deps.projectRoot)).filter((entry) => !entry.bare && entry.branch !== null).map((entry) => entry.branch));
11533
+ return new Set(this.deps.git.listWorktrees(resolve6(this.deps.projectRoot)).filter((entry) => !entry.bare && entry.branch !== null).map((entry) => entry.branch));
11403
11534
  }
11404
11535
  listProjectWorktrees() {
11405
- const projectRoot2 = resolve5(this.deps.projectRoot);
11406
- return this.deps.git.listWorktrees(projectRoot2).filter((entry) => !entry.bare && resolve5(entry.path) !== projectRoot2);
11536
+ const projectRoot2 = resolve6(this.deps.projectRoot);
11537
+ return this.deps.git.listWorktrees(projectRoot2).filter((entry) => !entry.bare && resolve6(entry.path) !== projectRoot2);
11407
11538
  }
11408
11539
  async readManagedMetas() {
11409
11540
  const metas = await Promise.all(this.listProjectWorktrees().map(async (entry) => {
@@ -11603,15 +11734,15 @@ class LifecycleService {
11603
11734
  deleteBranch: true,
11604
11735
  deleteBranchForce: true
11605
11736
  }, this.deps.git);
11606
- await this.deps.reconciliation.reconcile(this.deps.projectRoot);
11737
+ await this.deps.reconciliation.reconcile(this.deps.projectRoot, { force: true });
11607
11738
  }
11608
11739
  async runLifecycleHook(input) {
11609
- console.debug(`[lifecycle-hook] name=${input.name} command=${input.command ?? "UNDEFINED"} meta=${input.meta ? "present" : "NULL"} cwd=${input.worktreePath}`);
11740
+ log.debug(`[lifecycle-hook] name=${input.name} command=${input.command ?? "UNDEFINED"} meta=${input.meta ? "present" : "NULL"} cwd=${input.worktreePath}`);
11610
11741
  if (!input.command || !input.meta) {
11611
- console.debug(`[lifecycle-hook] SKIPPING ${input.name}: command=${!!input.command} meta=${!!input.meta}`);
11742
+ log.debug(`[lifecycle-hook] SKIPPING ${input.name}: command=${!!input.command} meta=${!!input.meta}`);
11612
11743
  return;
11613
11744
  }
11614
- console.debug(`[lifecycle-hook] RUNNING ${input.name}: ${input.command} in ${input.worktreePath}`);
11745
+ log.debug(`[lifecycle-hook] RUNNING ${input.name}: ${input.command} in ${input.worktreePath}`);
11615
11746
  const dotenvValues = await loadDotenvLocal(input.worktreePath);
11616
11747
  await this.deps.hooks.run({
11617
11748
  name: input.name,
@@ -11621,7 +11752,7 @@ class LifecycleService {
11621
11752
  WEBMUX_WORKTREE_PATH: input.worktreePath
11622
11753
  }, dotenvValues)
11623
11754
  });
11624
- console.debug(`[lifecycle-hook] COMPLETED ${input.name}`);
11755
+ log.debug(`[lifecycle-hook] COMPLETED ${input.name}`);
11625
11756
  }
11626
11757
  async reportCreateProgress(progress) {
11627
11758
  await this.deps.onCreateProgress?.(progress);
@@ -11645,6 +11776,7 @@ var init_lifecycle_service = __esm(() => {
11645
11776
  init_policies();
11646
11777
  init_session_service();
11647
11778
  init_worktree_service();
11779
+ init_log();
11648
11780
  LifecycleError = class LifecycleError extends Error {
11649
11781
  status;
11650
11782
  constructor(message, status2) {
@@ -11655,33 +11787,14 @@ var init_lifecycle_service = __esm(() => {
11655
11787
  });
11656
11788
 
11657
11789
  // backend/src/services/notification-service.ts
11658
- function buildNotification(event, id, timestamp) {
11790
+ function eventToNotificationInput(event) {
11659
11791
  switch (event.type) {
11660
11792
  case "agent_stopped":
11661
- return {
11662
- id,
11663
- branch: event.branch,
11664
- type: "agent_stopped",
11665
- message: `Agent stopped on ${event.branch}`,
11666
- timestamp
11667
- };
11793
+ return { branch: event.branch, type: "agent_stopped", message: `Agent stopped on ${event.branch}` };
11668
11794
  case "pr_opened":
11669
- return {
11670
- id,
11671
- branch: event.branch,
11672
- type: "pr_opened",
11673
- message: `PR opened on ${event.branch}`,
11674
- url: event.url,
11675
- timestamp
11676
- };
11795
+ return { branch: event.branch, type: "pr_opened", message: `PR opened on ${event.branch}`, url: event.url };
11677
11796
  case "runtime_error":
11678
- return {
11679
- id,
11680
- branch: event.branch,
11681
- type: "runtime_error",
11682
- message: `Runtime error on ${event.branch}: ${event.message}`,
11683
- timestamp
11684
- };
11797
+ return { branch: event.branch, type: "runtime_error", message: `Runtime error on ${event.branch}: ${event.message}` };
11685
11798
  default:
11686
11799
  return null;
11687
11800
  }
@@ -11706,10 +11819,15 @@ class NotificationService {
11706
11819
  this.broadcast("dismiss", { id });
11707
11820
  return true;
11708
11821
  }
11709
- recordEvent(event, now = () => new Date) {
11710
- const notification = buildNotification(event, this.nextId, now().getTime());
11711
- if (!notification)
11712
- return null;
11822
+ notify(input) {
11823
+ const notification = {
11824
+ id: this.nextId,
11825
+ branch: input.branch,
11826
+ type: input.type,
11827
+ message: input.message,
11828
+ ...input.url ? { url: input.url } : {},
11829
+ timestamp: Date.now()
11830
+ };
11713
11831
  this.nextId += 1;
11714
11832
  this.notifications.push(notification);
11715
11833
  while (this.notifications.length > this.maxItems) {
@@ -11718,6 +11836,12 @@ class NotificationService {
11718
11836
  this.broadcast("notification", notification);
11719
11837
  return notification;
11720
11838
  }
11839
+ recordEvent(event) {
11840
+ const input = eventToNotificationInput(event);
11841
+ if (!input)
11842
+ return null;
11843
+ return this.notify(input);
11844
+ }
11721
11845
  stream() {
11722
11846
  let controllerRef = null;
11723
11847
  const stream = new ReadableStream({
@@ -11767,6 +11891,7 @@ function makeDefaultState(input) {
11767
11891
  return {
11768
11892
  worktreeId: input.worktreeId,
11769
11893
  branch: input.branch,
11894
+ baseBranch: input.baseBranch ?? null,
11770
11895
  path: input.path,
11771
11896
  profile: input.profile ?? null,
11772
11897
  agentName: input.agentName ?? null,
@@ -11811,6 +11936,8 @@ class ProjectRuntime {
11811
11936
  this.reindexBranch(existing.branch, input.branch, input.worktreeId);
11812
11937
  existing.path = input.path;
11813
11938
  existing.branch = input.branch;
11939
+ if (input.baseBranch !== undefined)
11940
+ existing.baseBranch = input.baseBranch;
11814
11941
  existing.profile = input.profile ?? existing.profile;
11815
11942
  existing.agentName = input.agentName ?? existing.agentName;
11816
11943
  if (input.runtime)
@@ -11925,10 +12052,25 @@ var init_project_runtime = __esm(() => {
11925
12052
  init_tmux();
11926
12053
  });
11927
12054
 
12055
+ // backend/src/lib/async.ts
12056
+ async function mapWithConcurrency(items, limit, fn) {
12057
+ const results = new Array(items.length);
12058
+ let next = 0;
12059
+ const concurrency = Math.max(1, Math.min(limit, items.length || 1));
12060
+ async function worker() {
12061
+ while (next < items.length) {
12062
+ const index = next++;
12063
+ results[index] = await fn(items[index]);
12064
+ }
12065
+ }
12066
+ await Promise.all(Array.from({ length: concurrency }, () => worker()));
12067
+ return results;
12068
+ }
12069
+
11928
12070
  // backend/src/services/reconciliation-service.ts
11929
- import { basename as basename4, resolve as resolve6 } from "path";
12071
+ import { basename as basename4, resolve as resolve7 } from "path";
11930
12072
  function makeUnmanagedWorktreeId(path) {
11931
- return `unmanaged:${resolve6(path)}`;
12073
+ return `unmanaged:${resolve7(path)}`;
11932
12074
  }
11933
12075
  function isValidPort2(port) {
11934
12076
  return port !== null && Number.isInteger(port) && port >= 1 && port <= 65535;
@@ -11967,11 +12109,34 @@ function resolveBranch(entry, metaBranch) {
11967
12109
 
11968
12110
  class ReconciliationService {
11969
12111
  deps;
11970
- constructor(deps2) {
12112
+ freshnessMs;
12113
+ now;
12114
+ concurrency;
12115
+ inFlight = null;
12116
+ lastReconciledAt = 0;
12117
+ constructor(deps2, options = {}) {
11971
12118
  this.deps = deps2;
12119
+ this.freshnessMs = options.freshnessMs ?? 500;
12120
+ this.now = options.now ?? Date.now;
12121
+ this.concurrency = options.concurrency ?? 4;
12122
+ }
12123
+ async reconcile(repoRoot, options = {}) {
12124
+ if (this.inFlight) {
12125
+ return await this.inFlight;
12126
+ }
12127
+ if (!options.force && this.now() - this.lastReconciledAt < this.freshnessMs) {
12128
+ return;
12129
+ }
12130
+ const normalizedRepoRoot = resolve7(repoRoot);
12131
+ const reconcilePromise = this.runReconcile(normalizedRepoRoot).then(() => {
12132
+ this.lastReconciledAt = this.now();
12133
+ });
12134
+ this.inFlight = reconcilePromise.finally(() => {
12135
+ this.inFlight = null;
12136
+ });
12137
+ return await this.inFlight;
11972
12138
  }
11973
- async reconcile(repoRoot) {
11974
- const normalizedRepoRoot = resolve6(repoRoot);
12139
+ async runReconcile(normalizedRepoRoot) {
11975
12140
  const worktrees = this.deps.git.listWorktrees(normalizedRepoRoot);
11976
12141
  const sessionName = buildProjectSessionName(normalizedRepoRoot);
11977
12142
  let windows = [];
@@ -11981,40 +12146,33 @@ class ReconciliationService {
11981
12146
  windows = [];
11982
12147
  }
11983
12148
  const seenWorktreeIds = new Set;
11984
- for (const entry of worktrees) {
11985
- if (entry.bare)
11986
- continue;
11987
- if (resolve6(entry.path) === normalizedRepoRoot)
11988
- continue;
12149
+ const candidateEntries = worktrees.filter((entry) => !entry.bare && resolve7(entry.path) !== normalizedRepoRoot);
12150
+ const reconciledStates = await mapWithConcurrency(candidateEntries, this.concurrency, async (entry) => {
11989
12151
  const gitDir = this.deps.git.resolveWorktreeGitDir(entry.path);
11990
12152
  const meta = await readWorktreeMeta(gitDir);
11991
12153
  const branch = resolveBranch(entry, meta?.branch ?? null);
11992
12154
  const worktreeId = meta?.worktreeId ?? makeUnmanagedWorktreeId(entry.path);
11993
- seenWorktreeIds.add(worktreeId);
11994
- this.deps.runtime.upsertWorktree({
12155
+ const gitStatus = this.deps.git.readWorktreeStatus(entry.path);
12156
+ const window = findWindow(windows, sessionName, branch);
12157
+ return {
11995
12158
  worktreeId,
11996
12159
  branch,
12160
+ baseBranch: meta?.baseBranch ?? null,
11997
12161
  path: entry.path,
11998
12162
  profile: meta?.profile ?? null,
11999
12163
  agentName: meta?.agent ?? null,
12000
- runtime: meta?.runtime ?? "host"
12001
- });
12002
- const gitStatus = this.deps.git.readWorktreeStatus(entry.path);
12003
- this.deps.runtime.setGitState(worktreeId, {
12004
- exists: true,
12005
- branch,
12006
- dirty: gitStatus.dirty,
12007
- aheadCount: gitStatus.aheadCount,
12008
- currentCommit: gitStatus.currentCommit
12009
- });
12010
- const window = findWindow(windows, sessionName, branch);
12011
- this.deps.runtime.setSessionState(worktreeId, {
12012
- exists: window !== null,
12013
- sessionName: window?.sessionName ?? null,
12014
- paneCount: window?.paneCount ?? 0
12015
- });
12016
- if (meta) {
12017
- this.deps.runtime.setServices(worktreeId, await buildServiceStates(this.deps, {
12164
+ runtime: meta?.runtime ?? "host",
12165
+ git: {
12166
+ dirty: gitStatus.dirty,
12167
+ aheadCount: gitStatus.aheadCount,
12168
+ currentCommit: gitStatus.currentCommit
12169
+ },
12170
+ session: {
12171
+ exists: window !== null,
12172
+ sessionName: window?.sessionName ?? null,
12173
+ paneCount: window?.paneCount ?? 0
12174
+ },
12175
+ services: meta ? await buildServiceStates(this.deps, {
12018
12176
  allocatedPorts: meta.allocatedPorts,
12019
12177
  startupEnvValues: meta.startupEnvValues,
12020
12178
  worktreeId: meta.worktreeId,
@@ -12022,11 +12180,35 @@ class ReconciliationService {
12022
12180
  profile: meta.profile,
12023
12181
  agent: meta.agent,
12024
12182
  runtime: meta.runtime
12025
- }));
12026
- } else {
12027
- this.deps.runtime.setServices(worktreeId, []);
12028
- }
12029
- this.deps.runtime.setPrs(worktreeId, await readWorktreePrs(gitDir));
12183
+ }) : [],
12184
+ prs: await readWorktreePrs(gitDir)
12185
+ };
12186
+ });
12187
+ for (const state of reconciledStates) {
12188
+ seenWorktreeIds.add(state.worktreeId);
12189
+ this.deps.runtime.upsertWorktree({
12190
+ worktreeId: state.worktreeId,
12191
+ branch: state.branch,
12192
+ baseBranch: state.baseBranch,
12193
+ path: state.path,
12194
+ profile: state.profile,
12195
+ agentName: state.agentName,
12196
+ runtime: state.runtime
12197
+ });
12198
+ this.deps.runtime.setGitState(state.worktreeId, {
12199
+ exists: true,
12200
+ branch: state.branch,
12201
+ dirty: state.git.dirty,
12202
+ aheadCount: state.git.aheadCount,
12203
+ currentCommit: state.git.currentCommit
12204
+ });
12205
+ this.deps.runtime.setSessionState(state.worktreeId, {
12206
+ exists: state.session.exists,
12207
+ sessionName: state.session.sessionName,
12208
+ paneCount: state.session.paneCount
12209
+ });
12210
+ this.deps.runtime.setServices(state.worktreeId, state.services);
12211
+ this.deps.runtime.setPrs(state.worktreeId, state.prs);
12030
12212
  }
12031
12213
  for (const state of this.deps.runtime.listWorktrees()) {
12032
12214
  if (!seenWorktreeIds.has(state.worktreeId)) {
@@ -12047,6 +12229,7 @@ class WorktreeCreationTracker {
12047
12229
  set(progress) {
12048
12230
  const next = {
12049
12231
  branch: progress.branch,
12232
+ ...progress.baseBranch ? { baseBranch: progress.baseBranch } : {},
12050
12233
  path: progress.path,
12051
12234
  profile: progress.profile,
12052
12235
  agentName: progress.agent,
@@ -12138,23 +12321,26 @@ var init_runtime = __esm(() => {
12138
12321
  var exports_worktree_commands = {};
12139
12322
  __export(exports_worktree_commands, {
12140
12323
  runWorktreeCommand: () => runWorktreeCommand,
12324
+ parseSendCommandArgs: () => parseSendCommandArgs,
12141
12325
  parseBranchCommandArgs: () => parseBranchCommandArgs,
12142
12326
  parseAddCommandArgs: () => parseAddCommandArgs,
12143
12327
  getWorktreeCommandUsage: () => getWorktreeCommandUsage
12144
12328
  });
12145
- import { basename as basename5, resolve as resolve7 } from "path";
12329
+ import { basename as basename5, resolve as resolve8 } from "path";
12146
12330
  function getWorktreeCommandUsage(command) {
12147
12331
  switch (command) {
12148
12332
  case "add":
12149
12333
  return [
12150
12334
  "Usage:",
12151
- " webmux add [branch] [--profile <name>] [--agent <claude|codex>] [--prompt <text>] [--env KEY=VALUE]",
12335
+ " webmux add [branch] [--base <branch>] [--profile <name>] [--agent <claude|codex>] [--prompt <text>] [--env KEY=VALUE] [--detach]",
12152
12336
  "",
12153
12337
  "Options:",
12338
+ " --base <branch> Base branch for a new worktree (defaults to config)",
12154
12339
  " --profile <name> Worktree profile from .webmux.yaml",
12155
12340
  " --agent <claude|codex> Agent to launch in the worktree",
12156
12341
  " --prompt <text> Initial agent prompt",
12157
12342
  " --env KEY=VALUE Runtime env override (repeatable)",
12343
+ " -d, --detach Create worktree without switching to it",
12158
12344
  " --help Show this help message"
12159
12345
  ].join(`
12160
12346
  `);
@@ -12173,6 +12359,17 @@ function getWorktreeCommandUsage(command) {
12173
12359
  case "merge":
12174
12360
  return `Usage:
12175
12361
  webmux merge <branch>`;
12362
+ case "send":
12363
+ return [
12364
+ "Usage:",
12365
+ " webmux send <branch> <prompt> [--preamble <text>]",
12366
+ "",
12367
+ "Options:",
12368
+ " --prompt <text> Prompt text (alternative to positional arg)",
12369
+ " --preamble <text> Preamble text sent before the prompt",
12370
+ " --help Show this help message"
12371
+ ].join(`
12372
+ `);
12176
12373
  case "prune":
12177
12374
  return `Usage:
12178
12375
  webmux prune`;
@@ -12208,6 +12405,7 @@ function parseAgent(value) {
12208
12405
  function parseAddCommandArgs(args) {
12209
12406
  const input = {};
12210
12407
  const envOverrides = {};
12408
+ let detach = false;
12211
12409
  for (let index = 0;index < args.length; index++) {
12212
12410
  const arg = args[index];
12213
12411
  if (!arg)
@@ -12215,12 +12413,22 @@ function parseAddCommandArgs(args) {
12215
12413
  if (arg === "--help" || arg === "-h") {
12216
12414
  return null;
12217
12415
  }
12416
+ if (arg === "--detach" || arg === "-d") {
12417
+ detach = true;
12418
+ continue;
12419
+ }
12218
12420
  if (arg === "--profile" || arg.startsWith("--profile=")) {
12219
12421
  const { value, nextIndex } = readOptionValue(args, index, "--profile");
12220
12422
  input.profile = value;
12221
12423
  index = nextIndex;
12222
12424
  continue;
12223
12425
  }
12426
+ if (arg === "--base" || arg.startsWith("--base=")) {
12427
+ const { value, nextIndex } = readOptionValue(args, index, "--base");
12428
+ input.baseBranch = value;
12429
+ index = nextIndex;
12430
+ continue;
12431
+ }
12224
12432
  if (arg === "--agent" || arg.startsWith("--agent=")) {
12225
12433
  const { value, nextIndex } = readOptionValue(args, index, "--agent");
12226
12434
  input.agent = parseAgent(value);
@@ -12254,7 +12462,7 @@ function parseAddCommandArgs(args) {
12254
12462
  if (Object.keys(envOverrides).length > 0) {
12255
12463
  input.envOverrides = envOverrides;
12256
12464
  }
12257
- return input;
12465
+ return { input, detach };
12258
12466
  }
12259
12467
  function parseBranchCommandArgs(args) {
12260
12468
  let branch = null;
@@ -12278,6 +12486,55 @@ function parseBranchCommandArgs(args) {
12278
12486
  }
12279
12487
  return branch;
12280
12488
  }
12489
+ function parseSendCommandArgs(args) {
12490
+ let branch = null;
12491
+ let text = null;
12492
+ let preamble;
12493
+ for (let index = 0;index < args.length; index++) {
12494
+ const arg = args[index];
12495
+ if (!arg)
12496
+ continue;
12497
+ if (arg === "--help" || arg === "-h") {
12498
+ return null;
12499
+ }
12500
+ if (arg === "--prompt" || arg.startsWith("--prompt=")) {
12501
+ if (text)
12502
+ throw new CommandUsageError("Cannot use --prompt with a positional prompt argument");
12503
+ const { value, nextIndex } = readOptionValue(args, index, "--prompt");
12504
+ text = value;
12505
+ index = nextIndex;
12506
+ continue;
12507
+ }
12508
+ if (arg === "--preamble" || arg.startsWith("--preamble=")) {
12509
+ const { value, nextIndex } = readOptionValue(args, index, "--preamble");
12510
+ preamble = value;
12511
+ index = nextIndex;
12512
+ continue;
12513
+ }
12514
+ if (arg.startsWith("-")) {
12515
+ throw new CommandUsageError(`Unknown option: ${arg}`);
12516
+ }
12517
+ if (!branch) {
12518
+ branch = arg;
12519
+ continue;
12520
+ }
12521
+ if (!text) {
12522
+ text = arg;
12523
+ continue;
12524
+ }
12525
+ throw new CommandUsageError(`Unexpected argument: ${arg}. Use either a positional prompt or --prompt, not both`);
12526
+ }
12527
+ if (!branch) {
12528
+ throw new CommandUsageError("Missing required argument: <branch>");
12529
+ }
12530
+ if (!isValidWorktreeName(branch)) {
12531
+ throw new CommandUsageError("Invalid worktree name");
12532
+ }
12533
+ if (!text) {
12534
+ throw new CommandUsageError("Missing required argument: <prompt>");
12535
+ }
12536
+ return { branch, text, preamble };
12537
+ }
12281
12538
  function parsePruneCommandArgs(args) {
12282
12539
  for (const arg of args) {
12283
12540
  if (arg === "--help" || arg === "-h") {
@@ -12291,8 +12548,8 @@ function parsePruneCommandArgs(args) {
12291
12548
  return true;
12292
12549
  }
12293
12550
  function listProjectWorktrees(runtime) {
12294
- const projectDir = resolve7(runtime.projectDir);
12295
- return runtime.git.listWorktrees(projectDir).filter((entry) => !entry.bare && resolve7(entry.path) !== projectDir);
12551
+ const projectDir = resolve8(runtime.projectDir);
12552
+ return runtime.git.listWorktrees(projectDir).filter((entry) => !entry.bare && resolve8(entry.path) !== projectDir);
12296
12553
  }
12297
12554
  async function defaultConfirmPrune(worktreeCount) {
12298
12555
  const response = await Rt({
@@ -12302,7 +12559,7 @@ async function defaultConfirmPrune(worktreeCount) {
12302
12559
  return !Ct(response) && response;
12303
12560
  }
12304
12561
  function defaultSwitchToTmuxWindow(projectDir, branch) {
12305
- const sessionName = buildProjectSessionName(resolve7(projectDir));
12562
+ const sessionName = buildProjectSessionName(resolve8(projectDir));
12306
12563
  const windowName = buildWorktreeWindowName(branch);
12307
12564
  const target = `${sessionName}:${windowName}`;
12308
12565
  const selectResult = Bun.spawnSync(["tmux", "select-window", "-t", target], {
@@ -12331,7 +12588,7 @@ function defaultSwitchToTmuxWindow(projectDir, branch) {
12331
12588
  }
12332
12589
  }
12333
12590
  async function listWorktrees(runtime, stdout) {
12334
- const projectDir = resolve7(runtime.projectDir);
12591
+ const projectDir = resolve8(runtime.projectDir);
12335
12592
  const entries = listProjectWorktrees(runtime);
12336
12593
  if (entries.length === 0) {
12337
12594
  stdout("No worktrees found.");
@@ -12368,8 +12625,8 @@ async function runWorktreeCommand(context, deps2 = {}) {
12368
12625
  const confirmPrune = deps2.confirmPrune ?? defaultConfirmPrune;
12369
12626
  try {
12370
12627
  if (context.command === "add") {
12371
- const input = parseAddCommandArgs(context.args);
12372
- if (!input) {
12628
+ const parsed = parseAddCommandArgs(context.args);
12629
+ if (!parsed) {
12373
12630
  stdout(getWorktreeCommandUsage("add"));
12374
12631
  return 0;
12375
12632
  }
@@ -12377,9 +12634,11 @@ async function runWorktreeCommand(context, deps2 = {}) {
12377
12634
  projectDir: context.projectDir,
12378
12635
  port: context.port
12379
12636
  });
12380
- const result = await runtime2.lifecycleService.createWorktree(input);
12637
+ const result = await runtime2.lifecycleService.createWorktree(parsed.input);
12381
12638
  stdout(`Created worktree ${result.branch}`);
12382
- switchToTmuxWindow(runtime2.projectDir, result.branch);
12639
+ if (!parsed.detach) {
12640
+ switchToTmuxWindow(runtime2.projectDir, result.branch);
12641
+ }
12383
12642
  return 0;
12384
12643
  }
12385
12644
  if (context.command === "list") {
@@ -12420,6 +12679,39 @@ async function runWorktreeCommand(context, deps2 = {}) {
12420
12679
  stdout(`Pruned ${result.removedBranches.length} worktree${result.removedBranches.length === 1 ? "" : "s"}: ${result.removedBranches.join(", ")}`);
12421
12680
  return 0;
12422
12681
  }
12682
+ if (context.command === "send") {
12683
+ const parsed = parseSendCommandArgs(context.args);
12684
+ if (!parsed) {
12685
+ stdout(getWorktreeCommandUsage("send"));
12686
+ return 0;
12687
+ }
12688
+ const url = `http://localhost:${context.port}/api/worktrees/${encodeURIComponent(parsed.branch)}/send`;
12689
+ const body = { text: parsed.text };
12690
+ if (parsed.preamble)
12691
+ body.preamble = parsed.preamble;
12692
+ let response;
12693
+ try {
12694
+ response = await fetch(url, {
12695
+ method: "POST",
12696
+ headers: { "Content-Type": "application/json" },
12697
+ body: JSON.stringify(body)
12698
+ });
12699
+ } catch {
12700
+ throw new Error(`Could not connect to webmux server on port ${context.port}. Is it running?`);
12701
+ }
12702
+ if (!response.ok) {
12703
+ const errorBody = await response.text();
12704
+ let message = `Server returned ${response.status}`;
12705
+ try {
12706
+ const json = JSON.parse(errorBody);
12707
+ if (typeof json.error === "string")
12708
+ message = json.error;
12709
+ } catch {}
12710
+ throw new Error(message);
12711
+ }
12712
+ stdout(`Sent prompt to ${parsed.branch}`);
12713
+ return 0;
12714
+ }
12423
12715
  const command = context.command;
12424
12716
  const branch = parseBranchCommandArgs(context.args);
12425
12717
  if (!branch) {
@@ -12466,13 +12758,13 @@ var init_worktree_commands = __esm(() => {
12466
12758
  });
12467
12759
 
12468
12760
  // bin/src/webmux.ts
12469
- import { resolve as resolve8, dirname as dirname6, join as join10 } from "path";
12761
+ import { resolve as resolve9, dirname as dirname6, join as join10 } from "path";
12470
12762
  import { existsSync as existsSync5 } from "fs";
12471
12763
  import { fileURLToPath } from "url";
12472
12764
  // package.json
12473
12765
  var package_default = {
12474
12766
  name: "webmux",
12475
- version: "0.18.0",
12767
+ version: "0.20.0",
12476
12768
  description: "Web dashboard for workmux \u2014 browser UI with embedded terminals, PR monitoring, and CI integration",
12477
12769
  type: "module",
12478
12770
  repository: {
@@ -12526,13 +12818,13 @@ var package_default = {
12526
12818
  };
12527
12819
 
12528
12820
  // bin/src/webmux.ts
12529
- var PKG_ROOT = resolve8(dirname6(fileURLToPath(import.meta.url)), "..");
12821
+ var PKG_ROOT = resolve9(dirname6(fileURLToPath(import.meta.url)), "..");
12530
12822
  function usage2() {
12531
12823
  console.log(`
12532
12824
  webmux \u2014 Dev dashboard for managing Git worktrees
12533
12825
 
12534
12826
  Usage:
12535
- webmux serve Start the dashboard server
12827
+ webmux serve Start the dashboard server (--app opens in app mode)
12536
12828
  webmux init Interactive project setup
12537
12829
  webmux service Manage webmux as a system service
12538
12830
  webmux update Update webmux to the latest version
@@ -12542,11 +12834,13 @@ Usage:
12542
12834
  webmux close Close a worktree session without removing it
12543
12835
  webmux remove Remove a worktree
12544
12836
  webmux merge Merge a worktree into the main branch and remove it
12837
+ webmux send Send a prompt to a running worktree agent
12545
12838
  webmux prune Remove all worktrees in the current project
12546
12839
  webmux completion Generate shell completion script (bash, zsh)
12547
12840
 
12548
12841
  Options:
12549
12842
  --port N Set port (default: 5111)
12843
+ --app Open dashboard in browser app mode (minimal window)
12550
12844
  --debug Show debug-level logs
12551
12845
  --version Show version number
12552
12846
  --help Show this help message
@@ -12556,14 +12850,15 @@ Environment:
12556
12850
  `);
12557
12851
  }
12558
12852
  function isRootCommand(value) {
12559
- return value === "serve" || value === "init" || value === "service" || value === "update" || value === "add" || value === "list" || value === "open" || value === "close" || value === "remove" || value === "merge" || value === "prune" || value === "completion";
12853
+ return value === "serve" || value === "init" || value === "service" || value === "update" || value === "add" || value === "list" || value === "open" || value === "close" || value === "remove" || value === "merge" || value === "send" || value === "prune" || value === "completion";
12560
12854
  }
12561
12855
  function isServeRootOption(value) {
12562
- return value === "--port" || value === "--debug" || value === "--help" || value === "-h" || value === "--version" || value === "-V";
12856
+ return value === "--port" || value === "--app" || value === "--debug" || value === "--help" || value === "-h" || value === "--version" || value === "-V";
12563
12857
  }
12564
12858
  function parseRootArgs(args) {
12565
12859
  let port = parseInt(process.env.PORT || "5111", 10);
12566
12860
  let debug = false;
12861
+ let app = false;
12567
12862
  let command = null;
12568
12863
  const commandArgs = [];
12569
12864
  for (let index = 0;index < args.length; index++) {
@@ -12587,6 +12882,9 @@ function parseRootArgs(args) {
12587
12882
  index += 1;
12588
12883
  break;
12589
12884
  }
12885
+ case "--app":
12886
+ app = true;
12887
+ break;
12590
12888
  case "--debug":
12591
12889
  debug = true;
12592
12890
  break;
@@ -12610,12 +12908,13 @@ Run webmux --help for usage.`);
12610
12908
  return {
12611
12909
  port,
12612
12910
  debug,
12911
+ app,
12613
12912
  command,
12614
12913
  commandArgs
12615
12914
  };
12616
12915
  }
12617
12916
  function isWorktreeCommand(command) {
12618
- return command === "add" || command === "list" || command === "open" || command === "close" || command === "remove" || command === "merge" || command === "prune";
12917
+ return command === "add" || command === "list" || command === "open" || command === "close" || command === "remove" || command === "merge" || command === "send" || command === "prune";
12619
12918
  }
12620
12919
  async function loadEnvFile(path) {
12621
12920
  if (!existsSync5(path))
@@ -12636,10 +12935,44 @@ async function loadEnvFile(path) {
12636
12935
  }
12637
12936
  }
12638
12937
  }
12639
- function pipeWithPrefix(stream, prefix) {
12938
+ function findBrowserBinary() {
12939
+ const candidates = process.platform === "darwin" ? [
12940
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
12941
+ "/Applications/Chromium.app/Contents/MacOS/Chromium",
12942
+ "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
12943
+ "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser"
12944
+ ] : [
12945
+ "google-chrome",
12946
+ "google-chrome-stable",
12947
+ "chromium",
12948
+ "chromium-browser",
12949
+ "microsoft-edge",
12950
+ "brave-browser"
12951
+ ];
12952
+ for (const candidate of candidates) {
12953
+ const found = candidate.startsWith("/") ? existsSync5(candidate) : Bun.spawnSync(["which", candidate], { stdout: "pipe", stderr: "pipe" }).success;
12954
+ if (found)
12955
+ return candidate;
12956
+ }
12957
+ return null;
12958
+ }
12959
+ function openAppMode(url) {
12960
+ const browser = findBrowserBinary();
12961
+ if (!browser) {
12962
+ console.log(`[app] No Chromium-based browser found \u2014 open ${url} manually`);
12963
+ return;
12964
+ }
12965
+ console.log(`[app] Opening ${url} in app mode`);
12966
+ Bun.spawn([browser, `--app=${url}`], {
12967
+ stdout: "ignore",
12968
+ stderr: "ignore"
12969
+ });
12970
+ }
12971
+ function pipeWithPrefix(stream, prefix, onTrigger) {
12640
12972
  const reader = stream.getReader();
12641
12973
  const decoder = new TextDecoder;
12642
12974
  let buffer = "";
12975
+ let fired = false;
12643
12976
  (async () => {
12644
12977
  while (true) {
12645
12978
  const { done, value } = await reader.read();
@@ -12651,6 +12984,10 @@ function pipeWithPrefix(stream, prefix) {
12651
12984
  buffer = lines.pop();
12652
12985
  for (const line of lines) {
12653
12986
  console.log(`${prefix} ${line}`);
12987
+ if (onTrigger && !fired && line.includes(onTrigger.text)) {
12988
+ fired = true;
12989
+ onTrigger.callback();
12990
+ }
12654
12991
  }
12655
12992
  }
12656
12993
  if (buffer) {
@@ -12694,8 +13031,8 @@ async function main(args = process.argv.slice(2)) {
12694
13031
  const code = await proc.exited;
12695
13032
  process.exit(code);
12696
13033
  }
12697
- await loadEnvFile(resolve8(process.cwd(), ".env.local"));
12698
- await loadEnvFile(resolve8(process.cwd(), ".env"));
13034
+ await loadEnvFile(resolve9(process.cwd(), ".env.local"));
13035
+ await loadEnvFile(resolve9(process.cwd(), ".env"));
12699
13036
  if (isWorktreeCommand(parsed.command)) {
12700
13037
  const { runWorktreeCommand: runWorktreeCommand2 } = await Promise.resolve().then(() => (init_worktree_commands(), exports_worktree_commands));
12701
13038
  const exitCode = await runWorktreeCommand2({
@@ -12710,7 +13047,7 @@ async function main(args = process.argv.slice(2)) {
12710
13047
  usage2();
12711
13048
  process.exit(0);
12712
13049
  }
12713
- if (!existsSync5(resolve8(process.cwd(), ".webmux.yaml"))) {
13050
+ if (!existsSync5(resolve9(process.cwd(), ".webmux.yaml"))) {
12714
13051
  console.error("No .webmux.yaml found in this directory.\nRun `webmux init` to set up your project.");
12715
13052
  process.exit(1);
12716
13053
  }
@@ -12755,7 +13092,14 @@ async function main(args = process.argv.slice(2)) {
12755
13092
  stderr: "pipe"
12756
13093
  });
12757
13094
  children.push(be);
12758
- pipeWithPrefix(be.stdout, "[BE]");
13095
+ if (parsed.app) {
13096
+ pipeWithPrefix(be.stdout, "[BE]", {
13097
+ text: "Dev Dashboard API running at",
13098
+ callback: () => openAppMode(`http://localhost:${parsed.port}`)
13099
+ });
13100
+ } else {
13101
+ pipeWithPrefix(be.stdout, "[BE]");
13102
+ }
12759
13103
  pipeWithPrefix(be.stderr, "[BE]");
12760
13104
  await be.exited;
12761
13105
  }