@mstar-harness/cli 3.6.0-alpha.3 → 3.6.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.
Files changed (2) hide show
  1. package/dist/mstar-harness.js +386 -110
  2. package/package.json +1 -1
@@ -6,22 +6,38 @@ var __getProtoOf = Object.getPrototypeOf;
6
6
  var __defProp = Object.defineProperty;
7
7
  var __getOwnPropNames = Object.getOwnPropertyNames;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ function __accessProp(key) {
10
+ return this[key];
11
+ }
12
+ var __toESMCache_node;
13
+ var __toESMCache_esm;
9
14
  var __toESM = (mod, isNodeMode, target) => {
15
+ var canCache = mod != null && typeof mod === "object";
16
+ if (canCache) {
17
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
18
+ var cached = cache.get(mod);
19
+ if (cached)
20
+ return cached;
21
+ }
10
22
  target = mod != null ? __create(__getProtoOf(mod)) : {};
11
23
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
12
- for (let key of __getOwnPropNames(mod))
13
- if (!__hasOwnProp.call(to, key))
14
- __defProp(to, key, {
15
- get: () => mod[key],
16
- enumerable: true
17
- });
24
+ if (mod && typeof mod === "object" || typeof mod === "function") {
25
+ for (let key of __getOwnPropNames(mod))
26
+ if (!__hasOwnProp.call(to, key))
27
+ __defProp(to, key, {
28
+ get: __accessProp.bind(mod, key),
29
+ enumerable: true
30
+ });
31
+ }
32
+ if (canCache)
33
+ cache.set(mod, to);
18
34
  return to;
19
35
  };
20
36
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
21
37
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
22
38
 
23
- // ../../node_modules/cli-width/index.js
24
- var require_cli_width = __commonJS((exports, module) => {
39
+ // ../../node_modules/.bun/cli-width@4.1.0/node_modules/cli-width/index.js
40
+ var require_cli_width = __commonJS(function(exports, module) {
25
41
  module.exports = cliWidth;
26
42
  function normalizeOpts(options) {
27
43
  const defaultOpts = {
@@ -60,8 +76,8 @@ var require_cli_width = __commonJS((exports, module) => {
60
76
  }
61
77
  });
62
78
 
63
- // ../../node_modules/mute-stream/lib/index.js
64
- var require_lib = __commonJS((exports, module) => {
79
+ // ../../node_modules/.bun/mute-stream@3.0.0/node_modules/mute-stream/lib/index.js
80
+ var require_lib = __commonJS(function(exports, module) {
65
81
  var Stream = __require("stream");
66
82
 
67
83
  class MuteStream extends Stream {
@@ -180,8 +196,8 @@ var require_lib = __commonJS((exports, module) => {
180
196
  module.exports = MuteStream;
181
197
  });
182
198
 
183
- // ../../node_modules/picocolors/picocolors.js
184
- var require_picocolors = __commonJS((exports, module) => {
199
+ // ../../node_modules/.bun/picocolors@1.1.1/node_modules/picocolors/picocolors.js
200
+ var require_picocolors = __commonJS(function(exports, module) {
185
201
  var p = process || {};
186
202
  var argv = p.argv || [];
187
203
  var env = p.env || {};
@@ -250,8 +266,8 @@ var require_picocolors = __commonJS((exports, module) => {
250
266
  module.exports.createColors = createColors;
251
267
  });
252
268
 
253
- // ../../node_modules/commander/lib/error.js
254
- var require_error = __commonJS((exports) => {
269
+ // ../../node_modules/.bun/commander@14.0.3/node_modules/commander/lib/error.js
270
+ var require_error = __commonJS(function(exports) {
255
271
  class CommanderError extends Error {
256
272
  constructor(exitCode, code, message) {
257
273
  super(message);
@@ -274,8 +290,8 @@ var require_error = __commonJS((exports) => {
274
290
  exports.InvalidArgumentError = InvalidArgumentError;
275
291
  });
276
292
 
277
- // ../../node_modules/commander/lib/argument.js
278
- var require_argument = __commonJS((exports) => {
293
+ // ../../node_modules/.bun/commander@14.0.3/node_modules/commander/lib/argument.js
294
+ var require_argument = __commonJS(function(exports) {
279
295
  var { InvalidArgumentError } = require_error();
280
296
 
281
297
  class Argument {
@@ -354,8 +370,8 @@ var require_argument = __commonJS((exports) => {
354
370
  exports.humanReadableArgName = humanReadableArgName;
355
371
  });
356
372
 
357
- // ../../node_modules/commander/lib/help.js
358
- var require_help = __commonJS((exports) => {
373
+ // ../../node_modules/.bun/commander@14.0.3/node_modules/commander/lib/help.js
374
+ var require_help = __commonJS(function(exports) {
359
375
  var { humanReadableArgName } = require_argument();
360
376
 
361
377
  class Help {
@@ -711,8 +727,8 @@ ${itemIndentStr}`);
711
727
  exports.stripColor = stripColor;
712
728
  });
713
729
 
714
- // ../../node_modules/commander/lib/option.js
715
- var require_option = __commonJS((exports) => {
730
+ // ../../node_modules/.bun/commander@14.0.3/node_modules/commander/lib/option.js
731
+ var require_option = __commonJS(function(exports) {
716
732
  var { InvalidArgumentError } = require_error();
717
733
 
718
734
  class Option {
@@ -895,8 +911,8 @@ var require_option = __commonJS((exports) => {
895
911
  exports.DualOptions = DualOptions;
896
912
  });
897
913
 
898
- // ../../node_modules/commander/lib/suggestSimilar.js
899
- var require_suggestSimilar = __commonJS((exports) => {
914
+ // ../../node_modules/.bun/commander@14.0.3/node_modules/commander/lib/suggestSimilar.js
915
+ var require_suggestSimilar = __commonJS(function(exports) {
900
916
  var maxDistance = 3;
901
917
  function editDistance(a, b) {
902
918
  if (Math.abs(a.length - b.length) > maxDistance)
@@ -968,8 +984,8 @@ var require_suggestSimilar = __commonJS((exports) => {
968
984
  exports.suggestSimilar = suggestSimilar;
969
985
  });
970
986
 
971
- // ../../node_modules/commander/lib/command.js
972
- var require_command = __commonJS((exports) => {
987
+ // ../../node_modules/.bun/commander@14.0.3/node_modules/commander/lib/command.js
988
+ var require_command = __commonJS(function(exports) {
973
989
  var EventEmitter = __require("node:events").EventEmitter;
974
990
  var childProcess = __require("node:child_process");
975
991
  var path2 = __require("node:path");
@@ -1222,7 +1238,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1222
1238
  this._exitCallback = (err) => {
1223
1239
  if (err.code !== "commander.executeSubCommandAsync") {
1224
1240
  throw err;
1225
- } else {}
1241
+ }
1226
1242
  };
1227
1243
  }
1228
1244
  return this;
@@ -2323,8 +2339,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
2323
2339
  exports.useColor = useColor;
2324
2340
  });
2325
2341
 
2326
- // ../../node_modules/commander/index.js
2327
- var require_commander = __commonJS((exports) => {
2342
+ // ../../node_modules/.bun/commander@14.0.3/node_modules/commander/index.js
2343
+ var require_commander = __commonJS(function(exports) {
2328
2344
  var { Argument } = require_argument();
2329
2345
  var { Command } = require_command();
2330
2346
  var { CommanderError, InvalidArgumentError } = require_error();
@@ -2343,8 +2359,8 @@ var require_commander = __commonJS((exports) => {
2343
2359
  exports.InvalidOptionArgumentError = InvalidArgumentError;
2344
2360
  });
2345
2361
 
2346
- // ../../node_modules/picocolors/picocolors.js
2347
- var require_picocolors2 = __commonJS((exports, module) => {
2362
+ // ../../node_modules/.bun/picocolors@1.1.1/node_modules/picocolors/picocolors.js
2363
+ var require_picocolors2 = __commonJS(function(exports, module) {
2348
2364
  var p = process || {};
2349
2365
  var argv = p.argv || [];
2350
2366
  var env = p.env || {};
@@ -2415,10 +2431,10 @@ var require_picocolors2 = __commonJS((exports, module) => {
2415
2431
 
2416
2432
  // src/index.ts
2417
2433
  import { execFileSync as execFileSync10 } from "child_process";
2434
+ import { createHash, randomUUID as randomUUID3 } from "crypto";
2418
2435
  import fs8 from "fs";
2419
2436
  import path12 from "path";
2420
-
2421
- // ../../node_modules/@inquirer/core/dist/lib/key.js
2437
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/key.js
2422
2438
  var keybindings = ["emacs", "vim"];
2423
2439
  var keybindingLookup = new Set(keybindings);
2424
2440
  function isKeybinding(value) {
@@ -2435,7 +2451,7 @@ var isDownKey = (key, keybindings2 = []) => key.name === "down" || keybindings2.
2435
2451
  var isBackspaceKey = (key) => key.name === "backspace";
2436
2452
  var isNumberKey = (key) => "1234567890".includes(key.name);
2437
2453
  var isEnterKey = (key) => key.name === "enter" || key.name === "return";
2438
- // ../../node_modules/@inquirer/core/dist/lib/errors.js
2454
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/errors.js
2439
2455
  class AbortPromptError extends Error {
2440
2456
  name = "AbortPromptError";
2441
2457
  message = "Prompt was aborted";
@@ -2461,10 +2477,10 @@ class HookError extends Error {
2461
2477
  class ValidationError extends Error {
2462
2478
  name = "ValidationError";
2463
2479
  }
2464
- // ../../node_modules/@inquirer/core/dist/lib/use-state.js
2480
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/use-state.js
2465
2481
  import { AsyncResource as AsyncResource2 } from "node:async_hooks";
2466
2482
 
2467
- // ../../node_modules/@inquirer/core/dist/lib/hook-engine.js
2483
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/hook-engine.js
2468
2484
  import { AsyncLocalStorage, AsyncResource } from "node:async_hooks";
2469
2485
  var hookStorage = new AsyncLocalStorage;
2470
2486
  function createStore(rl) {
@@ -2569,7 +2585,7 @@ var effectScheduler = {
2569
2585
  }
2570
2586
  };
2571
2587
 
2572
- // ../../node_modules/@inquirer/core/dist/lib/use-state.js
2588
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/use-state.js
2573
2589
  function isFactory(value) {
2574
2590
  return typeof value === "function";
2575
2591
  }
@@ -2578,7 +2594,7 @@ function isReducer(value) {
2578
2594
  }
2579
2595
  function useState(defaultValue) {
2580
2596
  return withPointer((pointer) => {
2581
- const setState = AsyncResource2.bind(function setState(newValue) {
2597
+ const setState = AsyncResource2.bind(function setState2(newValue) {
2582
2598
  const currentValue = pointer.get();
2583
2599
  const nextValue = isReducer(newValue) ? newValue(currentValue) : newValue;
2584
2600
  if (!Object.is(currentValue, nextValue)) {
@@ -2595,7 +2611,7 @@ function useState(defaultValue) {
2595
2611
  });
2596
2612
  }
2597
2613
 
2598
- // ../../node_modules/@inquirer/core/dist/lib/use-effect.js
2614
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/use-effect.js
2599
2615
  function useEffect(cb, depArray) {
2600
2616
  withPointer((pointer) => {
2601
2617
  const oldDeps = pointer.get();
@@ -2607,10 +2623,10 @@ function useEffect(cb, depArray) {
2607
2623
  });
2608
2624
  }
2609
2625
 
2610
- // ../../node_modules/@inquirer/core/dist/lib/theme.js
2626
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/theme.js
2611
2627
  import { styleText } from "node:util";
2612
2628
 
2613
- // ../../node_modules/@inquirer/figures/dist/index.js
2629
+ // ../../node_modules/.bun/@inquirer+figures@2.0.9/node_modules/@inquirer/figures/dist/index.js
2614
2630
  import process2 from "node:process";
2615
2631
  function isUnicodeSupported() {
2616
2632
  if (!process2.platform.startsWith("win")) {
@@ -2899,7 +2915,7 @@ var figures = shouldUseMain ? mainSymbols : fallbackSymbols;
2899
2915
  var dist_default = figures;
2900
2916
  var replacements = Object.entries(specialMainSymbols);
2901
2917
 
2902
- // ../../node_modules/@inquirer/core/dist/lib/theme.js
2918
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/theme.js
2903
2919
  var defaultTheme = {
2904
2920
  prefix: {
2905
2921
  idle: styleText("blue", "?"),
@@ -2927,7 +2943,7 @@ function getDefaultTheme() {
2927
2943
  };
2928
2944
  }
2929
2945
 
2930
- // ../../node_modules/@inquirer/core/dist/lib/make-theme.js
2946
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/make-theme.js
2931
2947
  function isPlainObject(value) {
2932
2948
  if (typeof value !== "object" || value === null)
2933
2949
  return false;
@@ -2955,7 +2971,7 @@ function makeTheme(...themes) {
2955
2971
  return deepMerge(...themesToMerge);
2956
2972
  }
2957
2973
 
2958
- // ../../node_modules/@inquirer/core/dist/lib/use-prefix.js
2974
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/use-prefix.js
2959
2975
  function usePrefix({ status = "idle", theme }) {
2960
2976
  const [showLoader, setShowLoader] = useState(false);
2961
2977
  const [tick, setTick] = useState(0);
@@ -2985,7 +3001,7 @@ function usePrefix({ status = "idle", theme }) {
2985
3001
  const iconName = status === "loading" ? "idle" : status;
2986
3002
  return typeof prefix === "string" ? prefix : prefix[iconName] ?? prefix["idle"];
2987
3003
  }
2988
- // ../../node_modules/@inquirer/core/dist/lib/use-memo.js
3004
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/use-memo.js
2989
3005
  function useMemo(fn, dependencies) {
2990
3006
  return withPointer((pointer) => {
2991
3007
  const prev = pointer.get();
@@ -2997,11 +3013,11 @@ function useMemo(fn, dependencies) {
2997
3013
  return prev.value;
2998
3014
  });
2999
3015
  }
3000
- // ../../node_modules/@inquirer/core/dist/lib/use-ref.js
3016
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/use-ref.js
3001
3017
  function useRef(val) {
3002
3018
  return useState({ current: val })[0];
3003
3019
  }
3004
- // ../../node_modules/@inquirer/core/dist/lib/use-keypress.js
3020
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/use-keypress.js
3005
3021
  function useKeypress(userHandler) {
3006
3022
  const signal = useRef(userHandler);
3007
3023
  signal.current = userHandler;
@@ -3019,10 +3035,10 @@ function useKeypress(userHandler) {
3019
3035
  };
3020
3036
  }, []);
3021
3037
  }
3022
- // ../../node_modules/@inquirer/core/dist/lib/utils.js
3038
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/utils.js
3023
3039
  var import_cli_width = __toESM(require_cli_width(), 1);
3024
3040
 
3025
- // ../../node_modules/fast-string-truncated-width/dist/utils.js
3041
+ // ../../node_modules/.bun/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/utils.js
3026
3042
  var getCodePointsLength = (() => {
3027
3043
  const SURROGATE_PAIR_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
3028
3044
  return (input) => {
@@ -3041,7 +3057,7 @@ var isWideNotCJKTNotEmoji = (x) => {
3041
3057
  return x === 8987 || x === 9001 || x >= 12272 && x <= 12287 || x >= 12289 && x <= 12350 || x >= 12441 && x <= 12543 || x >= 12549 && x <= 12591 || x >= 12593 && x <= 12686 || x >= 12688 && x <= 12771 || x >= 12783 && x <= 12830 || x >= 12832 && x <= 12871 || x >= 12880 && x <= 19903 || x >= 65040 && x <= 65049 || x >= 65072 && x <= 65106 || x >= 65108 && x <= 65126 || x >= 65128 && x <= 65131 || x >= 127488 && x <= 127490 || x >= 127504 && x <= 127547 || x >= 127552 && x <= 127560 || x >= 131072 && x <= 196605 || x >= 196608 && x <= 262141;
3042
3058
  };
3043
3059
 
3044
- // ../../node_modules/fast-string-truncated-width/dist/index.js
3060
+ // ../../node_modules/.bun/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/index.js
3045
3061
  var ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
3046
3062
  var CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
3047
3063
  var CJKT_WIDE_RE = /(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/yu;
@@ -3140,7 +3156,7 @@ var getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {})
3140
3156
  };
3141
3157
  var dist_default2 = getStringTruncatedWidth;
3142
3158
 
3143
- // ../../node_modules/fast-string-width/dist/index.js
3159
+ // ../../node_modules/.bun/fast-string-width@3.0.2/node_modules/fast-string-width/dist/index.js
3144
3160
  var NO_TRUNCATION2 = {
3145
3161
  limit: Infinity,
3146
3162
  ellipsis: "",
@@ -3151,7 +3167,7 @@ var fastStringWidth = (input, options = {}) => {
3151
3167
  };
3152
3168
  var dist_default3 = fastStringWidth;
3153
3169
 
3154
- // ../../node_modules/fast-wrap-ansi/lib/main.js
3170
+ // ../../node_modules/.bun/fast-wrap-ansi@0.2.2/node_modules/fast-wrap-ansi/lib/main.js
3155
3171
  var ESC = "\x1B";
3156
3172
  var CSI = "\u009b";
3157
3173
  var END_CODE = 39;
@@ -3363,7 +3379,7 @@ function wrapAnsi(string, columns, options) {
3363
3379
  `);
3364
3380
  }
3365
3381
 
3366
- // ../../node_modules/@inquirer/core/dist/lib/utils.js
3382
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/utils.js
3367
3383
  function breakLines(content, width) {
3368
3384
  return content.split(`
3369
3385
  `).flatMap((line) => wrapAnsi(line, width, { trim: false, wordWrap: false }).split(`
@@ -3374,7 +3390,7 @@ function readlineWidth() {
3374
3390
  return import_cli_width.default({ defaultWidth: 80, output: readline().output });
3375
3391
  }
3376
3392
 
3377
- // ../../node_modules/@inquirer/core/dist/lib/pagination/use-pagination.js
3393
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/pagination/use-pagination.js
3378
3394
  function usePointerPosition({ active, renderedItems, pageSize, loop }) {
3379
3395
  const state = useRef({
3380
3396
  lastPointer: active,
@@ -3440,12 +3456,12 @@ function usePagination({ items, active, renderItem, pageSize, loop = true }) {
3440
3456
  return pageBuffer.filter((line) => typeof line === "string").join(`
3441
3457
  `);
3442
3458
  }
3443
- // ../../node_modules/@inquirer/core/dist/lib/create-prompt.js
3459
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/create-prompt.js
3444
3460
  var import_mute_stream = __toESM(require_lib(), 1);
3445
3461
  import * as readline2 from "node:readline";
3446
3462
  import { AsyncResource as AsyncResource3 } from "node:async_hooks";
3447
3463
 
3448
- // ../../node_modules/signal-exit/dist/mjs/signals.js
3464
+ // ../../node_modules/.bun/signal-exit@4.1.0/node_modules/signal-exit/dist/mjs/signals.js
3449
3465
  var signals = [];
3450
3466
  signals.push("SIGHUP", "SIGINT", "SIGTERM");
3451
3467
  if (process.platform !== "win32") {
@@ -3455,7 +3471,7 @@ if (process.platform === "linux") {
3455
3471
  signals.push("SIGIO", "SIGPOLL", "SIGPWR", "SIGSTKFLT");
3456
3472
  }
3457
3473
 
3458
- // ../../node_modules/signal-exit/dist/mjs/index.js
3474
+ // ../../node_modules/.bun/signal-exit@4.1.0/node_modules/signal-exit/dist/mjs/index.js
3459
3475
  var processOk = (process3) => !!process3 && typeof process3 === "object" && typeof process3.removeListener === "function" && typeof process3.emit === "function" && typeof process3.reallyExit === "function" && typeof process3.listeners === "function" && typeof process3.kill === "function" && typeof process3.pid === "number" && typeof process3.on === "function";
3460
3476
  var kExitEmitter = Symbol.for("signal-exit emitter");
3461
3477
  var global = globalThis;
@@ -3653,10 +3669,10 @@ var {
3653
3669
  unload
3654
3670
  } = signalExitWrap(processOk(process3) ? new SignalExit(process3) : new SignalExitFallback);
3655
3671
 
3656
- // ../../node_modules/@inquirer/core/dist/lib/screen-manager.js
3672
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/screen-manager.js
3657
3673
  import { stripVTControlCharacters } from "node:util";
3658
3674
 
3659
- // ../../node_modules/@inquirer/ansi/dist/index.js
3675
+ // ../../node_modules/.bun/@inquirer+ansi@2.0.8/node_modules/@inquirer/ansi/dist/index.js
3660
3676
  var ESC2 = "\x1B[";
3661
3677
  var cursorLeft = ESC2 + "G";
3662
3678
  var cursorHide = ESC2 + "?25l";
@@ -3672,7 +3688,7 @@ var cursorTo = (x, y) => {
3672
3688
  var eraseLine = ESC2 + "2K";
3673
3689
  var eraseLines = (lines) => lines > 0 ? (eraseLine + cursorUp(1)).repeat(lines - 1) + eraseLine + cursorLeft : "";
3674
3690
 
3675
- // ../../node_modules/@inquirer/core/dist/lib/screen-manager.js
3691
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/screen-manager.js
3676
3692
  var height = (content) => content.split(`
3677
3693
  `).length;
3678
3694
  var lastLine = (content) => content.split(`
@@ -3738,7 +3754,7 @@ class ScreenManager {
3738
3754
  }
3739
3755
  }
3740
3756
 
3741
- // ../../node_modules/@inquirer/core/dist/lib/promise-polyfill.js
3757
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/promise-polyfill.js
3742
3758
  class PromisePolyfill extends Promise {
3743
3759
  static withResolver() {
3744
3760
  let resolve;
@@ -3751,7 +3767,7 @@ class PromisePolyfill extends Promise {
3751
3767
  }
3752
3768
  }
3753
3769
 
3754
- // ../../node_modules/@inquirer/core/dist/lib/create-prompt.js
3770
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/create-prompt.js
3755
3771
  import path from "node:path";
3756
3772
  var nativeSetImmediate = globalThis.setImmediate;
3757
3773
  function getCallSites() {
@@ -3862,7 +3878,7 @@ function createPrompt(view) {
3862
3878
  };
3863
3879
  return prompt;
3864
3880
  }
3865
- // ../../node_modules/@inquirer/core/dist/lib/Separator.js
3881
+ // ../../node_modules/.bun/@inquirer+core@12.0.2+1c220d1d55e2409f/node_modules/@inquirer/core/dist/lib/Separator.js
3866
3882
  import { styleText as styleText2 } from "node:util";
3867
3883
  class Separator {
3868
3884
  separator = styleText2("dim", Array.from({ length: 15 }).join(dist_default.line));
@@ -3876,7 +3892,7 @@ class Separator {
3876
3892
  return Boolean(choice && typeof choice === "object" && "type" in choice && choice.type === "separator");
3877
3893
  }
3878
3894
  }
3879
- // ../../node_modules/@inquirer/select/dist/index.js
3895
+ // ../../node_modules/.bun/@inquirer+select@5.2.4+1c220d1d55e2409f/node_modules/@inquirer/select/dist/index.js
3880
3896
  import { styleText as styleText3 } from "node:util";
3881
3897
  var selectTheme = {
3882
3898
  icon: { cursor: dist_default.pointer },
@@ -4051,7 +4067,7 @@ var dist_default4 = createPrompt((config, done) => {
4051
4067
  // src/index.ts
4052
4068
  var import_picocolors2 = __toESM(require_picocolors(), 1);
4053
4069
 
4054
- // ../../node_modules/commander/esm.mjs
4070
+ // ../../node_modules/.bun/commander@14.0.3/node_modules/commander/esm.mjs
4055
4071
  var import__ = __toESM(require_commander(), 1);
4056
4072
  var {
4057
4073
  program,
@@ -8544,6 +8560,9 @@ function prReviewSeatPrompt(opts) {
8544
8560
  if (!isAbsolute9(worktreePath)) {
8545
8561
  throw new TypeError(`prReviewSeatPrompt: worktreePath must be an absolute path - got ${JSON.stringify(opts.worktreePath)}`);
8546
8562
  }
8563
+ if (opts.diffFile !== undefined && opts.diffFile !== "" && !isAbsolute9(opts.diffFile)) {
8564
+ throw new TypeError(`prReviewSeatPrompt: diffFile must be an absolute path - got ${JSON.stringify(opts.diffFile)}`);
8565
+ }
8547
8566
  const slug = `${domain}-${seat}`;
8548
8567
  const lines = [];
8549
8568
  lines.push(`# PR review audit seat \u2014 Stage ${opts.stage}${opts.securitySeat === true ? " (security)" : ""}`);
@@ -8569,6 +8588,9 @@ function prReviewSeatPrompt(opts) {
8569
8588
  const sections = opts.stage === 1 ? tier === "quick" ? "Scoping, Evidence rules" : "Review pipeline, Worktree isolation, Scoping, Evidence rules" : "Merge class, Attack and vet, Evidence rules, Sizing & change shape";
8570
8589
  lines.push(`1. \`${prReviewRef}\` \u2014 read at least these sections: ${sections}.`);
8571
8590
  lines.push(`2. The review worktree: \`${worktreePath}\` \u2014 your ONLY working directory this session; read-only (no edits, no fixes, no stash, no commits, no posts).`);
8591
+ if (opts.diffFile) {
8592
+ lines.push(`- Read the pinned diff snapshot FIRST: \`${opts.diffFile}\` \u2014 it is the review's diff basis (already computed at setup); read it before opening files.`);
8593
+ }
8572
8594
  if (opts.stage === 2) {
8573
8595
  lines.push(`3. \`${join15(skillRoot, "references", "finding-format.md")}\` \u2014 the template every finding follows.`);
8574
8596
  if (opts.securitySeat === true) {
@@ -11455,8 +11477,13 @@ function addTimeoutMs() {
11455
11477
  const parsed = Number(raw);
11456
11478
  return Number.isFinite(parsed) && parsed > 0 ? parsed : DSH_ADD_TIMEOUT_MS;
11457
11479
  }
11458
- var DSH_PLUGIN_SPECS = ["@mstar-harness/dsh", "dsh-llm-fallbacks"];
11480
+ var DSH_FALLBACKS_VERSION = "0.4.1";
11481
+ var DSH_PLUGIN_SPECS = ["@mstar-harness/dsh", `dsh-llm-fallbacks@${DSH_FALLBACKS_VERSION}`];
11459
11482
  var DSH_FALLBACKS_SPEC = DSH_PLUGIN_SPECS[1];
11483
+ function dshLoaderName(spec) {
11484
+ const at = spec.lastIndexOf("@");
11485
+ return at > 0 ? spec.slice(0, at) : spec;
11486
+ }
11460
11487
  var DSH_INSTALL_HINT = "Install the DeepSeek Harness CLI (@deepseek-ai/dsh), e.g. `pnpm add -g @deepseek-ai/dsh` or `npm install -g @deepseek-ai/dsh`, then re-run init.";
11461
11488
  function runDsh(args, dryRun, timeoutMs) {
11462
11489
  return runCliCommand([DSH_BIN, ...args], { dryRun, timeoutMs, env: process.env });
@@ -11533,7 +11560,7 @@ function runInit2(scope, dryRun, initFlags) {
11533
11560
  notes.push(`skipped-by-flag: ${spec} (--no-fallbacks)`);
11534
11561
  continue;
11535
11562
  }
11536
- if (!dryRun && installed.has(spec)) {
11563
+ if (!dryRun && (installed.has(spec) || installed.has(dshLoaderName(spec)))) {
11537
11564
  notes.push(`skipped-existing: ${spec} (already installed in profile ${DSH_PROFILE})`);
11538
11565
  continue;
11539
11566
  }
@@ -11578,7 +11605,7 @@ function runDoctor2(scope) {
11578
11605
  }
11579
11606
  const byName = new Map(entries.map((entry) => [entry.name, entry]));
11580
11607
  for (const spec of DSH_PLUGIN_SPECS) {
11581
- const entry = byName.get(spec);
11608
+ const entry = byName.get(spec) ?? byName.get(dshLoaderName(spec));
11582
11609
  const state = !entry ? "uninstalled" : entry.enabled ? "mounted" : "disabled";
11583
11610
  notes.push(`${spec}: ${state}`);
11584
11611
  if (state === "mounted")
@@ -11599,9 +11626,8 @@ var dshAdapter = {
11599
11626
  import fs5 from "node:fs";
11600
11627
  import path8 from "node:path";
11601
11628
  import { execFileSync as execFileSync8 } from "node:child_process";
11602
- var OMP_PLUGIN_MARKER = ".omp-plugin/plugin.json";
11603
- var CLAUDE_PLUGIN_MARKER = ".claude-plugin/plugin.json";
11604
- var PACKAGE_NAMES = new Set(["morning-star", PLUGIN_NAME, "github:btspoony/mstar-harness"]);
11629
+ var OMP_PACKAGE_REL = path8.join("packages", "omp");
11630
+ var PACKAGE_NAMES = new Set(["morning-star", PLUGIN_NAME, "github:btspoony/mstar-harness", "@mstar-harness/omp"]);
11605
11631
  var SKILL_SMOKE = ["mstar-host", "mstar-harness-core", "pm"];
11606
11632
  var COMMAND_SMOKE = ["iteration-start", "iteration-drive", "iteration-loop", "codebase-audit"];
11607
11633
  function ompAvailable() {
@@ -11664,11 +11690,9 @@ function findInstalledPlugin(plugins) {
11664
11690
  }
11665
11691
  function validatePluginTree(pluginRoot) {
11666
11692
  const errors2 = [];
11667
- for (const marker of [OMP_PLUGIN_MARKER, CLAUDE_PLUGIN_MARKER]) {
11668
- const markerPath = path8.join(pluginRoot, marker);
11669
- if (!fs5.existsSync(markerPath)) {
11670
- errors2.push(`Missing omp plugin marker: ${markerPath}`);
11671
- }
11693
+ const markerPath = path8.join(pluginRoot, "plugin.json");
11694
+ if (!fs5.existsSync(markerPath)) {
11695
+ errors2.push(`Missing omp plugin marker: ${markerPath}`);
11672
11696
  }
11673
11697
  for (const skill of SKILL_SMOKE) {
11674
11698
  const skillPath = path8.join(pluginRoot, "skills", skill, "SKILL.md");
@@ -11705,9 +11729,33 @@ function runInit3(scope, dryRun) {
11705
11729
  }
11706
11730
  }
11707
11731
  if (!ompAvailable()) {
11708
- notes.push("omp CLI not found on PATH. Install Oh My Pi (`omp`), then re-run init or manually: omp plugin install github:btspoony/mstar-harness");
11732
+ notes.push("omp CLI not found on PATH. Install Oh My Pi (`omp`), then re-run init or manually: omp plugin install @mstar-harness/omp");
11709
11733
  } else {
11710
- const linkArgs = ["plugin", "link", HARNESS_REPO_PATH];
11734
+ const ompPackagePath = path8.join(HARNESS_REPO_PATH, OMP_PACKAGE_REL);
11735
+ if (!dryRun && !fs5.existsSync(path8.join(ompPackagePath, "plugin.json"))) {
11736
+ try {
11737
+ runCliCommand(["bun", "install"], { cwd: HARNESS_REPO_PATH, dryRun });
11738
+ runCliCommand(["bun", "run", "engine:build"], { cwd: HARNESS_REPO_PATH, dryRun });
11739
+ runCliCommand(["bun", "run", "omp:build"], { cwd: HARNESS_REPO_PATH, dryRun });
11740
+ notes.push("Built the omp package (engine dist + discovery mirrors) before linking.");
11741
+ } catch (buildError) {
11742
+ const buildMessage = buildError instanceof Error ? buildError.message : String(buildError);
11743
+ notes.push(`Warning: could not build packages/omp (${buildMessage}). Falling back to: omp plugin install @mstar-harness/omp`);
11744
+ const installArgs = ["plugin", "install", "@mstar-harness/omp"];
11745
+ if (scope === "project")
11746
+ installArgs.push("--scope", "project");
11747
+ try {
11748
+ runOmp(installArgs, dryRun);
11749
+ notes.push(`Installed @mstar-harness/omp via omp plugin install (${scope}).`);
11750
+ } catch (installError) {
11751
+ notes.push(`omp plugin install also failed: ${installError instanceof Error ? installError.message : String(installError)}`);
11752
+ }
11753
+ notes.push(...postInstallNotes(scope, dryRun, projectRoot));
11754
+ return { location: HARNESS_REPO_PATH, notes };
11755
+ }
11756
+ }
11757
+ notes.push(`Linked omp plugin tree resolved via the workspace engine member; dist + root mirrors are gitignored build outputs (rebuilt automatically above when absent)`);
11758
+ const linkArgs = ["plugin", "link", ompPackagePath];
11711
11759
  if (scope === "project")
11712
11760
  linkArgs.push("--scope", "project");
11713
11761
  if (dryRun) {
@@ -11715,16 +11763,16 @@ function runInit3(scope, dryRun) {
11715
11763
  } else {
11716
11764
  try {
11717
11765
  runOmp(linkArgs, dryRun);
11718
- notes.push(`Linked local harness into omp plugins (${scope}): omp plugin link ${HARNESS_REPO_PATH}${scope === "project" ? " --scope project" : ""}`);
11766
+ notes.push(`Linked local harness omp package into omp plugins (${scope}): omp plugin link ${ompPackagePath}${scope === "project" ? " --scope project" : ""}`);
11719
11767
  } catch (error) {
11720
11768
  const message = error instanceof Error ? error.message : String(error);
11721
- notes.push(`omp plugin link failed (${message}). Falling back guidance: omp plugin install github:btspoony/mstar-harness`);
11769
+ notes.push(`omp plugin link failed (${message}). Falling back guidance: omp plugin install @mstar-harness/omp`);
11722
11770
  try {
11723
- const installArgs = ["plugin", "install", "github:btspoony/mstar-harness"];
11771
+ const installArgs = ["plugin", "install", "@mstar-harness/omp"];
11724
11772
  if (scope === "project")
11725
11773
  installArgs.push("--scope", "project");
11726
11774
  runOmp(installArgs, dryRun);
11727
- notes.push(`Installed github:btspoony/mstar-harness via omp plugin install (${scope}).`);
11775
+ notes.push(`Installed @mstar-harness/omp via omp plugin install (${scope}).`);
11728
11776
  } catch (installError) {
11729
11777
  const installMessage = installError instanceof Error ? installError.message : String(installError);
11730
11778
  notes.push(`omp plugin install also failed: ${installMessage}`);
@@ -11739,16 +11787,28 @@ function runInit3(scope, dryRun) {
11739
11787
  notes.push("Verify with: omp plugin list");
11740
11788
  notes.push("Enter PM with /skill:pm ; commands: /iteration-start /iteration-drive /iteration-loop /codebase-audit");
11741
11789
  notes.push(`Host adapter: mstar-host \u2192 references/omp.md (skill://mstar-host/references/omp.md)`);
11742
- notes.push(`Alternate install without CLI link: omp plugin install ${REPO_URL.replace("https://github.com/", "github:").replace(/\.git$/, "")}`);
11790
+ notes.push(`Alternate install without CLI link: omp plugin install @mstar-harness/omp`);
11743
11791
  return {
11744
11792
  location: HARNESS_REPO_PATH,
11745
11793
  notes
11746
11794
  };
11747
11795
  }
11796
+ function postInstallNotes(scope, dryRun, projectRoot) {
11797
+ const notes = [];
11798
+ if (scope === "project") {
11799
+ notes.push(...appendHarnessProjectGitignore(projectRoot, dryRun));
11800
+ notes.push(...appendGitignore(projectRoot, [".omp/plugins/", ".omp/plugin-overrides.json", ".omp/plugins/installed_plugins.json"], dryRun));
11801
+ }
11802
+ notes.push("Verify with: omp plugin list");
11803
+ notes.push("Enter PM with /skill:pm ; commands: /iteration-start /iteration-drive /iteration-loop /codebase-audit");
11804
+ notes.push(`Host adapter: mstar-host \u2192 references/omp.md (skill://mstar-host/references/omp.md)`);
11805
+ notes.push(`Alternate install without CLI link: omp plugin install @mstar-harness/omp`);
11806
+ return notes;
11807
+ }
11748
11808
  function runDoctor3(scope) {
11749
11809
  const errors2 = [];
11750
11810
  errors2.push(...validateLocalHarnessRepo());
11751
- errors2.push(...validatePluginTree(HARNESS_REPO_PATH));
11811
+ errors2.push(...validatePluginTree(path8.join(HARNESS_REPO_PATH, OMP_PACKAGE_REL)));
11752
11812
  if (!ompAvailable()) {
11753
11813
  errors2.push("omp CLI not found on PATH (required for omp target doctor checks).");
11754
11814
  } else {
@@ -14136,6 +14196,9 @@ prReviewCommand.command("validate-report").description("Validate a saved local P
14136
14196
  function gitSync(args, cwd) {
14137
14197
  return execFileSync10("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
14138
14198
  }
14199
+ function gitRaw(args, cwd) {
14200
+ return execFileSync10("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"], maxBuffer: GIT_CAPTURE_MAX_BYTES });
14201
+ }
14139
14202
  function ghSync(args, input) {
14140
14203
  return execFileSync10("gh", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], ...input !== undefined ? { input } : {} }).trim();
14141
14204
  }
@@ -14161,7 +14224,11 @@ function refResolves(ref, cwd) {
14161
14224
  }
14162
14225
  function probeChangesetEmpty(diffCmdArgs, cwd, worktreePath) {
14163
14226
  if (diffCmdArgs[0] === "__working_tree__") {
14164
- const dirty = gitIf(["diff"], worktreePath).length > 0 || gitIf(["diff", "--cached"], worktreePath).length > 0;
14227
+ const diffOut = gitProbe(["diff"], worktreePath);
14228
+ const cachedOut = gitProbe(["diff", "--cached"], worktreePath);
14229
+ if (diffOut === null || cachedOut === null)
14230
+ return false;
14231
+ const dirty = diffOut.length > 0 || cachedOut.length > 0;
14165
14232
  if (dirty)
14166
14233
  return false;
14167
14234
  let untracked = "";
@@ -14178,17 +14245,26 @@ function probeChangesetEmpty(diffCmdArgs, cwd, worktreePath) {
14178
14245
  const sha = diffCmdArgs[1];
14179
14246
  const EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
14180
14247
  const diffFrom = refResolves(`${sha}^`, worktreePath) ? `${sha}^` : EMPTY_TREE;
14181
- return gitIf(["diff", diffFrom, sha], worktreePath).trim().length === 0;
14248
+ const probe2 = gitProbe(["diff", diffFrom, sha], worktreePath);
14249
+ return probe2 === null ? false : probe2.trim().length === 0;
14182
14250
  }
14183
- return gitIf(diffCmdArgs, worktreePath).length === 0;
14251
+ const probe = gitProbe(diffCmdArgs, worktreePath);
14252
+ return probe === null ? false : probe.length === 0;
14184
14253
  }
14185
14254
  function gitIf(args, cwd) {
14186
14255
  try {
14187
- return execFileSync10("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
14256
+ return execFileSync10("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], maxBuffer: GIT_CAPTURE_MAX_BYTES });
14188
14257
  } catch {
14189
14258
  return "";
14190
14259
  }
14191
14260
  }
14261
+ function gitProbe(args, cwd) {
14262
+ try {
14263
+ return execFileSync10("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], maxBuffer: GIT_CAPTURE_MAX_BYTES });
14264
+ } catch {
14265
+ return null;
14266
+ }
14267
+ }
14192
14268
  function probeChangesetEmptyPreworktree(mode, headSpec, cwd) {
14193
14269
  if (mode === "working-tree")
14194
14270
  return probeChangesetEmpty(["__working_tree__"], cwd, cwd);
@@ -14315,7 +14391,7 @@ function ghApi(apiPath, payload) {
14315
14391
  input: payload
14316
14392
  });
14317
14393
  }
14318
- prReviewCommand.command("worktree-setup").description("Create the isolated review worktree per pr-review.md \xA7 Worktree isolation: resolves the real base, picks a " + "collision-free branch name, fetches with explicit refspecs, creates the worktree, computes the diff basis INSIDE it, " + "and records a sidecar json consumed by worktree-cleanup; prints {reviewBranch, worktreePath, base, mergeBase, diffCmd} " + "(input modes: --pr <n> | --branch <b> | --diff | --working-tree | --commit <sha>)").option("--pr <n>", "PR number input mode (pull/<n>/head via gh)").option("--branch <name>", "Bare remote-branch input mode").option("--diff", "Arbitrary diff input mode \u2014 no worktree, no refs").option("--working-tree", "Uncommitted working-tree input mode \u2014 no worktree, no refs").option("--commit <sha>", "Single-commit input mode").option("--path <dir>", "Worktree target directory (default: ../<repo-name>.review-pr<N> beside the repo)").action((options) => {
14394
+ prReviewCommand.command("worktree-setup").description("Create the isolated review worktree per pr-review.md \xA7 Worktree isolation: resolves the real base, picks a " + "collision-free branch name, fetches with explicit refspecs, creates the worktree, computes the diff basis INSIDE it, " + "and records a sidecar json consumed by worktree-cleanup; prints {reviewBranch, worktreePath, base, mergeBase, diffCmd, diffFile} " + "(input modes: --pr <n> | --branch <b> | --diff | --working-tree | --commit <sha>)").option("--pr <n>", "PR number input mode (pull/<n>/head via gh)").option("--branch <name>", "Bare remote-branch input mode").option("--diff", "Arbitrary diff input mode \u2014 no worktree, no refs").option("--working-tree", "Uncommitted working-tree input mode \u2014 no worktree, no refs").option("--commit <sha>", "Single-commit input mode").option("--path <dir>", "Worktree target directory (default: <repo>/.worktrees/review-<branch>)").action((options) => {
14319
14395
  try {
14320
14396
  const modesDeclared = [
14321
14397
  options.pr !== undefined,
@@ -14355,7 +14431,7 @@ prReviewCommand.command("worktree-setup").description("Create the isolated revie
14355
14431
  process.exitCode = 1;
14356
14432
  return;
14357
14433
  }
14358
- console.log(JSON.stringify({ reviewBranch: null, worktreePath: repoRoot, base: null, mergeBase: null, diffCmd: mode === "diff" ? "(provided changeset)" : "git diff + git diff --cached + ls-files --others" }, null, 2));
14434
+ console.log(JSON.stringify({ reviewBranch: null, worktreePath: repoRoot, base: null, mergeBase: null, diffCmd: mode === "diff" ? "(provided changeset)" : "git diff + git diff --cached + ls-files --others", diffFile: null }, null, 2));
14359
14435
  return;
14360
14436
  }
14361
14437
  let prNumber = 0;
@@ -14405,7 +14481,21 @@ prReviewCommand.command("worktree-setup").description("Create the isolated revie
14405
14481
  const baseCandidate = mode === "pr" ? namePrNumber : Number(String(Math.abs([...headSpec].reduce((h, ch) => (h * 31 + ch.charCodeAt(0)) % 1000003, 7))));
14406
14482
  const reviewBranch = pickReviewBranchName(existing, baseCandidate === 0 ? 1 : baseCandidate, cliToday().replace(/-/g, ""));
14407
14483
  const branchSuffix = mode === "pr" ? "" : `-${headSpec.slice(0, 8)}`;
14408
- const worktreePath = path12.resolve(options.path ?? joinDirnameBeside(repoRoot, `.review-${reviewBranch}${branchSuffix}`));
14484
+ const worktreePath = path12.resolve(options.path ?? path12.join(repoRoot, ".worktrees", `review-${reviewBranch}${branchSuffix}`));
14485
+ if (options.path === undefined) {
14486
+ fs8.mkdirSync(path12.join(repoRoot, ".worktrees"), { recursive: true });
14487
+ if (gitIf(["check-ignore", ".worktrees/"], repoRoot) === "") {
14488
+ const excludePath = path12.join(repoRoot, ".git", "info", "exclude");
14489
+ const existing2 = fs8.existsSync(excludePath) ? fs8.readFileSync(excludePath, "utf8") : "";
14490
+ if (!existing2.split(`
14491
+ `).some((line) => line.trim() === ".worktrees/")) {
14492
+ fs8.appendFileSync(excludePath, `${existing2 === "" || existing2.endsWith(`
14493
+ `) ? "" : `
14494
+ `}.worktrees/
14495
+ `);
14496
+ }
14497
+ }
14498
+ }
14409
14499
  const originUrl = gitIf(["remote", "get-url", "origin"], repoRoot);
14410
14500
  let fetched = true;
14411
14501
  try {
@@ -14421,7 +14511,11 @@ prReviewCommand.command("worktree-setup").description("Create the isolated revie
14421
14511
  } catch {
14422
14512
  fetched = false;
14423
14513
  }
14424
- const rollbackNewWorktree = (branchToDelete) => {
14514
+ let wroteSnapshot = false;
14515
+ let wroteSidecar = false;
14516
+ let pendingSidecar;
14517
+ let sidecarFd;
14518
+ const cleanupOnFailure = (branchToDelete) => {
14425
14519
  try {
14426
14520
  if (fs8.existsSync(worktreePath))
14427
14521
  gitSync(["worktree", "remove", "--force", worktreePath], repoRoot);
@@ -14429,6 +14523,12 @@ prReviewCommand.command("worktree-setup").description("Create the isolated revie
14429
14523
  if (branchToDelete !== "" && !existing.has(branchToDelete)) {
14430
14524
  gitSync(["branch", "-D", branchToDelete], repoRoot);
14431
14525
  }
14526
+ if (wroteSidecar && sidecarFd !== undefined) {
14527
+ removeOwnedFreshSidecarFile(sidecarFd, worktreePath);
14528
+ sidecarFd = undefined;
14529
+ }
14530
+ if (wroteSnapshot && pendingSidecar !== undefined)
14531
+ removeOwnedSnapshotFile(worktreePath, pendingSidecar);
14432
14532
  } catch {}
14433
14533
  };
14434
14534
  const fetchedHeadResolves = mode === "pr" ? refResolves(reviewBranch, repoRoot) : mode === "branch" ? originUrl !== "" && refResolves(`origin/${options.branch}`, repoRoot) : mode === "commit" ? Boolean(gitIf(["rev-parse", "--verify", "--quiet", `${headSpec}^{commit}`], repoRoot).trim()) : refResolves(headSpec, repoRoot);
@@ -14461,48 +14561,222 @@ prReviewCommand.command("worktree-setup").description("Create the isolated revie
14461
14561
  const changesetEmpty = probeChangesetEmpty(diffArgs, worktreePath, worktreePath);
14462
14562
  const emptyGate = preflightChangeset(mode, { refsResolve: true, changesetEmpty });
14463
14563
  if (changesetEmpty) {
14464
- rollbackNewWorktree(mode === "pr" ? reviewBranch : "");
14564
+ cleanupOnFailure(mode === "pr" ? reviewBranch : "");
14465
14565
  }
14466
14566
  if (!emptyGate.ok && emptyGate.violations.some((v) => v.code === "prreview.preflight.changeset-empty")) {
14467
14567
  printChecklist("pr-review worktree-setup preflight", emptyGate);
14468
14568
  process.exitCode = 1;
14469
14569
  return;
14470
14570
  }
14471
- const recordedBase = mode === "pr" || mode !== "commit" && !baseRef.startsWith("origin/") ? `origin/${baseRef}` : baseRef;
14472
- const sidecar = {
14473
- reviewBranch: mode === "pr" ? reviewBranch : "",
14474
- worktreePath,
14475
- base: recordedBase,
14476
- mergeBase,
14477
- diffCmd,
14478
- reportSaved: false,
14479
- createdAt: new Date().toISOString(),
14480
- repoRoot
14571
+ const captureAndRecordSnapshot = () => {
14572
+ const diffFile = prReviewArtifactPathFor(worktreePath, "diff");
14573
+ const sidecarPath = prReviewArtifactPathFor(worktreePath, "json");
14574
+ const snapshotParts = [];
14575
+ if (mode === "commit") {
14576
+ snapshotParts.push(Buffer.from(`# Review package: ${baseRef} (single commit)
14577
+
14578
+ ## Commits
14579
+ `), gitRaw(["log", "--oneline", "-1", headSpec], worktreePath), Buffer.from(`
14580
+ ## Files changed
14581
+ `), gitRaw(["show", "--stat", headSpec], worktreePath), Buffer.from(`
14582
+ ## Diff
14583
+ `), gitRaw(["show", "-U10", headSpec], worktreePath));
14584
+ } else {
14585
+ const range = diffArgs[1];
14586
+ const [rangeBase, rangeHead] = range.split("...");
14587
+ snapshotParts.push(Buffer.from(`# Review package: ${baseRef}..${headSpec}
14588
+
14589
+ ## Commits
14590
+ `), gitRaw(["log", "--oneline", `${rangeBase}..${rangeHead}`], worktreePath), Buffer.from(`
14591
+ ## Files changed
14592
+ `), gitRaw(["diff", "--stat", range], worktreePath), Buffer.from(`
14593
+ ## Diff
14594
+ `), gitRaw(["diff", "-U10", range], worktreePath));
14595
+ }
14596
+ const snapshot = Buffer.concat(snapshotParts);
14597
+ const recordedBase = mode === "pr" || mode !== "commit" && !baseRef.startsWith("origin/") ? `origin/${baseRef}` : baseRef;
14598
+ const sidecar2 = {
14599
+ reviewBranch: mode === "pr" ? reviewBranch : "",
14600
+ worktreePath,
14601
+ base: recordedBase,
14602
+ mergeBase,
14603
+ diffCmd,
14604
+ reportSaved: false,
14605
+ createdAt: new Date().toISOString(),
14606
+ repoRoot,
14607
+ diffFile,
14608
+ diffFileSha256: createHash("sha256").update(snapshot).digest("hex")
14609
+ };
14610
+ try {
14611
+ sidecarFd = fs8.openSync(sidecarPath, "wx+");
14612
+ } catch (error) {
14613
+ if (error.code !== "EEXIST" && error.code !== "EISDIR")
14614
+ throw error;
14615
+ throw new Error(`cannot record setup sidecar at ${sidecarPath} - run mstar pr-review worktree-cleanup first (never cleaning a foreign review)`);
14616
+ }
14617
+ writeFdSync(sidecarFd, Buffer.from(JSON.stringify(sidecar2, null, 2), "utf8"));
14618
+ wroteSidecar = true;
14619
+ try {
14620
+ fs8.writeFileSync(diffFile, snapshot, { flag: "wx" });
14621
+ } catch (error) {
14622
+ if (error.code !== "EEXIST" && error.code !== "EISDIR")
14623
+ throw error;
14624
+ throw new Error(`refusing to overwrite pre-existing non-snapshot path ${diffFile}`);
14625
+ }
14626
+ wroteSnapshot = true;
14627
+ const snapshotStat = fs8.lstatSync(diffFile);
14628
+ sidecar2.diffFileDev = snapshotStat.dev;
14629
+ sidecar2.diffFileIno = String(snapshotStat.ino);
14630
+ sidecar2.diffFileMtimeMs = snapshotStat.mtimeMs;
14631
+ pendingSidecar = sidecar2;
14632
+ fs8.ftruncateSync(sidecarFd, 0);
14633
+ writeFdSync(sidecarFd, Buffer.from(JSON.stringify(sidecar2, null, 2), "utf8"));
14634
+ fs8.closeSync(sidecarFd);
14635
+ sidecarFd = undefined;
14636
+ return sidecar2;
14481
14637
  };
14482
- fs8.writeFileSync(sidecarPathFor(worktreePath), JSON.stringify(sidecar, null, 2));
14638
+ let sidecar;
14639
+ try {
14640
+ sidecar = captureAndRecordSnapshot();
14641
+ } catch (error) {
14642
+ cleanupOnFailure(mode === "pr" ? reviewBranch : "");
14643
+ throw error;
14644
+ }
14483
14645
  console.log(JSON.stringify({
14484
14646
  reviewBranch: sidecar.reviewBranch === "" ? null : sidecar.reviewBranch,
14485
14647
  worktreePath: sidecar.worktreePath,
14486
14648
  base: sidecar.base,
14487
14649
  mergeBase: sidecar.mergeBase === "" ? null : sidecar.mergeBase,
14488
- diffCmd: sidecar.diffCmd
14650
+ diffCmd: sidecar.diffCmd,
14651
+ diffFile: sidecar.diffFile
14489
14652
  }, null, 2));
14490
14653
  } catch (error) {
14491
14654
  failScript(error, "pr-review worktree-setup");
14492
14655
  }
14493
14656
  });
14494
- function sidecarPathFor(worktreePath) {
14657
+ function prReviewArtifactPathFor(worktreePath, suffix) {
14495
14658
  const parent = path12.dirname(path12.resolve(worktreePath));
14496
14659
  const name = path12.basename(path12.resolve(worktreePath));
14497
- return path12.join(parent, `.${name}.prreview.json`);
14660
+ return path12.join(parent, `.${name}.prreview.${suffix}`);
14661
+ }
14662
+ function writeFdSync(fd, buf) {
14663
+ let written = 0;
14664
+ while (written < buf.length)
14665
+ written += fs8.writeSync(fd, buf, written, buf.length - written, written);
14666
+ }
14667
+ function removeOwnedSnapshotFile(worktreePath, sidecar) {
14668
+ const snapshotPath = prReviewArtifactPathFor(worktreePath, "diff");
14669
+ let fd;
14670
+ try {
14671
+ fd = fs8.openSync(snapshotPath, "r");
14672
+ } catch (error) {
14673
+ if (error.code === "ENOENT")
14674
+ return;
14675
+ console.error(import_picocolors2.default.yellow(`worktree-cleanup: snapshot at ${snapshotPath} left in place (cannot open: ${error.message})`));
14676
+ return;
14677
+ }
14678
+ try {
14679
+ const st = fs8.fstatSync(fd);
14680
+ if (!st.isFile())
14681
+ return;
14682
+ const recordedIno = sidecar.diffFileIno;
14683
+ const recordedDev = sidecar.diffFileDev;
14684
+ const recordedMtimeMs = sidecar.diffFileMtimeMs;
14685
+ const owned = typeof recordedIno === "string" && recordedIno !== "" && typeof recordedDev === "number" && Number.isFinite(recordedDev) && typeof recordedMtimeMs === "number" && Number.isFinite(recordedMtimeMs) && String(st.ino) === recordedIno && st.dev === recordedDev && st.mtimeMs === recordedMtimeMs;
14686
+ if (!owned) {
14687
+ console.error(import_picocolors2.default.yellow(`worktree-cleanup: snapshot at ${snapshotPath} left in place (file identity does not match the recorded snapshot)`));
14688
+ return;
14689
+ }
14690
+ if (st.nlink !== 1) {
14691
+ console.error(import_picocolors2.default.yellow(`worktree-cleanup: snapshot at ${snapshotPath} left in place (link count does not match the recorded snapshot)`));
14692
+ return;
14693
+ }
14694
+ const tmp = `${snapshotPath}.cleanup.${process.pid}.${randomUUID3()}`;
14695
+ try {
14696
+ fs8.renameSync(snapshotPath, tmp);
14697
+ } catch (error) {
14698
+ console.error(import_picocolors2.default.yellow(`worktree-cleanup: snapshot at ${snapshotPath} left in place (cannot detach: ${error.message})`));
14699
+ return;
14700
+ }
14701
+ const st2 = fs8.fstatSync(fd);
14702
+ let tmpStat;
14703
+ try {
14704
+ tmpStat = fs8.lstatSync(tmp);
14705
+ } catch {
14706
+ tmpStat = undefined;
14707
+ }
14708
+ if (tmpStat !== undefined && tmpStat.ino === st2.ino && tmpStat.dev === st2.dev && st2.nlink === 1 && tmpStat.nlink === 1) {
14709
+ fs8.unlinkSync(tmp);
14710
+ const st3 = fs8.fstatSync(fd);
14711
+ if (st3.nlink !== 0) {
14712
+ console.error(import_picocolors2.default.yellow(`worktree-cleanup: unlink at ${tmp} detached a pathname replacement, not the verified snapshot inode (${snapshotPath} still holds ${st3.nlink} link(s)) - the replacement is gone, the verified snapshot was NOT deleted`));
14713
+ }
14714
+ } else {
14715
+ try {
14716
+ fs8.linkSync(tmp, snapshotPath);
14717
+ fs8.unlinkSync(tmp);
14718
+ } catch (error) {
14719
+ if (error.code === "EEXIST") {
14720
+ console.error(import_picocolors2.default.yellow(`worktree-cleanup: snapshot replacement left at ${tmp} (snapshot path was recreated concurrently)`));
14721
+ } else {
14722
+ console.error(import_picocolors2.default.yellow(`worktree-cleanup: snapshot replacement left at ${tmp} (restore failed: ${error.message})`));
14723
+ }
14724
+ }
14725
+ }
14726
+ } finally {
14727
+ fs8.closeSync(fd);
14728
+ }
14498
14729
  }
14499
- function joinDirnameBeside(repoRoot, leaf) {
14500
- return path12.join(path12.dirname(path12.resolve(repoRoot)), leaf);
14730
+ function removeOwnedFreshSidecarFile(sidecarFd, worktreePath) {
14731
+ const sidecarPath = prReviewArtifactPathFor(worktreePath, "json");
14732
+ try {
14733
+ const st = fs8.fstatSync(sidecarFd);
14734
+ if (!st.isFile() || st.nlink !== 1) {
14735
+ console.error(import_picocolors2.default.yellow(`worktree-setup rollback: sidecar at ${sidecarPath} left in place (identity no longer held)`));
14736
+ return;
14737
+ }
14738
+ const tmp = `${sidecarPath}.cleanup.${process.pid}.${randomUUID3()}`;
14739
+ try {
14740
+ fs8.renameSync(sidecarPath, tmp);
14741
+ } catch (error) {
14742
+ console.error(import_picocolors2.default.yellow(`worktree-setup rollback: sidecar at ${sidecarPath} left in place (cannot detach: ${error.message})`));
14743
+ return;
14744
+ }
14745
+ const st2 = fs8.fstatSync(sidecarFd);
14746
+ let tmpStat;
14747
+ try {
14748
+ tmpStat = fs8.lstatSync(tmp);
14749
+ } catch {
14750
+ tmpStat = undefined;
14751
+ }
14752
+ if (tmpStat !== undefined && tmpStat.ino === st2.ino && tmpStat.dev === st2.dev) {
14753
+ fs8.unlinkSync(tmp);
14754
+ const st3 = fs8.fstatSync(sidecarFd);
14755
+ if (st3.nlink !== 0) {
14756
+ console.error(import_picocolors2.default.yellow(`worktree-setup rollback: unlink at ${tmp} detached a pathname replacement, not the verified sidecar inode (${sidecarPath} still holds ${st3.nlink} link(s)) - the replacement is gone, the verified sidecar was NOT deleted`));
14757
+ }
14758
+ } else {
14759
+ try {
14760
+ fs8.linkSync(tmp, sidecarPath);
14761
+ fs8.unlinkSync(tmp);
14762
+ } catch (error) {
14763
+ if (error.code === "EEXIST") {
14764
+ console.error(import_picocolors2.default.yellow(`worktree-setup rollback: sidecar replacement left at ${tmp} (sidecar path was recreated concurrently)`));
14765
+ } else {
14766
+ console.error(import_picocolors2.default.yellow(`worktree-setup rollback: sidecar replacement left at ${tmp} (restore failed: ${error.message})`));
14767
+ }
14768
+ }
14769
+ }
14770
+ } finally {
14771
+ try {
14772
+ fs8.closeSync(sidecarFd);
14773
+ } catch {}
14774
+ }
14501
14775
  }
14502
14776
  prReviewCommand.command("worktree-cleanup").description("Remove the review worktree per pr-review.md \xA7 Worktree isolation cleanup: refuses unless --report-saved is given OR the " + "setup sidecar records report-saved; removes the worktree, prunes, and deletes EXACTLY the recorded review branch \u2014 a " + "--branch argument that disagrees with the sidecar is refused (never delete a foreign/pre-existing branch)").requiredOption("--path <dir>", "Worktree directory created by worktree-setup").requiredOption("--branch <name>", "The recorded review branch (must match the setup sidecar for PR mode)").option("--report-saved", "Assert the local report has been saved before removal").action((options) => {
14503
14777
  try {
14504
14778
  const worktreePath = path12.resolve(resolveCliPath(options.path));
14505
- const sidecarPath = sidecarPathFor(worktreePath);
14779
+ const sidecarPath = prReviewArtifactPathFor(worktreePath, "json");
14506
14780
  if (!fs8.existsSync(sidecarPath)) {
14507
14781
  throw new Error(`no setup sidecar found at ${sidecarPath} - run pr-review worktree-setup first (foreign worktrees are never cleaned here)`);
14508
14782
  }
@@ -14534,6 +14808,7 @@ prReviewCommand.command("worktree-cleanup").description("Remove the review workt
14534
14808
  }
14535
14809
  gitSync(["branch", "-D", sidecar.reviewBranch], gitRoot);
14536
14810
  }
14811
+ removeOwnedSnapshotFile(worktreePath, sidecar);
14537
14812
  fs8.rmSync(sidecarPath, { force: true });
14538
14813
  console.log(import_picocolors2.default.green(`worktree-cleanup: removed ${worktreePath}${sidecar.reviewBranch !== "" ? ` + deleted ${sidecar.reviewBranch}` : " (no local branch to delete)"}`));
14539
14814
  } catch (error) {
@@ -14583,7 +14858,7 @@ function measureLargestTouchedTotal(diffOutput, headRef, cwd) {
14583
14858
  }
14584
14859
  return maxTotal;
14585
14860
  }
14586
- prReviewCommand.command("seat-prompt").description("Generate the read-only audit-seat prompt per pr-review.md \xA7 Seat prompts (Hard Rules 4/5 verbatim, payload-return contract, " + "no-verdict/no-post clauses, slug <domain>-<seat>, Merge-class instruction on stage 2); prints the prompt").requiredOption("--stage <1|2>", "Pipeline stage (1 = collect, 2 = domain/security)").requiredOption("--domain <d>", "Review domain for this seat").requiredOption("--seat <id>", "Seat id (slug becomes <domain>-<seat>)").requiredOption("--worktree <path>", "Absolute review worktree path").option("--security", "Mark this seat as the security-lens seat (stage 2)").option("--skill-root <dir>", "Skill root containing references/pr-review.md (default: resolved skills/mstar-audit)").option("--recon <facts...>", "Recon facts (variadic: --recon fact1 fact2 ...)").option("--tier <quick|default|deep>", "Prompt tier (SP-A): quick shrinks read-first + folds the security lens in-seat; deep adds cross-domain security seat + stage-as-wave (default: default)").action((options) => {
14861
+ prReviewCommand.command("seat-prompt").description("Generate the read-only audit-seat prompt per pr-review.md \xA7 Seat prompts (Hard Rules 4/5 verbatim, payload-return contract, " + "no-verdict/no-post clauses, slug <domain>-<seat>, Merge-class instruction on stage 2); prints the prompt").requiredOption("--stage <1|2>", "Pipeline stage (1 = collect, 2 = domain/security)").requiredOption("--domain <d>", "Review domain for this seat").requiredOption("--seat <id>", "Seat id (slug becomes <domain>-<seat>)").requiredOption("--worktree <path>", "Absolute review worktree path").option("--security", "Mark this seat as the security-lens seat (stage 2)").option("--skill-root <dir>", "Skill root containing references/pr-review.md (default: resolved skills/mstar-audit)").option("--recon <facts...>", "Recon facts (variadic: --recon fact1 fact2 ...)").option("--tier <quick|default|deep>", "Prompt tier (SP-A): quick shrinks read-first + folds the security lens in-seat; deep adds cross-domain security seat + stage-as-wave (default: default)").option("--diff-file <path>", "Absolute path to the pinned diff snapshot written by worktree-setup (read-first ingredient)").action((options) => {
14587
14862
  try {
14588
14863
  if (options.stage !== "1" && options.stage !== "2") {
14589
14864
  throw new SddScriptError(`usage: pr-review seat-prompt \u2014 --stage must be 1 or 2, got ${JSON.stringify(options.stage)}`, 2);
@@ -14601,7 +14876,8 @@ prReviewCommand.command("seat-prompt").description("Generate the read-only audit
14601
14876
  worktreePath: path12.resolve(options.worktree),
14602
14877
  reconFacts: options.recon ?? [],
14603
14878
  ...options.security === true ? { securitySeat: true } : {},
14604
- ...tier !== undefined ? { tier } : {}
14879
+ ...tier !== undefined ? { tier } : {},
14880
+ ...options.diffFile !== undefined && options.diffFile !== "" ? { diffFile: path12.resolve(resolveCliPath(options.diffFile)) } : {}
14605
14881
  });
14606
14882
  console.log(prompt);
14607
14883
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mstar-harness/cli",
3
- "version": "3.6.0-alpha.3",
3
+ "version": "3.6.0",
4
4
  "description": "Morning Star harness CLI — installer bootstrap + mstar workflow verbs (path/status/lease/sdd/iteration/dispatch/worktree/lint/design-md/audit/compound/host/skill).",
5
5
  "license": "MIT",
6
6
  "repository": {