@userreason/wizard 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +44 -51
  2. package/dist/agent-note.js +6 -5
  3. package/dist/agent-skill.js +5 -4
  4. package/dist/analytics.js +2 -2
  5. package/dist/bin.js +55 -51
  6. package/dist/{chunk-SFODN2YB.js → chunk-4INLEQE2.js} +2 -2
  7. package/dist/{chunk-77SK7TKZ.js → chunk-7AAH6C4L.js} +928 -631
  8. package/dist/{chunk-Z6ZY7X2K.js → chunk-7O7H3PIM.js} +6 -6
  9. package/dist/{chunk-VXWLSQYK.js → chunk-CSZW2ULJ.js} +39 -17
  10. package/dist/{chunk-P6DOSGRZ.js → chunk-DMXUXEQI.js} +1 -1
  11. package/dist/{chunk-GOYBYAUH.js → chunk-EVNEX5N5.js} +1 -1
  12. package/dist/{chunk-UN24JFV2.js → chunk-KF37D5WL.js} +1 -1
  13. package/dist/{chunk-5IO5LY22.js → chunk-LEJFE4U5.js} +2 -2
  14. package/dist/{chunk-MFGJ2KPT.js → chunk-NNPYUATH.js} +1 -1
  15. package/dist/chunk-PJQOSDYS.js +50 -0
  16. package/dist/{chunk-YYFC7TM2.js → chunk-Q5U5UOQN.js} +7 -5
  17. package/dist/{chunk-NZ65XDNL.js → chunk-SB3AYQWG.js} +4 -4
  18. package/dist/{chunk-CADA5WZ3.js → chunk-TOID3NYP.js} +13 -6
  19. package/dist/{chunk-ZHHIHHLU.js → chunk-TRBSH5G7.js} +5 -5
  20. package/dist/{chunk-2UEUVLCB.js → chunk-XASPGFYK.js} +3 -3
  21. package/dist/{chunk-F4FKAUQN.js → chunk-XPFKXLIZ.js} +2 -2
  22. package/dist/{chunk-HIF6NUNK.js → chunk-ZHJV247H.js} +6 -8
  23. package/dist/cli-access.js +3 -3
  24. package/dist/connection.js +2 -2
  25. package/dist/first-survey.js +2 -2
  26. package/dist/footer.js +5 -4
  27. package/dist/global-cli.js +5 -4
  28. package/dist/install-diagnostics.js +9 -0
  29. package/dist/integrate.js +4 -3
  30. package/dist/project.js +3 -2
  31. package/dist/setup-flow.js +9 -8
  32. package/dist/setup.js +8 -7
  33. package/dist/startup.js +2 -2
  34. package/dist/state.js +5 -4
  35. package/dist/ui.js +2 -2
  36. package/package.json +1 -1
@@ -8,7 +8,7 @@ import {
8
8
  // node_modules/typescript/lib/typescript.js
9
9
  var require_typescript = __commonJS({
10
10
  "node_modules/typescript/lib/typescript.js"(exports, module) {
11
- var ts2 = {};
11
+ var ts3 = {};
12
12
  ((module2) => {
13
13
  "use strict";
14
14
  var __defProp = Object.defineProperty;
@@ -2271,7 +2271,7 @@ var require_typescript = __commonJS({
2271
2271
  walkUpParenthesizedTypesAndGetParentAndChild: () => walkUpParenthesizedTypesAndGetParentAndChild,
2272
2272
  whitespaceOrMapCommentRegExp: () => whitespaceOrMapCommentRegExp,
2273
2273
  writeCommentRange: () => writeCommentRange,
2274
- writeFile: () => writeFile4,
2274
+ writeFile: () => writeFile3,
2275
2275
  writeFileEnsuringDirectories: () => writeFileEnsuringDirectories,
2276
2276
  zipWith: () => zipWith
2277
2277
  });
@@ -20914,7 +20914,7 @@ ${lanes.join("\n")}
20914
20914
  sourceFilePath = isSourceFileInCommonSourceDirectory ? sourceFilePath.substring(commonSourceDirectory.length) : sourceFilePath;
20915
20915
  return combinePaths(newDirPath, sourceFilePath);
20916
20916
  }
20917
- function writeFile4(host, diagnostics, fileName, text2, writeByteOrderMark, sourceFiles, data) {
20917
+ function writeFile3(host, diagnostics, fileName, text2, writeByteOrderMark, sourceFiles, data) {
20918
20918
  host.writeFile(
20919
20919
  fileName,
20920
20920
  text2,
@@ -33436,8 +33436,8 @@ ${lanes.join("\n")}
33436
33436
  return void 0;
33437
33437
  }
33438
33438
  function tryRenameExternalModule(factory2, moduleName, sourceFile3) {
33439
- const rename7 = sourceFile3.renamedDependencies && sourceFile3.renamedDependencies.get(moduleName.text);
33440
- return rename7 ? factory2.createStringLiteral(rename7) : void 0;
33439
+ const rename6 = sourceFile3.renamedDependencies && sourceFile3.renamedDependencies.get(moduleName.text);
33440
+ return rename6 ? factory2.createStringLiteral(rename6) : void 0;
33441
33441
  }
33442
33442
  function tryGetModuleNameFromFile(factory2, file, host, options) {
33443
33443
  if (!file) {
@@ -36865,8 +36865,8 @@ ${lanes.join("\n")}
36865
36865
  function isMissingList(arr) {
36866
36866
  return !!arr.isMissingList;
36867
36867
  }
36868
- function parseBracketedList(kind, parseElement, open10, close) {
36869
- if (parseExpected(open10)) {
36868
+ function parseBracketedList(kind, parseElement, open9, close) {
36869
+ if (parseExpected(open9)) {
36870
36870
  const result = parseDelimitedList(kind, parseElement);
36871
36871
  parseExpected(close);
36872
36872
  return result;
@@ -39301,7 +39301,7 @@ ${lanes.join("\n")}
39301
39301
  );
39302
39302
  return finishNode(factory2.createJsxSpreadAttribute(expression), pos);
39303
39303
  }
39304
- function parseJsxClosingElement(open10, inExpressionContext) {
39304
+ function parseJsxClosingElement(open9, inExpressionContext) {
39305
39305
  const pos = getNodePos();
39306
39306
  parseExpected(
39307
39307
  31
@@ -39315,7 +39315,7 @@ ${lanes.join("\n")}
39315
39315
  /*shouldAdvance*/
39316
39316
  false
39317
39317
  )) {
39318
- if (inExpressionContext || !tagNamesAreEquivalent(open10.tagName, tagName)) {
39318
+ if (inExpressionContext || !tagNamesAreEquivalent(open9.tagName, tagName)) {
39319
39319
  nextToken();
39320
39320
  } else {
39321
39321
  scanJsxText();
@@ -129665,7 +129665,7 @@ ${lanes.join("\n")}
129665
129665
  return;
129666
129666
  }
129667
129667
  const buildInfo = host.getBuildInfo() || { version };
129668
- writeFile4(
129668
+ writeFile3(
129669
129669
  host,
129670
129670
  emitterDiagnostics,
129671
129671
  buildInfoPath,
@@ -129877,7 +129877,7 @@ ${lanes.join("\n")}
129877
129877
  }
129878
129878
  if (sourceMapFilePath) {
129879
129879
  const sourceMap = sourceMapGenerator.toString();
129880
- writeFile4(
129880
+ writeFile3(
129881
129881
  host,
129882
129882
  emitterDiagnostics,
129883
129883
  sourceMapFilePath,
@@ -129892,7 +129892,7 @@ ${lanes.join("\n")}
129892
129892
  }
129893
129893
  const text2 = writer.getText();
129894
129894
  const data = { sourceMapUrlPos, diagnostics: transform2.diagnostics };
129895
- writeFile4(host, emitterDiagnostics, jsFilePath, text2, !!compilerOptions.emitBOM, sourceFiles, data);
129895
+ writeFile3(host, emitterDiagnostics, jsFilePath, text2, !!compilerOptions.emitBOM, sourceFiles, data);
129896
129896
  writer.clear();
129897
129897
  return !data.skippedDtsWrite;
129898
129898
  }
@@ -167558,19 +167558,19 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
167558
167558
  }
167559
167559
  function convertNamedExport(sourceFile3, assignment, changes, exports2) {
167560
167560
  const { text: text2 } = assignment.left.name;
167561
- const rename7 = exports2.get(text2);
167562
- if (rename7 !== void 0) {
167561
+ const rename6 = exports2.get(text2);
167562
+ if (rename6 !== void 0) {
167563
167563
  const newNodes = [
167564
167564
  makeConst(
167565
167565
  /*modifiers*/
167566
167566
  void 0,
167567
- rename7,
167567
+ rename6,
167568
167568
  assignment.right
167569
167569
  ),
167570
167570
  makeExportDeclaration([factory.createExportSpecifier(
167571
167571
  /*isTypeOnly*/
167572
167572
  false,
167573
- rename7,
167573
+ rename6,
167574
167574
  text2
167575
167575
  )])
167576
167576
  ];
@@ -188111,18 +188111,18 @@ ${content}
188111
188111
  /* Code */
188112
188112
  );
188113
188113
  }
188114
- function spanForObjectOrArrayLiteral(node, open10 = 19) {
188114
+ function spanForObjectOrArrayLiteral(node, open9 = 19) {
188115
188115
  return spanForNode(
188116
188116
  node,
188117
188117
  /*autoCollapse*/
188118
188118
  false,
188119
188119
  /*useFullStart*/
188120
188120
  !isArrayLiteralExpression(node.parent) && !isCallExpression(node.parent),
188121
- open10
188121
+ open9
188122
188122
  );
188123
188123
  }
188124
- function spanForNode(hintSpanNode, autoCollapse = false, useFullStart = true, open10 = 19, close = open10 === 19 ? 20 : 24) {
188125
- const openToken = findChildOfKind(n, open10, sourceFile3);
188124
+ function spanForNode(hintSpanNode, autoCollapse = false, useFullStart = true, open9 = 19, close = open9 === 19 ? 20 : 24) {
188125
+ const openToken = findChildOfKind(n, open9, sourceFile3);
188126
188126
  const closeToken = findChildOfKind(n, close, sourceFile3);
188127
188127
  return openToken && closeToken && spanBetweenTokens(openToken, closeToken, hintSpanNode, sourceFile3, autoCollapse, useFullStart);
188128
188128
  }
@@ -190913,9 +190913,9 @@ ${options.prefix}` : "\n" : options.prefix
190913
190913
  return end;
190914
190914
  }
190915
190915
  function getClassOrObjectBraceEnds(cls, sourceFile3) {
190916
- const open10 = findChildOfKind(cls, 19, sourceFile3);
190916
+ const open9 = findChildOfKind(cls, 19, sourceFile3);
190917
190917
  const close = findChildOfKind(cls, 20, sourceFile3);
190918
- return [open10 == null ? void 0 : open10.end, close == null ? void 0 : close.end];
190918
+ return [open9 == null ? void 0 : open9.end, close == null ? void 0 : close.end];
190919
190919
  }
190920
190920
  function getMembersOrProperties(node) {
190921
190921
  return isObjectLiteralExpression(node) ? node.properties : node.members;
@@ -197774,7 +197774,7 @@ ${options.prefix}` : "\n" : options.prefix
197774
197774
  walkUpParenthesizedTypesAndGetParentAndChild: () => walkUpParenthesizedTypesAndGetParentAndChild,
197775
197775
  whitespaceOrMapCommentRegExp: () => whitespaceOrMapCommentRegExp,
197776
197776
  writeCommentRange: () => writeCommentRange,
197777
- writeFile: () => writeFile4,
197777
+ writeFile: () => writeFile3,
197778
197778
  writeFileEnsuringDirectories: () => writeFileEnsuringDirectories,
197779
197779
  zipWith: () => zipWith
197780
197780
  });
@@ -210736,9 +210736,9 @@ Additional information: BADCLIENT: Bad error code, ${badCode} not found in range
210736
210736
  };
210737
210737
  }
210738
210738
  })({ get exports() {
210739
- return ts2;
210739
+ return ts3;
210740
210740
  }, set exports(v) {
210741
- ts2 = v;
210741
+ ts3 = v;
210742
210742
  if (typeof module !== "undefined" && module.exports) {
210743
210743
  module.exports = v;
210744
210744
  }
@@ -211799,8 +211799,8 @@ var productionProfile = {
211799
211799
  kind: "production",
211800
211800
  apiEnvironment: "production",
211801
211801
  docsUrl: PRODUCTION_DOCS,
211802
- sdkVersion: "0.5.0",
211803
- cliVersion: "0.2.0"
211802
+ sdkVersion: "0.5.3",
211803
+ cliVersion: "0.2.1"
211804
211804
  };
211805
211805
  function parsePackageProfile(value) {
211806
211806
  const data = object(value, "package profile");
@@ -211874,14 +211874,14 @@ async function discoverAuthConfig(url, development = false, fetcher = fetch) {
211874
211874
  if (!response.headers.get("content-type")?.toLowerCase().startsWith("application/json") || !response.body)
211875
211875
  throw new Error("Invalid UserReason authentication configuration response");
211876
211876
  const reader = response.body.getReader(), chunks = [];
211877
- let bytes = 0;
211877
+ let bytes2 = 0;
211878
211878
  try {
211879
211879
  while (true) {
211880
211880
  const part = await reader.read();
211881
211881
  if (part.done)
211882
211882
  break;
211883
- bytes += part.value.byteLength;
211884
- if (bytes > 4096) {
211883
+ bytes2 += part.value.byteLength;
211884
+ if (bytes2 > 4096) {
211885
211885
  await reader.cancel();
211886
211886
  throw new Error("UserReason authentication configuration response is too large");
211887
211887
  }
@@ -211890,7 +211890,7 @@ async function discoverAuthConfig(url, development = false, fetcher = fetch) {
211890
211890
  } finally {
211891
211891
  reader.releaseLock();
211892
211892
  }
211893
- const buffer = new Uint8Array(bytes);
211893
+ const buffer = new Uint8Array(bytes2);
211894
211894
  let offset = 0;
211895
211895
  for (const chunk of chunks) {
211896
211896
  buffer.set(chunk, offset);
@@ -212618,8 +212618,8 @@ function detectAgentHarness(env = process.env) {
212618
212618
  function createUiKit({ level, light = false, ascii = false, stream = process.stdout } = {}) {
212619
212619
  const lv = level ?? detectColorLevel({ stream });
212620
212620
  const rgb = light ? LIGHT : DARK, p256 = light ? LIGHT256 : DARK256, p16 = light ? LIGHT16 : DARK16;
212621
- const open10 = (role) => lv === 3 ? `${ESC}38;2;${rgb[role].join(";")}m` : lv === 2 ? `${ESC}38;5;${p256[role]}m` : `${ESC}${p16[role]}m`;
212622
- const paint = (role) => (text2) => lv === 0 ? String(text2) : `${open10(role)}${text2}${ESC}39m`;
212621
+ const open9 = (role) => lv === 3 ? `${ESC}38;2;${rgb[role].join(";")}m` : lv === 2 ? `${ESC}38;5;${p256[role]}m` : `${ESC}${p16[role]}m`;
212622
+ const paint = (role) => (text2) => lv === 0 ? String(text2) : `${open9(role)}${text2}${ESC}39m`;
212623
212623
  const c = {
212624
212624
  accent: paint("accent"),
212625
212625
  good: paint("good"),
@@ -212786,18 +212786,18 @@ async function telemetryEnabled() {
212786
212786
  function validRecord(value) {
212787
212787
  if (!value || typeof value !== "object" || Array.isArray(value))
212788
212788
  return false;
212789
- const record3 = value;
212789
+ const record2 = value;
212790
212790
  const common = ["event_id", "occurred_at", "run_id", "surface", "release_version", "execution_mode", "workspace_id", "site_id", "source_site_environment"];
212791
- const allowed = record3.event === "ur.wizard.step" ? [...common, "event", "flow_version", "content_version", "step_id", "phase", "duration_ms", "reason", "selection_source", "framework", "package_manager", "resumed", "guidance_file"] : [...common, "event", "command", "success_count", "failure_count", "total_duration_ms", "max_duration_ms"];
212792
- if (Object.keys(record3).some((key) => !allowed.includes(key)) || !idPattern.test(record3.event_id) || !idPattern.test(record3.run_id) || !versionPattern.test(record3.release_version) || !["interactive", "agent", "ci", "noninteractive"].includes(record3.execution_mode))
212791
+ const allowed = record2.event === "ur.wizard.step" ? [...common, "event", "flow_version", "content_version", "step_id", "phase", "duration_ms", "reason", "selection_source", "framework", "package_manager", "resumed", "guidance_file"] : [...common, "event", "command", "success_count", "failure_count", "total_duration_ms", "max_duration_ms"];
212792
+ if (Object.keys(record2).some((key) => !allowed.includes(key)) || !idPattern.test(record2.event_id) || !idPattern.test(record2.run_id) || !versionPattern.test(record2.release_version) || !["interactive", "agent", "ci", "noninteractive"].includes(record2.execution_mode))
212793
212793
  return false;
212794
- if (!Number.isFinite(Date.parse(record3.occurred_at)) || Date.now() - Date.parse(record3.occurred_at) > ttl || Date.parse(record3.occurred_at) > Date.now() + 3e5)
212794
+ if (!Number.isFinite(Date.parse(record2.occurred_at)) || Date.now() - Date.parse(record2.occurred_at) > ttl || Date.parse(record2.occurred_at) > Date.now() + 3e5)
212795
212795
  return false;
212796
- if (record3.workspace_id && !idPattern.test(record3.workspace_id) || record3.site_id && (!record3.workspace_id || !idPattern.test(record3.site_id)) || record3.source_site_environment && !["development", "production"].includes(record3.source_site_environment))
212796
+ if (record2.workspace_id && !idPattern.test(record2.workspace_id) || record2.site_id && (!record2.workspace_id || !idPattern.test(record2.site_id)) || record2.source_site_environment && !["development", "production"].includes(record2.source_site_environment))
212797
212797
  return false;
212798
- if (record3.event === "ur.wizard.step")
212799
- return record3.surface === "wizard" && WIZARD_STEPS.includes(record3.step_id) && WIZARD_PHASES.includes(record3.phase) && versionPattern.test(record3.flow_version) && versionPattern.test(record3.content_version) && (record3.duration_ms === void 0 || number(record3.duration_ms)) && (record3.reason === void 0 || TELEMETRY_REASONS.includes(record3.reason)) && (record3.selection_source === void 0 || ["prompt", "flag", "default"].includes(record3.selection_source)) && (record3.framework === void 0 || ["react", "next", "vue", "vanilla"].includes(record3.framework)) && (record3.package_manager === void 0 || ["npm", "pnpm", "yarn"].includes(record3.package_manager)) && (record3.resumed === void 0 || typeof record3.resumed === "boolean") && (record3.guidance_file === void 0 || ["AGENTS.md", "CLAUDE.md"].includes(record3.guidance_file));
212800
- return record3.event === "ur.cli.usage" && record3.surface === "cli" && commands.has(record3.command) && Number.isSafeInteger(record3.success_count) && number(record3.success_count, 1e4) && Number.isSafeInteger(record3.failure_count) && number(record3.failure_count, 1e4) && record3.success_count + record3.failure_count > 0 && number(record3.total_duration_ms, 864e9) && number(record3.max_duration_ms) && record3.total_duration_ms >= record3.max_duration_ms;
212798
+ if (record2.event === "ur.wizard.step")
212799
+ return record2.surface === "wizard" && WIZARD_STEPS.includes(record2.step_id) && WIZARD_PHASES.includes(record2.phase) && versionPattern.test(record2.flow_version) && versionPattern.test(record2.content_version) && (record2.duration_ms === void 0 || number(record2.duration_ms)) && (record2.reason === void 0 || TELEMETRY_REASONS.includes(record2.reason)) && (record2.selection_source === void 0 || ["prompt", "flag", "default"].includes(record2.selection_source)) && (record2.framework === void 0 || ["react", "next", "vue", "vanilla"].includes(record2.framework)) && (record2.package_manager === void 0 || ["npm", "pnpm", "yarn"].includes(record2.package_manager)) && (record2.resumed === void 0 || typeof record2.resumed === "boolean") && (record2.guidance_file === void 0 || ["AGENTS.md", "CLAUDE.md"].includes(record2.guidance_file));
212800
+ return record2.event === "ur.cli.usage" && record2.surface === "cli" && commands.has(record2.command) && Number.isSafeInteger(record2.success_count) && number(record2.success_count, 1e4) && Number.isSafeInteger(record2.failure_count) && number(record2.failure_count, 1e4) && record2.success_count + record2.failure_count > 0 && number(record2.total_duration_ms, 864e9) && number(record2.max_duration_ms) && record2.total_duration_ms >= record2.max_duration_ms;
212801
212801
  }
212802
212802
  var ToolTelemetry = class {
212803
212803
  options;
@@ -212861,18 +212861,18 @@ var ToolTelemetry = class {
212861
212861
  step(step_id, phase, details = {}) {
212862
212862
  if (!this.active || this.options.surface !== "wizard" || this.pending.length >= maximumRecords)
212863
212863
  return;
212864
- const record3 = { ...this.common(), ...this.wizardContext, ...details, event: "ur.wizard.step", flow_version: WIZARD_FLOW_VERSION, content_version: WIZARD_CONTENT_VERSION, step_id, phase };
212865
- if (record3.duration_ms !== void 0)
212866
- record3.duration_ms = duration(record3.duration_ms);
212867
- if (validRecord(record3))
212868
- this.pending.push({ scope: this.scope(), record: record3 });
212864
+ const record2 = { ...this.common(), ...this.wizardContext, ...details, event: "ur.wizard.step", flow_version: WIZARD_FLOW_VERSION, content_version: WIZARD_CONTENT_VERSION, step_id, phase };
212865
+ if (record2.duration_ms !== void 0)
212866
+ record2.duration_ms = duration(record2.duration_ms);
212867
+ if (validRecord(record2))
212868
+ this.pending.push({ scope: this.scope(), record: record2 });
212869
212869
  }
212870
212870
  command(command2, success, durationMs) {
212871
212871
  if (!this.active || this.options.surface !== "cli")
212872
212872
  return;
212873
- const record3 = { ...this.common(), event: "ur.cli.usage", command: commands.has(command2) ? command2 : "unknown", success_count: success ? 1 : 0, failure_count: success ? 0 : 1, total_duration_ms: duration(durationMs), max_duration_ms: duration(durationMs) };
212874
- if (validRecord(record3))
212875
- this.pending.push({ scope: this.scope(), record: record3 });
212873
+ const record2 = { ...this.common(), event: "ur.cli.usage", command: commands.has(command2) ? command2 : "unknown", success_count: success ? 1 : 0, failure_count: success ? 0 : 1, total_duration_ms: duration(durationMs), max_duration_ms: duration(durationMs) };
212874
+ if (validRecord(record2))
212875
+ this.pending.push({ scope: this.scope(), record: record2 });
212876
212876
  }
212877
212877
  /** Save a bounded checkpoint without introducing a network call into a wizard step. */
212878
212878
  checkpoint() {
@@ -212915,29 +212915,29 @@ ${scope2}`).digest("hex");
212915
212915
  } catch {
212916
212916
  }
212917
212917
  state.records = this.aggregate([...state.records, ...queued], new Set(state.frozen_ids)).slice(-maximumRecords);
212918
- state.frozen_ids = state.frozen_ids.filter((id) => state.records.some((record3) => record3.event_id === id));
212918
+ state.frozen_ids = state.frozen_ids.filter((id) => state.records.some((record2) => record2.event_id === id));
212919
212919
  await atomicJson(path, state);
212920
212920
  this.pending = this.pending.filter((item) => item.scope !== scope2);
212921
212921
  if (!state.records.length || storeOnly || this.options.offline || !authorized || !force && Date.now() - state.last_attempt < (this.options.minimumIntervalMs ?? 6e4))
212922
212922
  continue;
212923
212923
  const records = [];
212924
- for (const record3 of state.records.slice(0, 50)) {
212925
- const candidate = { schema_version: 1, installation_id: state.installation_id, records: [...records, record3] };
212924
+ for (const record2 of state.records.slice(0, 50)) {
212925
+ const candidate = { schema_version: 1, installation_id: state.installation_id, records: [...records, record2] };
212926
212926
  if (Buffer.byteLength(JSON.stringify(candidate)) > 3e4)
212927
212927
  break;
212928
- records.push(record3);
212928
+ records.push(record2);
212929
212929
  }
212930
212930
  if (!records.length)
212931
212931
  continue;
212932
212932
  state.last_attempt = Date.now();
212933
- state.frozen_ids = [.../* @__PURE__ */ new Set([...state.frozen_ids, ...records.map((record3) => record3.event_id)])];
212933
+ state.frozen_ids = [.../* @__PURE__ */ new Set([...state.frozen_ids, ...records.map((record2) => record2.event_id)])];
212934
212934
  await atomicJson(path, state);
212935
212935
  const response = await this.fetcher(`${this.origin}/v1/telemetry/developer-tools`, { method: "POST", headers: { "Content-Type": "application/json", ...scope2 !== "anonymous" && this.session ? { Authorization: `Bearer ${this.session.accessToken}` } : {} }, redirect: "error", signal: AbortSignal.timeout(scope2 === "anonymous" ? 500 : 1500), body: JSON.stringify({ schema_version: 1, installation_id: state.installation_id, records }) });
212936
212936
  await response.body?.cancel().catch(() => {
212937
212937
  });
212938
212938
  if (response.ok) {
212939
212939
  state.records = state.records.slice(records.length);
212940
- state.frozen_ids = state.frozen_ids.filter((id) => state.records.some((record3) => record3.event_id === id));
212940
+ state.frozen_ids = state.frozen_ids.filter((id) => state.records.some((record2) => record2.event_id === id));
212941
212941
  await atomicJson(path, state);
212942
212942
  }
212943
212943
  } catch {
@@ -212953,22 +212953,22 @@ ${scope2}`).digest("hex");
212953
212953
  }
212954
212954
  aggregate(records, frozen) {
212955
212955
  const result = [], aggregates = /* @__PURE__ */ new Map();
212956
- for (const record3 of records) {
212957
- if (record3.event !== "ur.cli.usage" || frozen.has(record3.event_id)) {
212958
- result.push(record3);
212956
+ for (const record2 of records) {
212957
+ if (record2.event !== "ur.cli.usage" || frozen.has(record2.event_id)) {
212958
+ result.push(record2);
212959
212959
  continue;
212960
212960
  }
212961
- const key = JSON.stringify([record3.command, record3.release_version, record3.execution_mode, record3.workspace_id, record3.site_id, record3.source_site_environment]);
212961
+ const key = JSON.stringify([record2.command, record2.release_version, record2.execution_mode, record2.workspace_id, record2.site_id, record2.source_site_environment]);
212962
212962
  const previous = aggregates.get(key);
212963
- if (!previous || previous.success_count + record3.success_count > 1e4 || previous.failure_count + record3.failure_count > 1e4 || previous.total_duration_ms + record3.total_duration_ms > 864e9) {
212964
- const next = { ...record3 };
212963
+ if (!previous || previous.success_count + record2.success_count > 1e4 || previous.failure_count + record2.failure_count > 1e4 || previous.total_duration_ms + record2.total_duration_ms > 864e9) {
212964
+ const next = { ...record2 };
212965
212965
  aggregates.set(key, next);
212966
212966
  result.push(next);
212967
212967
  } else {
212968
- previous.success_count += record3.success_count;
212969
- previous.failure_count += record3.failure_count;
212970
- previous.total_duration_ms += record3.total_duration_ms;
212971
- previous.max_duration_ms = Math.max(previous.max_duration_ms, record3.max_duration_ms);
212968
+ previous.success_count += record2.success_count;
212969
+ previous.failure_count += record2.failure_count;
212970
+ previous.total_duration_ms += record2.total_duration_ms;
212971
+ previous.max_duration_ms = Math.max(previous.max_duration_ms, record2.max_duration_ms);
212972
212972
  }
212973
212973
  }
212974
212974
  return result;
@@ -213024,6 +213024,235 @@ import { createHash as createHash4, randomUUID as randomUUID5 } from "node:crypt
213024
213024
  import { lstat as lstat2, realpath, readdir as readdir2, open as open4, readFile as readFile4 } from "node:fs/promises";
213025
213025
  import { isAbsolute, relative, resolve, sep } from "node:path";
213026
213026
  import { execFile } from "node:child_process";
213027
+
213028
+ // node_modules/@userreason/cli/dist/recommendation-source.js
213029
+ var import_typescript = __toESM(require_typescript(), 1);
213030
+ import { posix } from "node:path";
213031
+ var bytes = (text2) => Buffer.byteLength(text2);
213032
+ var limits = { roots: 64, total: 164e3, file: 26e3, span: 16e3, workflow: 38e3, support: 8e3, shared: 5e3, excerpts: 200 };
213033
+ function analyze(file) {
213034
+ const ast = import_typescript.default.createSourceFile(file.path, file.text, import_typescript.default.ScriptTarget.Latest, true, /\.[cm]?jsx?$/.test(file.path) ? import_typescript.default.ScriptKind.JSX : /\.tsx$/.test(file.path) ? import_typescript.default.ScriptKind.TSX : import_typescript.default.ScriptKind.TS);
213035
+ const imports = [], tags = /* @__PURE__ */ new Set(), handlers = /* @__PURE__ */ new Set(), templates = [];
213036
+ const walk = (node) => {
213037
+ if (import_typescript.default.isImportDeclaration(node) && import_typescript.default.isStringLiteral(node.moduleSpecifier)) {
213038
+ const names = [], bindings = node.importClause?.namedBindings;
213039
+ if (node.importClause?.name)
213040
+ names.push(node.importClause.name.text);
213041
+ if (bindings && import_typescript.default.isNamedImports(bindings))
213042
+ names.push(...bindings.elements.map((element) => element.name.text));
213043
+ imports.push({ specifier: node.moduleSpecifier.text, names });
213044
+ }
213045
+ if (import_typescript.default.isExportDeclaration(node) && node.moduleSpecifier && import_typescript.default.isStringLiteral(node.moduleSpecifier))
213046
+ imports.push({ specifier: node.moduleSpecifier.text, names: [] });
213047
+ if (import_typescript.default.isJsxOpeningElement(node) || import_typescript.default.isJsxSelfClosingElement(node))
213048
+ tags.add(node.tagName.getText(ast).split(".")[0]);
213049
+ if (import_typescript.default.isJsxAttribute(node) && /^on[A-Z]/.test(node.name.getText(ast))) {
213050
+ const ids = (child) => {
213051
+ if (import_typescript.default.isIdentifier(child))
213052
+ handlers.add(child.text);
213053
+ import_typescript.default.forEachChild(child, ids);
213054
+ };
213055
+ import_typescript.default.forEachChild(node, ids);
213056
+ }
213057
+ if (import_typescript.default.isPropertyAssignment(node) && node.name.getText(ast) === "templateUrl" && import_typescript.default.isStringLiteral(node.initializer))
213058
+ templates.push(node.initializer.text);
213059
+ import_typescript.default.forEachChild(node, walk);
213060
+ };
213061
+ walk(ast);
213062
+ if (/\.(?:vue|svelte|html)$/.test(file.path))
213063
+ for (const match of file.text.matchAll(/(?:\([\w.:-]+\)|@[\w.:-]+)\s*=\s*["']([^"']+)["']/g))
213064
+ for (const call of match[1].matchAll(/([A-Za-z_$][\w$]*)\s*\(/g))
213065
+ handlers.add(call[1]);
213066
+ return { ast, imports, rendered: new Set(imports.filter((item) => item.names.some((name) => tags.has(name))).map((item) => item.specifier)), handlers, templates };
213067
+ }
213068
+ function recommendationSourceWindows(file, requiredHandlers = []) {
213069
+ const lines = file.text.split("\n");
213070
+ const make = (start, end) => ({ path: file.path, start, end, text: lines.slice(start - 1, end).join("\n") });
213071
+ if (bytes(file.text) <= limits.file)
213072
+ return [make(1, lines.length)];
213073
+ if (!/\.[cm]?[jt]sx?$/.test(file.path))
213074
+ return [];
213075
+ const a = analyze(file), units = [];
213076
+ for (const handler of requiredHandlers)
213077
+ a.handlers.add(handler);
213078
+ const add = (node, priority) => units.push({ start: a.ast.getLineAndCharacterOfPosition(node.getStart(a.ast)).line + 1, end: a.ast.getLineAndCharacterOfPosition(node.end).line + 1, priority });
213079
+ const inspect = (node) => {
213080
+ if (import_typescript.default.isImportDeclaration(node) || import_typescript.default.isExportDeclaration(node)) {
213081
+ add(node, 2);
213082
+ return;
213083
+ }
213084
+ if ((import_typescript.default.isFunctionDeclaration(node) || import_typescript.default.isArrowFunction(node) || import_typescript.default.isFunctionExpression(node)) && node.body && import_typescript.default.isBlock(node.body)) {
213085
+ for (const statement of node.body.statements) {
213086
+ const raw = statement.getText(a.ast);
213087
+ const names = import_typescript.default.isVariableStatement(statement) ? statement.declarationList.declarations.map((declaration) => declaration.name.getText(a.ast)) : import_typescript.default.isFunctionDeclaration(statement) && statement.name ? [statement.name.text] : [];
213088
+ add(statement, /return\s*\(?\s*</.test(raw) || /useEffect|useState|useCallback|useMemo/.test(raw) || names.some((name) => a.handlers.has(name)) ? 0 : 1);
213089
+ }
213090
+ return;
213091
+ }
213092
+ if (import_typescript.default.isClassDeclaration(node)) {
213093
+ for (const member of node.members)
213094
+ add(member, member.name && a.handlers.has(member.name.getText(a.ast)) ? 0 : 1);
213095
+ return;
213096
+ }
213097
+ if (import_typescript.default.isVariableStatement(node)) {
213098
+ let expanded = false;
213099
+ for (const declaration of node.declarationList.declarations)
213100
+ if (declaration.initializer && (import_typescript.default.isArrowFunction(declaration.initializer) || import_typescript.default.isFunctionExpression(declaration.initializer))) {
213101
+ inspect(declaration.initializer);
213102
+ expanded = true;
213103
+ }
213104
+ if (!expanded)
213105
+ add(node, 2);
213106
+ return;
213107
+ }
213108
+ add(node, 2);
213109
+ };
213110
+ for (const node of a.ast.statements)
213111
+ inspect(node);
213112
+ const selected = [];
213113
+ let retained = 0;
213114
+ for (const unit of units.sort((a2, b) => a2.priority - b.priority || a2.start - b.start)) {
213115
+ if (selected.some((window2) => window2.start <= unit.start && window2.end >= unit.end))
213116
+ continue;
213117
+ const window = make(unit.start, unit.end), length = bytes(window.text);
213118
+ if (length > limits.span || retained + length > limits.file)
213119
+ continue;
213120
+ selected.push(window);
213121
+ retained += length;
213122
+ }
213123
+ return selected.sort((a2, b) => a2.start - b.start);
213124
+ }
213125
+ var shell = (path) => /^(?:app|main|router|routes|layout)\.[cm]?[jt]sx?$/i.test(posix.basename(path)) || /\/app\.component\.(?:ts|html)$/.test(path);
213126
+ var rank = (path) => /\/(?:routes|pages|screens|views)\//.test("/" + path) ? 0 : /\.component\.html$/.test(path) ? 1 : 2;
213127
+ var family = (path) => {
213128
+ const parts = path.split("/"), index = parts.findIndex((part) => ["routes", "pages", "screens", "views"].includes(part));
213129
+ return index >= 0 ? parts.slice(0, index + 2).join("/") : posix.dirname(path);
213130
+ };
213131
+ function connectedRecommendationSource(candidates, maxPacketBytes = 262144) {
213132
+ const files2 = new Map(candidates.map((file) => [file.path, file])), analyses = /* @__PURE__ */ new Map();
213133
+ const record2 = (path) => {
213134
+ if (!analyses.has(path))
213135
+ analyses.set(path, analyze(files2.get(path)));
213136
+ return analyses.get(path);
213137
+ };
213138
+ const resolve3 = (from, specifier) => {
213139
+ const base = specifier.startsWith(".") ? posix.normalize(posix.join(posix.dirname(from), specifier)) : specifier.startsWith("@/") ? `src/${specifier.slice(2)}` : "";
213140
+ if (!base)
213141
+ return void 0;
213142
+ return [base, ...[".tsx", ".ts", ".jsx", ".js", ".vue", ".svelte", ".html", "/index.tsx", "/index.ts", "/index.jsx", "/index.js"].map((ext) => base + ext)].find((path) => files2.has(path));
213143
+ };
213144
+ const references = (path) => {
213145
+ const a = record2(path);
213146
+ return [
213147
+ ...a.imports.flatMap((item) => {
213148
+ const target = resolve3(path, item.specifier);
213149
+ return target ? [{ target, rendered: a.rendered.has(item.specifier), template: false }] : [];
213150
+ }),
213151
+ ...a.templates.flatMap((template) => {
213152
+ const target = resolve3(path, template);
213153
+ return target ? [{ target, rendered: true, template: true }] : [];
213154
+ }),
213155
+ .../\.component\.html$/.test(path) && files2.has(path.replace(/\.html$/, ".ts")) ? [{ target: path.replace(/\.html$/, ".ts"), rendered: true, template: true }] : []
213156
+ ].sort((a2, b) => Number(b.rendered) - Number(a2.rendered) || a2.target.localeCompare(b.target));
213157
+ };
213158
+ const buckets = /* @__PURE__ */ new Map();
213159
+ for (const file of candidates.filter((file2) => rank(file2.path) < 2 && !shell(file2.path))) {
213160
+ const key = family(file.path);
213161
+ buckets.set(key, [...buckets.get(key) ?? [], file]);
213162
+ }
213163
+ for (const bucket of buckets.values())
213164
+ bucket.sort((a, b) => a.path.split("/").length - b.path.split("/").length || a.path.localeCompare(b.path));
213165
+ const queues = [...buckets].sort((a, b) => a[0].localeCompare(b[0])), seeds = [];
213166
+ for (let i = 0; seeds.length < Math.min(limits.roots, [...buckets.values()].reduce((n, values) => n + values.length, 0)); i++)
213167
+ for (const [, bucket] of queues)
213168
+ if (bucket[i] && seeds.length < limits.roots)
213169
+ seeds.push(bucket[i].path);
213170
+ if (!seeds.length)
213171
+ seeds.push(...candidates.filter((file) => shell(file.path)).map((file) => file.path).slice(0, limits.roots));
213172
+ if (!seeds.length)
213173
+ seeds.push(...candidates.filter((file) => /\.(?:[cm]?[jt]sx?|vue|svelte|html)$/.test(file.path)).map((file) => file.path).slice(0, limits.roots));
213174
+ const rootSet = new Set(seeds), owner = new Map(seeds.map((path) => [path, path]));
213175
+ const find = (path) => {
213176
+ const seen2 = /* @__PURE__ */ new Set();
213177
+ while (owner.get(path) !== path && !seen2.has(path)) {
213178
+ seen2.add(path);
213179
+ path = owner.get(path);
213180
+ }
213181
+ return path;
213182
+ };
213183
+ for (const seed of seeds)
213184
+ for (const edge of references(seed))
213185
+ if (edge.rendered && rootSet.has(edge.target) && find(seed) !== find(edge.target))
213186
+ owner.set(find(edge.target), find(seed));
213187
+ const groups = /* @__PURE__ */ new Map();
213188
+ for (const seed of seeds) {
213189
+ const key = find(seed);
213190
+ groups.set(key, [...groups.get(key) ?? [], seed]);
213191
+ }
213192
+ const workflows = [];
213193
+ for (const roots of groups.values()) {
213194
+ const windows = [], seen2 = /* @__PURE__ */ new Set(), queue = roots.map((path) => ({ path, depth: 0 }));
213195
+ let retained2 = 0, support = 0;
213196
+ const append2 = (path, supporting, handlers = []) => {
213197
+ for (const window of recommendationSourceWindows(files2.get(path), handlers)) {
213198
+ const key = `${path}:${window.start}:${window.end}`, length = bytes(window.text);
213199
+ if (seen2.has(key) || retained2 + length > limits.workflow || supporting && support + length > limits.support)
213200
+ continue;
213201
+ seen2.add(key);
213202
+ windows.push(window);
213203
+ retained2 += length;
213204
+ if (supporting)
213205
+ support += length;
213206
+ }
213207
+ };
213208
+ for (const root of roots)
213209
+ append2(root, false);
213210
+ const visited = /* @__PURE__ */ new Set();
213211
+ while (queue.length) {
213212
+ const item = queue.shift();
213213
+ if (visited.has(item.path) || item.depth > 2)
213214
+ continue;
213215
+ visited.add(item.path);
213216
+ for (const edge of references(item.path).slice(0, 12)) {
213217
+ if (rootSet.has(edge.target) && !roots.includes(edge.target))
213218
+ continue;
213219
+ append2(edge.target, !roots.includes(edge.target), edge.template ? [...record2(item.path).handlers] : []);
213220
+ if (edge.rendered || edge.template)
213221
+ queue.push({ path: edge.target, depth: item.depth + 1 });
213222
+ }
213223
+ }
213224
+ if (windows.length)
213225
+ workflows.push(windows);
213226
+ }
213227
+ const selected = [], seen = /* @__PURE__ */ new Set();
213228
+ let retained = 0, wireBytes = 512;
213229
+ const append = (window) => {
213230
+ const key = `${window.path}:${window.start}:${window.end}`, length = bytes(window.text);
213231
+ if (seen.has(key) || selected.length >= limits.excerpts || retained + length > limits.total)
213232
+ return;
213233
+ const encoded = bytes(JSON.stringify({ kind: "local_source", id: `source_${selected.length + 1}`, path: window.path, file_hash: "0".repeat(64), excerpt_hash: "0".repeat(64), snapshot_id: "00000000-0000-4000-8000-000000000000", start_line: window.start, end_line: window.end, excerpt: window.text })) + 1;
213234
+ if (wireBytes + encoded > maxPacketBytes)
213235
+ return;
213236
+ seen.add(key);
213237
+ selected.push(window);
213238
+ retained += length;
213239
+ wireBytes += encoded;
213240
+ };
213241
+ let shared = 0;
213242
+ for (const file of candidates.filter((file2) => shell(file2.path)).slice(0, 8))
213243
+ for (const window of recommendationSourceWindows(file))
213244
+ if (shared + bytes(window.text) <= limits.shared) {
213245
+ append(window);
213246
+ shared += bytes(window.text);
213247
+ }
213248
+ for (let i = 0; i < Math.max(0, ...workflows.map((windows) => windows.length)); i++)
213249
+ for (const windows of workflows)
213250
+ if (windows[i])
213251
+ append(windows[i]);
213252
+ return selected;
213253
+ }
213254
+
213255
+ // node_modules/@userreason/cli/dist/first-survey-source.js
213027
213256
  var sourceHash = (value) => createHash4("sha256").update(value).digest("hex");
213028
213257
  var forbidden = /(^|\/)(?:\.git|\.env(?:\..*)?|node_modules|vendor|dist|build|coverage|\.next|\.nuxt|\.cache|\.output|public|uploads?|datasets?|fixtures?|__fixtures__|backups?|credentials?|secrets?)(\/|$)|(?:\.min\.[cm]?js|\.map|\.lock|\.(?:pem|key|p12|pfx|sqlite|db|csv|parquet|log|snap))$|(^|\/)(?:package-lock\.json|yarn\.lock|pnpm-lock\.yaml|\.npmrc|\.netrc|id_rsa|id_ed25519)$/i;
213029
213258
  var sourceFile = /(?:\.(?:[cm]?[jt]sx?|vue|svelte|json|md))$/i;
@@ -213044,12 +213273,12 @@ async function collectFirstSurveySource(input) {
213044
213273
  const root = await realpath(input.root);
213045
213274
  if (root !== input.root || !(await lstat2(root)).isDirectory())
213046
213275
  throw new Error("Application root must be a canonical directory, not a symlink");
213047
- const maxFiles = safeLimits(input.maxFiles, 200, 200);
213048
- const maxBytes = safeLimits(input.maxBytes, input.recommendations ? 2 * 1024 * 1024 : 500 * 1024, input.recommendations ? 2 * 1024 * 1024 : 500 * 1024);
213049
- const maxPacketBytes = safeLimits(input.maxPacketBytes, 1e4, 1e4);
213276
+ const maxFiles = safeLimits(input.maxFiles, input.benchmark ? 1200 : 200, input.benchmark ? 1200 : 200);
213277
+ const maxBytes = safeLimits(input.maxBytes, input.benchmark ? 12 * 1024 * 1024 : input.recommendations ? 2 * 1024 * 1024 : 500 * 1024, input.benchmark ? 12 * 1024 * 1024 : input.recommendations ? 2 * 1024 * 1024 : 500 * 1024);
213278
+ const maxPacketBytes = safeLimits(input.maxPacketBytes, input.benchmark ? 262144 : 1e4, input.benchmark ? 262144 : 1e4);
213050
213279
  const snapshot_id = input.snapshotId ?? randomUUID5();
213051
213280
  const omitted = [], evidence = [];
213052
- let inspected = 0, bytes = 0, packetBytes = 0, truncated = false, entries = 0;
213281
+ let inspected = 0, bytes2 = 0, packetBytes = 0, truncated = false, entries = 0;
213053
213282
  const candidates = [];
213054
213283
  const rootIgnore = (0, import_ignore.default)();
213055
213284
  for (const name of [".gitignore", ".ignore", ".userreasonignore"]) {
@@ -213071,7 +213300,7 @@ async function collectFirstSurveySource(input) {
213071
213300
  const check = () => input.signal?.throwIfAborted();
213072
213301
  async function walk(directory2, inherited) {
213073
213302
  check();
213074
- if (entries >= 2e3 || inspected >= maxFiles || bytes >= maxBytes) {
213303
+ if (entries >= (input.benchmark ? 2e4 : 2e3) || inspected >= maxFiles || bytes2 >= maxBytes) {
213075
213304
  truncated = true;
213076
213305
  return;
213077
213306
  }
@@ -213087,18 +213316,20 @@ async function collectFirstSurveySource(input) {
213087
213316
  }
213088
213317
  }
213089
213318
  const names = (await readdir2(directory2)).sort((a, b) => {
213090
- const rank = (s) => /^(package\.json|README\.md)$/.test(s) ? 0 : /init|route|page|screen|state|event|app|main/i.test(s) ? 1 : 2;
213091
- return rank(a) - rank(b) || a.localeCompare(b);
213319
+ const rank2 = (s) => /^(package\.json|README\.md)$/.test(s) ? 0 : /init|route|page|screen|state|event|app|main/i.test(s) ? 1 : 2;
213320
+ return rank2(a) - rank2(b) || a.localeCompare(b);
213092
213321
  });
213093
213322
  for (const name of names) {
213094
213323
  check();
213095
- if (++entries > 2e3 || inspected >= maxFiles || bytes >= maxBytes) {
213324
+ if (++entries > (input.benchmark ? 2e4 : 2e3) || inspected >= maxFiles || bytes2 >= maxBytes) {
213096
213325
  truncated = true;
213097
213326
  break;
213098
213327
  }
213099
213328
  const absolute = resolve(directory2, name), path = relative(root, absolute).split(sep).join("/");
213100
213329
  if (forbidden.test(path))
213101
213330
  continue;
213331
+ if (input.benchmark && /(?:^|\/)(?:scripts|tools|test|tests|__tests__|e2e|docs|examples|storybook|\.storybook)(?:\/|$)/i.test(path))
213332
+ continue;
213102
213333
  if (input.recommendations && /^(?:\.agents|\.cursor|\.codex)(?:\/|$)/.test(path))
213103
213334
  continue;
213104
213335
  const stat = await lstat2(absolute);
@@ -213124,13 +213355,13 @@ async function collectFirstSurveySource(input) {
213124
213355
  continue;
213125
213356
  inspected++;
213126
213357
  const fileBudget = input.recommendations ? 256e3 : 32768;
213127
- if (stat.size > fileBudget || stat.size + bytes > maxBytes) {
213358
+ if (stat.size > fileBudget || stat.size + bytes2 > maxBytes) {
213128
213359
  omitted.push({ path, reason: "size budget" });
213129
213360
  truncated = true;
213130
213361
  continue;
213131
213362
  }
213132
- const { constants: constants6 } = await import("node:fs");
213133
- const handle = await open4(absolute, constants6.O_RDONLY | constants6.O_NOFOLLOW);
213363
+ const { constants: constants5 } = await import("node:fs");
213364
+ const handle = await open4(absolute, constants5.O_RDONLY | constants5.O_NOFOLLOW);
213134
213365
  let data;
213135
213366
  try {
213136
213367
  const opened = await handle.stat();
@@ -213144,7 +213375,7 @@ async function collectFirstSurveySource(input) {
213144
213375
  } finally {
213145
213376
  await handle.close();
213146
213377
  }
213147
- bytes += data.length;
213378
+ bytes2 += data.length;
213148
213379
  let text2;
213149
213380
  try {
213150
213381
  text2 = new TextDecoder("utf-8", { fatal: true }).decode(data);
@@ -213183,10 +213414,15 @@ async function collectFirstSurveySource(input) {
213183
213414
  }
213184
213415
  }
213185
213416
  await walk(root, [{ base: root, rules: rootIgnore }]);
213186
- if (input.recommendations) {
213187
- const rank = (p) => /\/(?:pages|screens|views)\//i.test("/" + p) ? 0 : /\/(?:app|routes?)\.[^.]+$/i.test(p) ? 1 : /components\//.test(p) ? 2 : 3;
213417
+ if (input.benchmark) {
213418
+ for (const file of connectedRecommendationSource(candidates, maxPacketBytes)) {
213419
+ evidence.push({ kind: "local_source", id: `source_${evidence.length + 1}`, path: file.path, file_hash: sourceHash(candidates.find((c) => c.path === file.path).text), excerpt_hash: sourceHash(file.text), snapshot_id, start_line: file.start, end_line: file.end, excerpt: file.text });
213420
+ }
213421
+ truncated = candidates.length > evidence.length || evidence.some((e) => e.start_line !== 1 || e.excerpt !== candidates.find((c) => c.path === e.path)?.text);
213422
+ } else if (input.recommendations) {
213423
+ const rank2 = (p) => /\/(?:pages|screens|views)\//i.test("/" + p) ? 0 : /\/(?:app|routes?)\.[^.]+$/i.test(p) ? 1 : /components\//.test(p) ? 2 : 3;
213188
213424
  const interactions = (f) => (f.text.match(/onClick|onSubmit|onChange|const handle[A-Z]|function handle[A-Z]/g) ?? []).length;
213189
- candidates.sort((a, b) => rank(a.path) - rank(b.path) || a.path.split("/").length - b.path.split("/").length || interactions(b) - interactions(a) || a.path.localeCompare(b.path));
213425
+ candidates.sort((a, b) => rank2(a.path) - rank2(b.path) || a.path.split("/").length - b.path.split("/").length || interactions(b) - interactions(a) || a.path.localeCompare(b.path));
213190
213426
  const areas = /* @__PURE__ */ new Map();
213191
213427
  for (const file of candidates) {
213192
213428
  const key = file.path.split("/").slice(0, -1).join("/");
@@ -213389,7 +213625,7 @@ async function firstSurvey(client, root, workspace2, site2, ui, mode = "start")
213389
213625
  state = { ...state, id: randomUUID6(), state: "source_review", plan: void 0, digest: void 0, saves: {} };
213390
213626
  }
213391
213627
  const metadata = object(await client.request("/onboarding/v1/planning/describe", lookup()), "planning destination");
213392
- const limits = { input_tokens: 12e3, output_tokens: 4e3, deadline_ms: 35e3 };
213628
+ const limits2 = { input_tokens: 12e3, output_tokens: 4e3, deadline_ms: 35e3 };
213393
213629
  if (!state.plan) {
213394
213630
  if (state.state === "analyzing") {
213395
213631
  const existing = object(await client.request("/onboarding/v1/planning/get", lookup()), "plan");
@@ -213405,7 +213641,7 @@ async function firstSurvey(client, root, workspace2, site2, ui, mode = "start")
213405
213641
  ui.show("Only the chosen application root is inspected. No sibling packages are included. Secret detection is best effort; review every excerpt.");
213406
213642
  const selection = await ui.answer("Relative files/directories to include, comma separated (blank: bounded application root; no siblings)");
213407
213643
  const preview = await collectFirstSurveySource({ root, signal: ui.signal, selected: selection.trim() ? selection.split(",").map((p) => p.trim()) : void 0 });
213408
- ui.show(JSON.stringify({ root, packages: preview.packages, installed_sdk: preview.packages.length ? "metadata found, runtime unverified" : "unknown: verify using installed skill", manifest: preview.evidence.map(({ excerpt, ...rest }) => rest), omitted: preview.omitted, truncated: preview.truncated, destination: metadata.destination, provider_model: metadata.model, provider_prices: metadata.prices, provider_policy: metadata.policy, configuration_fingerprint: metadata.configuration_fingerprint, retention: "Receipt and private plan: seven days, deleted on next planning activity; submitted source packets are not stored by UserReason; generated plans can quote source. Provider policy must be reviewed separately.", budget: `${limits.input_tokens} input / ${limits.output_tokens} completion tokens (including reasoning); ${limits.deadline_ms / 1e3} seconds`, capabilities: preview.capabilities, capability_status: preview.capability_status }));
213644
+ ui.show(JSON.stringify({ root, packages: preview.packages, installed_sdk: preview.packages.length ? "metadata found, runtime unverified" : "unknown: verify using installed skill", manifest: preview.evidence.map(({ excerpt, ...rest }) => rest), omitted: preview.omitted, truncated: preview.truncated, destination: metadata.destination, provider_model: metadata.model, provider_prices: metadata.prices, provider_policy: metadata.policy, configuration_fingerprint: metadata.configuration_fingerprint, retention: "Receipt and private plan: seven days, deleted on next planning activity; submitted source packets are not stored by UserReason; generated plans can quote source. Provider policy must be reviewed separately.", budget: `${limits2.input_tokens} input / ${limits2.output_tokens} completion tokens (including reasoning); ${limits2.deadline_ms / 1e3} seconds`, capabilities: preview.capabilities, capability_status: preview.capability_status }));
213409
213645
  ui.show(JSON.stringify(preview.evidence));
213410
213646
  if (!await ui.confirm("Approve uploading exactly this source packet to the displayed provider?")) {
213411
213647
  ui.show("Manual path: use prompt validate with your own evidence-labelled definition, then explicitly approve prompt create. No source processing is required.");
@@ -213428,7 +213664,7 @@ async function firstSurvey(client, root, workspace2, site2, ui, mode = "start")
213428
213664
  check();
213429
213665
  state.state = "analyzing";
213430
213666
  await save();
213431
- const response = object(await client.request("/onboarding/v1/planning/analyze", { schema_version: 1, session_id: state.id, request_id: randomUUID6(), scope: lookup().scope, packages: preview.packages, capabilities: preview.capabilities, evidence, previous_plan_digest: state.digest ?? null, limits, consent: { packet_digest: sourceHash(JSON.stringify(evidence)), destination: metadata.destination, policy_version: "first-survey-v1", configuration_fingerprint: metadata.configuration_fingerprint, authorized_at: (/* @__PURE__ */ new Date()).toISOString(), git_authorized: git } }, ui.signal), "analysis");
213667
+ const response = object(await client.request("/onboarding/v1/planning/analyze", { schema_version: 1, session_id: state.id, request_id: randomUUID6(), scope: lookup().scope, packages: preview.packages, capabilities: preview.capabilities, evidence, previous_plan_digest: state.digest ?? null, limits: limits2, consent: { packet_digest: sourceHash(JSON.stringify(evidence)), destination: metadata.destination, policy_version: "first-survey-v1", configuration_fingerprint: metadata.configuration_fingerprint, authorized_at: (/* @__PURE__ */ new Date()).toISOString(), git_authorized: git } }, ui.signal), "analysis");
213432
213668
  check();
213433
213669
  state.plan = response.result;
213434
213670
  state.digest = sourceHash(JSON.stringify(state.plan));
@@ -213512,227 +213748,11 @@ async function firstSurvey(client, root, workspace2, site2, ui, mode = "start")
213512
213748
  }
213513
213749
  }
213514
213750
 
213515
- // node_modules/@userreason/cli/dist/first-survey-preparation.js
213516
- function prepareFirstSurveyLocally(root) {
213517
- const controller = new AbortController();
213518
- const prepared = collectFirstSurveySource({ root, signal: controller.signal, recommendations: true }).then((preview) => ({ preview }), () => ({ preview: void 0 }));
213519
- return {
213520
- root,
213521
- async take(signal) {
213522
- signal?.throwIfAborted();
213523
- const cached = await prepared;
213524
- signal?.throwIfAborted();
213525
- if (cached.preview) {
213526
- try {
213527
- await verifyFirstSurveySource(root, cached.preview.evidence);
213528
- return cached.preview;
213529
- } catch {
213530
- signal?.throwIfAborted();
213531
- }
213532
- }
213533
- return collectFirstSurveySource({ root, signal, recommendations: true });
213534
- },
213535
- cancel() {
213536
- controller.abort();
213537
- }
213538
- };
213539
- }
213540
-
213541
- // node_modules/@userreason/cli/dist/recommended-surveys.js
213542
- import { randomUUID as randomUUID7 } from "node:crypto";
213751
+ // node_modules/@userreason/cli/dist/setup-store.js
213752
+ import { createHash as createHash5, randomUUID as randomUUID7 } from "node:crypto";
213543
213753
  import { constants as constants2 } from "node:fs";
213544
- import { mkdir as mkdir6, open as open6, rename as rename4, unlink as unlink3, writeFile as writeFile3 } from "node:fs/promises";
213754
+ import { lstat as lstat4, mkdir as mkdir6, open as open6, opendir, readFile as readFile6, realpath as realpath2, rename as rename4, rm as rm3 } from "node:fs/promises";
213545
213755
  import { join as join6 } from "node:path";
213546
- var record2 = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : {};
213547
- async function recommendedSurveys(client, root, workspace2, site2, ui, options = {}) {
213548
- if (!options.sourceConsent)
213549
- return { state: "skipped" };
213550
- if (!ui.chooseMany)
213551
- throw Error("Survey selection requires a checkbox interface");
213552
- const scope2 = {
213553
- api: client.config.apiUrl,
213554
- workspace_id: workspace2,
213555
- site_id: site2
213556
- };
213557
- const scopeKey = sourceHash(JSON.stringify([root, scope2]));
213558
- const dir = join6(configDirectory(), "recommended-surveys");
213559
- await mkdir6(dir, { recursive: true, mode: 448 });
213560
- const path = join6(dir, scopeKey + ".json");
213561
- const lock = await open6(path + ".lock", "wx", 384);
213562
- const preparation = options.preparation ?? prepareFirstSurveyLocally(root);
213563
- let state = {
213564
- version: 1,
213565
- scope: scopeKey,
213566
- expires: Date.now() + 7 * 864e5,
213567
- candidates: [],
213568
- sources: [],
213569
- receipts: {}
213570
- };
213571
- const save = async () => {
213572
- const tmp = path + "." + randomUUID7() + ".tmp";
213573
- await writeFile3(tmp, JSON.stringify(state), { flag: "wx", mode: 384 });
213574
- await rename4(tmp, path);
213575
- };
213576
- const check = () => ui.signal?.throwIfAborted();
213577
- try {
213578
- try {
213579
- const file = await open6(path, constants2.O_RDONLY | constants2.O_NOFOLLOW);
213580
- try {
213581
- if ((await file.stat()).size > 128e3)
213582
- throw Error("Invalid recommendation cache");
213583
- const old = JSON.parse(await file.readFile("utf8"));
213584
- if (old.version !== 1 || old.scope !== scopeKey)
213585
- throw Error("Recommendation scope changed");
213586
- if (old.expires > Date.now())
213587
- state = old;
213588
- } finally {
213589
- await file.close();
213590
- }
213591
- } catch (e) {
213592
- if (e.code !== "ENOENT")
213593
- throw e;
213594
- }
213595
- check();
213596
- if (!state.selected) {
213597
- if (state.candidates.length) {
213598
- try {
213599
- await verifyFirstSurveySource(root, state.sources);
213600
- } catch {
213601
- state.candidates = [];
213602
- state.sources = [];
213603
- }
213604
- }
213605
- if (!state.candidates.length) {
213606
- const generate = async () => {
213607
- const preview = await preparation.take(ui.signal);
213608
- if (!preview.evidence.length)
213609
- throw Error("No product source available");
213610
- const metadata = record2(await client.request("/onboarding/v1/planning/describe", { schema_version: 1, session_id: randomUUID7(), scope: scope2 }, ui.signal));
213611
- if (!record2(metadata.recommendations).version)
213612
- throw Error("Development recommendation pipeline is unavailable");
213613
- await verifyFirstSurveySource(root, preview.evidence);
213614
- const response = record2(await client.request("/onboarding/v1/planning/analyze", {
213615
- schema_version: 1,
213616
- session_id: randomUUID7(),
213617
- request_id: randomUUID7(),
213618
- scope: scope2,
213619
- packages: preview.packages,
213620
- capabilities: [
213621
- ...preview.capabilities,
213622
- "recommended_surveys:v1"
213623
- ],
213624
- evidence: preview.evidence,
213625
- previous_plan_digest: null,
213626
- limits: {
213627
- input_tokens: 12e3,
213628
- output_tokens: 4e3,
213629
- deadline_ms: 4e4
213630
- },
213631
- consent: {
213632
- packet_digest: sourceHash(JSON.stringify(preview.evidence)),
213633
- destination: metadata.destination,
213634
- configuration_fingerprint: metadata.configuration_fingerprint,
213635
- policy_version: "first-survey-v1",
213636
- authorized_at: (/* @__PURE__ */ new Date()).toISOString(),
213637
- git_authorized: false
213638
- }
213639
- }, ui.signal));
213640
- await verifyFirstSurveySource(root, preview.evidence);
213641
- const candidates = record2(response.result).candidates;
213642
- if (!Array.isArray(candidates))
213643
- throw Error("Invalid recommendations");
213644
- state.candidates = candidates.slice(0, 3);
213645
- state.sources = preview.evidence.map(({ path: path2, file_hash }) => ({
213646
- path: path2,
213647
- file_hash
213648
- }));
213649
- await save();
213650
- };
213651
- try {
213652
- if (ui.loading)
213653
- await ui.loading("Finding recommended surveys", generate);
213654
- else
213655
- await generate();
213656
- } catch (error) {
213657
- check();
213658
- ui.show("Recommendations are unavailable right now. Setup is complete; rerun the wizard to try again.");
213659
- return {
213660
- state: "unavailable",
213661
- error: error instanceof Error ? error.message : "unavailable"
213662
- };
213663
- }
213664
- }
213665
- if (!state.candidates.length) {
213666
- ui.show("No supported survey recommendations yet. Setup is complete.");
213667
- return { state: "empty" };
213668
- }
213669
- ui.show("Select surveys to get started. We\u2019ll create drafts in your workspace. Nothing will be published.");
213670
- const selected = await ui.chooseMany("Recommended surveys", state.candidates.map((c) => ({
213671
- value: c.id,
213672
- label: `${String(c.definition.name)} \u2014 ${c.question}`,
213673
- hint: `${c.opportunity.claim} Delivery can be configured later.`
213674
- })), []);
213675
- check();
213676
- if (!selected.length)
213677
- return { state: "skipped" };
213678
- if (new Set(selected).size !== selected.length || selected.some((id) => !state.candidates.some((c) => c.id === id)))
213679
- throw Error("Invalid survey selection");
213680
- await verifyFirstSurveySource(root, state.sources);
213681
- for (const id of selected) {
213682
- const c = state.candidates.find((c2) => c2.id === id);
213683
- const validation = record2(await client.read("prompts.validate", {
213684
- workspaceId: workspace2,
213685
- siteId: site2,
213686
- definition: c.definition
213687
- }));
213688
- if (validation.valid !== true)
213689
- throw Error("A recommended draft did not validate");
213690
- }
213691
- state.selected = selected;
213692
- for (const id of selected)
213693
- state.receipts[id] = {
213694
- prompt: randomUUID7(),
213695
- request: randomUUID7(),
213696
- definition: state.candidates.find((c) => c.id === id).definition
213697
- };
213698
- await save();
213699
- }
213700
- let count = 0;
213701
- for (const id of state.selected) {
213702
- check();
213703
- const receipt = state.receipts[id];
213704
- if (!receipt)
213705
- throw Error("Missing draft receipt");
213706
- if (!receipt.result) {
213707
- receipt.result = await client.promptCommand({
213708
- workspaceId: workspace2,
213709
- siteId: site2,
213710
- action: "create",
213711
- promptId: receipt.prompt,
213712
- requestId: receipt.request,
213713
- definition: receipt.definition
213714
- });
213715
- await save();
213716
- }
213717
- const saved = record2(receipt.result), link = record2(saved.links).edit;
213718
- ui.show(`Draft saved: ${String(receipt.definition.name)}${typeof link === "string" ? `
213719
- ${link}` : ""}`);
213720
- count++;
213721
- }
213722
- ui.show(`${count} survey draft${count === 1 ? "" : "s"} saved. Nothing was published.`);
213723
- return { state: "saved", count, receipts: state.receipts };
213724
- } finally {
213725
- preparation.cancel();
213726
- await lock.close();
213727
- await unlink3(path + ".lock");
213728
- }
213729
- }
213730
-
213731
- // node_modules/@userreason/cli/dist/setup-store.js
213732
- import { createHash as createHash5, randomUUID as randomUUID8 } from "node:crypto";
213733
- import { constants as constants3 } from "node:fs";
213734
- import { lstat as lstat4, mkdir as mkdir7, open as open7, opendir, readFile as readFile6, realpath as realpath2, rename as rename5, rm as rm3 } from "node:fs/promises";
213735
- import { join as join7 } from "node:path";
213736
213756
  var SetupError = class extends Error {
213737
213757
  code;
213738
213758
  constructor(code, message) {
@@ -213755,7 +213775,7 @@ function parseStoredSetup(value) {
213755
213775
  function storePath(origin2, setupId) {
213756
213776
  const key = createHash5("sha256").update(`${apiUrl(origin2)}
213757
213777
  ${uuid(setupId)}`).digest("hex");
213758
- return join7(configDirectory(), "setup-v1", `${key}.json`);
213778
+ return join6(configDirectory(), "setup-v1", `${key}.json`);
213759
213779
  }
213760
213780
  var retentionMs = 7 * 24 * 60 * 60 * 1e3;
213761
213781
  var pruneBatch = 128;
@@ -213763,7 +213783,7 @@ async function readSetupRecord(path) {
213763
213783
  const before = await lstat4(path);
213764
213784
  if (!before.isFile() || before.isSymbolicLink() || before.size > 65536)
213765
213785
  throw new Error("invalid setup file");
213766
- const file = await open7(path, constants3.O_RDONLY | (constants3.O_NOFOLLOW ?? 0));
213786
+ const file = await open6(path, constants2.O_RDONLY | (constants2.O_NOFOLLOW ?? 0));
213767
213787
  try {
213768
213788
  const info = await file.stat();
213769
213789
  if (!info.isFile() || info.ino !== before.ino || info.dev !== before.dev || info.size > 65536)
@@ -213799,7 +213819,7 @@ async function pruneSetupSessions(now = Date.now()) {
213799
213819
  return { scanned: 0, removed: 0 };
213800
213820
  let directory2;
213801
213821
  try {
213802
- const path = join7(configDirectory(), "setup-v1"), info = await lstat4(path);
213822
+ const path = join6(configDirectory(), "setup-v1"), info = await lstat4(path);
213803
213823
  if (!info.isDirectory() || info.isSymbolicLink())
213804
213824
  return { scanned: 0, removed: 0 };
213805
213825
  directory2 = await opendir(path);
@@ -213815,7 +213835,7 @@ async function pruneSetupSessions(now = Date.now()) {
213815
213835
  }
213816
213836
  if (!entry.isFile() || !/^[a-f0-9]{64}\.json$/.test(entry.name))
213817
213837
  continue;
213818
- const path = join7(configDirectory(), "setup-v1", entry.name);
213838
+ const path = join6(configDirectory(), "setup-v1", entry.name);
213819
213839
  try {
213820
213840
  const { data, info } = await readSetupRecord(path);
213821
213841
  if (storePath(data.api_url, data.setup_id) !== path || Date.parse(data.created_at) > now - retentionMs)
@@ -213831,22 +213851,22 @@ async function pruneSetupSessions(now = Date.now()) {
213831
213851
  }
213832
213852
  async function saveSetupSession(value) {
213833
213853
  const data = parseStoredSetup(value), path = storePath(data.api_url, data.setup_id);
213834
- const temporary = `${path}.${randomUUID8()}.tmp`;
213854
+ const temporary = `${path}.${randomUUID7()}.tmp`;
213835
213855
  try {
213836
- const directory2 = join7(configDirectory(), "setup-v1");
213837
- await mkdir7(directory2, { recursive: true, mode: 448 });
213856
+ const directory2 = join6(configDirectory(), "setup-v1");
213857
+ await mkdir6(directory2, { recursive: true, mode: 448 });
213838
213858
  const info = await lstat4(directory2);
213839
213859
  if (!info.isDirectory() || info.isSymbolicLink())
213840
213860
  throw new SetupError("setup_store_failed", "The setup store must be a regular private directory, not a symbolic link.");
213841
213861
  await pruneSetupSessions();
213842
- const file = await open7(temporary, "wx", 384);
213862
+ const file = await open6(temporary, "wx", 384);
213843
213863
  try {
213844
213864
  await file.writeFile(JSON.stringify(data) + "\n");
213845
213865
  await file.sync();
213846
213866
  } finally {
213847
213867
  await file.close();
213848
213868
  }
213849
- await rename5(temporary, path);
213869
+ await rename4(temporary, path);
213850
213870
  } catch (error) {
213851
213871
  if (error instanceof SetupError)
213852
213872
  throw error;
@@ -213861,7 +213881,7 @@ async function loadSetupSession(origin2, setupId, directory2, now = Date.now())
213861
213881
  let info;
213862
213882
  const path = storePath(origin2, setupId);
213863
213883
  try {
213864
- const parent = await lstat4(join7(configDirectory(), "setup-v1"));
213884
+ const parent = await lstat4(join6(configDirectory(), "setup-v1"));
213865
213885
  if (!parent.isDirectory() || parent.isSymbolicLink())
213866
213886
  throw new Error("invalid setup directory");
213867
213887
  ({ data, info } = await readSetupRecord(path));
@@ -213880,11 +213900,11 @@ async function loadSetupSession(origin2, setupId, directory2, now = Date.now())
213880
213900
  }
213881
213901
  async function setupPrivateDirectory(...parts) {
213882
213902
  let path = configDirectory();
213883
- await mkdir7(path, { recursive: true, mode: 448 });
213903
+ await mkdir6(path, { recursive: true, mode: 448 });
213884
213904
  for (const part of ["", "setup-v1", ...parts]) {
213885
213905
  if (part) {
213886
- path = join7(path, part);
213887
- await mkdir7(path, { mode: 448 }).catch((error) => {
213906
+ path = join6(path, part);
213907
+ await mkdir6(path, { mode: 448 }).catch((error) => {
213888
213908
  if (error.code !== "EEXIST")
213889
213909
  throw error;
213890
213910
  });
@@ -213895,17 +213915,59 @@ async function setupPrivateDirectory(...parts) {
213895
213915
  }
213896
213916
  return path;
213897
213917
  }
213918
+ async function recoverSetupProjectLock(directory2) {
213919
+ const locks = await setupPrivateDirectory("project-locks");
213920
+ const path = join6(locks, `${await setupProjectFingerprint(directory2)}.lock`);
213921
+ let info;
213922
+ try {
213923
+ info = await lstat4(path);
213924
+ } catch (error) {
213925
+ if (error.code === "ENOENT")
213926
+ return false;
213927
+ throw error;
213928
+ }
213929
+ if (!info.isFile() || info.isSymbolicLink() || info.nlink !== 1 || info.size > 1024)
213930
+ throw new SetupError("setup_lock_failed", "The project lock needs manual review.");
213931
+ const file = await open6(path, constants2.O_RDONLY | (constants2.O_NOFOLLOW ?? 0));
213932
+ try {
213933
+ const now = await file.stat();
213934
+ if (now.ino !== info.ino || now.dev !== info.dev)
213935
+ throw new Error("changed lock");
213936
+ const value = JSON.parse(await file.readFile("utf8"));
213937
+ if (!Number.isInteger(value.pid) || value.pid < 1 || typeof value.owner !== "string")
213938
+ throw new Error("invalid lock");
213939
+ try {
213940
+ process.kill(value.pid, 0);
213941
+ throw new SetupError("setup_project_locked", `Another wizard is still running for this project (PID ${value.pid}). Return to its terminal and finish or stop that run before retrying.`);
213942
+ } catch (error) {
213943
+ if (error.code !== "ESRCH")
213944
+ throw error;
213945
+ }
213946
+ return removeSameRecord(path, info);
213947
+ } finally {
213948
+ await file.close();
213949
+ }
213950
+ }
213898
213951
  async function withSetupProjectLock(directory2, operation) {
213899
213952
  const fingerprint = await setupProjectFingerprint(directory2);
213900
213953
  const locks = await setupPrivateDirectory("project-locks");
213901
- const path = join7(locks, `${fingerprint}.lock`), owner = randomUUID8();
213954
+ const path = join6(locks, `${fingerprint}.lock`), owner = randomUUID7();
213902
213955
  let file;
213903
213956
  try {
213904
- file = await open7(path, "wx", 384);
213957
+ file = await open6(path, "wx", 384);
213905
213958
  } catch (error) {
213906
- if (error.code === "EEXIST")
213907
- throw new SetupError("setup_project_locked", "Another setup owns this project. Reconcile its local results before retrying; an expired server lease does not release this lock.");
213908
- throw new SetupError("setup_lock_failed", "Unable to lock this project for setup. Check local configuration-directory access.");
213959
+ if (error.code !== "EEXIST")
213960
+ throw new SetupError("setup_lock_failed", "Unable to lock this project for setup. Check local configuration-directory access.");
213961
+ try {
213962
+ await recoverSetupProjectLock(directory2);
213963
+ file = await open6(path, "wx", 384);
213964
+ } catch (recoveryError) {
213965
+ if (recoveryError instanceof SetupError)
213966
+ throw recoveryError;
213967
+ if (recoveryError.code === "EEXIST")
213968
+ throw new SetupError("setup_project_locked", "Another wizard acquired this project. Return to its terminal and finish or stop that run before retrying.");
213969
+ throw new SetupError("setup_lock_failed", "The existing project lock could not be verified safely. No lock or installation receipt was removed.");
213970
+ }
213909
213971
  }
213910
213972
  const lockInfo = await file.stat();
213911
213973
  try {
@@ -213923,7 +213985,7 @@ async function withSetupProjectLock(directory2, operation) {
213923
213985
  }
213924
213986
 
213925
213987
  // node_modules/@userreason/cli/dist/setup.js
213926
- import { createHash as createHash6, randomBytes, randomUUID as randomUUID9 } from "node:crypto";
213988
+ import { createHash as createHash6, randomBytes, randomUUID as randomUUID8 } from "node:crypto";
213927
213989
 
213928
213990
  // node_modules/@userreason/cli/dist/setup-wire.js
213929
213991
  var fail = () => {
@@ -213983,6 +214045,22 @@ var revision = refine(text(1, 19, /^[1-9][0-9]*$/), (value) => BigInt(value) <=
213983
214045
  var generation = integer(1, 2147483647);
213984
214046
  var shortText = (value) => text(1, 240, /^[^\u0000-\u001f\u007f]*$/)(typeof value === "string" ? value.trim() : value);
213985
214047
  var identifier = text(1, 80, /^[A-Za-z0-9_-]+$/);
214048
+ var canonicalOrigin = refine(text(1, 2048), (value) => {
214049
+ try {
214050
+ const url = new URL(value);
214051
+ return ["https:", "http:"].includes(url.protocol) && !url.username && !url.password && !url.hostname.includes("*") && url.origin === value;
214052
+ } catch {
214053
+ return false;
214054
+ }
214055
+ });
214056
+ var localRegistry = refine(text(1, 200), (value) => {
214057
+ try {
214058
+ const url = new URL(value);
214059
+ return url.protocol === "http:" && ["127.0.0.1", "localhost", "[::1]"].includes(url.hostname) && !url.username && !url.password && url.pathname === "/" && !url.search && !url.hash;
214060
+ } catch {
214061
+ return false;
214062
+ }
214063
+ });
213986
214064
  var relativePath = refine(text(1, 240), (value) => !value.startsWith("/") && !/[\\:\u0000-\u001f\u007f]/.test(value) && value.split("/").every((part) => !["", ".", ".."].includes(part)));
213987
214065
  var scope = { schema_version: literal(1), setup_id: uuid2 };
213988
214066
  var setupPhases = ["configuring", "awaiting_local_approval", "applying", "ready_for_recommendations", "analyzing", "selecting_drafts", "creating_drafts", "agent_test", "complete", "cancelled", "expired"];
@@ -213998,7 +214076,9 @@ var parseSetupCapabilities = shape({
213998
214076
  insert_footer: bool,
213999
214077
  source_review: bool,
214000
214078
  sample_read: bool,
214079
+ onboarding_v2: optional(bool),
214001
214080
  project_name: optional(refine(shortText, (value) => value.length <= 120 && !/[\/\\]/.test(value))),
214081
+ launcher: optional(shape({ wizard_version: text(1, 80, /^\d+\.\d+\.\d+(?:-[A-Za-z0-9.-]+)?(?:\+[A-Za-z0-9.-]+)?$/), api_origin: canonicalOrigin, registry: optional(localRegistry) })),
214002
214082
  terminal: optional(shape({ platform: oneOf(["macos", "windows", "linux", "other"]), app: oneOf(["apple_terminal", "iterm2", "windows_terminal", "vscode", "cursor", "warp", "ghostty", "wezterm", "alacritty", "kitty", "generic"]) }))
214003
214083
  });
214004
214084
  var choices = shape({ install_sdk: bool, install_skill: bool, footer_badge: bool });
@@ -214045,14 +214125,14 @@ function parseSetupLocalPlan(value) {
214045
214125
  var sampleState = refine(shape({ status: oneOf(["not_started", "waiting", "received", "skipped"]), first_received_at: nullable(timestamp), latest_received_at: nullable(timestamp), latest_request_id: nullable(uuid2) }), (value) => value.first_received_at === null === (value.latest_received_at === null) && value.latest_received_at === null === (value.latest_request_id === null) && (value.status !== "received" || value.first_received_at !== null));
214046
214126
  var draftOutcome = refine(shape({ candidate_id: identifier, status: oneOf(["pending", "succeeded", "failed"]), prompt_id: uuid2, request_id: uuid2, revision: nullable(revision), code: nullable(oneOf(resultCodes)) }), (value) => value.status !== "succeeded" || value.revision !== null);
214047
214127
  var sourceErrors = ["planning_unavailable", "planning_paused", "planning_daily_budget", "planning_allowance_exhausted", "planning_provider_unavailable", "planning_policy_changed", "planning_consent_expired", "planning_input_budget", "planning_invalid_output", "planning_timeout", "source_changed", "source_unavailable", "recommendations_no_source", "operation_failed"];
214048
- var sourceState = refine(shape({ preparation_id: uuid2, status: oneOf(["pending", "approved", "analyzing", "ready", "failed", "skipped"]), packet_digest: hash, provider_fingerprint: hash, authorized_at: nullable(timestamp), expires_at: timestamp, error_code: nullable(oneOf(sourceErrors)) }), (value) => (!["approved", "analyzing", "ready"].includes(value.status) || value.authorized_at !== null) && (value.authorized_at === null || Date.parse(value.expires_at) > Date.parse(value.authorized_at) && Date.parse(value.expires_at) - Date.parse(value.authorized_at) <= 6e5));
214049
- var sourceFile2 = refine(shape({ path: relativePath, file_hash: hash, excerpt_hash: hash, bytes: integer(0, 12e3), start_line: integer(1, Number.MAX_SAFE_INTEGER), end_line: integer(1, Number.MAX_SAFE_INTEGER) }), (value) => value.end_line >= value.start_line);
214050
- var parseSetupSourceManifest = refine(bounded(shape({ packet_digest: hash, snapshot_id: uuid2, files: array(sourceFile2, 0, 200, (value) => value.path), omitted_files: integer(0, 1e6), truncated: bool, git_included: literal(false) })), (value) => value.files.reduce((sum, file) => sum + file.bytes, 0) <= 12e3);
214128
+ var sourceState = refine(shape({ preparation_id: uuid2, status: oneOf(["pending", "approved", "analyzing", "ready", "failed", "skipped"]), packet_digest: hash, provider_fingerprint: hash, authorized_at: nullable(timestamp), expires_at: timestamp, error_code: nullable(oneOf(sourceErrors)), analysis_id: optional(uuid2), analysis_started_at: optional(timestamp), analysis_completed_at: optional(timestamp), deadline_at: optional(timestamp), timings: optional(shape({ extraction_ms: optional(integer(0, Number.MAX_SAFE_INTEGER)), consolidation_ms: optional(integer(0, Number.MAX_SAFE_INTEGER)), authoring_ms: optional(integer(0, Number.MAX_SAFE_INTEGER)), total_ms: optional(integer(0, Number.MAX_SAFE_INTEGER)) })) }), (value) => (!["approved", "analyzing", "ready"].includes(value.status) || value.authorized_at !== null) && (!value.deadline_at || Boolean(value.analysis_started_at && Date.parse(value.deadline_at) > Date.parse(value.analysis_started_at) && Date.parse(value.deadline_at) - Date.parse(value.analysis_started_at) <= 24e4)) && (!value.analysis_completed_at || Boolean(value.analysis_started_at && Date.parse(value.analysis_completed_at) >= Date.parse(value.analysis_started_at))) && (value.authorized_at === null || Date.parse(value.expires_at) > Date.parse(value.authorized_at) && Date.parse(value.expires_at) - Date.parse(value.authorized_at) <= 6e5));
214129
+ var sourceFile2 = refine(shape({ path: relativePath, file_hash: hash, excerpt_hash: hash, bytes: integer(0, 262144), start_line: integer(1, Number.MAX_SAFE_INTEGER), end_line: integer(1, Number.MAX_SAFE_INTEGER) }), (value) => value.end_line >= value.start_line);
214130
+ var parseSetupSourceManifest = refine(bounded(shape({ packet_digest: hash, snapshot_id: uuid2, files: array(sourceFile2, 0, 200, (value) => `${value.path}:${value.start_line}:${value.end_line}`), omitted_files: integer(0, 1e6), truncated: bool, git_included: literal(false) })), (value) => value.files.reduce((sum, file) => sum + file.bytes, 0) <= 262144);
214051
214131
  var sourcePackage = shape({ name: (value) => text(1, 100)(typeof value === "string" ? value.trim() : value), version: (value) => text(1, 100)(typeof value === "string" ? value.trim() : value) });
214052
214132
  var sourcePackages = array(sourcePackage, 0, 30, (value) => value.name);
214053
214133
  var evidencePath = refine(text(1, 500), (value) => !value.startsWith("/") && !value.includes("\\") && !value.split("/").some((part) => ["", ".", ".."].includes(part)));
214054
- var sourceEvidence = refine(shape({ kind: literal("local_source"), id: identifier, path: evidencePath, file_hash: hash, excerpt_hash: hash, snapshot_id: uuid2, start_line: integer(1, Number.MAX_SAFE_INTEGER), end_line: integer(1, Number.MAX_SAFE_INTEGER), excerpt: text(0, 12e3) }), (value) => value.end_line >= value.start_line && value.excerpt.split("\n").length === value.end_line - value.start_line + 1);
214055
- var planningLimits = shape({ input_tokens: integer(256, 12e3), output_tokens: integer(256, 4e3), deadline_ms: integer(1e3, 4e4) });
214134
+ var sourceEvidence = refine(shape({ kind: literal("local_source"), id: identifier, path: evidencePath, file_hash: hash, excerpt_hash: hash, snapshot_id: uuid2, start_line: integer(1, Number.MAX_SAFE_INTEGER), end_line: integer(1, Number.MAX_SAFE_INTEGER), excerpt: text(0, 3e4) }), (value) => value.end_line >= value.start_line && value.excerpt.split("\n").length === value.end_line - value.start_line + 1);
214135
+ var planningLimits = shape({ input_tokens: integer(256, 262144), output_tokens: integer(256, 32768), deadline_ms: integer(1e3, 24e4) });
214056
214136
  var providerDestination = refine(text(1, 200), (value) => {
214057
214137
  try {
214058
214138
  const url = new URL(value);
@@ -214112,7 +214192,7 @@ var parseSetupPollInput = shape(scope);
214112
214192
  var parseSetupLocalPlanInput = bounded(shape({ ...scope, request_id: uuid2, expected_revision: revision, plan: localPlan }));
214113
214193
  var parseSetupSourceInfoInput = shape(scope);
214114
214194
  var parseSetupSourcePlanInput = refine(bounded(shape({ ...scope, request_id: uuid2, expected_revision: revision, manifest: parseSetupSourceManifest, packages: sourcePackages })), (value) => value.request_id === value.manifest.snapshot_id);
214115
- var parseSetupSourceUploadInput = refine(bounded(shape({ ...scope, preparation_id: uuid2, project_fingerprint: hash, evidence: array(sourceEvidence, 0, 220, (value) => value.id) })), (value) => new Set(value.evidence.map((item) => item.path)).size === value.evidence.length && Buffer.byteLength(JSON.stringify(value.evidence)) <= 12e3 && value.evidence.every((item) => item.snapshot_id === value.preparation_id));
214195
+ var parseSetupSourceUploadInput = refine(shape({ ...scope, preparation_id: uuid2, project_fingerprint: hash, evidence: array(sourceEvidence, 0, 220, (value) => value.id) }), (value) => Buffer.byteLength(JSON.stringify(value)) <= 3e5 && new Set(value.evidence.map((item) => `${item.path}:${item.start_line}:${item.end_line}`)).size === value.evidence.length && Buffer.byteLength(JSON.stringify(value.evidence)) <= 262144 && value.evidence.every((item) => item.snapshot_id === value.preparation_id));
214116
214196
  var parseSetupSourceInfo = refine(bounded(shape({ schema_version: literal(1), session: parseSetupSession, preparation: nullable(shape({ preparation_id: uuid2, manifest: parseSetupSourceManifest, packages: sourcePackages, configuration: planningConfiguration })) })), (value) => value.preparation === null || value.preparation.preparation_id === value.preparation.manifest.snapshot_id);
214117
214197
  var parseSetupClaimInput = shape({ ...scope, request_id: uuid2, executor_generation: generation });
214118
214198
  var parseSetupClaimResult = bounded(shape({ schema_version: literal(1), command: nullable(command), session: parseSetupSession }));
@@ -214196,7 +214276,7 @@ async function request(origin2, operation, body, token, options, retries = 0) {
214196
214276
  if (!["discovery", "start", "exchange", "poll", "plan", "claim", "start-command", "report", "heartbeat", "reconcile", "sample-read", "source-info", "source-plan", "source-upload"].includes(operation))
214197
214277
  throw new SetupError("invalid_setup_operation", "Unsupported setup operation.");
214198
214278
  const encoded = body === void 0 ? void 0 : JSON.stringify(body);
214199
- if (encoded && Buffer.byteLength(encoded) > 65536)
214279
+ if (encoded && Buffer.byteLength(encoded) > (operation === "source-upload" ? 3e5 : 65536))
214200
214280
  throw new SetupError("setup_request_too_large", "Setup request exceeds 64 KiB.");
214201
214281
  const url = `${apiUrl(origin2)}${operation === "discovery" ? "/onboarding/v1/auth-config?setup=1" : `/onboarding/v1/setup/${operation}`}`;
214202
214282
  const measurementDisabled = options.measurementDisabled === true || !await telemetryEnabled().catch(() => false);
@@ -214209,7 +214289,7 @@ async function request(origin2, operation, body, token, options, retries = 0) {
214209
214289
  redirect: "error",
214210
214290
  headers: { Accept: "application/json", ...encoded === void 0 ? {} : { "Content-Type": "application/json" }, ...token ? { Authorization: `Bearer ${token}` } : {}, ...measurementDisabled ? { "x-ur-measurement-disabled": "1" } : {} },
214211
214291
  ...encoded === void 0 ? {} : { body: encoded },
214212
- signal: AbortSignal.any([AbortSignal.timeout(operation === "source-upload" ? 5e4 : 1e4), ...options.signal ? [options.signal] : []])
214292
+ signal: AbortSignal.any([AbortSignal.timeout(operation === "source-upload" ? 25e4 : 1e4), ...options.signal ? [options.signal] : []])
214213
214293
  });
214214
214294
  } catch (error) {
214215
214295
  options.signal?.throwIfAborted();
@@ -214296,7 +214376,9 @@ async function finishBrowserSetup(pending, options) {
214296
214376
  throw new SetupError("invalid_setup_response", "The approved setup response does not match this project or active session.");
214297
214377
  const connected = { schema_version: 1, state: "connected", setup_id: pending.setup_id, api_url: pending.api_url, project_fingerprint: pending.project_fingerprint, created_at: new Date(now()).toISOString(), expires_at: result.expires_at, access_token: result.access_token };
214298
214378
  await saveSetupSession(connected);
214299
- return { client: new BrowserSetupClient(connected, options), session: result.session };
214379
+ const client = new BrowserSetupClient(connected, options);
214380
+ const session2 = await client.heartbeat({ schema_version: 1, setup_id: connected.setup_id, executor_generation: result.session.executor_generation, operation_id: null, lease_generation: null });
214381
+ return { client, session: session2 };
214300
214382
  }
214301
214383
  options.onProgress?.("waiting");
214302
214384
  await delay(Math.max(0, Math.min(2e3, deadline - now())), options);
@@ -214308,9 +214390,11 @@ async function resumeBrowserSetup(origin2, setupId, directory2, options = {}) {
214308
214390
  if (saved.state === "pending")
214309
214391
  return finishBrowserSetup(saved, options);
214310
214392
  const client = new BrowserSetupClient(saved, options);
214311
- return { client, session: await client.poll() };
214393
+ const current = await client.poll();
214394
+ const session2 = terminal.has(current.phase) ? current : await client.heartbeat({ schema_version: 1, setup_id: saved.setup_id, executor_generation: current.executor_generation, operation_id: null, lease_generation: null });
214395
+ return { client, session: session2 };
214312
214396
  }
214313
- var BrowserSetupClient = class {
214397
+ var BrowserSetupClient = class _BrowserSetupClient {
214314
214398
  #stored;
214315
214399
  #options;
214316
214400
  constructor(stored, options = {}) {
@@ -214325,6 +214409,10 @@ var BrowserSetupClient = class {
214325
214409
  const { setup_id, api_url, project_fingerprint, expires_at } = this.#stored;
214326
214410
  return { setup_id, api_url, project_fingerprint, expires_at };
214327
214411
  }
214412
+ /** Share the same saved capability while binding requests to one run's lifetime. */
214413
+ withSignal(signal) {
214414
+ return new _BrowserSetupClient(this.#stored, { ...this.#options, signal: AbortSignal.any([signal, ...this.#options.signal ? [this.#options.signal] : []]) });
214415
+ }
214328
214416
  async call(operation, body, retries = 0) {
214329
214417
  if (Date.parse(this.#stored.expires_at) <= (this.#options.now ?? Date.now)())
214330
214418
  throw new SetupError("setup_expired", "Setup access expired. Start a new setup; it cannot be refreshed into ordinary CLI access.");
@@ -214395,7 +214483,7 @@ var BrowserSetupClient = class {
214395
214483
  this.scoped(body);
214396
214484
  return this.view(await this.call("reconcile", body));
214397
214485
  }
214398
- async sample(requestId = randomUUID9()) {
214486
+ async sample(requestId = randomUUID8()) {
214399
214487
  const active = await this.poll();
214400
214488
  if (active.phase !== "agent_test" || !["waiting", "received"].includes(active.sample.status))
214401
214489
  throw new SetupError("setup_sample_unavailable", "This setup is not waiting for its optional sample read. Open that step in the browser first.");
@@ -214406,17 +214494,177 @@ var BrowserSetupClient = class {
214406
214494
  }
214407
214495
  };
214408
214496
 
214497
+ // node_modules/@userreason/cli/dist/setup-diagnostics.js
214498
+ function sanitizeSetupDiagnostic(value, secrets = []) {
214499
+ let text2 = value.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "").replace(/[\x00-\x08\x0b-\x1f\x7f]/g, "");
214500
+ const environmentSecrets = Object.entries(process.env).filter(([key, value2]) => /token|secret|password|api[_-]?key|authorization/i.test(key) && value2 && value2.length >= 4).map(([, value2]) => value2);
214501
+ for (const secret2 of [...secrets, ...environmentSecrets].filter((value2) => value2.length >= 4).sort((a, b) => b.length - a.length))
214502
+ text2 = text2.split(secret2).join("[redacted]");
214503
+ text2 = text2.replace(/\b(Bearer|Basic)\s+[^\s]+/gi, "$1 [redacted]");
214504
+ text2 = text2.replace(/((?:_authToken|_password|password|access_token|refresh_token|api_key|authorization)\s*[:=]\s*)[^\s]+/gi, "$1[redacted]");
214505
+ text2 = text2.replace(/\b(?:gh[pousr]_[A-Za-z0-9_]+|github_pat_[A-Za-z0-9_]+|npm_[A-Za-z0-9]+|sk-[A-Za-z0-9_-]{16,})\b/g, "[redacted]");
214506
+ text2 = text2.replace(/https?:\/\/[^\s<>"']+/g, (value2) => {
214507
+ try {
214508
+ const url = new URL(value2);
214509
+ url.username = "";
214510
+ url.password = "";
214511
+ url.search = "";
214512
+ url.hash = "";
214513
+ return url.toString();
214514
+ } catch {
214515
+ return "[invalid URL]";
214516
+ }
214517
+ });
214518
+ return text2.trim().slice(0, 8e3);
214519
+ }
214520
+
214409
214521
  // node_modules/@userreason/cli/dist/setup-executor.js
214410
- import { randomUUID as randomUUID10 } from "node:crypto";
214411
- import { constants as constants5 } from "node:fs";
214412
- import { lstat as lstat6, open as open9, opendir as opendir2, rename as rename6, rm as rm4 } from "node:fs/promises";
214413
- import { join as join9 } from "node:path";
214522
+ import { randomUUID as randomUUID9 } from "node:crypto";
214523
+ import { constants as constants4 } from "node:fs";
214524
+ import { lstat as lstat6, open as open8, opendir as opendir2, rename as rename5, rm as rm4 } from "node:fs/promises";
214525
+ import { join as join8 } from "node:path";
214526
+
214527
+ // node_modules/@userreason/cli/dist/setup-heartbeat.js
214528
+ var terminal2 = /* @__PURE__ */ new Set(["complete", "cancelled", "expired"]);
214529
+ function setupAbortable(work, signal) {
214530
+ if (!signal)
214531
+ return work;
214532
+ signal.throwIfAborted();
214533
+ return new Promise((resolve3, reject) => {
214534
+ const abort = () => reject(signal.reason);
214535
+ signal.addEventListener("abort", abort, { once: true });
214536
+ work.then(resolve3, reject).finally(() => signal.removeEventListener("abort", abort));
214537
+ });
214538
+ }
214539
+ var SetupHeartbeat = class {
214540
+ client;
214541
+ options;
214542
+ session;
214543
+ timer;
214544
+ pending;
214545
+ stopped = false;
214546
+ paused = 0;
214547
+ failure;
214548
+ lease;
214549
+ lifetime = new AbortController();
214550
+ signal;
214551
+ constructor(client, options = {}) {
214552
+ this.client = client;
214553
+ this.options = options;
214554
+ this.signal = AbortSignal.any([this.lifetime.signal, ...options.signal ? [options.signal] : []]);
214555
+ }
214556
+ observe(next) {
214557
+ const current = this.session;
214558
+ if (!current || BigInt(next.revision) >= BigInt(current.revision)) {
214559
+ const heartbeat = current?.heartbeat_at && (!next.heartbeat_at || Date.parse(current.heartbeat_at) > Date.parse(next.heartbeat_at)) ? current.heartbeat_at : next.heartbeat_at;
214560
+ this.session = { ...next, heartbeat_at: heartbeat };
214561
+ }
214562
+ if (terminal2.has(this.session.phase) && !this.signal.aborted)
214563
+ this.lifetime.abort(new Error("Setup ended"));
214564
+ if (!this.stopped && !this.timer && !this.pending && !this.paused && !terminal2.has(this.session.phase))
214565
+ this.schedule(0);
214566
+ return this.session;
214567
+ }
214568
+ get current() {
214569
+ return this.session;
214570
+ }
214571
+ setLease(lease) {
214572
+ this.lease = lease;
214573
+ }
214574
+ latest(fallback) {
214575
+ return this.observe(fallback);
214576
+ }
214577
+ check() {
214578
+ this.options.signal?.throwIfAborted();
214579
+ if (this.failure)
214580
+ throw this.failure;
214581
+ }
214582
+ schedule(delay2 = this.options.heartbeatMs ?? 1e4) {
214583
+ if (this.stopped || this.paused || !this.session || terminal2.has(this.session.phase) || this.signal.aborted)
214584
+ return;
214585
+ this.timer = setTimeout(() => {
214586
+ this.timer = void 0;
214587
+ void this.pulse();
214588
+ }, delay2);
214589
+ }
214590
+ async pulse() {
214591
+ if (this.pending)
214592
+ return this.pending;
214593
+ if (this.stopped || this.paused || this.signal.aborted || !this.session || terminal2.has(this.session.phase))
214594
+ return;
214595
+ if (this.timer) {
214596
+ clearTimeout(this.timer);
214597
+ this.timer = void 0;
214598
+ }
214599
+ const session2 = this.session;
214600
+ this.pending = setupAbortable(this.client.heartbeat({
214601
+ schema_version: 1,
214602
+ setup_id: this.client.identity.setup_id,
214603
+ executor_generation: session2.executor_generation,
214604
+ operation_id: this.lease?.operation_id ?? null,
214605
+ lease_generation: this.lease?.lease_generation ?? null
214606
+ }), this.signal).then((value) => {
214607
+ this.observe(value);
214608
+ }).catch((error) => {
214609
+ if (!this.stopped && !this.options.signal?.aborted) {
214610
+ this.failure = error;
214611
+ this.lifetime.abort(error);
214612
+ }
214613
+ }).finally(() => {
214614
+ this.pending = void 0;
214615
+ this.schedule();
214616
+ });
214617
+ return this.pending;
214618
+ }
214619
+ /** Finish the old lease's in-flight heartbeat before closing it in a report. */
214620
+ async duringReport(operation) {
214621
+ this.paused++;
214622
+ if (this.timer) {
214623
+ clearTimeout(this.timer);
214624
+ this.timer = void 0;
214625
+ }
214626
+ try {
214627
+ await this.pending;
214628
+ this.lease = void 0;
214629
+ return await operation();
214630
+ } finally {
214631
+ this.paused--;
214632
+ this.schedule();
214633
+ }
214634
+ }
214635
+ async stop() {
214636
+ this.stopped = true;
214637
+ if (this.timer)
214638
+ clearTimeout(this.timer);
214639
+ this.lifetime.abort(new Error("Setup run ended"));
214640
+ await this.pending;
214641
+ }
214642
+ };
214643
+ function observeSetupClient(client, heartbeat, signal) {
214644
+ return new Proxy(client, { get(target, key, receiver) {
214645
+ const value = Reflect.get(target, key, target);
214646
+ if (typeof value !== "function")
214647
+ return value;
214648
+ if (key === "withSignal")
214649
+ return value.bind(target);
214650
+ return async (...args) => {
214651
+ if (key !== "report")
214652
+ signal?.throwIfAborted();
214653
+ const requestSignal = ["poll", "discovery", "sourceInfo", "sourceUpload"].includes(String(key)) ? signal : void 0;
214654
+ const result = await setupAbortable(Reflect.apply(value, target, args), requestSignal);
214655
+ const view = result && typeof result === "object" && "session" in result ? result.session : result;
214656
+ if (view && typeof view === "object" && "phase" in view && "revision" in view && typeof view.phase === "string" && typeof view.revision === "string")
214657
+ heartbeat.observe(view);
214658
+ return result;
214659
+ };
214660
+ } });
214661
+ }
214414
214662
 
214415
214663
  // node_modules/@userreason/cli/dist/setup-files.js
214416
214664
  import { createHash as createHash7 } from "node:crypto";
214417
- import { constants as constants4 } from "node:fs";
214418
- import { lstat as lstat5, mkdir as mkdir8, open as open8, realpath as realpath3 } from "node:fs/promises";
214419
- import { join as join8, relative as relative2, resolve as resolve2, sep as sep2 } from "node:path";
214665
+ import { constants as constants3 } from "node:fs";
214666
+ import { lstat as lstat5, mkdir as mkdir7, open as open7, realpath as realpath3 } from "node:fs/promises";
214667
+ import { join as join7, relative as relative2, resolve as resolve2, sep as sep2 } from "node:path";
214420
214668
  var setupHash = (value) => createHash7("sha256").update(value).digest("hex");
214421
214669
  function setupCanonical(value) {
214422
214670
  if (Array.isArray(value))
@@ -214435,14 +214683,14 @@ async function checkedPath(directory2, name, createParents = false) {
214435
214683
  throw new SetupError("setup_path_unsafe", "The reviewed path escapes the project.");
214436
214684
  let parent = root;
214437
214685
  for (const part of name.split("/").slice(0, -1)) {
214438
- parent = join8(parent, part);
214686
+ parent = join7(parent, part);
214439
214687
  let info = await lstat5(parent).catch((error) => {
214440
214688
  if (error.code === "ENOENT")
214441
214689
  return null;
214442
214690
  throw error;
214443
214691
  });
214444
214692
  if (!info && createParents) {
214445
- await mkdir8(parent);
214693
+ await mkdir7(parent);
214446
214694
  info = await lstat5(parent);
214447
214695
  }
214448
214696
  if (!info)
@@ -214464,15 +214712,15 @@ async function readSetupFile(directory2, path) {
214464
214712
  }
214465
214713
  if (!before.isFile() || before.isSymbolicLink() || before.nlink !== 1 || before.size > 2e6)
214466
214714
  throw new SetupError("setup_path_unsafe", "A reviewed file is not a bounded ordinary file.");
214467
- const handle = await open8(target, constants4.O_RDONLY | (constants4.O_NOFOLLOW ?? 0));
214715
+ const handle = await open7(target, constants3.O_RDONLY | (constants3.O_NOFOLLOW ?? 0));
214468
214716
  try {
214469
214717
  const current = await handle.stat();
214470
214718
  if (before.dev !== current.dev || before.ino !== current.ino || current.nlink !== 1 || current.size > 2e6)
214471
214719
  throw new SetupError("setup_path_unsafe", "A reviewed file changed while reading.");
214472
- const bytes = await handle.readFile();
214473
- if (bytes.length > 2e6)
214720
+ const bytes2 = await handle.readFile();
214721
+ if (bytes2.length > 2e6)
214474
214722
  throw new SetupError("setup_path_unsafe", "A reviewed file exceeds the size limit.");
214475
- return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
214723
+ return new TextDecoder("utf-8", { fatal: true }).decode(bytes2);
214476
214724
  } finally {
214477
214725
  await handle.close();
214478
214726
  }
@@ -214486,7 +214734,7 @@ async function writeSetupFile(directory2, file) {
214486
214734
  if (file.before === file.after)
214487
214735
  return;
214488
214736
  const info = file.before === null ? null : await lstat5(target);
214489
- const handle = await open8(target, info ? constants4.O_WRONLY | (constants4.O_NOFOLLOW ?? 0) : constants4.O_WRONLY | constants4.O_CREAT | constants4.O_EXCL | (constants4.O_NOFOLLOW ?? 0), 420);
214737
+ const handle = await open7(target, info ? constants3.O_WRONLY | (constants3.O_NOFOLLOW ?? 0) : constants3.O_WRONLY | constants3.O_CREAT | constants3.O_EXCL | (constants3.O_NOFOLLOW ?? 0), 420);
214490
214738
  try {
214491
214739
  const now = await handle.stat();
214492
214740
  if (!now.isFile() || now.nlink !== 1 || info && (now.dev !== info.dev || now.ino !== info.ino))
@@ -214508,7 +214756,7 @@ async function verifySetupFiles(directory2, files2, state) {
214508
214756
  }
214509
214757
 
214510
214758
  // node_modules/@userreason/cli/dist/setup-executor.js
214511
- var terminal2 = /* @__PURE__ */ new Set(["complete", "cancelled", "expired"]);
214759
+ var terminal3 = /* @__PURE__ */ new Set(["complete", "cancelled", "expired"]);
214512
214760
  var stopped = /* @__PURE__ */ new Set(["ready_for_recommendations", "analyzing", "selecting_drafts", "creating_drafts", "agent_test"]);
214513
214761
  var limit = 8e6;
214514
214762
  var retention = 7 * 864e5;
@@ -214539,27 +214787,27 @@ function validatePrepared(value) {
214539
214787
  async function journalPath(client) {
214540
214788
  const directory2 = await setupPrivateDirectory("receipts");
214541
214789
  await pruneSetupExecutionReceipts();
214542
- return join9(directory2, `${setupHash(`${client.identity.api_url}
214790
+ return join8(directory2, `${setupHash(`${client.identity.api_url}
214543
214791
  ${client.identity.setup_id}`)}.json`);
214544
214792
  }
214545
214793
  async function pruneSetupExecutionReceipts(now = Date.now()) {
214546
214794
  const directory2 = await setupPrivateDirectory("receipts");
214547
- let removed = 0, scanned = 0, bytes = 0;
214795
+ let removed = 0, scanned = 0, bytes2 = 0;
214548
214796
  for await (const entry of await opendir2(directory2)) {
214549
214797
  if (++scanned > 128)
214550
214798
  break;
214551
214799
  if (!entry.isFile() || !/^[a-f0-9]{64}\.json$/.test(entry.name))
214552
214800
  continue;
214553
- const path = join9(directory2, entry.name);
214801
+ const path = join8(directory2, entry.name);
214554
214802
  let handle;
214555
214803
  try {
214556
214804
  const info = await lstat6(path);
214557
214805
  if (!info.isFile() || info.isSymbolicLink() || info.nlink !== 1 || info.size > limit)
214558
214806
  continue;
214559
- bytes += info.size;
214560
- if (bytes > 16e6)
214807
+ bytes2 += info.size;
214808
+ if (bytes2 > 16e6)
214561
214809
  break;
214562
- handle = await open9(path, constants5.O_RDONLY | (constants5.O_NOFOLLOW ?? 0));
214810
+ handle = await open8(path, constants4.O_RDONLY | (constants4.O_NOFOLLOW ?? 0));
214563
214811
  const opened = await handle.stat();
214564
214812
  if (opened.ino !== info.ino || opened.dev !== info.dev)
214565
214813
  continue;
@@ -214589,7 +214837,7 @@ function validateJournal(data, identity, active = true) {
214589
214837
  if (data.plan)
214590
214838
  data.plan = validatePrepared(data.plan);
214591
214839
  for (const [operationId, receipt] of Object.entries(data.receipts)) {
214592
- if (!uuid3(operationId) || !receipt || typeof receipt !== "object" || Array.isArray(receipt) || Object.keys(receipt).some((key) => !["input_digest", "stage", "outcome", "outputs", "request_id"].includes(key)) || !/^[a-f0-9]{64}$/.test(receipt.input_digest) || !["claimed", "running", "settled"].includes(receipt.stage) || !uuid3(receipt.request_id) || receipt.stage === "settled" !== Boolean(receipt.outcome))
214840
+ if (!uuid3(operationId) || !receipt || typeof receipt !== "object" || Array.isArray(receipt) || Object.keys(receipt).some((key) => !["input_digest", "stage", "outcome", "diagnostic", "outputs", "request_id"].includes(key)) || receipt.diagnostic !== void 0 && (typeof receipt.diagnostic !== "string" || receipt.diagnostic.length > 8e3) || !/^[a-f0-9]{64}$/.test(receipt.input_digest) || !["claimed", "running", "settled"].includes(receipt.stage) || !uuid3(receipt.request_id) || receipt.stage === "settled" !== Boolean(receipt.outcome))
214593
214841
  throw new Error("invalid operation receipt");
214594
214842
  const operation = data.plan?.operations.find((item) => setupDigest(item.effect) === receipt.input_digest);
214595
214843
  if (!operation)
@@ -214614,19 +214862,19 @@ async function loadJournal(path, client) {
214614
214862
  const info = await lstat6(path);
214615
214863
  if (!info.isFile() || info.isSymbolicLink() || info.nlink !== 1 || info.size > limit)
214616
214864
  throw new Error("unsafe receipt");
214617
- handle = await open9(path, constants5.O_RDONLY | (constants5.O_NOFOLLOW ?? 0));
214865
+ handle = await open8(path, constants4.O_RDONLY | (constants4.O_NOFOLLOW ?? 0));
214618
214866
  const current = await handle.stat();
214619
214867
  if (info.ino !== current.ino || info.dev !== current.dev || current.size > limit)
214620
214868
  throw new Error("changed receipt");
214621
- const bytes = await handle.readFile();
214622
- if (bytes.length > limit)
214869
+ const bytes2 = await handle.readFile();
214870
+ if (bytes2.length > limit)
214623
214871
  throw new Error("large receipt");
214624
- const data = JSON.parse(bytes.toString());
214872
+ const data = JSON.parse(bytes2.toString());
214625
214873
  return validateJournal(data, client.identity);
214626
214874
  } catch (error) {
214627
214875
  if (error.code === "ENOENT") {
214628
214876
  const now = Date.now();
214629
- return { version: 1, setup_id: client.identity.setup_id, api_url: client.identity.api_url, project_fingerprint: client.identity.project_fingerprint, created_at: new Date(now).toISOString(), retain_until: new Date(now + retention).toISOString(), plan_request_id: randomUUID10(), claim_request_id: randomUUID10(), receipts: {} };
214877
+ return { version: 1, setup_id: client.identity.setup_id, api_url: client.identity.api_url, project_fingerprint: client.identity.project_fingerprint, created_at: new Date(now).toISOString(), retain_until: new Date(now + retention).toISOString(), plan_request_id: randomUUID9(), claim_request_id: randomUUID9(), receipts: {} };
214630
214878
  }
214631
214879
  throw new SetupError("setup_receipt_invalid", "The local receipt needs review. No local effects were repeated.");
214632
214880
  } finally {
@@ -214637,16 +214885,16 @@ async function saveJournal(path, journal) {
214637
214885
  const contents = JSON.stringify(journal);
214638
214886
  if (Buffer.byteLength(contents) > limit)
214639
214887
  throw new SetupError("setup_plan_too_large", "The prepared local plan exceeds the private receipt limit.");
214640
- const temporary = `${path}.${randomUUID10()}.tmp`;
214888
+ const temporary = `${path}.${randomUUID9()}.tmp`;
214641
214889
  try {
214642
- const handle = await open9(temporary, "wx", 384);
214890
+ const handle = await open8(temporary, "wx", 384);
214643
214891
  try {
214644
214892
  await handle.writeFile(contents);
214645
214893
  await handle.sync();
214646
214894
  } finally {
214647
214895
  await handle.close();
214648
214896
  }
214649
- await rename6(temporary, path);
214897
+ await rename5(temporary, path);
214650
214898
  } finally {
214651
214899
  await rm4(temporary, { force: true }).catch(() => {
214652
214900
  });
@@ -214669,167 +214917,176 @@ async function verified(directory2, operation, runtime, receipt) {
214669
214917
  return false;
214670
214918
  return runtime.verify ? runtime.verify(operation) : operation.effect.kind !== "install_packages";
214671
214919
  }
214672
- async function runSetupExecutor(client, directory2, runtime, options = {}) {
214920
+ async function runSetupExecutor(client, directory2, runtime, options = {}, sharedHeartbeat) {
214673
214921
  if (await setupProjectFingerprint(directory2) !== client.identity.project_fingerprint)
214674
214922
  throw new SetupError("setup_binding_mismatch", "This executor belongs to another project.");
214675
- return withSetupProjectLock(directory2, async () => {
214676
- const path = await journalPath(client), journal = await loadJournal(path, client);
214677
- let session2 = await client.poll(), polls = 0;
214678
- const scope2 = { schema_version: 1, setup_id: client.identity.setup_id };
214679
- const pause2 = async () => {
214680
- if (options.sleep)
214681
- await options.sleep(options.pollMs ?? 2e3);
214682
- else
214683
- await new Promise((resolve3, reject) => {
214684
- const timer = setTimeout(done, options.pollMs ?? 2e3);
214685
- function done() {
214686
- options.signal?.removeEventListener("abort", abort);
214687
- resolve3();
214923
+ const heartbeat = sharedHeartbeat ?? new SetupHeartbeat(client, options);
214924
+ client = observeSetupClient(client, heartbeat, options.signal);
214925
+ try {
214926
+ return await withSetupProjectLock(directory2, async () => {
214927
+ const path = await journalPath(client), journal = await loadJournal(path, client);
214928
+ const shownErrors = /* @__PURE__ */ new Set();
214929
+ const showError = (id, receipt) => {
214930
+ if (!receipt.diagnostic || shownErrors.has(id))
214931
+ return;
214932
+ const operation = journal.plan?.operations.find((item) => setupDigest(item.effect) === receipt.input_digest);
214933
+ if (!operation)
214934
+ return;
214935
+ shownErrors.add(id);
214936
+ try {
214937
+ options.onOperationError?.({ kind: operation.effect.kind, message: sanitizeSetupDiagnostic(receipt.diagnostic), receiptPath: path });
214938
+ } catch {
214939
+ }
214940
+ };
214941
+ for (const [id, receipt] of Object.entries(journal.receipts))
214942
+ showError(id, receipt);
214943
+ let session2 = await client.poll(), polls = 0;
214944
+ const scope2 = { schema_version: 1, setup_id: client.identity.setup_id };
214945
+ const pause2 = async () => {
214946
+ if (options.sleep)
214947
+ await options.sleep(options.pollMs ?? 2e3);
214948
+ else
214949
+ await new Promise((resolve3, reject) => {
214950
+ const timer = setTimeout(done, options.pollMs ?? 2e3);
214951
+ function done() {
214952
+ options.signal?.removeEventListener("abort", abort);
214953
+ resolve3();
214954
+ }
214955
+ function abort() {
214956
+ clearTimeout(timer);
214957
+ reject(options.signal?.reason);
214958
+ }
214959
+ options.signal?.addEventListener("abort", abort, { once: true });
214960
+ });
214961
+ };
214962
+ while (true) {
214963
+ heartbeat.check();
214964
+ session2 = heartbeat.latest(session2);
214965
+ options.onSession?.(session2);
214966
+ if (terminal3.has(session2.phase) || stopped.has(session2.phase) || options.maxPolls !== void 0 && polls++ >= options.maxPolls) {
214967
+ if (session2.phase === "cancelled") {
214968
+ const known = session2.commands.find((command3) => command3.status === "running" && journal.receipts[command3.operation_id]?.outcome);
214969
+ if (known)
214970
+ session2 = await client.report({ ...scope2, operation_id: known.operation_id, executor_generation: known.executor_generation, lease_generation: known.lease_generation, ...journal.receipts[known.operation_id].outcome });
214971
+ }
214972
+ return session2;
214973
+ }
214974
+ if (session2.phase === "configuring") {
214975
+ if (!session2.site_id || !session2.workspace_id) {
214976
+ await heartbeat.pulse();
214977
+ heartbeat.check();
214978
+ session2 = heartbeat.latest(session2);
214979
+ await pause2();
214980
+ session2 = await client.poll();
214981
+ continue;
214688
214982
  }
214689
- function abort() {
214690
- clearTimeout(timer);
214691
- reject(options.signal?.reason);
214983
+ const targetDigest = setupDigest({ workspace_id: session2.workspace_id, site_id: session2.site_id, api_url: client.identity.api_url });
214984
+ if (!journal.plan || journal.plan.wire.choices_digest !== setupDigest(session2.choices) || journal.target_digest !== targetDigest) {
214985
+ if (Object.keys(journal.receipts).length)
214986
+ throw new SetupError("setup_plan_changed", "A completed local plan cannot be replaced without a new setup.");
214987
+ journal.plan = validatePrepared(await setupAbortable(runtime.prepare(session2), heartbeat.signal));
214988
+ journal.target_digest = targetDigest;
214989
+ journal.plan_request_id = randomUUID9();
214990
+ await saveJournal(path, journal);
214692
214991
  }
214693
- options.signal?.addEventListener("abort", abort, { once: true });
214694
- });
214695
- };
214696
- while (true) {
214697
- options.signal?.throwIfAborted();
214698
- options.onSession?.(session2);
214699
- if (terminal2.has(session2.phase) || stopped.has(session2.phase) || options.maxPolls !== void 0 && polls++ >= options.maxPolls) {
214700
- if (session2.phase === "cancelled") {
214701
- const known = session2.commands.find((command3) => command3.status === "running" && journal.receipts[command3.operation_id]?.outcome);
214702
- if (known)
214703
- session2 = await client.report({ ...scope2, operation_id: known.operation_id, executor_generation: known.executor_generation, lease_generation: known.lease_generation, ...journal.receipts[known.operation_id].outcome });
214992
+ try {
214993
+ session2 = await client.plan({ ...scope2, request_id: journal.plan_request_id, expected_revision: session2.revision, plan: journal.plan.wire });
214994
+ } catch (error) {
214995
+ if (!(error instanceof SetupError) || error.code !== "revision_conflict")
214996
+ throw error;
214997
+ session2 = await client.poll();
214998
+ }
214999
+ continue;
214704
215000
  }
214705
- return session2;
214706
- }
214707
- if (session2.phase === "configuring") {
214708
- if (!session2.site_id || !session2.workspace_id) {
214709
- session2 = await client.heartbeat({ ...scope2, executor_generation: session2.executor_generation, operation_id: null, lease_generation: null });
215001
+ if (!journal.plan || !session2.local_plan || setupDigest(session2.local_plan) !== setupDigest(journal.plan.wire))
215002
+ throw new SetupError("setup_plan_missing", "The browser-approved local plan is unavailable on this computer. No effects were applied.");
215003
+ if (session2.phase !== "applying") {
215004
+ await heartbeat.pulse();
215005
+ heartbeat.check();
215006
+ session2 = heartbeat.latest(session2);
214710
215007
  await pause2();
214711
215008
  session2 = await client.poll();
214712
215009
  continue;
214713
215010
  }
214714
- const targetDigest = setupDigest({ workspace_id: session2.workspace_id, site_id: session2.site_id, api_url: client.identity.api_url });
214715
- if (!journal.plan || journal.plan.wire.choices_digest !== setupDigest(session2.choices) || journal.target_digest !== targetDigest) {
214716
- if (Object.keys(journal.receipts).length)
214717
- throw new SetupError("setup_plan_changed", "A completed local plan cannot be replaced without a new setup.");
214718
- journal.plan = validatePrepared(await runtime.prepare(session2));
214719
- journal.target_digest = targetDigest;
214720
- journal.plan_request_id = randomUUID10();
215011
+ const unknown = session2.commands.find((command3) => command3.status === "outcome_unknown" || command3.status === "running" || command3.status === "leased" && journal.receipts[command3.operation_id]);
215012
+ if (unknown) {
215013
+ const operation2 = journal.plan.operations.find((item) => setupDigest(item.effect) === unknown.input_digest);
215014
+ if (!operation2)
215015
+ throw new SetupError("setup_command_mismatch", "The command does not match the local reviewed plan.");
215016
+ const receipt2 = journal.receipts[unknown.operation_id];
215017
+ if (unknown.status !== "outcome_unknown") {
215018
+ await pause2();
215019
+ session2 = await client.poll();
215020
+ continue;
215021
+ }
215022
+ const stillVerified = await verified(directory2, operation2, runtime, receipt2);
215023
+ const outcome = receipt2?.outcome && receipt2.outcome.status !== "succeeded" ? receipt2.outcome : stillVerified ? { status: "succeeded", result: { code: "already_present", verified: true } } : { status: "manual", result: { code: receipt2?.outcome?.status === "succeeded" ? "review_required" : "outcome_unknown" } };
215024
+ const requestId = receipt2?.request_id ?? randomUUID9();
215025
+ journal.receipts[unknown.operation_id] = { input_digest: unknown.input_digest, stage: "settled", outcome, diagnostic: receipt2?.diagnostic, outputs: receipt2?.outputs, request_id: requestId };
214721
215026
  await saveJournal(path, journal);
215027
+ session2 = await client.reconcile({ ...scope2, request_id: requestId, project_fingerprint: client.identity.project_fingerprint, executor_generation: session2.executor_generation, operation_id: unknown.operation_id, input_digest: unknown.input_digest, ...outcome });
215028
+ continue;
214722
215029
  }
214723
- session2 = await client.plan({ ...scope2, request_id: journal.plan_request_id, expected_revision: session2.revision, plan: journal.plan.wire });
214724
- continue;
214725
- }
214726
- if (!journal.plan || !session2.local_plan || setupDigest(session2.local_plan) !== setupDigest(journal.plan.wire))
214727
- throw new SetupError("setup_plan_missing", "The browser-approved local plan is unavailable on this computer. No effects were applied.");
214728
- if (session2.phase !== "applying") {
214729
- session2 = await client.heartbeat({ ...scope2, executor_generation: session2.executor_generation, operation_id: null, lease_generation: null });
214730
- await pause2();
214731
- session2 = await client.poll();
214732
- continue;
214733
- }
214734
- const unknown = session2.commands.find((command3) => command3.status === "outcome_unknown" || command3.status === "running" || command3.status === "leased" && journal.receipts[command3.operation_id]);
214735
- if (unknown) {
214736
- const operation2 = journal.plan.operations.find((item) => setupDigest(item.effect) === unknown.input_digest);
214737
- if (!operation2)
214738
- throw new SetupError("setup_command_mismatch", "The command does not match the local reviewed plan.");
214739
- const receipt2 = journal.receipts[unknown.operation_id];
214740
- if (unknown.status !== "outcome_unknown") {
215030
+ const claimed = await client.claim({ ...scope2, request_id: journal.claim_request_id, executor_generation: session2.executor_generation });
215031
+ session2 = claimed.session;
215032
+ const command2 = claimed.command;
215033
+ if (!command2) {
214741
215034
  await pause2();
214742
215035
  session2 = await client.poll();
214743
215036
  continue;
214744
215037
  }
214745
- const stillVerified = await verified(directory2, operation2, runtime, receipt2);
214746
- const outcome = receipt2?.outcome && receipt2.outcome.status !== "succeeded" ? receipt2.outcome : stillVerified ? { status: "succeeded", result: { code: "already_present", verified: true } } : { status: "manual", result: { code: receipt2?.outcome?.status === "succeeded" ? "review_required" : "outcome_unknown" } };
214747
- const requestId = receipt2?.request_id ?? randomUUID10();
214748
- journal.receipts[unknown.operation_id] = { input_digest: unknown.input_digest, stage: "settled", outcome, outputs: receipt2?.outputs, request_id: requestId };
215038
+ if (command2.status !== "leased")
215039
+ continue;
215040
+ const operation = journal.plan.operations.find((item) => item.effect.effect_id === command2.input.effect_id);
215041
+ if (!operation || setupDigest(operation.effect) !== command2.input_digest || setupDigest(operation.effect) !== setupDigest(command2.input))
215042
+ throw new SetupError("setup_command_mismatch", "The command differs from the approved local plan.");
215043
+ const lease = { ...scope2, operation_id: command2.operation_id, executor_generation: command2.executor_generation, lease_generation: command2.lease_generation };
215044
+ if (journal.receipts[command2.operation_id])
215045
+ throw new SetupError("setup_replay_refused", "A local receipt already exists. Reconcile before attempting this command again.");
215046
+ const receipt = { input_digest: command2.input_digest, stage: "claimed", request_id: randomUUID9() };
215047
+ journal.receipts[command2.operation_id] = receipt;
214749
215048
  await saveJournal(path, journal);
214750
- session2 = await client.reconcile({ ...scope2, request_id: requestId, project_fingerprint: client.identity.project_fingerprint, executor_generation: session2.executor_generation, operation_id: unknown.operation_id, input_digest: unknown.input_digest, ...outcome });
214751
- continue;
214752
- }
214753
- const claimed = await client.claim({ ...scope2, request_id: journal.claim_request_id, executor_generation: session2.executor_generation });
214754
- session2 = claimed.session;
214755
- const command2 = claimed.command;
214756
- if (!command2) {
214757
- await pause2();
214758
- session2 = await client.poll();
214759
- continue;
214760
- }
214761
- if (command2.status !== "leased")
214762
- continue;
214763
- const operation = journal.plan.operations.find((item) => item.effect.effect_id === command2.input.effect_id);
214764
- if (!operation || setupDigest(operation.effect) !== command2.input_digest || setupDigest(operation.effect) !== setupDigest(command2.input))
214765
- throw new SetupError("setup_command_mismatch", "The command differs from the approved local plan.");
214766
- const lease = { ...scope2, operation_id: command2.operation_id, executor_generation: command2.executor_generation, lease_generation: command2.lease_generation };
214767
- if (journal.receipts[command2.operation_id])
214768
- throw new SetupError("setup_replay_refused", "A local receipt already exists. Reconcile before attempting this command again.");
214769
- const receipt = { input_digest: command2.input_digest, stage: "claimed", request_id: randomUUID10() };
214770
- journal.receipts[command2.operation_id] = receipt;
214771
- await saveJournal(path, journal);
214772
- session2 = await client.startCommand(lease);
214773
- receipt.stage = "running";
214774
- await saveJournal(path, journal);
214775
- const controller = new AbortController();
214776
- const abort = () => controller.abort(options.signal?.reason);
214777
- options.signal?.addEventListener("abort", abort, { once: true });
214778
- if (options.signal?.aborted)
214779
- abort();
214780
- if (terminal2.has(session2.phase))
214781
- controller.abort(new Error("Setup ended before local execution"));
214782
- let heartbeatFailure, heartbeatBusy = false;
214783
- let inFlightHeartbeat;
214784
- const timer = setInterval(() => {
214785
- if (heartbeatBusy)
214786
- return;
214787
- heartbeatBusy = true;
214788
- inFlightHeartbeat = client.heartbeat(lease).then((value) => {
214789
- session2 = value;
214790
- if (terminal2.has(value.phase))
214791
- controller.abort(new Error("Setup ended"));
214792
- }, (error) => {
214793
- heartbeatFailure = error;
214794
- controller.abort(error);
214795
- }).finally(() => {
214796
- heartbeatBusy = false;
214797
- });
214798
- }, options.heartbeatMs ?? 1e4);
214799
- try {
214800
- controller.signal.throwIfAborted();
214801
- if (!await verifySetupFiles(directory2, operation.files, "before"))
214802
- throw new SetupError("setup_files_changed", "Files changed after browser approval.");
214803
- for (const guard of operation.guards ?? []) {
214804
- const content = await readSetupFile(directory2, guard.path);
214805
- if ((content === null ? null : setupHash(content)) !== guard.before_hash)
214806
- throw new SetupError("setup_files_changed", "A package configuration changed after review.");
214807
- }
214808
- if (operation.effect.kind === "install_packages")
214809
- for (const file of operation.effect.managed_outputs ?? []) {
214810
- const content = await readSetupFile(directory2, file.path);
214811
- if ((content === null ? null : setupHash(content)) !== file.before_hash)
214812
- throw new SetupError("setup_files_changed", "Package-manager outputs changed after approval.");
214813
- }
214814
- const code = await runtime.apply(operation, controller.signal);
214815
- controller.signal.throwIfAborted();
214816
- receipt.outputs = await outputs(directory2, operation);
214817
- if (!await verified(directory2, operation, runtime, receipt))
214818
- throw new SetupError("setup_verification_failed", "The completed effect did not match the reviewed files.");
214819
- receipt.outcome = { status: "succeeded", result: { code, verified: true } };
214820
- } catch (error) {
214821
- receipt.outcome = { status: error instanceof SetupError && error.code === "setup_files_changed" ? "manual" : "failed", result: { code: controller.signal.aborted || heartbeatFailure ? "outcome_unknown" : error instanceof SetupError && error.code === "setup_files_changed" ? "review_required" : "operation_failed" } };
214822
- } finally {
214823
- clearInterval(timer);
214824
- await inFlightHeartbeat;
214825
- options.signal?.removeEventListener("abort", abort);
215049
+ heartbeat.setLease(lease);
215050
+ session2 = await client.startCommand(lease);
215051
+ receipt.stage = "running";
215052
+ await saveJournal(path, journal);
215053
+ const operationSignal = heartbeat.signal;
215054
+ try {
215055
+ operationSignal.throwIfAborted();
215056
+ if (!await verifySetupFiles(directory2, operation.files, "before"))
215057
+ throw new SetupError("setup_files_changed", "Files changed after browser approval.");
215058
+ for (const guard of operation.guards ?? []) {
215059
+ const content = await readSetupFile(directory2, guard.path);
215060
+ if ((content === null ? null : setupHash(content)) !== guard.before_hash)
215061
+ throw new SetupError("setup_files_changed", "A package configuration changed after review.");
215062
+ }
215063
+ if (operation.effect.kind === "install_packages")
215064
+ for (const file of operation.effect.managed_outputs ?? []) {
215065
+ const content = await readSetupFile(directory2, file.path);
215066
+ if ((content === null ? null : setupHash(content)) !== file.before_hash)
215067
+ throw new SetupError("setup_files_changed", "Package-manager outputs changed after approval.");
215068
+ }
215069
+ const code = await runtime.apply(operation, operationSignal);
215070
+ operationSignal.throwIfAborted();
215071
+ receipt.outputs = await outputs(directory2, operation);
215072
+ if (!await verified(directory2, operation, runtime, receipt))
215073
+ throw new SetupError("setup_verification_failed", "The completed effect did not match the reviewed files.");
215074
+ receipt.outcome = { status: "succeeded", result: { code, verified: true } };
215075
+ } catch (error) {
215076
+ receipt.outcome = { status: error instanceof SetupError && error.code === "setup_files_changed" ? "manual" : "failed", result: { code: operationSignal.aborted ? "outcome_unknown" : error instanceof SetupError && error.code === "setup_files_changed" ? "review_required" : "operation_failed" } };
215077
+ receipt.diagnostic = sanitizeSetupDiagnostic(error instanceof Error ? error.message : "Local operation failed without an error message.");
215078
+ }
215079
+ receipt.stage = "settled";
215080
+ journal.claim_request_id = randomUUID9();
215081
+ await saveJournal(path, journal);
215082
+ showError(command2.operation_id, receipt);
215083
+ session2 = await heartbeat.duringReport(() => client.report({ ...lease, ...receipt.outcome }));
214826
215084
  }
214827
- receipt.stage = "settled";
214828
- journal.claim_request_id = randomUUID10();
214829
- await saveJournal(path, journal);
214830
- session2 = await client.report({ ...lease, ...receipt.outcome });
214831
- }
214832
- });
215085
+ });
215086
+ } finally {
215087
+ if (!sharedHeartbeat)
215088
+ await heartbeat.stop();
215089
+ }
214833
215090
  }
214834
215091
 
214835
215092
  // node_modules/@userreason/cli/dist/setup-terminal.js
@@ -214840,20 +215097,21 @@ function detectSetupTerminal(platform = process.platform, environment = process.
214840
215097
  }
214841
215098
 
214842
215099
  // node_modules/@userreason/cli/dist/setup-runner.js
214843
- import { randomUUID as randomUUID12 } from "node:crypto";
215100
+ import { randomUUID as randomUUID11 } from "node:crypto";
214844
215101
  import { realpath as realpath4 } from "node:fs/promises";
214845
215102
 
214846
215103
  // node_modules/@userreason/cli/dist/setup-source.js
214847
- import { randomUUID as randomUUID11 } from "node:crypto";
214848
- async function prepareSetupSource(directory2, preparationId = randomUUID11(), signal) {
215104
+ import { randomUUID as randomUUID10 } from "node:crypto";
215105
+ async function prepareSetupSource(directory2, preparationId = randomUUID10(), signal, expanded = false) {
214849
215106
  signal?.throwIfAborted();
214850
- const preview = await collectFirstSurveySource({ root: directory2, snapshotId: preparationId, recommendations: true, signal });
215107
+ const preview = await collectFirstSurveySource({ root: directory2, snapshotId: preparationId, recommendations: true, benchmark: expanded, signal });
214851
215108
  await verifyFirstSurveySource(directory2, preview.evidence);
214852
215109
  const evidence = preview.evidence, packages = preview.packages;
214853
215110
  const prepared = {
214854
215111
  preparation_id: preparationId,
214855
215112
  evidence,
214856
215113
  packages,
215114
+ expanded,
214857
215115
  manifest: {
214858
215116
  packet_digest: setupDigest({ evidence, packages }),
214859
215117
  snapshot_id: preparationId,
@@ -214880,8 +215138,8 @@ async function prepareSetupSource(directory2, preparationId = randomUUID11(), si
214880
215138
  });
214881
215139
  return prepared;
214882
215140
  }
214883
- async function restoreSetupSource(directory2, approved, signal) {
214884
- const prepared = await prepareSetupSource(directory2, approved.preparation_id, signal);
215141
+ async function restoreSetupSource(directory2, approved, signal, expanded) {
215142
+ const prepared = await prepareSetupSource(directory2, approved.preparation_id, signal, expanded ?? approved.manifest.files.reduce((n, file) => n + file.bytes, 0) > 1e4);
214885
215143
  if (setupDigest(prepared.manifest) !== setupDigest(approved.manifest) || setupDigest(prepared.packages) !== setupDigest(approved.packages))
214886
215144
  throw new SetupError("setup_source_changed", "Application source or installed package metadata changed. Review a new source packet in the browser before analysis.");
214887
215145
  return prepared;
@@ -214895,12 +215153,12 @@ async function verifySetupSource(directory2, packet, signal) {
214895
215153
  } catch {
214896
215154
  throw new SetupError("setup_source_changed", "Application files changed. Review a new source packet before analysis.");
214897
215155
  }
214898
- await restoreSetupSource(directory2, packet, signal);
215156
+ await restoreSetupSource(directory2, packet, signal, packet.expanded);
214899
215157
  signal?.throwIfAborted();
214900
215158
  }
214901
215159
 
214902
215160
  // node_modules/@userreason/cli/dist/setup-runner.js
214903
- var terminal3 = /* @__PURE__ */ new Set(["complete", "cancelled", "expired"]);
215161
+ var terminal4 = /* @__PURE__ */ new Set(["complete", "cancelled", "expired"]);
214904
215162
  var localPhases = /* @__PURE__ */ new Set(["configuring", "awaiting_local_approval", "applying"]);
214905
215163
  function pause(milliseconds, options) {
214906
215164
  options.signal?.throwIfAborted();
@@ -214918,133 +215176,173 @@ function pause(milliseconds, options) {
214918
215176
  options.signal?.addEventListener("abort", abort, { once: true });
214919
215177
  });
214920
215178
  }
214921
- async function runBrowserSetup(client, directory2, runtime, options = {}) {
214922
- directory2 = await realpath4(directory2);
214923
- let polls = 0;
214924
- while (true) {
214925
- let session2 = await runSetupExecutor(client, directory2, runtime, options);
214926
- if (terminal3.has(session2.phase) || localPhases.has(session2.phase))
214927
- return session2;
214928
- const result = await withSetupProjectLock(directory2, async () => {
214929
- let packet, observedPreparation;
214930
- let preparationAttempted = false, failedPreparationRevision, notifiedSample = false, heartbeatError;
214931
- const uploadAttempts = /* @__PURE__ */ new Set(), issues = /* @__PURE__ */ new Set();
214932
- const scope2 = { schema_version: 1, setup_id: client.identity.setup_id };
214933
- const accept = (next) => {
214934
- if (BigInt(next.revision) >= BigInt(session2.revision))
214935
- session2 = next;
214936
- };
214937
- const issue = (code) => {
214938
- if (!issues.has(code)) {
214939
- issues.add(code);
214940
- options.onSourceIssue?.(code);
214941
- }
214942
- };
214943
- let sourceAvailable = false;
215179
+ async function prepareEarly(client, directory2, options) {
215180
+ const scope2 = { schema_version: 1, setup_id: client.identity.setup_id };
215181
+ try {
215182
+ let session2 = await client.poll();
215183
+ if (session2.source || !(await client.discovery()).browser_setup.source_analysis)
215184
+ return;
215185
+ const packet = options.preparedSource ? await setupAbortable(options.preparedSource, options.signal) ?? await prepareSetupSource(directory2, randomUUID11(), options.signal, true) : await prepareSetupSource(directory2, randomUUID11(), options.signal, true);
215186
+ let conflicts = 0;
215187
+ while (true) {
215188
+ session2 = await client.poll();
215189
+ if (session2.source || terminal4.has(session2.phase))
215190
+ return;
214944
215191
  try {
214945
- sourceAvailable = (await client.discovery()).browser_setup.source_analysis && session2.capabilities.source_review;
215192
+ session2 = await client.sourcePlan({ ...scope2, request_id: packet.preparation_id, expected_revision: session2.revision, manifest: packet.manifest, packages: packet.packages });
215193
+ break;
214946
215194
  } catch (error) {
214947
- if (!(error instanceof BrowserSetupUnavailable))
215195
+ if (!(error instanceof SetupError) || error.code !== "revision_conflict" || ++conflicts >= 5)
214948
215196
  throw error;
214949
215197
  }
214950
- let heartbeat;
214951
- const timer = setInterval(() => {
214952
- if (heartbeat)
214953
- return;
214954
- heartbeat = client.heartbeat({ ...scope2, executor_generation: session2.executor_generation, operation_id: null, lease_generation: null }).then(accept, (error) => {
214955
- heartbeatError = error;
214956
- }).finally(() => {
214957
- heartbeat = void 0;
214958
- });
214959
- }, options.heartbeatMs ?? 1e4);
214960
- try {
214961
- while (true) {
214962
- options.signal?.throwIfAborted();
214963
- if (heartbeatError)
214964
- throw heartbeatError;
214965
- options.onSession?.(session2);
214966
- if (terminal3.has(session2.phase) || localPhases.has(session2.phase) || options.maxPolls !== void 0 && polls++ >= options.maxPolls)
214967
- return session2;
214968
- if (session2.phase === "agent_test" && session2.sample.status === "waiting" && !notifiedSample) {
214969
- notifiedSample = true;
214970
- options.onSample?.(session2);
214971
- }
214972
- const source = session2.source;
214973
- if (!source && failedPreparationRevision && session2.revision !== failedPreparationRevision) {
214974
- preparationAttempted = false;
214975
- failedPreparationRevision = void 0;
214976
- issues.clear();
214977
- }
214978
- if (source?.preparation_id !== observedPreparation) {
214979
- if (observedPreparation && !source)
214980
- preparationAttempted = false;
214981
- packet = void 0;
214982
- observedPreparation = source?.preparation_id;
214983
- issues.clear();
215198
+ }
215199
+ if (session2.source?.status !== "approved" || session2.source.preparation_id !== packet.preparation_id)
215200
+ return;
215201
+ await verifySetupSource(directory2, packet, options.signal);
215202
+ options.onSession?.(session2);
215203
+ await client.sourceUpload({ ...scope2, preparation_id: packet.preparation_id, project_fingerprint: client.identity.project_fingerprint, evidence: packet.evidence });
215204
+ } catch (error) {
215205
+ options.signal?.throwIfAborted();
215206
+ options.onSourceIssue?.(error instanceof SetupError ? error.code : "source_unavailable");
215207
+ }
215208
+ }
215209
+ async function runBrowserSetup(client, directory2, runtime, options = {}) {
215210
+ directory2 = await realpath4(directory2);
215211
+ const lifetime = new AbortController();
215212
+ const runSignal = AbortSignal.any([lifetime.signal, ...options.signal ? [options.signal] : []]);
215213
+ const base = client.withSignal?.(runSignal) ?? client;
215214
+ const heartbeat = new SetupHeartbeat(base, { ...options, signal: runSignal });
215215
+ client = observeSetupClient(base.withSignal?.(heartbeat.signal) ?? base, heartbeat, heartbeat.signal);
215216
+ const suppliedSignal = options.signal;
215217
+ options = { ...options, signal: heartbeat.signal };
215218
+ let polls = 0;
215219
+ const early = options.automaticSetup ? prepareEarly(client, directory2, options) : Promise.resolve();
215220
+ void early.catch(() => {
215221
+ });
215222
+ try {
215223
+ while (true) {
215224
+ let session2;
215225
+ session2 = await runSetupExecutor(client, directory2, runtime, options, heartbeat);
215226
+ await early;
215227
+ if (options.automaticSetup)
215228
+ session2 = await client.poll();
215229
+ if (terminal4.has(session2.phase) || localPhases.has(session2.phase))
215230
+ return session2;
215231
+ const result = await withSetupProjectLock(directory2, async () => {
215232
+ let packet, observedPreparation;
215233
+ let preparationAttempted = false, failedPreparationRevision, notifiedSample = false;
215234
+ const uploadAttempts = /* @__PURE__ */ new Set(), issues = /* @__PURE__ */ new Set();
215235
+ const scope2 = { schema_version: 1, setup_id: client.identity.setup_id };
215236
+ const accept = (next) => {
215237
+ if (BigInt(next.revision) >= BigInt(session2.revision))
215238
+ session2 = next;
215239
+ };
215240
+ const issue = (code) => {
215241
+ if (!issues.has(code)) {
215242
+ issues.add(code);
215243
+ options.onSourceIssue?.(code);
214984
215244
  }
214985
- if (session2.phase === "ready_for_recommendations" && !source && sourceAvailable && !preparationAttempted) {
214986
- preparationAttempted = true;
214987
- try {
214988
- packet = await prepareSetupSource(directory2, randomUUID12(), options.signal);
214989
- options.onSourcePrepared?.(packet);
214990
- accept(await client.sourcePlan({
214991
- ...scope2,
214992
- request_id: packet.preparation_id,
214993
- expected_revision: session2.revision,
214994
- manifest: packet.manifest,
214995
- packages: packet.packages
214996
- }));
214997
- observedPreparation = session2.source?.preparation_id;
214998
- } catch (error) {
214999
- options.signal?.throwIfAborted();
215000
- failedPreparationRevision = session2.revision;
215001
- issue(error instanceof SetupError ? error.code : "source_unavailable");
215002
- }
215003
- } else if (source?.status === "approved" && sourceAvailable && !uploadAttempts.has(source.preparation_id)) {
215004
- uploadAttempts.add(source.preparation_id);
215005
- try {
215006
- const info = await client.sourceInfo();
215007
- accept(info.session);
215008
- const approved = info.preparation, current = session2.source;
215009
- if (!approved || current?.status !== "approved" || approved.preparation_id !== source.preparation_id || approved.manifest.packet_digest !== current.packet_digest || approved.configuration.configuration_fingerprint !== current.provider_fingerprint)
215010
- throw new SetupError("setup_source_changed", "Review a new source packet in the browser.");
215011
- if (Date.parse(current.expires_at) <= Date.now())
215012
- throw new SetupError("planning_consent_expired", "Review source consent again in the browser.");
215013
- packet = packet?.preparation_id === approved.preparation_id ? packet : await restoreSetupSource(directory2, approved, options.signal);
215014
- options.onSourcePrepared?.(packet);
215015
- await verifySetupSource(directory2, packet, options.signal);
215016
- if (heartbeatError)
215017
- throw heartbeatError;
215018
- if (terminal3.has(session2.phase) || session2.source?.preparation_id !== approved.preparation_id || session2.source.status !== "approved")
215019
- throw new SetupError("setup_source_changed", "Source approval changed before upload.");
215020
- accept(await client.sourceUpload({
215021
- ...scope2,
215022
- preparation_id: packet.preparation_id,
215023
- project_fingerprint: client.identity.project_fingerprint,
215024
- evidence: packet.evidence
215025
- }));
215245
+ };
215246
+ let sourceAvailable = false;
215247
+ try {
215248
+ sourceAvailable = (await client.discovery()).browser_setup.source_analysis && session2.capabilities.source_review;
215249
+ } catch (error) {
215250
+ if (!(error instanceof BrowserSetupUnavailable))
215251
+ throw error;
215252
+ }
215253
+ try {
215254
+ while (true) {
215255
+ heartbeat.check();
215256
+ session2 = heartbeat.latest(session2);
215257
+ options.onSession?.(session2);
215258
+ if (terminal4.has(session2.phase) || localPhases.has(session2.phase) || options.maxPolls !== void 0 && polls++ >= options.maxPolls)
215259
+ return session2;
215260
+ if (session2.phase === "agent_test" && session2.sample.status === "waiting" && !notifiedSample) {
215261
+ notifiedSample = true;
215262
+ options.onSample?.(session2);
215263
+ }
215264
+ const source = session2.source;
215265
+ if (!source && failedPreparationRevision && session2.revision !== failedPreparationRevision) {
215266
+ preparationAttempted = false;
215267
+ failedPreparationRevision = void 0;
215268
+ issues.clear();
215269
+ }
215270
+ if (source?.preparation_id !== observedPreparation) {
215271
+ if (observedPreparation && !source)
215272
+ preparationAttempted = false;
215026
215273
  packet = void 0;
215027
- } catch (error) {
215028
- options.signal?.throwIfAborted();
215029
- issue(error instanceof SetupError ? error.code : "source_unavailable");
215274
+ observedPreparation = source?.preparation_id;
215275
+ issues.clear();
215276
+ }
215277
+ if (session2.phase === "ready_for_recommendations" && !source && sourceAvailable && !preparationAttempted) {
215278
+ preparationAttempted = true;
215279
+ try {
215280
+ packet = await prepareSetupSource(directory2, randomUUID11(), options.signal, options.automaticSetup);
215281
+ options.onSourcePrepared?.(packet);
215282
+ accept(await client.sourcePlan({
215283
+ ...scope2,
215284
+ request_id: packet.preparation_id,
215285
+ expected_revision: session2.revision,
215286
+ manifest: packet.manifest,
215287
+ packages: packet.packages
215288
+ }));
215289
+ observedPreparation = session2.source?.preparation_id;
215290
+ } catch (error) {
215291
+ options.signal?.throwIfAborted();
215292
+ failedPreparationRevision = session2.revision;
215293
+ issue(error instanceof SetupError ? error.code : "source_unavailable");
215294
+ }
215295
+ } else if (source?.status === "approved" && sourceAvailable && !uploadAttempts.has(source.preparation_id)) {
215296
+ uploadAttempts.add(source.preparation_id);
215297
+ try {
215298
+ const info = await client.sourceInfo();
215299
+ accept(info.session);
215300
+ const approved = info.preparation, current = session2.source;
215301
+ if (!approved || current?.status !== "approved" || approved.preparation_id !== source.preparation_id || approved.manifest.packet_digest !== current.packet_digest || approved.configuration.configuration_fingerprint !== current.provider_fingerprint)
215302
+ throw new SetupError("setup_source_changed", "Review a new source packet in the browser.");
215303
+ if (Date.parse(current.expires_at) <= Date.now())
215304
+ throw new SetupError("planning_consent_expired", "Review source consent again in the browser.");
215305
+ packet = packet?.preparation_id === approved.preparation_id ? packet : await restoreSetupSource(directory2, approved, options.signal, options.automaticSetup);
215306
+ options.onSourcePrepared?.(packet);
215307
+ await verifySetupSource(directory2, packet, options.signal);
215308
+ heartbeat.check();
215309
+ if (terminal4.has(session2.phase) || session2.source?.preparation_id !== approved.preparation_id || session2.source.status !== "approved")
215310
+ throw new SetupError("setup_source_changed", "Source approval changed before upload.");
215311
+ accept(await client.sourceUpload({
215312
+ ...scope2,
215313
+ preparation_id: packet.preparation_id,
215314
+ project_fingerprint: client.identity.project_fingerprint,
215315
+ evidence: packet.evidence
215316
+ }));
215317
+ packet = void 0;
215318
+ } catch (error) {
215319
+ options.signal?.throwIfAborted();
215320
+ issue(error instanceof SetupError ? error.code : "source_unavailable");
215321
+ }
215030
215322
  }
215323
+ await pause(options.pollMs ?? 2e3, options);
215324
+ accept(await client.poll());
215031
215325
  }
215032
- await pause(options.pollMs ?? 2e3, options);
215033
- accept(await client.poll());
215326
+ } finally {
215327
+ packet = void 0;
215034
215328
  }
215035
- } finally {
215036
- clearInterval(timer);
215037
- await heartbeat;
215038
- packet = void 0;
215039
- }
215040
- });
215041
- if (!localPhases.has(result.phase) || options.maxPolls !== void 0)
215042
- return result;
215329
+ });
215330
+ if (!localPhases.has(result.phase) || options.maxPolls !== void 0)
215331
+ return result;
215332
+ }
215333
+ } catch (error) {
215334
+ const current = heartbeat.current;
215335
+ if (!suppliedSignal?.aborted && current && terminal4.has(current.phase))
215336
+ return current;
215337
+ throw error;
215338
+ } finally {
215339
+ lifetime.abort(new Error("Setup run ended"));
215340
+ await Promise.allSettled([early, heartbeat.stop()]);
215043
215341
  }
215044
215342
  }
215045
215343
 
215046
215344
  // node_modules/@userreason/cli/dist/project.js
215047
- var import_typescript = __toESM(require_typescript(), 1);
215345
+ var import_typescript2 = __toESM(require_typescript(), 1);
215048
215346
 
215049
215347
  // node_modules/@userreason/cli/dist/help.js
215050
215348
  var GROUPS = [
@@ -215088,8 +215386,6 @@ export {
215088
215386
  ToolTelemetry,
215089
215387
  firstSurveyHandoff,
215090
215388
  firstSurvey,
215091
- prepareFirstSurveyLocally,
215092
- recommendedSurveys,
215093
215389
  SetupError,
215094
215390
  withSetupProjectLock,
215095
215391
  BrowserSetupUnavailable,
@@ -215100,6 +215396,7 @@ export {
215100
215396
  readSetupFile,
215101
215397
  writeSetupFile,
215102
215398
  verifySetupFiles,
215399
+ sanitizeSetupDiagnostic,
215103
215400
  runSetupExecutor,
215104
215401
  detectSetupTerminal,
215105
215402
  runBrowserSetup