@gluecharm-lab/easyspecs-cli 0.0.28 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.cjs CHANGED
@@ -959,8 +959,8 @@ var require_command = __commonJS({
959
959
  "node_modules/commander/lib/command.js"(exports2) {
960
960
  var EventEmitter = require("node:events").EventEmitter;
961
961
  var childProcess = require("node:child_process");
962
- var path60 = require("node:path");
963
- var fs63 = require("node:fs");
962
+ var path61 = require("node:path");
963
+ var fs64 = require("node:fs");
964
964
  var process2 = require("node:process");
965
965
  var { Argument: Argument2, humanReadableArgName } = require_argument();
966
966
  var { CommanderError: CommanderError2 } = require_error();
@@ -1892,11 +1892,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
1892
1892
  let launchWithNode = false;
1893
1893
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1894
1894
  function findFile(baseDir, baseName) {
1895
- const localBin = path60.resolve(baseDir, baseName);
1896
- if (fs63.existsSync(localBin)) return localBin;
1897
- if (sourceExt.includes(path60.extname(baseName))) return void 0;
1895
+ const localBin = path61.resolve(baseDir, baseName);
1896
+ if (fs64.existsSync(localBin)) return localBin;
1897
+ if (sourceExt.includes(path61.extname(baseName))) return void 0;
1898
1898
  const foundExt = sourceExt.find(
1899
- (ext) => fs63.existsSync(`${localBin}${ext}`)
1899
+ (ext) => fs64.existsSync(`${localBin}${ext}`)
1900
1900
  );
1901
1901
  if (foundExt) return `${localBin}${foundExt}`;
1902
1902
  return void 0;
@@ -1908,21 +1908,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
1908
1908
  if (this._scriptPath) {
1909
1909
  let resolvedScriptPath;
1910
1910
  try {
1911
- resolvedScriptPath = fs63.realpathSync(this._scriptPath);
1911
+ resolvedScriptPath = fs64.realpathSync(this._scriptPath);
1912
1912
  } catch (err) {
1913
1913
  resolvedScriptPath = this._scriptPath;
1914
1914
  }
1915
- executableDir = path60.resolve(
1916
- path60.dirname(resolvedScriptPath),
1915
+ executableDir = path61.resolve(
1916
+ path61.dirname(resolvedScriptPath),
1917
1917
  executableDir
1918
1918
  );
1919
1919
  }
1920
1920
  if (executableDir) {
1921
1921
  let localFile = findFile(executableDir, executableFile);
1922
1922
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
1923
- const legacyName = path60.basename(
1923
+ const legacyName = path61.basename(
1924
1924
  this._scriptPath,
1925
- path60.extname(this._scriptPath)
1925
+ path61.extname(this._scriptPath)
1926
1926
  );
1927
1927
  if (legacyName !== this._name) {
1928
1928
  localFile = findFile(
@@ -1933,7 +1933,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1933
1933
  }
1934
1934
  executableFile = localFile || executableFile;
1935
1935
  }
1936
- launchWithNode = sourceExt.includes(path60.extname(executableFile));
1936
+ launchWithNode = sourceExt.includes(path61.extname(executableFile));
1937
1937
  let proc;
1938
1938
  if (process2.platform !== "win32") {
1939
1939
  if (launchWithNode) {
@@ -2773,7 +2773,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2773
2773
  * @return {Command}
2774
2774
  */
2775
2775
  nameFromFilename(filename) {
2776
- this._name = path60.basename(filename, path60.extname(filename));
2776
+ this._name = path61.basename(filename, path61.extname(filename));
2777
2777
  return this;
2778
2778
  }
2779
2779
  /**
@@ -2787,9 +2787,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
2787
2787
  * @param {string} [path]
2788
2788
  * @return {(string|null|Command)}
2789
2789
  */
2790
- executableDir(path61) {
2791
- if (path61 === void 0) return this._executableDir;
2792
- this._executableDir = path61;
2790
+ executableDir(path62) {
2791
+ if (path62 === void 0) return this._executableDir;
2792
+ this._executableDir = path62;
2793
2793
  return this;
2794
2794
  }
2795
2795
  /**
@@ -5993,7 +5993,7 @@ var require_compile = __commonJS({
5993
5993
  const schOrFunc = root.refs[ref];
5994
5994
  if (schOrFunc)
5995
5995
  return schOrFunc;
5996
- let _sch = resolve20.call(this, root, ref);
5996
+ let _sch = resolve23.call(this, root, ref);
5997
5997
  if (_sch === void 0) {
5998
5998
  const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
5999
5999
  const { schemaId } = this.opts;
@@ -6020,7 +6020,7 @@ var require_compile = __commonJS({
6020
6020
  function sameSchemaEnv(s1, s2) {
6021
6021
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
6022
6022
  }
6023
- function resolve20(root, ref) {
6023
+ function resolve23(root, ref) {
6024
6024
  let sch;
6025
6025
  while (typeof (sch = this.refs[ref]) == "string")
6026
6026
  ref = sch;
@@ -6235,8 +6235,8 @@ var require_utils = __commonJS({
6235
6235
  }
6236
6236
  return ind;
6237
6237
  }
6238
- function removeDotSegments(path60) {
6239
- let input = path60;
6238
+ function removeDotSegments(path61) {
6239
+ let input = path61;
6240
6240
  const output = [];
6241
6241
  let nextSlash = -1;
6242
6242
  let len = 0;
@@ -6435,8 +6435,8 @@ var require_schemes = __commonJS({
6435
6435
  wsComponent.secure = void 0;
6436
6436
  }
6437
6437
  if (wsComponent.resourceName) {
6438
- const [path60, query] = wsComponent.resourceName.split("?");
6439
- wsComponent.path = path60 && path60 !== "/" ? path60 : void 0;
6438
+ const [path61, query] = wsComponent.resourceName.split("?");
6439
+ wsComponent.path = path61 && path61 !== "/" ? path61 : void 0;
6440
6440
  wsComponent.query = query;
6441
6441
  wsComponent.resourceName = void 0;
6442
6442
  }
@@ -6595,7 +6595,7 @@ var require_fast_uri = __commonJS({
6595
6595
  }
6596
6596
  return uri;
6597
6597
  }
6598
- function resolve20(baseURI, relativeURI, options) {
6598
+ function resolve23(baseURI, relativeURI, options) {
6599
6599
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
6600
6600
  const resolved = resolveComponent(parse(baseURI, schemelessOptions), parse(relativeURI, schemelessOptions), schemelessOptions, true);
6601
6601
  schemelessOptions.skipEscape = true;
@@ -6822,7 +6822,7 @@ var require_fast_uri = __commonJS({
6822
6822
  var fastUri = {
6823
6823
  SCHEMES,
6824
6824
  normalize: normalize8,
6825
- resolve: resolve20,
6825
+ resolve: resolve23,
6826
6826
  resolveComponent,
6827
6827
  equal,
6828
6828
  serialize,
@@ -10622,12 +10622,12 @@ var require_dist = __commonJS({
10622
10622
  throw new Error(`Unknown format "${name}"`);
10623
10623
  return f;
10624
10624
  };
10625
- function addFormats2(ajv2, list, fs63, exportName) {
10625
+ function addFormats2(ajv2, list, fs64, exportName) {
10626
10626
  var _a;
10627
10627
  var _b;
10628
10628
  (_a = (_b = ajv2.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
10629
10629
  for (const f of list)
10630
- ajv2.addFormat(f, fs63[f]);
10630
+ ajv2.addFormat(f, fs64[f]);
10631
10631
  }
10632
10632
  module2.exports = exports2 = formatsPlugin;
10633
10633
  Object.defineProperty(exports2, "__esModule", { value: true });
@@ -10636,21 +10636,65 @@ var require_dist = __commonJS({
10636
10636
  });
10637
10637
 
10638
10638
  // src/cli/main.ts
10639
- var fs62 = __toESM(require("node:fs"));
10640
- var path59 = __toESM(require("node:path"));
10639
+ var fs63 = __toESM(require("node:fs"));
10640
+ var path60 = __toESM(require("node:path"));
10641
10641
 
10642
10642
  // src/cli/exitCodes.ts
10643
+ var OsExit = {
10644
+ /** Unknown / unclassified factory failure */
10645
+ factoryUnknown: 49,
10646
+ /** Rollup: multiple failed generate_context phases with distinct OS codes in one run */
10647
+ factoryMultiPhaseRollup: 59,
10648
+ createAnalysisWorktree: 50,
10649
+ materializeOpenCodeAgents: 51,
10650
+ synthesisConvergence: 52,
10651
+ referenceCoverage: 53,
10652
+ zeroReferenceRemediation: 54,
10653
+ referenceCoverageExecutionReport: 55,
10654
+ linkMappingPipeline: 56,
10655
+ assembleApplicationContextIndex: 57,
10656
+ backendContextSync: 58,
10657
+ driftEmptyBundle: 60,
10658
+ driftUnresolvedReferenceRoot: 61,
10659
+ driftManifestFailed: 62,
10660
+ driftReportWriteFailed: 63,
10661
+ driftIndexPatchFailed: 64,
10662
+ diagnoseReferenceCoveragePipeline: 70,
10663
+ diagnoseReferenceCoverageThreshold: 71,
10664
+ diagnoseCoordinationDuplicatesPolicy: 72,
10665
+ diagnoseCoordinationDuplicatesEngine: 73,
10666
+ diagnoseCoverageReport: 74,
10667
+ diagnoseZeroReferenceReadCoverage: 75,
10668
+ diagnoseZeroReferenceLinkMapping: 76,
10669
+ diagnoseZeroReferencePool: 77,
10670
+ contextLinkGraph: 78,
10671
+ resumeSynthesisIndex: 79,
10672
+ runSynthesisPipeline: 80,
10673
+ aceLearnTrace: 81,
10674
+ aceAutoLearnPool: 82,
10675
+ updateContextFactory: 83,
10676
+ /** SRS-72 readiness gate (a): OpenCode not installed / not callable. */
10677
+ readinessOpenCodeNotInstalled: 84,
10678
+ /** SRS-72 readiness gate (b): credentials not ready. */
10679
+ readinessOpenCodeCredentials: 85,
10680
+ /** SRS-72 readiness gate (c): default model not configured. */
10681
+ readinessOpenCodeModel: 86,
10682
+ /** SRS-72 readiness gate (d): mandatory OpenCode config file missing. */
10683
+ readinessOpenCodeMandatoryConfig: 87
10684
+ };
10643
10685
  var ExitCode = {
10644
10686
  ok: 0,
10645
10687
  usage: 2,
10646
10688
  misconfiguration: 3,
10647
10689
  opencode: 4,
10648
- validation: 5,
10649
10690
  auth: 6,
10650
10691
  upload: 7,
10651
10692
  cancelled: 8,
10652
10693
  internal: 99
10653
10694
  };
10695
+ function failureExitIdFromParts(exitCode, minor) {
10696
+ return `${String(exitCode)}.${String(minor)}`;
10697
+ }
10654
10698
  function describeExitCode(code) {
10655
10699
  switch (code) {
10656
10700
  case ExitCode.ok:
@@ -10661,8 +10705,6 @@ function describeExitCode(code) {
10661
10705
  return "Configuration or repo layout problem \u2014 fix `.easyspecs/config.json`, paths, or prerequisites, then retry.";
10662
10706
  case ExitCode.opencode:
10663
10707
  return "OpenCode (agent runner) failed \u2014 check `opencode` install, credentials, and stderr from the tool run.";
10664
- case ExitCode.validation:
10665
- return "Validation or factory pipeline did not succeed \u2014 see `error` above and logs for the failing phase (synthesis, coverage, remediation, index, etc.).";
10666
10708
  case ExitCode.auth:
10667
10709
  return "Authentication failed or session missing \u2014 run `easyspecs-cli auth login` or fix CI credentials in config.";
10668
10710
  case ExitCode.upload:
@@ -10671,6 +10713,74 @@ function describeExitCode(code) {
10671
10713
  return "Operation was cancelled (abort/stop).";
10672
10714
  case ExitCode.internal:
10673
10715
  return "Unexpected internal CLI error \u2014 retry; if it persists, report with full stderr and `--verbose` output.";
10716
+ case OsExit.factoryUnknown:
10717
+ return "Factory pipeline failed (phase could not be classified). See `error` and logs; retry with --verbose.";
10718
+ case OsExit.factoryMultiPhaseRollup:
10719
+ return "Multiple factory pipeline phases failed in one run. Inspect `factoryFailures` for each phase.";
10720
+ case OsExit.createAnalysisWorktree:
10721
+ return "Analysis Git worktree could not be prepared. Check disk space, permissions, and a valid Git checkout.";
10722
+ case OsExit.materializeOpenCodeAgents:
10723
+ return "OpenCode agent files could not be installed into the analysis worktree.";
10724
+ case OsExit.synthesisConvergence:
10725
+ return "Context synthesis did not finish successfully. Inspect OpenCode logs and workstation output.";
10726
+ case OsExit.referenceCoverage:
10727
+ return "Reference coverage could not be computed or written. Check coverage JSON and schema.";
10728
+ case OsExit.zeroReferenceRemediation:
10729
+ return "Zero-reference remediation did not complete. Inspect remediation logs and outputs.";
10730
+ case OsExit.referenceCoverageExecutionReport:
10731
+ return "Coverage execution report could not be generated. Ensure coverage inputs exist.";
10732
+ case OsExit.linkMappingPipeline:
10733
+ return "Context link graph could not be updated. Check coordination JSON and markdown.";
10734
+ case OsExit.assembleApplicationContextIndex:
10735
+ return "Application context index could not be assembled or failed schema validation.";
10736
+ case OsExit.backendContextSync:
10737
+ return "Upload or cloud sync after analysis did not succeed.";
10738
+ case OsExit.driftEmptyBundle:
10739
+ return "Context drift: reference bundle was empty or could not be read.";
10740
+ case OsExit.driftUnresolvedReferenceRoot:
10741
+ return "Context drift: reference root document could not be resolved.";
10742
+ case OsExit.driftManifestFailed:
10743
+ return "Context drift: comparison manifest could not be built.";
10744
+ case OsExit.driftReportWriteFailed:
10745
+ return "Context drift: report markdown could not be written.";
10746
+ case OsExit.driftIndexPatchFailed:
10747
+ return "Context drift: reference index could not be updated with the drift link.";
10748
+ case OsExit.diagnoseReferenceCoveragePipeline:
10749
+ return "diagnose reference-coverage: pipeline or write failed.";
10750
+ case OsExit.diagnoseReferenceCoverageThreshold:
10751
+ return "diagnose reference-coverage: percentNonReferenced exceeded the configured threshold.";
10752
+ case OsExit.diagnoseCoordinationDuplicatesPolicy:
10753
+ return "diagnose coordination-duplicates: strict mode reported duplicates or orphan markdown.";
10754
+ case OsExit.diagnoseCoordinationDuplicatesEngine:
10755
+ return "diagnose coordination-duplicates: scan or I/O failed.";
10756
+ case OsExit.diagnoseCoverageReport:
10757
+ return "diagnose coverage-report: report generation failed.";
10758
+ case OsExit.diagnoseZeroReferenceReadCoverage:
10759
+ return "diagnose zero-reference: could not read coverage / zero-reference inputs.";
10760
+ case OsExit.diagnoseZeroReferenceLinkMapping:
10761
+ return "diagnose zero-reference: link mapping after remediation failed.";
10762
+ case OsExit.diagnoseZeroReferencePool:
10763
+ return "diagnose zero-reference: remediation pool reported failures or cancellation.";
10764
+ case OsExit.contextLinkGraph:
10765
+ return "context link-graph: link mapping pipeline failed.";
10766
+ case OsExit.resumeSynthesisIndex:
10767
+ return "run synthesis resume-*: index assembly after remediation failed.";
10768
+ case OsExit.runSynthesisPipeline:
10769
+ return "run synthesis: pipeline did not complete successfully.";
10770
+ case OsExit.aceLearnTrace:
10771
+ return "ace learn: processing a trace failed.";
10772
+ case OsExit.aceAutoLearnPool:
10773
+ return "ace auto-learn: one or more learn runs failed.";
10774
+ case OsExit.updateContextFactory:
10775
+ return "update context: factory run did not succeed.";
10776
+ case OsExit.readinessOpenCodeNotInstalled:
10777
+ return "OpenCode CLI is not installed or not callable on PATH \u2014 install `opencode` or set `easyspecs.openCode.executable`.";
10778
+ case OsExit.readinessOpenCodeCredentials:
10779
+ return "OpenCode credentials not ready for factory run.";
10780
+ case OsExit.readinessOpenCodeModel:
10781
+ return "OpenCode default model is not configured \u2014 add a model in repo `opencode.json` or `easyspecs.openCodeRuntime.providers`.";
10782
+ case OsExit.readinessOpenCodeMandatoryConfig:
10783
+ return "Mandatory OpenCode project config is missing \u2014 create `opencode.json` at the repository / analysis root.";
10674
10784
  default:
10675
10785
  return `Non-zero exit (${String(code)}) \u2014 see stderr and any JSON \`error\` field for detail.`;
10676
10786
  }
@@ -10700,6 +10810,12 @@ var {
10700
10810
  } = import_index.default;
10701
10811
 
10702
10812
  // src/cli/cliProgram.ts
10813
+ function addNoWorktreeCliOption(cmd) {
10814
+ return cmd.option(
10815
+ "--in-place",
10816
+ "Use repository root as the analysis checkout (no detached git worktree). Synonym: --no-worktree (see main argv rewrite)."
10817
+ ).option("--noworktree", "Alias for --in-place (SRS-71)");
10818
+ }
10703
10819
  function createEasyspecsCliProgram() {
10704
10820
  const program2 = new Command();
10705
10821
  program2.name("easyspecs-cli").allowExcessArguments(false).enablePositionalOptions();
@@ -10717,7 +10833,9 @@ function createEasyspecsCliProgram() {
10717
10833
  const runSynthesis = run.command("synthesis").description("Run synthesis pipeline");
10718
10834
  runSynthesis.command("resume-missing").description("Resume remediation pool for missing artefacts").option("--worktree <path>", "Path to an analysis checkout");
10719
10835
  runSynthesis.command("resume-synthesis").description("Resume synthesis pipeline").option("--worktree <path>", "Path to an analysis checkout");
10720
- program2.command("analysis").description("Run full Factory (Generate Context)").option("--force-new-context-analysis", "Force a new analysis even when cloud cache says analyzed").addOption(new Option("--synthesis-only", "(deprecated; no effect)").hideHelp()).allowUnknownOption(true);
10836
+ const analysisCmd = program2.command("analysis").description("Run full Factory (Generate Context)").option("--force-new-context-analysis", "Force a new analysis even when cloud cache says analyzed").addOption(new Option("--synthesis-only", "(deprecated; no effect)").hideHelp());
10837
+ addNoWorktreeCliOption(analysisCmd);
10838
+ analysisCmd.allowUnknownOption(true);
10721
10839
  const diagnose = program2.command("diagnose").description("Deterministic diagnostics");
10722
10840
  const addRootAndWorktree = (c) => c.option("--root <root>", "workspace|worktree").option("--worktree <path>", "Path to an analysis checkout");
10723
10841
  addRootAndWorktree(diagnose.command("reference-coverage").description("Compute reference coverage"));
@@ -10727,11 +10845,12 @@ function createEasyspecsCliProgram() {
10727
10845
  diagnose.command("zero-reference").description("Run zero-reference remediation").option("--worktree <path>", "Path to an analysis checkout");
10728
10846
  const context = program2.command("context").description("Context operations");
10729
10847
  addRootAndWorktree(context.command("link-graph").description("Validate EasySpecs navigation links in context markdown"));
10730
- addRootAndWorktree(
10731
- context.command("drift").description("Compare repo to reference docs; write drift report and update index (worktree + promote)").argument("<referencePath>", "File or directory (spec, SRS, PRD, \u2026)").option("--label <slug>", "Slug for drift-<slug>-<date>.md").option("--index <path>", "Override reference root markdown (relative to repo root)").option("--dry-run", "Validate reference only; skip worktree, agent, and writes")
10732
- );
10848
+ const driftCmd = context.command("drift").description("Compare repo to reference docs; write drift report and update index (worktree + promote)").argument("<referencePath>", "File or directory (spec, SRS, PRD, \u2026)").option("--label <slug>", "Slug for drift-<slug>-<date>.md").option("--index <path>", "Override reference root markdown (relative to repo root)").option("--dry-run", "Validate reference only; skip worktree, agent, and writes");
10849
+ addNoWorktreeCliOption(driftCmd);
10850
+ addRootAndWorktree(driftCmd);
10733
10851
  const update = program2.command("update").description("Incremental context refresh");
10734
- update.command("context").description("Update context since last baseline (git delta, optional remediation, promote)").allowUnknownOption(true);
10852
+ const updateContextCmd = update.command("context").description("Update context since last baseline (git delta, optional remediation, promote)").allowUnknownOption(true);
10853
+ addNoWorktreeCliOption(updateContextCmd);
10735
10854
  const download = program2.command("download").description("Download resources");
10736
10855
  download.command("context").description("Download context from EasySpecs cloud").option("--force", "Overwrite existing local files").option("--replace-from-cloud", "Remove local files before writing cloud versions");
10737
10856
  const upload = program2.command("upload").description("Upload resources");
@@ -12568,7 +12687,7 @@ function stringifyForSrs13Debug(value) {
12568
12687
  return truncateForSrs13DebugLog(String(value));
12569
12688
  }
12570
12689
  }
12571
- function logSrs13HttpDebug(log, path60, method, requestBody, error) {
12690
+ function logSrs13HttpDebug(log, path61, method, requestBody, error) {
12572
12691
  if (!log) {
12573
12692
  return;
12574
12693
  }
@@ -12578,7 +12697,7 @@ function logSrs13HttpDebug(log, path60, method, requestBody, error) {
12578
12697
  } catch {
12579
12698
  bodyBytes = 0;
12580
12699
  }
12581
- log(`[pipeline:upload] debug ${method} ${path60} \u2014 request body ~${bodyBytes} bytes (JSON below):`);
12700
+ log(`[pipeline:upload] debug ${method} ${path61} \u2014 request body ~${bodyBytes} bytes (JSON below):`);
12582
12701
  log(stringifyForSrs13Debug(requestBody));
12583
12702
  const raw = httpApiResponseBody(error);
12584
12703
  const status = error && typeof error === "object" && "status" in error ? Number(error.status) : void 0;
@@ -14275,9 +14394,9 @@ function parsePsRssDarwinKilobytes(stdout) {
14275
14394
  return n;
14276
14395
  }
14277
14396
  function readLinuxPidRssBytes(pid) {
14278
- const path60 = `/proc/${pid}/status`;
14397
+ const path61 = `/proc/${pid}/status`;
14279
14398
  try {
14280
- const content = fs18.readFileSync(path60, "utf8");
14399
+ const content = fs18.readFileSync(path61, "utf8");
14281
14400
  const kb = parseVmRssKilobytesFromProcStatus(content);
14282
14401
  if (kb === null) {
14283
14402
  return { kind: "unknown", reason: "VmRSS_missing" };
@@ -14465,9 +14584,9 @@ function runOpenCodeAgent(cwd, args, options) {
14465
14584
  log?.(`${procTag} command: ${formatCliCommandForLog(cmd, args)}`);
14466
14585
  log?.(`${procTag} cwd: ${JSON.stringify(cwd)}`);
14467
14586
  log?.(`${procTag} argv: ${JSON.stringify(args)}`);
14468
- return new Promise((resolve20) => {
14587
+ return new Promise((resolve23) => {
14469
14588
  if (sig?.aborted) {
14470
- resolve20({ ok: false, message: "Stopped by user.", cancelled: true });
14589
+ resolve23({ ok: false, message: "Stopped by user.", cancelled: true });
14471
14590
  return;
14472
14591
  }
14473
14592
  const spawnEnv = options?.childEnv && Object.keys(options.childEnv).length > 0 ? { ...process.env, ...options.childEnv } : process.env;
@@ -14562,7 +14681,7 @@ ${truncateForDiag(outBody, DIAG_STDOUT_MAX)}`);
14562
14681
  if (diag) {
14563
14682
  finishDiag(diag.label, diag.code, diag.dumpStreams);
14564
14683
  }
14565
- resolve20(result);
14684
+ resolve23(result);
14566
14685
  };
14567
14686
  let onAbort;
14568
14687
  const clearAbortHandler = () => {
@@ -18997,6 +19116,23 @@ function readHeadBranchShort(repoRoot) {
18997
19116
  const b = (r.stdout ?? "").trim();
18998
19117
  return b.length > 0 ? b : void 0;
18999
19118
  }
19119
+ function createInPlaceWorktreeHandle(repositoryRootAbs) {
19120
+ const root = path27.resolve(repositoryRootAbs);
19121
+ return {
19122
+ path: root,
19123
+ repoRoot: root,
19124
+ remove() {
19125
+ }
19126
+ };
19127
+ }
19128
+ function resolveAnalysisCheckoutHandle(worktreePath, repositoryRoot) {
19129
+ const wt = path27.resolve(worktreePath);
19130
+ const repo = path27.resolve(repositoryRoot);
19131
+ if (wt === repo) {
19132
+ return createInPlaceWorktreeHandle(repo);
19133
+ }
19134
+ return attachWorktreeHandle(worktreePath, repositoryRoot);
19135
+ }
19000
19136
  function attachWorktreeHandle(worktreePath, repositoryRoot) {
19001
19137
  const wt = path27.resolve(worktreePath);
19002
19138
  const repo = path27.resolve(repositoryRoot);
@@ -21269,8 +21405,8 @@ async function drainWorkstationPool(p) {
21269
21405
  const artefactRunId = readArtefactRunSnapshot(storageContext)?.runId ?? "unknown-run";
21270
21406
  let active = 0;
21271
21407
  let wake;
21272
- const waitTurn = () => new Promise((resolve20) => {
21273
- wake = resolve20;
21408
+ const waitTurn = () => new Promise((resolve23) => {
21409
+ wake = resolve23;
21274
21410
  });
21275
21411
  const persist = async () => {
21276
21412
  const items = {};
@@ -21439,6 +21575,26 @@ async function prepareSynthesisWorktree(storageContext, repoRoot, log, options)
21439
21575
  if (options?.clearPriorArtefactRun !== false) {
21440
21576
  await clearArtefactRun(storageContext);
21441
21577
  }
21578
+ if (options?.inPlace === true) {
21579
+ const repoResolved = path32.resolve(repoRoot);
21580
+ log(`[worktree] in-place analysis \u2014 using repository root ${repoResolved}`);
21581
+ const handle2 = createInPlaceWorktreeHandle(repoResolved);
21582
+ const sourceBranchAtCreation = readHeadBranchShort(repoResolved);
21583
+ let finalized2 = false;
21584
+ const finalize2 = () => {
21585
+ if (finalized2) {
21586
+ return;
21587
+ }
21588
+ finalized2 = true;
21589
+ log(`[worktree] in-place mode \u2014 no teardown`);
21590
+ };
21591
+ return {
21592
+ ok: true,
21593
+ handle: handle2,
21594
+ finalize: finalize2,
21595
+ ...sourceBranchAtCreation ? { sourceBranchAtCreation } : {}
21596
+ };
21597
+ }
21442
21598
  const wt = createAnalysisWorktree(repoRoot, { log });
21443
21599
  if (!wt.ok) {
21444
21600
  return { ok: false, error: wt.error };
@@ -21597,6 +21753,7 @@ function promoteContextDirectoryToWorkspaceFs(sourceContextDir, workspaceRootFs)
21597
21753
 
21598
21754
  // src/shared/factoryPipelineExitConditions.ts
21599
21755
  var FACTORY_PIPELINE_EXIT_CONDITIONS = {
21756
+ diagnose_readiness: "OpenCode CLI, credentials, default model, and mandatory project `opencode.json` are ready before worktree / agent work (SRS-72).",
21600
21757
  create_analysis_worktree: "Git analysis checkout exists under the configured temp parent (SRS-8); ready for agent materialization.",
21601
21758
  materialize_opencode_agents: "Bundled OpenCode agent definitions are copied into the analysis worktree (`.opencode/` tree).",
21602
21759
  synthesis_convergence: "Missing artefact count is 0. May run again after remediation (R5) if a refreshed check finds new expected outputs.",
@@ -21608,13 +21765,225 @@ var FACTORY_PIPELINE_EXIT_CONDITIONS = {
21608
21765
  backend_context_sync: "Context upload finished with no failures (quiet SRS-13 path; or cancel)."
21609
21766
  };
21610
21767
 
21768
+ // src/readiness/factoryReadiness.ts
21769
+ var fs39 = __toESM(require("node:fs"));
21770
+ var os6 = __toESM(require("node:os"));
21771
+ var path34 = __toESM(require("node:path"));
21772
+ var MANDATORY_OPEN_CODE_CONFIG_REL_PATHS = ["opencode.json"];
21773
+ var READINESS_OPENCODE_NOT_INSTALLED = "READINESS_OPENCODE_NOT_INSTALLED";
21774
+ var READINESS_OPENCODE_CREDENTIALS = "READINESS_OPENCODE_CREDENTIALS";
21775
+ var READINESS_OPENCODE_MODEL = "READINESS_OPENCODE_MODEL";
21776
+ var READINESS_OPENCODE_MANDATORY_CONFIG = "READINESS_OPENCODE_MANDATORY_CONFIG";
21777
+ function userOpenCodeConfigPath() {
21778
+ if (process.platform === "win32") {
21779
+ const base = process.env.APPDATA || path34.join(os6.homedir(), "AppData", "Roaming");
21780
+ return path34.join(base, "opencode", "config.json");
21781
+ }
21782
+ const xdg = process.env.XDG_CONFIG_HOME?.trim();
21783
+ const cfgRoot = xdg && xdg.length > 0 ? xdg : path34.join(os6.homedir(), ".config");
21784
+ return path34.join(cfgRoot, "opencode", "config.json");
21785
+ }
21786
+ function buildOpenCodeConfigInventory(analysisRootAbs) {
21787
+ const root = path34.resolve(analysisRootAbs);
21788
+ const list = [
21789
+ { path: path34.join(root, "opencode.json"), exists: false },
21790
+ { path: path34.join(root, ".opencode", "config.json"), exists: false },
21791
+ { path: userOpenCodeConfigPath(), exists: false }
21792
+ ];
21793
+ return list.map((e) => ({ ...e, exists: fs39.existsSync(e.path) }));
21794
+ }
21795
+ function defaultModelFromEasyspecsConfig(cfg) {
21796
+ const providers = cfg.easyspecs?.openCodeRuntime?.providers;
21797
+ if (!providers || typeof providers !== "object") {
21798
+ return void 0;
21799
+ }
21800
+ for (const rec of Object.values(providers)) {
21801
+ const dm = rec?.defaultModel?.trim();
21802
+ if (dm) {
21803
+ return dm;
21804
+ }
21805
+ }
21806
+ return void 0;
21807
+ }
21808
+ function pickString(v) {
21809
+ return typeof v === "string" && v.trim().length > 0 ? v.trim() : void 0;
21810
+ }
21811
+ function extractModelFromOpenCodeJson(data) {
21812
+ if (!data || typeof data !== "object") {
21813
+ return void 0;
21814
+ }
21815
+ const o = data;
21816
+ const direct = pickString(o.model) ?? pickString(o.defaultModel);
21817
+ if (direct) {
21818
+ return direct;
21819
+ }
21820
+ const models = o.models;
21821
+ if (models && typeof models === "object") {
21822
+ const m = models;
21823
+ const def = pickString(m.default) ?? pickString(m.defaultModel);
21824
+ if (def) {
21825
+ return def;
21826
+ }
21827
+ }
21828
+ const agent = o.agent;
21829
+ if (agent && typeof agent === "object") {
21830
+ const a = agent;
21831
+ const am = pickString(a.model) ?? pickString(a.defaultModel);
21832
+ if (am) {
21833
+ return am;
21834
+ }
21835
+ }
21836
+ return void 0;
21837
+ }
21838
+ function sanitizeModelSummary(raw) {
21839
+ const t = raw.trim();
21840
+ if (!t) {
21841
+ return "(not configured)";
21842
+ }
21843
+ if (t.length > 160) {
21844
+ return `${t.slice(0, 157)}\u2026`;
21845
+ }
21846
+ const lower = t.toLowerCase();
21847
+ if (lower.includes("bearer ") || lower.includes("authorization:") || lower.startsWith("sk-")) {
21848
+ return "(redacted)";
21849
+ }
21850
+ return t;
21851
+ }
21852
+ function resolveModelFromContext(ctx) {
21853
+ const fromCfg = defaultModelFromEasyspecsConfig(ctx.repoConfig);
21854
+ if (fromCfg) {
21855
+ return { configured: true, summary: sanitizeModelSummary(fromCfg) };
21856
+ }
21857
+ const p = path34.join(path34.resolve(ctx.analysisRootAbs), "opencode.json");
21858
+ try {
21859
+ const txt = fs39.readFileSync(p, "utf-8");
21860
+ const data = JSON.parse(txt);
21861
+ const m = extractModelFromOpenCodeJson(data);
21862
+ if (m) {
21863
+ return { configured: true, summary: sanitizeModelSummary(m) };
21864
+ }
21865
+ } catch {
21866
+ }
21867
+ return { configured: false, summary: "(not configured)" };
21868
+ }
21869
+ function buildReadinessProbeFacts(ctx) {
21870
+ const oc = ctx.__testOnlyOpenCodeReadiness?.() ?? getOpenCodeReadiness({
21871
+ executable: ctx.openCodeExecutable,
21872
+ skipCredentialsCheck: ctx.openCodeSkipCredentialsCheck,
21873
+ providerEnvFromConfig: ctx.providerEnvFromConfig
21874
+ });
21875
+ const openCodeConfigFiles = buildOpenCodeConfigInventory(ctx.analysisRootAbs);
21876
+ const mandatoryOk = MANDATORY_OPEN_CODE_CONFIG_REL_PATHS.every((rel) => {
21877
+ const abs = path34.join(path34.resolve(ctx.analysisRootAbs), rel);
21878
+ return fs39.existsSync(abs);
21879
+ });
21880
+ const model = resolveModelFromContext(ctx);
21881
+ const agentsDir = resolveOpenCodeAgentsDir(ctx.repoRootAbs, ctx.repoConfig);
21882
+ return {
21883
+ installed: oc.installed,
21884
+ credentialsReady: oc.credentialsReady,
21885
+ skipCredentialsCheck: ctx.openCodeSkipCredentialsCheck === true,
21886
+ modelConfigured: model.configured,
21887
+ modelSummary: model.summary,
21888
+ mandatoryConfigPathsOk: mandatoryOk,
21889
+ openCodeConfigFiles,
21890
+ agentsDir,
21891
+ agentsDirExists: fs39.existsSync(agentsDir)
21892
+ };
21893
+ }
21894
+ function buildReadinessLineBlock(facts, ctx) {
21895
+ const apiDisp = ctx.apiBaseUrl.trim().length > 0 ? ctx.apiBaseUrl : "(empty \u2014 stub auth only)";
21896
+ const lines = [
21897
+ `cliVersion=${ctx.cliVersion}`,
21898
+ `repoRoot=${ctx.repoRootAbs}`,
21899
+ `apiBaseUrl=${apiDisp}`,
21900
+ `opencode installed=${String(facts.installed)} credentialsReady=${String(facts.credentialsReady)}`,
21901
+ `opencode modelConfigured=${String(facts.modelConfigured)} modelSummary=${facts.modelSummary}`
21902
+ ];
21903
+ for (const e of facts.openCodeConfigFiles) {
21904
+ lines.push(`opencodeConfigFile ${e.path} exists=${String(e.exists)}`);
21905
+ }
21906
+ lines.push(`agentsDir=${facts.agentsDir} exists=${String(facts.agentsDirExists)}`);
21907
+ return lines;
21908
+ }
21909
+ function evaluateReadinessGates(facts) {
21910
+ if (!facts.installed) {
21911
+ return {
21912
+ ok: false,
21913
+ gate: "a",
21914
+ exitCode: OsExit.readinessOpenCodeNotInstalled,
21915
+ readinessReasonCode: READINESS_OPENCODE_NOT_INSTALLED
21916
+ };
21917
+ }
21918
+ if (!facts.credentialsReady && !facts.skipCredentialsCheck) {
21919
+ return {
21920
+ ok: false,
21921
+ gate: "b",
21922
+ exitCode: OsExit.readinessOpenCodeCredentials,
21923
+ readinessReasonCode: READINESS_OPENCODE_CREDENTIALS
21924
+ };
21925
+ }
21926
+ if (!facts.modelConfigured) {
21927
+ return {
21928
+ ok: false,
21929
+ gate: "c",
21930
+ exitCode: OsExit.readinessOpenCodeModel,
21931
+ readinessReasonCode: READINESS_OPENCODE_MODEL
21932
+ };
21933
+ }
21934
+ if (!facts.mandatoryConfigPathsOk) {
21935
+ return {
21936
+ ok: false,
21937
+ gate: "d",
21938
+ exitCode: OsExit.readinessOpenCodeMandatoryConfig,
21939
+ readinessReasonCode: READINESS_OPENCODE_MANDATORY_CONFIG
21940
+ };
21941
+ }
21942
+ return { ok: true };
21943
+ }
21944
+ function buildReadinessJsonFields(facts) {
21945
+ return {
21946
+ modelConfigured: facts.modelConfigured,
21947
+ credentialsReady: facts.credentialsReady,
21948
+ openCodeConfigFiles: facts.openCodeConfigFiles,
21949
+ agentsDir: facts.agentsDir,
21950
+ agentsDirExists: facts.agentsDirExists
21951
+ };
21952
+ }
21953
+ function emitCliFactoryReadinessPreflight(log, bannerPrefix, ctx) {
21954
+ const facts = buildReadinessProbeFacts(ctx);
21955
+ const lines = buildReadinessLineBlock(facts, ctx);
21956
+ log(`${bannerPrefix} \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}`);
21957
+ for (const ln of lines) {
21958
+ log(ln);
21959
+ }
21960
+ const gateRes = evaluateReadinessGates(facts);
21961
+ if (!gateRes.ok) {
21962
+ log(`${bannerPrefix} \u2014 failed (readinessReasonCode=${gateRes.readinessReasonCode})`);
21963
+ log(`Exit ${String(gateRes.exitCode)} \u2014 ${describeExitCode(gateRes.exitCode)}`);
21964
+ return { ok: false, facts, failure: gateRes };
21965
+ }
21966
+ log(`${bannerPrefix} \u2014 succeeded (detail: all checks ok)`);
21967
+ return { ok: true, facts };
21968
+ }
21969
+
21611
21970
  // src/factory/factoryValidationFailures.ts
21612
21971
  function factoryFailureDisplayId(row2) {
21613
21972
  return row2.failureExitId;
21614
21973
  }
21974
+ function parseMajorFromFailureExitId(id) {
21975
+ const m = /^(\d+)\.\d+$/.exec(id.trim());
21976
+ if (!m) {
21977
+ return void 0;
21978
+ }
21979
+ const n = Number(m[1]);
21980
+ return Number.isFinite(n) ? n : void 0;
21981
+ }
21615
21982
  function normalizeFactoryFailureRow(r) {
21616
- const failureExitId = r.failureExitId ?? r.validationExitId ?? "5.0";
21617
- const exitCode = typeof r.exitCode === "number" ? r.exitCode : ExitCode.validation;
21983
+ const failureExitId = r.failureExitId ?? r.validationExitId ?? failureExitIdFromParts(OsExit.factoryUnknown, 0);
21984
+ const exitCodeFromField = typeof r.exitCode === "number" ? r.exitCode : void 0;
21985
+ const exitCodeFromId = parseMajorFromFailureExitId(failureExitId);
21986
+ const exitCode = exitCodeFromField ?? exitCodeFromId ?? OsExit.factoryUnknown;
21618
21987
  const factory = r.factory ?? "generate_context";
21619
21988
  const base = {
21620
21989
  factory,
@@ -21625,12 +21994,10 @@ function normalizeFactoryFailureRow(r) {
21625
21994
  ...typeof r.detail === "string" ? { detail: r.detail } : {},
21626
21995
  ...typeof r.validationSubcode === "string" ? { validationSubcode: r.validationSubcode } : {}
21627
21996
  };
21628
- if (exitCode === ExitCode.validation) {
21629
- return { ...base, validationExitId: r.validationExitId ?? failureExitId };
21630
- }
21631
- return base;
21997
+ return { ...base, validationExitId: r.validationExitId ?? failureExitId };
21632
21998
  }
21633
21999
  var FACTORY_VALIDATION_PHASE_ORDER = [
22000
+ "diagnose_readiness",
21634
22001
  "create_analysis_worktree",
21635
22002
  "materialize_opencode_agents",
21636
22003
  "synthesis_convergence",
@@ -21644,31 +22011,34 @@ var FACTORY_VALIDATION_PHASE_ORDER = [
21644
22011
  var DETAIL_MAX = 600;
21645
22012
  var ERROR_JOIN_MAX = 900;
21646
22013
  var ADDITIONAL_APPEND_MAX = 200;
21647
- var PHASE_TO_EXIT_ID = {
21648
- unknown_factory_phase: "5.0",
21649
- create_analysis_worktree: "5.1",
21650
- materialize_opencode_agents: "5.2",
21651
- synthesis_convergence: "5.3",
21652
- reference_coverage: "5.4",
21653
- zero_reference_remediation_convergence: "5.5",
21654
- reference_coverage_execution_report: "5.6",
21655
- link_mapping_pipeline: "5.7",
21656
- assemble_application_context_index: "5.8",
21657
- backend_context_sync: "5.9"
22014
+ var PHASE_TO_OS_EXIT = {
22015
+ unknown_factory_phase: OsExit.factoryUnknown,
22016
+ diagnose_readiness: OsExit.readinessOpenCodeModel,
22017
+ create_analysis_worktree: OsExit.createAnalysisWorktree,
22018
+ materialize_opencode_agents: OsExit.materializeOpenCodeAgents,
22019
+ synthesis_convergence: OsExit.synthesisConvergence,
22020
+ reference_coverage: OsExit.referenceCoverage,
22021
+ zero_reference_remediation_convergence: OsExit.zeroReferenceRemediation,
22022
+ reference_coverage_execution_report: OsExit.referenceCoverageExecutionReport,
22023
+ link_mapping_pipeline: OsExit.linkMappingPipeline,
22024
+ assemble_application_context_index: OsExit.assembleApplicationContextIndex,
22025
+ backend_context_sync: OsExit.backendContextSync
21658
22026
  };
21659
- var EXIT_ID_TITLES = {
21660
- "5.0": "EasySpecs stopped: the failing pipeline phase could not be identified. Retry with --verbose; report this outcome if it persists.",
21661
- "5.1": "Could not prepare the analysis Git worktree (temporary checkout). Check disk space, repo permissions, and that the project is a valid Git checkout.",
21662
- "5.2": "Could not install OpenCode agent files into the analysis worktree. Check bundled extension assets and disk permissions under the worktree path.",
21663
- "5.3": "Context synthesis did not finish: required context files are still missing or invalid after retries. Inspect OpenCode errors and workstation logs for this phase.",
21664
- "5.4": "Reference coverage could not be computed or written. Check coverage-reference-validation.json prerequisites and disk/schema errors.",
21665
- "5.5": "Zero-reference remediation did not complete successfully. Inspect remediation logs and zero-reference outputs for this checkout.",
21666
- "5.6": "Reference coverage execution report could not be generated. Ensure coverage inputs exist from the coverage phase; see coverage-reference-validation.json.",
21667
- "5.7": "Context link graph (navigation links) could not be updated. Check coordination JSON and markdown under .gluecharm/context.",
21668
- "5.8": "Application context index could not be assembled or failed schema validation. Inspect index-application-context.json and preceding context files.",
21669
- "5.9": "Upload / cloud sync after analysis did not succeed. Check auth, project id, network, and upload error details."
22027
+ var TITLE_BY_PHASE = {
22028
+ unknown_factory_phase: "EasySpecs stopped: the failing pipeline phase could not be identified. Retry with --verbose; report this outcome if it persists.",
22029
+ diagnose_readiness: "Factory readiness preflight failed: OpenCode install, credentials, default model, or mandatory `opencode.json` is not satisfied. See stderr lines above and `readinessReasonCode` in JSON.",
22030
+ create_analysis_worktree: "Could not prepare the analysis Git worktree (temporary checkout). Check disk space, repo permissions, and that the project is a valid Git checkout.",
22031
+ materialize_opencode_agents: "Could not install OpenCode agent files into the analysis worktree. Check bundled extension assets and disk permissions under the worktree path.",
22032
+ synthesis_convergence: "Context synthesis did not finish: required context files are still missing or invalid after retries. Inspect OpenCode errors and workstation logs for this phase.",
22033
+ reference_coverage: "Reference coverage could not be computed or written. Check coverage-reference-validation.json prerequisites and disk/schema errors.",
22034
+ zero_reference_remediation_convergence: "Zero-reference remediation did not complete successfully. Inspect remediation logs and zero-reference outputs for this checkout.",
22035
+ reference_coverage_execution_report: "Reference coverage execution report could not be generated. Ensure coverage inputs exist from the coverage phase; see coverage-reference-validation.json.",
22036
+ link_mapping_pipeline: "Context link graph (navigation links) could not be updated. Check coordination JSON and markdown under .gluecharm/context.",
22037
+ assemble_application_context_index: "Application context index could not be assembled or failed schema validation. Inspect index-application-context.json and preceding context files.",
22038
+ backend_context_sync: "Upload / cloud sync after analysis did not succeed. Check auth, project id, network, and upload error details."
21670
22039
  };
21671
22040
  var READABLE_PHASE_LABEL = {
22041
+ diagnose_readiness: "Diagnose readiness",
21672
22042
  create_analysis_worktree: "Analysis worktree",
21673
22043
  materialize_opencode_agents: "OpenCode agents",
21674
22044
  synthesis_convergence: "Synthesis",
@@ -21700,11 +22070,11 @@ function inferValidationSubcode(phase, detail) {
21700
22070
  }
21701
22071
  return void 0;
21702
22072
  }
21703
- function phaseToValidationExitId(phase) {
21704
- return PHASE_TO_EXIT_ID[phase] ?? "5.0";
22073
+ function phaseToSemanticOsExitForGenerateContext(phase) {
22074
+ return PHASE_TO_OS_EXIT[phase] ?? OsExit.factoryUnknown;
21705
22075
  }
21706
- function titleForValidationExitId(validationExitId) {
21707
- return EXIT_ID_TITLES[validationExitId] ?? EXIT_ID_TITLES["5.0"];
22076
+ function titleForGenerateContextPhase(phase) {
22077
+ return TITLE_BY_PHASE[phase] ?? TITLE_BY_PHASE.unknown_factory_phase;
21708
22078
  }
21709
22079
  function readableLabelForFactoryPhase(phase) {
21710
22080
  return READABLE_PHASE_LABEL[phase] ?? phase;
@@ -21713,33 +22083,53 @@ function phaseIndex(key) {
21713
22083
  const i = FACTORY_VALIDATION_PHASE_ORDER.indexOf(key);
21714
22084
  return i >= 0 ? i : 999;
21715
22085
  }
22086
+ function finalizeFactoryFailuresForProcessExit(rows) {
22087
+ if (rows.length === 0) {
22088
+ return [];
22089
+ }
22090
+ const candidates = [...new Set(rows.map((r) => r.exitCode))];
22091
+ const processExit = candidates.length > 1 ? OsExit.factoryMultiPhaseRollup : candidates[0] ?? OsExit.factoryUnknown;
22092
+ return rows.map((r, i) => {
22093
+ const minor = processExit === OsExit.factoryMultiPhaseRollup ? i : 0;
22094
+ const fid = failureExitIdFromParts(processExit, minor);
22095
+ return {
22096
+ ...r,
22097
+ exitCode: processExit,
22098
+ failureExitId: fid,
22099
+ validationExitId: fid
22100
+ };
22101
+ });
22102
+ }
21716
22103
  function buildFactoryFailuresFromRows(phases) {
21717
22104
  const failed = phases.filter((p) => p.status === "failed");
21718
22105
  failed.sort((a, b) => phaseIndex(a.key) - phaseIndex(b.key));
21719
- return failed.map((p) => {
21720
- const id = phaseToValidationExitId(p.key);
22106
+ const semantic = failed.map((p) => {
22107
+ const os8 = phaseToSemanticOsExitForGenerateContext(p.key);
21721
22108
  const sub = inferValidationSubcode(p.key, p.detail);
22109
+ const fid = failureExitIdFromParts(os8, 0);
21722
22110
  return {
21723
22111
  factory: "generate_context",
21724
22112
  phase: p.key,
21725
- exitCode: ExitCode.validation,
21726
- failureExitId: id,
21727
- validationExitId: id,
21728
- title: titleForValidationExitId(id),
22113
+ exitCode: os8,
22114
+ failureExitId: fid,
22115
+ validationExitId: fid,
22116
+ title: titleForGenerateContextPhase(p.key),
21729
22117
  detail: trimDetail(p.detail),
21730
22118
  ...sub !== void 0 ? { validationSubcode: sub } : {}
21731
22119
  };
21732
22120
  });
22121
+ return finalizeFactoryFailuresForProcessExit(semantic);
21733
22122
  }
21734
22123
  function syntheticUnknownFactoryFailure(message) {
22124
+ const fid = failureExitIdFromParts(OsExit.factoryUnknown, 0);
21735
22125
  return [
21736
22126
  {
21737
22127
  factory: "generate_context",
21738
22128
  phase: "unknown_factory_phase",
21739
- exitCode: ExitCode.validation,
21740
- failureExitId: "5.0",
21741
- validationExitId: "5.0",
21742
- title: titleForValidationExitId("5.0"),
22129
+ exitCode: OsExit.factoryUnknown,
22130
+ failureExitId: fid,
22131
+ validationExitId: fid,
22132
+ title: titleForGenerateContextPhase("unknown_factory_phase"),
21743
22133
  detail: trimDetail(message)
21744
22134
  }
21745
22135
  ];
@@ -21747,7 +22137,8 @@ function syntheticUnknownFactoryFailure(message) {
21747
22137
  function primaryFailureAliases(failures) {
21748
22138
  const last = failures[failures.length - 1];
21749
22139
  if (!last) {
21750
- return { failurePhase: "unknown_factory_phase", validationExitId: "5.0" };
22140
+ const fid = failureExitIdFromParts(OsExit.factoryUnknown, 0);
22141
+ return { failurePhase: "unknown_factory_phase", validationExitId: fid };
21751
22142
  }
21752
22143
  return {
21753
22144
  failurePhase: last.phase,
@@ -21767,7 +22158,7 @@ function exitMeaningFromFactoryFailures(failures) {
21767
22158
  function composeFactoryValidationError(orchestratorMessage, failures) {
21768
22159
  const m = orchestratorMessage?.trim() ?? "";
21769
22160
  if (failures.length <= 1) {
21770
- return m.length > 0 ? m : failures[0]?.title ?? "Validation failed.";
22161
+ return m.length > 0 ? m : failures[0]?.title ?? "Factory pipeline failed.";
21771
22162
  }
21772
22163
  const extraIds = failures.slice(1).map((f) => factoryFailureDisplayId(f)).join(", ");
21773
22164
  let appendix = `(+${String(failures.length - 1)} additional phase failure(s): ${extraIds})`;
@@ -21784,6 +22175,7 @@ function composeFactoryValidationError(orchestratorMessage, failures) {
21784
22175
 
21785
22176
  // src/factory/generateContextFactory.ts
21786
22177
  var FACTORY_PIPELINE_KEYS = [
22178
+ "diagnose_readiness",
21787
22179
  "create_analysis_worktree",
21788
22180
  "materialize_opencode_agents",
21789
22181
  "synthesis_convergence",
@@ -21812,7 +22204,7 @@ function sleepUntilAborted(ms, signal) {
21812
22204
  if (signal.aborted) {
21813
22205
  return Promise.reject(new DOMException("The operation was aborted.", "AbortError"));
21814
22206
  }
21815
- return new Promise((resolve20, reject) => {
22207
+ return new Promise((resolve23, reject) => {
21816
22208
  const onAbort = () => {
21817
22209
  clearTimeout(t);
21818
22210
  signal.removeEventListener("abort", onAbort);
@@ -21820,7 +22212,7 @@ function sleepUntilAborted(ms, signal) {
21820
22212
  };
21821
22213
  const t = setTimeout(() => {
21822
22214
  signal.removeEventListener("abort", onAbort);
21823
- resolve20();
22215
+ resolve23();
21824
22216
  }, ms);
21825
22217
  signal.addEventListener("abort", onAbort, { once: true });
21826
22218
  });
@@ -21919,6 +22311,59 @@ async function runGenerateContextFactory(deps) {
21919
22311
  };
21920
22312
  let pingPong = 0;
21921
22313
  try {
22314
+ if (!deps.readiness) {
22315
+ setRowTimed("diagnose_readiness", "succeeded", "Readiness context omitted (narrow unit test).");
22316
+ await post();
22317
+ } else {
22318
+ setRowTimed("diagnose_readiness", "running", "Running diagnose readiness preflight\u2026");
22319
+ await post();
22320
+ const facts = buildReadinessProbeFacts(deps.readiness);
22321
+ const lines = buildReadinessLineBlock(facts, deps.readiness);
22322
+ const gateRes = evaluateReadinessGates(facts);
22323
+ const stamp = (/* @__PURE__ */ new Date()).toISOString();
22324
+ const rlog = deps.readinessLog ?? deps.factoryLog;
22325
+ rlog?.(`[factory] diagnose readiness \u2014 ${stamp}`);
22326
+ for (const ln of lines) {
22327
+ rlog?.(ln);
22328
+ }
22329
+ if (!gateRes.ok) {
22330
+ rlog?.(
22331
+ `[factory] diagnose readiness \u2014 failed (readinessReasonCode=${gateRes.readinessReasonCode})`
22332
+ );
22333
+ rlog?.(`Exit ${String(gateRes.exitCode)} \u2014 ${describeExitCode(gateRes.exitCode)}`);
22334
+ const detail = `${gateRes.readinessReasonCode} (gate ${gateRes.gate})`;
22335
+ setRowTimed("diagnose_readiness", "failed", detail);
22336
+ await post();
22337
+ const fr = {
22338
+ factory: "generate_context",
22339
+ phase: "diagnose_readiness",
22340
+ exitCode: gateRes.exitCode,
22341
+ failureExitId: failureExitIdFromParts(gateRes.exitCode, 0),
22342
+ validationExitId: failureExitIdFromParts(gateRes.exitCode, 0),
22343
+ title: titleForGenerateContextPhase("diagnose_readiness"),
22344
+ detail: detail.length > 600 ? `${detail.slice(0, 597)}\u2026` : detail
22345
+ };
22346
+ const ff = finalizeFactoryFailuresForProcessExit([fr]);
22347
+ const msg = `Readiness failed: ${gateRes.readinessReasonCode}`;
22348
+ const r = {
22349
+ ok: false,
22350
+ message: msg,
22351
+ totalElapsedMs: macroEnd(),
22352
+ factoryFailures: ff,
22353
+ readinessFailure: {
22354
+ exitCode: gateRes.exitCode,
22355
+ readinessReasonCode: gateRes.readinessReasonCode,
22356
+ readinessGate: gateRes.gate
22357
+ }
22358
+ };
22359
+ logFactoryEnd(r);
22360
+ return r;
22361
+ }
22362
+ const joined = lines.join(" | ");
22363
+ const okDetail = joined.length > 600 ? `${lines[0] ?? "ok"} | \u2026 (${String(lines.length)} lines)` : joined;
22364
+ setRowTimed("diagnose_readiness", "succeeded", okDetail);
22365
+ await post();
22366
+ }
21922
22367
  outer: while (true) {
21923
22368
  if (isAborted(signal)) {
21924
22369
  setRowTimed("synthesis_convergence", "cancelled", "Stopped.");
@@ -21935,7 +22380,15 @@ async function runGenerateContextFactory(deps) {
21935
22380
  return fin({ ok: false, cancelled: true, message: "Factory stopped.", totalElapsedMs: macroEnd() });
21936
22381
  }
21937
22382
  if (!resumeSynthesis) {
21938
- setRowTimed("create_analysis_worktree", "running", "Creating git analysis worktree\u2026");
22383
+ if (deps.analysisInPlace === true) {
22384
+ setRowTimed(
22385
+ "create_analysis_worktree",
22386
+ "running",
22387
+ "In-place analysis \u2014 preparing repository root (no temp worktree)\u2026"
22388
+ );
22389
+ } else {
22390
+ setRowTimed("create_analysis_worktree", "running", "Creating git analysis worktree\u2026");
22391
+ }
21939
22392
  await post();
21940
22393
  const wtRes = await deps.runPrepareAnalysisWorktree(false);
21941
22394
  if (!wtRes.ok) {
@@ -21943,7 +22396,15 @@ async function runGenerateContextFactory(deps) {
21943
22396
  await post();
21944
22397
  return fail(wtRes.error ?? "Worktree creation failed.");
21945
22398
  }
21946
- setRowTimed("create_analysis_worktree", "succeeded", "Analysis checkout ready.");
22399
+ if (deps.analysisInPlace === true) {
22400
+ setRowTimed(
22401
+ "create_analysis_worktree",
22402
+ "skipped",
22403
+ "In-place analysis \u2014 using repository root (no detached checkout)."
22404
+ );
22405
+ } else {
22406
+ setRowTimed("create_analysis_worktree", "succeeded", "Analysis checkout ready.");
22407
+ }
21947
22408
  await post();
21948
22409
  if (isAborted(signal)) {
21949
22410
  setRowTimed("materialize_opencode_agents", "cancelled");
@@ -22249,8 +22710,8 @@ async function runGenerateContextFactory(deps) {
22249
22710
  }
22250
22711
 
22251
22712
  // src/factory/generateContextFactoryHeadlessHost.ts
22252
- var fs47 = __toESM(require("node:fs"));
22253
- var path43 = __toESM(require("node:path"));
22713
+ var fs48 = __toESM(require("node:fs"));
22714
+ var path44 = __toESM(require("node:path"));
22254
22715
 
22255
22716
  // src/stores/pipelineRunStore.ts
22256
22717
  var STORAGE_KEY2 = SRS53_PIPELINE_RUN_KEY_V2;
@@ -22350,12 +22811,12 @@ async function noteAgentsMaterialized(context) {
22350
22811
  }
22351
22812
 
22352
22813
  // src/pipelines/remediation/missingWorkstations.ts
22353
- var fs40 = __toESM(require("fs"));
22354
- var path35 = __toESM(require("path"));
22814
+ var fs41 = __toESM(require("fs"));
22815
+ var path36 = __toESM(require("path"));
22355
22816
 
22356
22817
  // src/analysis/analysisDetailMarkdownDiscovery.ts
22357
- var fs39 = __toESM(require("fs"));
22358
- var path34 = __toESM(require("path"));
22818
+ var fs40 = __toESM(require("fs"));
22819
+ var path35 = __toESM(require("path"));
22359
22820
  var SLUG4 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
22360
22821
  var FE2 = /^FE-\d+$/;
22361
22822
  var UC2 = /^UC-\d+$/;
@@ -22376,7 +22837,7 @@ var STEM_TO_AGENT = {
22376
22837
  };
22377
22838
  function readJson5(filePath) {
22378
22839
  try {
22379
- let raw = fs39.readFileSync(filePath, "utf-8");
22840
+ let raw = fs40.readFileSync(filePath, "utf-8");
22380
22841
  if (raw.length > 0 && raw.charCodeAt(0) === 65279) {
22381
22842
  raw = raw.slice(1);
22382
22843
  }
@@ -22417,7 +22878,7 @@ function expectedFeatureDetailBasenameFromRow(row2) {
22417
22878
  return `${code}-${slug}.md`;
22418
22879
  }
22419
22880
  function ctxPath(contextDir2, basename17) {
22420
- return path34.join(contextDir2, basename17);
22881
+ return path35.join(contextDir2, basename17);
22421
22882
  }
22422
22883
  function pushTarget(targets, stem, outputBasename, taskDescription, contextDir2) {
22423
22884
  const meta = STEM_TO_AGENT[stem];
@@ -22433,7 +22894,7 @@ function pushTarget(targets, stem, outputBasename, taskDescription, contextDir2)
22433
22894
  function discoverDetailMarkdownGroups(contextDir2) {
22434
22895
  const groups = [];
22435
22896
  const featureTargets = [];
22436
- const flPath = path34.join(contextDir2, "features-list.json");
22897
+ const flPath = path35.join(contextDir2, "features-list.json");
22437
22898
  const fl = readJson5(flPath);
22438
22899
  const features = Array.isArray(fl?.features) ? fl.features : [];
22439
22900
  for (const row2 of features) {
@@ -22463,7 +22924,7 @@ function discoverDetailMarkdownGroups(contextDir2) {
22463
22924
  if (!FE2.test(feCode)) {
22464
22925
  continue;
22465
22926
  }
22466
- const ucListPath = path34.join(contextDir2, `${feCode}-use-cases-list.json`);
22927
+ const ucListPath = path35.join(contextDir2, `${feCode}-use-cases-list.json`);
22467
22928
  const ucFile = readJson5(ucListPath);
22468
22929
  const ucs = Array.isArray(ucFile?.useCases) ? ucFile.useCases : [];
22469
22930
  for (const ucRow of ucs) {
@@ -22483,7 +22944,7 @@ function discoverDetailMarkdownGroups(contextDir2) {
22483
22944
  Follow bundled agent **agent-md-use-case-detail**: include **## Data inputs and validation** (concrete fields, mandatory vs optional, rules, failure behaviour). **## Code flow** must trace **implementation order** (entrypoint \u2192 validation \u2192 business rules \u2192 persistence \u2192 response) with **real** symbols and files\u2014not generic \u201Cuser does X\u201D. Add a **Mermaid** fenced diagram under Code flow when there are **two or more** implementation stages. **## Evidence index** must cite **each major stage** (validation, persistence, response), not only the outer entrypoint.`,
22484
22945
  contextDir2
22485
22946
  );
22486
- const scPath = path34.join(contextDir2, `${feCode}_${ucCode}-scenarios-list.json`);
22947
+ const scPath = path35.join(contextDir2, `${feCode}_${ucCode}-scenarios-list.json`);
22487
22948
  const scFile = readJson5(scPath);
22488
22949
  const scs = Array.isArray(scFile?.scenarios) ? scFile.scenarios : [];
22489
22950
  for (const scRow of scs) {
@@ -22554,7 +23015,7 @@ Follow bundled agent **agent-md-use-case-detail**: include **## Data inputs and
22554
23015
  groups.push({ id: "detail-services", label: "Detail markdown \u2014 Services", targets: svcTargets });
22555
23016
  groups.push({ id: "detail-methods", label: "Detail markdown \u2014 Methods", targets: meTargets });
22556
23017
  const entTargets = [];
22557
- const dmPath = path34.join(contextDir2, "data-model-list.json");
23018
+ const dmPath = path35.join(contextDir2, "data-model-list.json");
22558
23019
  const dmFile = readJson5(dmPath);
22559
23020
  const ents = Array.isArray(dmFile?.entities) ? dmFile.entities : [];
22560
23021
  for (const erow of ents) {
@@ -22583,7 +23044,7 @@ Follow bundled agent **agent-md-use-case-detail**: include **## Data inputs and
22583
23044
  if (!DM2.test(dmCode)) {
22584
23045
  continue;
22585
23046
  }
22586
- const flPath2 = path34.join(contextDir2, `${dmCode}-fields-list.json`);
23047
+ const flPath2 = path35.join(contextDir2, `${dmCode}-fields-list.json`);
22587
23048
  const flFile = readJson5(flPath2);
22588
23049
  const flds = Array.isArray(flFile?.fields) ? flFile.fields : [];
22589
23050
  for (const frow of flds) {
@@ -22642,9 +23103,9 @@ function fileAndValidationFromKind(kind) {
22642
23103
  return { filePresentYesNo: "no", validationYesNo: "na" };
22643
23104
  }
22644
23105
  function classifyMissingWorkstationOutputFileStatus(row2, contextDir2, worktreeRoot) {
22645
- const abs = path35.join(contextDir2, row2.relativePath);
23106
+ const abs = path36.join(contextDir2, row2.relativePath);
22646
23107
  try {
22647
- const st = fs40.statSync(abs);
23108
+ const st = fs41.statSync(abs);
22648
23109
  if (!st.isFile()) {
22649
23110
  return { kind: "absent", detail: "Path exists but is not a regular file." };
22650
23111
  }
@@ -22681,8 +23142,8 @@ function classifyMissingWorkstationOutputFileStatus(row2, contextDir2, worktreeR
22681
23142
  detail: "Unknown coordination list basename \u2014 no JSON Schema mapping."
22682
23143
  };
22683
23144
  }
22684
- const schemaAbs = path35.join(worktreeRoot, ".opencode", "schemas", "context-lists", schemaBn);
22685
- if (!fs40.existsSync(schemaAbs)) {
23145
+ const schemaAbs = path36.join(worktreeRoot, ".opencode", "schemas", "context-lists", schemaBn);
23146
+ if (!fs41.existsSync(schemaAbs)) {
22686
23147
  return {
22687
23148
  kind: "invalid",
22688
23149
  detail: `Schema not found (${schemaBn}). Run **Materialize agents** on this checkout.`
@@ -22711,7 +23172,7 @@ function classifyWorkstationOutputOnDisk(item, contextDir2, worktreeRoot) {
22711
23172
  return classifyMissingWorkstationOutputFileStatus(row2, contextDir2, worktreeRoot).kind;
22712
23173
  }
22713
23174
  function isWorkstationRunSnapshotForWorktree(snapshot, worktreeRoot) {
22714
- return !!(snapshot && snapshot.overallStatus !== "running" && snapshot.overallStatus !== "idle" && path35.resolve(snapshot.analysisRoot) === path35.resolve(worktreeRoot));
23175
+ return !!(snapshot && snapshot.overallStatus !== "running" && snapshot.overallStatus !== "idle" && path36.resolve(snapshot.analysisRoot) === path36.resolve(worktreeRoot));
22715
23176
  }
22716
23177
  function expectedBasenameForCoordPayload(p) {
22717
23178
  const { step, listTarget } = p;
@@ -22785,10 +23246,10 @@ function labelContextForCoordPayload(p) {
22785
23246
  }
22786
23247
  function contextPathForWorkItem(item, contextDir2) {
22787
23248
  if (item.kind === "markdown") {
22788
- return path35.join(contextDir2, item.payload.outputBasename);
23249
+ return path36.join(contextDir2, item.payload.outputBasename);
22789
23250
  }
22790
23251
  const bn = expectedBasenameForCoordPayload(item.payload);
22791
- return bn ? path35.join(contextDir2, bn) : null;
23252
+ return bn ? path36.join(contextDir2, bn) : null;
22792
23253
  }
22793
23254
  function syntheticRunnerId(key) {
22794
23255
  return `remediation:${key}`;
@@ -22798,7 +23259,7 @@ function rowFromSkippedItem(item, contextDir2) {
22798
23259
  return null;
22799
23260
  }
22800
23261
  const abs = contextPathForWorkItem(item, contextDir2);
22801
- const rel = abs ? path35.basename(abs) : item.kind === "markdown" ? item.payload.outputBasename : item.id;
23262
+ const rel = abs ? path36.basename(abs) : item.kind === "markdown" ? item.payload.outputBasename : item.id;
22802
23263
  if (abs && nonEmptyContextFile(abs)) {
22803
23264
  return null;
22804
23265
  }
@@ -22918,7 +23379,7 @@ function listMissingWorkstations(contextDir2, worktreeRoot, snapshot) {
22918
23379
  }
22919
23380
  }
22920
23381
  }
22921
- if (!fs40.existsSync(contextDir2)) {
23382
+ if (!fs41.existsSync(contextDir2)) {
22922
23383
  return [...map.values()].sort((a, b) => a.key.localeCompare(b.key));
22923
23384
  }
22924
23385
  const dynamic = discoverDynamicAnalysisTestSteps(contextDir2);
@@ -22973,7 +23434,7 @@ function toMissingWorkstationUiRows(rows, contextDir2, worktreeRoot) {
22973
23434
  }
22974
23435
 
22975
23436
  // src/pipelines/remediation/missingWorkstationsPool.ts
22976
- var path36 = __toESM(require("path"));
23437
+ var path37 = __toESM(require("path"));
22977
23438
  function reconcileSkippedWorkItemsWithDisk(byId, contextDir2, worktreeRoot) {
22978
23439
  for (const item of byId.values()) {
22979
23440
  if (item.status !== "skipped") {
@@ -23033,7 +23494,7 @@ async function runRemediationPipelineMissingPass(p) {
23033
23494
  onItemComplete,
23034
23495
  sourceBranchAtWorktreeCreation
23035
23496
  } = p;
23036
- const contextDir2 = path36.join(worktreeRoot, ".gluecharm", "context");
23497
+ const contextDir2 = path37.join(worktreeRoot, ".gluecharm", "context");
23037
23498
  const snap = readArtefactRunSnapshot(storageContext);
23038
23499
  const snapOk = isWorkstationRunSnapshotForWorktree(snap, worktreeRoot);
23039
23500
  let byId;
@@ -23099,18 +23560,18 @@ async function runRemediationPipelineMissingPass(p) {
23099
23560
 
23100
23561
  // src/pipelines/coverage/coveragePipeline.ts
23101
23562
  var import_child_process5 = require("child_process");
23102
- var fs42 = __toESM(require("fs"));
23103
- var path38 = __toESM(require("path"));
23563
+ var fs43 = __toESM(require("fs"));
23564
+ var path39 = __toESM(require("path"));
23104
23565
 
23105
23566
  // src/analysis/coverageReferenceValidationSchemaValidate.ts
23106
- var fs41 = __toESM(require("fs"));
23107
- var path37 = __toESM(require("path"));
23567
+ var fs42 = __toESM(require("fs"));
23568
+ var path38 = __toESM(require("path"));
23108
23569
  var import__5 = __toESM(require__());
23109
23570
  function stripUtf8Bom4(s) {
23110
23571
  return s.length > 0 && s.charCodeAt(0) === 65279 ? s.slice(1) : s;
23111
23572
  }
23112
23573
  function bundledCoverageReferenceValidationSchemaPath() {
23113
- return path37.join(
23574
+ return path38.join(
23114
23575
  resolveRepoResourcesRoot(),
23115
23576
  "schemas",
23116
23577
  "context-lists",
@@ -23133,7 +23594,7 @@ function getValidate() {
23133
23594
  return compiledValidate;
23134
23595
  }
23135
23596
  const schemaPath = bundledCoverageReferenceValidationSchemaPath();
23136
- const schemaRaw = stripUtf8Bom4(fs41.readFileSync(schemaPath, "utf-8"));
23597
+ const schemaRaw = stripUtf8Bom4(fs42.readFileSync(schemaPath, "utf-8"));
23137
23598
  const schema = JSON.parse(schemaRaw);
23138
23599
  const ajv2 = new import__5.default({ allErrors: true, strict: false });
23139
23600
  compiledValidate = ajv2.compile(schema);
@@ -23149,7 +23610,7 @@ function validateCoverageReferenceValidationData(data) {
23149
23610
  function readAndValidateCoverageReferenceValidationFile(jsonAbsolutePath) {
23150
23611
  let raw;
23151
23612
  try {
23152
- raw = stripUtf8Bom4(fs41.readFileSync(jsonAbsolutePath, "utf-8"));
23613
+ raw = stripUtf8Bom4(fs42.readFileSync(jsonAbsolutePath, "utf-8"));
23153
23614
  } catch (e) {
23154
23615
  return {
23155
23616
  ok: false,
@@ -23190,8 +23651,8 @@ var DEFAULT_IGNORE_DIR_BASENAMES = [
23190
23651
  ];
23191
23652
  var GIT_LS_FILES_MAX_BUFFER = 64 * 1024 * 1024;
23192
23653
  function tryLoadGitNonIgnoredPathSet(repositoryRootAbs) {
23193
- const root = path38.resolve(repositoryRootAbs);
23194
- if (!fs42.existsSync(path38.join(root, ".git"))) {
23654
+ const root = path39.resolve(repositoryRootAbs);
23655
+ if (!fs43.existsSync(path39.join(root, ".git"))) {
23195
23656
  return null;
23196
23657
  }
23197
23658
  const env = { ...process.env, GIT_TERMINAL_PROMPT: "0" };
@@ -23259,12 +23720,12 @@ var REFERENCE_COVERAGE_IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
23259
23720
  ".emf"
23260
23721
  ]);
23261
23722
  function isReferenceCoverageExcludedImagePath(relPosix) {
23262
- const ext = path38.extname(relPosix).toLowerCase();
23723
+ const ext = path39.extname(relPosix).toLowerCase();
23263
23724
  return ext.length > 0 && REFERENCE_COVERAGE_IMAGE_EXTENSIONS.has(ext);
23264
23725
  }
23265
23726
  var REFERENCE_COVERAGE_EXCLUDED_FILE_BASENAMES = /* @__PURE__ */ new Set([".gitignore"]);
23266
23727
  function isReferenceCoverageExcludedDefaultBasename(relPosix) {
23267
- const base = path38.basename(relPosix.replace(/\\/g, "/")).toLowerCase();
23728
+ const base = path39.basename(relPosix.replace(/\\/g, "/")).toLowerCase();
23268
23729
  return REFERENCE_COVERAGE_EXCLUDED_FILE_BASENAMES.has(base);
23269
23730
  }
23270
23731
  function decodeBufferForLineCount(buf) {
@@ -23301,12 +23762,12 @@ function normalizeRepoRelativePath(repoRoot, raw) {
23301
23762
  if (!trimmed || trimmed.includes("\0")) {
23302
23763
  return null;
23303
23764
  }
23304
- const abs = path38.resolve(repoRoot, trimmed);
23305
- const rel = path38.relative(repoRoot, abs);
23306
- if (rel.startsWith("..") || path38.isAbsolute(rel)) {
23765
+ const abs = path39.resolve(repoRoot, trimmed);
23766
+ const rel = path39.relative(repoRoot, abs);
23767
+ if (rel.startsWith("..") || path39.isAbsolute(rel)) {
23307
23768
  return null;
23308
23769
  }
23309
- return rel.split(path38.sep).join("/");
23770
+ return rel.split(path39.sep).join("/");
23310
23771
  }
23311
23772
  function collectJsonSourceReferences(node, out) {
23312
23773
  if (node === null || typeof node !== "object") {
@@ -23346,12 +23807,12 @@ function extractEvidenceIndexPathCitations(body) {
23346
23807
  function listContextFilesRecursive(dir, acc) {
23347
23808
  let entries;
23348
23809
  try {
23349
- entries = fs42.readdirSync(dir, { withFileTypes: true });
23810
+ entries = fs43.readdirSync(dir, { withFileTypes: true });
23350
23811
  } catch {
23351
23812
  return;
23352
23813
  }
23353
23814
  for (const e of entries) {
23354
- const full = path38.join(dir, e.name);
23815
+ const full = path39.join(dir, e.name);
23355
23816
  if (e.isDirectory()) {
23356
23817
  listContextFilesRecursive(full, acc);
23357
23818
  } else if (e.isFile()) {
@@ -23364,7 +23825,7 @@ function walkRepositoryFiles(repoRoot, ignoreBasenames, maxBytes, excludedOut, g
23364
23825
  const walk = (dir) => {
23365
23826
  let entries;
23366
23827
  try {
23367
- entries = fs42.readdirSync(dir, { withFileTypes: true });
23828
+ entries = fs43.readdirSync(dir, { withFileTypes: true });
23368
23829
  } catch {
23369
23830
  return;
23370
23831
  }
@@ -23372,8 +23833,8 @@ function walkRepositoryFiles(repoRoot, ignoreBasenames, maxBytes, excludedOut, g
23372
23833
  if (ignoreBasenames.has(e.name)) {
23373
23834
  continue;
23374
23835
  }
23375
- const full = path38.join(dir, e.name);
23376
- const rel = path38.relative(repoRoot, full).split(path38.sep).join("/");
23836
+ const full = path39.join(dir, e.name);
23837
+ const rel = path39.relative(repoRoot, full).split(path39.sep).join("/");
23377
23838
  if (rel.startsWith("..")) {
23378
23839
  continue;
23379
23840
  }
@@ -23394,7 +23855,7 @@ function walkRepositoryFiles(repoRoot, ignoreBasenames, maxBytes, excludedOut, g
23394
23855
  }
23395
23856
  let st;
23396
23857
  try {
23397
- st = fs42.statSync(full);
23858
+ st = fs43.statSync(full);
23398
23859
  } catch {
23399
23860
  continue;
23400
23861
  }
@@ -23404,7 +23865,7 @@ function walkRepositoryFiles(repoRoot, ignoreBasenames, maxBytes, excludedOut, g
23404
23865
  }
23405
23866
  let buf;
23406
23867
  try {
23407
- buf = fs42.readFileSync(full);
23868
+ buf = fs43.readFileSync(full);
23408
23869
  } catch {
23409
23870
  excludedOut.push({ path: rel, reason: "read error" });
23410
23871
  continue;
@@ -23424,23 +23885,23 @@ function walkRepositoryFiles(repoRoot, ignoreBasenames, maxBytes, excludedOut, g
23424
23885
  }
23425
23886
  function collectReferencesFromContext(contextDirAbs, repositoryRootAbs, warnings) {
23426
23887
  const references = [];
23427
- if (!fs42.existsSync(contextDirAbs)) {
23888
+ if (!fs43.existsSync(contextDirAbs)) {
23428
23889
  warnings.push(`Context directory missing: ${contextDirAbs}`);
23429
23890
  return references;
23430
23891
  }
23431
23892
  const allFiles = [];
23432
23893
  listContextFilesRecursive(contextDirAbs, allFiles);
23433
23894
  for (const abs of allFiles) {
23434
- const ext = path38.extname(abs).toLowerCase();
23435
- const base = path38.basename(abs);
23436
- const sourceArtefact = path38.relative(contextDirAbs, abs).split(path38.sep).join("/");
23895
+ const ext = path39.extname(abs).toLowerCase();
23896
+ const base = path39.basename(abs);
23897
+ const sourceArtefact = path39.relative(contextDirAbs, abs).split(path39.sep).join("/");
23437
23898
  if (ext === ".json") {
23438
23899
  if (SKIP_CONTEXT_JSON.has(base)) {
23439
23900
  continue;
23440
23901
  }
23441
23902
  let raw;
23442
23903
  try {
23443
- raw = fs42.readFileSync(abs, "utf-8");
23904
+ raw = fs43.readFileSync(abs, "utf-8");
23444
23905
  } catch (e) {
23445
23906
  warnings.push(`Skip JSON (read error): ${sourceArtefact} \u2014 ${e instanceof Error ? e.message : String(e)}`);
23446
23907
  continue;
@@ -23471,7 +23932,7 @@ function collectReferencesFromContext(contextDirAbs, repositoryRootAbs, warnings
23471
23932
  if (ext === ".md") {
23472
23933
  let text;
23473
23934
  try {
23474
- const buf = fs42.readFileSync(abs);
23935
+ const buf = fs43.readFileSync(abs);
23475
23936
  text = decodeBufferForLineCount(buf);
23476
23937
  } catch (e) {
23477
23938
  warnings.push(`Skip markdown (read/decode error): ${sourceArtefact} \u2014 ${e instanceof Error ? e.message : String(e)}`);
@@ -23515,12 +23976,12 @@ function sortReferenceRows(a, b) {
23515
23976
  return (a.startLine ?? 0) - (b.startLine ?? 0);
23516
23977
  }
23517
23978
  function buildCoverageReferenceValidationDocument(repositoryRootAbs, contextDirAbs, options) {
23518
- const repoRoot = path38.resolve(repositoryRootAbs);
23979
+ const repoRoot = path39.resolve(repositoryRootAbs);
23519
23980
  const warnings = [];
23520
23981
  const ignoreDirs = [...DEFAULT_IGNORE_DIR_BASENAMES];
23521
23982
  const ignoreSet = new Set(ignoreDirs);
23522
23983
  const maxBytes = options?.maxFileBytes ?? MAX_FILE_BYTES;
23523
- const references = collectReferencesFromContext(path38.resolve(contextDirAbs), repoRoot, warnings);
23984
+ const references = collectReferencesFromContext(path39.resolve(contextDirAbs), repoRoot, warnings);
23524
23985
  references.sort(sortReferenceRows);
23525
23986
  const referencedSet = /* @__PURE__ */ new Set();
23526
23987
  for (const r of references) {
@@ -23528,7 +23989,7 @@ function buildCoverageReferenceValidationDocument(repositoryRootAbs, contextDirA
23528
23989
  }
23529
23990
  const excludedFiles = [];
23530
23991
  const gitNonIgnoredPaths = tryLoadGitNonIgnoredPathSet(repoRoot);
23531
- if (fs42.existsSync(path38.join(repoRoot, ".git")) && gitNonIgnoredPaths === null) {
23992
+ if (fs43.existsSync(path39.join(repoRoot, ".git")) && gitNonIgnoredPaths === null) {
23532
23993
  warnings.push(
23533
23994
  "Repository has .git but git ls-files failed or git is unavailable; .gitignore / exclude-standard not applied."
23534
23995
  );
@@ -23577,12 +24038,12 @@ function buildCoverageReferenceValidationDocument(repositoryRootAbs, contextDirA
23577
24038
  return { document: doc, warnings };
23578
24039
  }
23579
24040
  function runCoveragePipeline(opts) {
23580
- const repoRoot = path38.resolve(opts.repositoryRootAbs);
23581
- const contextDir2 = path38.resolve(opts.contextDirAbs);
23582
- if (!fs42.existsSync(repoRoot)) {
24041
+ const repoRoot = path39.resolve(opts.repositoryRootAbs);
24042
+ const contextDir2 = path39.resolve(opts.contextDirAbs);
24043
+ if (!fs43.existsSync(repoRoot)) {
23583
24044
  return { ok: false, error: `Repository root does not exist: ${repoRoot}` };
23584
24045
  }
23585
- if (!fs42.existsSync(contextDir2)) {
24046
+ if (!fs43.existsSync(contextDir2)) {
23586
24047
  return {
23587
24048
  ok: false,
23588
24049
  error: `Missing .gluecharm/context: ${contextDir2}`
@@ -23600,11 +24061,11 @@ ${schemaCheck.errors.join("\n")}`,
23600
24061
  warnings
23601
24062
  };
23602
24063
  }
23603
- const outPath = path38.join(contextDir2, COVERAGE_REFERENCE_VALIDATION_BASENAME);
24064
+ const outPath = path39.join(contextDir2, COVERAGE_REFERENCE_VALIDATION_BASENAME);
23604
24065
  if (opts.write) {
23605
24066
  try {
23606
24067
  const payload = stableStringifyCoverageDocument(document);
23607
- fs42.writeFileSync(outPath, payload, "utf-8");
24068
+ fs43.writeFileSync(outPath, payload, "utf-8");
23608
24069
  } catch (e) {
23609
24070
  return {
23610
24071
  ok: false,
@@ -23618,12 +24079,12 @@ ${schemaCheck.errors.join("\n")}`,
23618
24079
 
23619
24080
  // src/pipelines/remediation/zeroReferenceWorkstationChain.ts
23620
24081
  var crypto = __toESM(require("crypto"));
23621
- var fs44 = __toESM(require("fs"));
23622
- var path40 = __toESM(require("path"));
24082
+ var fs45 = __toESM(require("fs"));
24083
+ var path41 = __toESM(require("path"));
23623
24084
 
23624
24085
  // src/analysis/zeroReferenceRemediationSchemaValidate.ts
23625
- var fs43 = __toESM(require("fs"));
23626
- var path39 = __toESM(require("path"));
24086
+ var fs44 = __toESM(require("fs"));
24087
+ var path40 = __toESM(require("path"));
23627
24088
  var import__6 = __toESM(require__());
23628
24089
  function stripUtf8Bom5(s) {
23629
24090
  return s.length > 0 && s.charCodeAt(0) === 65279 ? s.slice(1) : s;
@@ -23643,8 +24104,8 @@ function formatAjvErrors6(errors) {
23643
24104
  }
23644
24105
  var ajv = new import__6.default({ allErrors: true, strict: false });
23645
24106
  function compileSchema(basename17) {
23646
- const schemaPath = path39.join(schemasDir(), basename17);
23647
- const schemaRaw = stripUtf8Bom5(fs43.readFileSync(schemaPath, "utf-8"));
24107
+ const schemaPath = path40.join(schemasDir(), basename17);
24108
+ const schemaRaw = stripUtf8Bom5(fs44.readFileSync(schemaPath, "utf-8"));
23648
24109
  const schema = JSON.parse(schemaRaw);
23649
24110
  return ajv.compile(schema);
23650
24111
  }
@@ -23688,7 +24149,7 @@ var ZERO_REF_STAGING_JSON_TOTAL_ATTEMPTS = 5;
23688
24149
  var ZERO_REF_STAGING_FILE_PREVIEW_MAX_CHARS = 6e3;
23689
24150
  function readStagingOutputPreview(outAbs) {
23690
24151
  try {
23691
- const s = fs44.readFileSync(outAbs, "utf-8");
24152
+ const s = fs45.readFileSync(outAbs, "utf-8");
23692
24153
  if (s.length <= ZERO_REF_STAGING_FILE_PREVIEW_MAX_CHARS) {
23693
24154
  return s;
23694
24155
  }
@@ -23938,17 +24399,17 @@ function expandArgvTemplate4(template, vars) {
23938
24399
  });
23939
24400
  }
23940
24401
  function schemaRef2(worktreeRoot, schemaBasename) {
23941
- return path40.join(worktreeRoot, ".opencode", "schemas", "context-lists", schemaBasename);
24402
+ return path41.join(worktreeRoot, ".opencode", "schemas", "context-lists", schemaBasename);
23942
24403
  }
23943
24404
  function stagingDir(contextDirAbs) {
23944
- return path40.join(contextDirAbs, "_zero-ref-staging");
24405
+ return path41.join(contextDirAbs, "_zero-ref-staging");
23945
24406
  }
23946
24407
  function stagingPathForTarget(contextDirAbs, kind, targetFilePathPosix) {
23947
24408
  const h = crypto.createHash("sha256").update(targetFilePathPosix, "utf8").digest("hex").slice(0, 16);
23948
- return path40.join(stagingDir(contextDirAbs), `${kind}-${h}.json`);
24409
+ return path41.join(stagingDir(contextDirAbs), `${kind}-${h}.json`);
23949
24410
  }
23950
24411
  function readNonReferencedFilesFromRepositoryRoot(repositoryRootAbs) {
23951
- const p = path40.join(repositoryRootAbs, ".gluecharm", "context", "coverage-reference-validation.json");
24412
+ const p = path41.join(repositoryRootAbs, ".gluecharm", "context", "coverage-reference-validation.json");
23952
24413
  const r = readAndValidateCoverageReferenceValidationFile(p);
23953
24414
  if (!r.ok) {
23954
24415
  return { ok: false, error: r.errors.join("; ") };
@@ -23971,14 +24432,14 @@ function readNonReferencedFilesFromRepositoryRoot(repositoryRootAbs) {
23971
24432
  return { ok: true, paths, ...generatedAt ? { generatedAt } : {} };
23972
24433
  }
23973
24434
  function readOrInitRoutingDoc(routingAbs, coverageReferenceGeneratedAt) {
23974
- if (!fs44.existsSync(routingAbs)) {
24435
+ if (!fs45.existsSync(routingAbs)) {
23975
24436
  return {
23976
24437
  schemaVersion: ROUTING_SCHEMA_VERSION,
23977
24438
  ...coverageReferenceGeneratedAt ? { coverageReferenceGeneratedAt } : {},
23978
24439
  records: {}
23979
24440
  };
23980
24441
  }
23981
- const raw = fs44.readFileSync(routingAbs, "utf-8");
24442
+ const raw = fs45.readFileSync(routingAbs, "utf-8");
23982
24443
  const data = JSON.parse(raw);
23983
24444
  if (!data.records || typeof data.records !== "object") {
23984
24445
  return {
@@ -23990,10 +24451,10 @@ function readOrInitRoutingDoc(routingAbs, coverageReferenceGeneratedAt) {
23990
24451
  return data;
23991
24452
  }
23992
24453
  function readOrInitTriageDoc(triageAbs) {
23993
- if (!fs44.existsSync(triageAbs)) {
24454
+ if (!fs45.existsSync(triageAbs)) {
23994
24455
  return { schemaVersion: TRIAGE_SCHEMA_VERSION, records: {} };
23995
24456
  }
23996
- const raw = fs44.readFileSync(triageAbs, "utf-8");
24457
+ const raw = fs45.readFileSync(triageAbs, "utf-8");
23997
24458
  const data = JSON.parse(raw);
23998
24459
  if (!data.records || typeof data.records !== "object") {
23999
24460
  return { schemaVersion: TRIAGE_SCHEMA_VERSION, records: {} };
@@ -24041,10 +24502,10 @@ function slugifyFeatureLabel(s) {
24041
24502
  return t.length > 0 ? t : "feature";
24042
24503
  }
24043
24504
  function lineCountRepoFile(worktreeRootAbs, relPosix) {
24044
- const abs = path40.join(worktreeRootAbs, ...relPosix.split("/"));
24505
+ const abs = path41.join(worktreeRootAbs, ...relPosix.split("/"));
24045
24506
  let buf;
24046
24507
  try {
24047
- buf = fs44.readFileSync(abs);
24508
+ buf = fs45.readFileSync(abs);
24048
24509
  } catch {
24049
24510
  return 1;
24050
24511
  }
@@ -24096,9 +24557,9 @@ var LIST_STEP_HINT = {
24096
24557
  };
24097
24558
  async function applyCoordinationListTriageMerge(input) {
24098
24559
  const cfg = LIST_MERGE_CFG[input.listKind];
24099
- const listPath = path40.join(input.contextDirAbs, cfg.listBasename);
24100
- const schemaPath = path40.join(resolveContextListSchemasDir(), cfg.schemaBasename);
24101
- if (!fs44.existsSync(listPath)) {
24560
+ const listPath = path41.join(input.contextDirAbs, cfg.listBasename);
24561
+ const schemaPath = path41.join(resolveContextListSchemasDir(), cfg.schemaBasename);
24562
+ if (!fs45.existsSync(listPath)) {
24102
24563
  return {
24103
24564
  ok: false,
24104
24565
  message: `${cfg.listBasename} not found \u2014 run coordination step ${LIST_STEP_HINT[input.listKind]} first.`
@@ -24109,7 +24570,7 @@ async function applyCoordinationListTriageMerge(input) {
24109
24570
  return withCoordinationListFileLock(listPath, {}, async () => {
24110
24571
  let raw;
24111
24572
  try {
24112
- raw = fs44.readFileSync(listPath, "utf-8");
24573
+ raw = fs45.readFileSync(listPath, "utf-8");
24113
24574
  } catch (e) {
24114
24575
  return { ok: false, message: e instanceof Error ? e.message : String(e) };
24115
24576
  }
@@ -24177,7 +24638,7 @@ async function applyCoordinationListTriageMerge(input) {
24177
24638
  });
24178
24639
  const tmp = `${listPath}.tmp.${process.pid}`;
24179
24640
  try {
24180
- fs44.writeFileSync(tmp, `${JSON.stringify(doc, null, 2)}
24641
+ fs45.writeFileSync(tmp, `${JSON.stringify(doc, null, 2)}
24181
24642
  `, "utf-8");
24182
24643
  } catch (e) {
24183
24644
  return { ok: false, message: e instanceof Error ? e.message : String(e) };
@@ -24185,13 +24646,13 @@ async function applyCoordinationListTriageMerge(input) {
24185
24646
  const v = validateCoordinationListJson(tmp, schemaPath);
24186
24647
  if (!v.ok) {
24187
24648
  try {
24188
- fs44.unlinkSync(tmp);
24649
+ fs45.unlinkSync(tmp);
24189
24650
  } catch {
24190
24651
  }
24191
24652
  return { ok: false, message: `${cfg.listBasename} validation failed: ${JSON.stringify(v.failure)}` };
24192
24653
  }
24193
24654
  try {
24194
- fs44.renameSync(tmp, listPath);
24655
+ fs45.renameSync(tmp, listPath);
24195
24656
  } catch (e) {
24196
24657
  return { ok: false, message: e instanceof Error ? e.message : String(e) };
24197
24658
  }
@@ -24201,10 +24662,10 @@ async function applyCoordinationListTriageMerge(input) {
24201
24662
  }
24202
24663
  async function runClassifierAgent(common, contextDirAbs, targetFilePathPosix, workspaceLabel) {
24203
24664
  const outAbs = stagingPathForTarget(contextDirAbs, "classifier", targetFilePathPosix);
24204
- fs44.mkdirSync(path40.dirname(outAbs), { recursive: true });
24205
- const runDir = path40.join(common.worktreeRoot, ".opencode", "_run");
24206
- fs44.mkdirSync(runDir, { recursive: true });
24207
- const outputBasename = path40.basename(outAbs);
24665
+ fs45.mkdirSync(path41.dirname(outAbs), { recursive: true });
24666
+ const runDir = path41.join(common.worktreeRoot, ".opencode", "_run");
24667
+ fs45.mkdirSync(runDir, { recursive: true });
24668
+ const outputBasename = path41.basename(outAbs);
24208
24669
  const listTaskDescription = [
24209
24670
  `Target file (repo-relative, POSIX): **${targetFilePathPosix}**`,
24210
24671
  `Workspace label hint: **${workspaceLabel}**.`,
@@ -24240,8 +24701,8 @@ async function runClassifierAgent(common, contextDirAbs, targetFilePathPosix, wo
24240
24701
  parentContextBlock: "",
24241
24702
  ...repairAppendix ? { repairAppendix } : {}
24242
24703
  });
24243
- const promptPath = path40.join(runDir, `zero-ref-classify-a${attempt}-${Date.now()}.prompt.txt`);
24244
- fs44.writeFileSync(promptPath, body, "utf-8");
24704
+ const promptPath = path41.join(runDir, `zero-ref-classify-a${attempt}-${Date.now()}.prompt.txt`);
24705
+ fs45.writeFileSync(promptPath, body, "utf-8");
24245
24706
  const argv = expandArgvTemplate4(common.argvTemplate, {
24246
24707
  promptFile: promptPath,
24247
24708
  agentId: ZERO_REF_CLASSIFY_AGENT_STEM,
@@ -24268,7 +24729,7 @@ async function runClassifierAgent(common, contextDirAbs, targetFilePathPosix, wo
24268
24729
  const canRetry = attempt < ZERO_REF_STAGING_JSON_TOTAL_ATTEMPTS - 1;
24269
24730
  let st;
24270
24731
  try {
24271
- st = fs44.statSync(outAbs);
24732
+ st = fs45.statSync(outAbs);
24272
24733
  } catch {
24273
24734
  st = void 0;
24274
24735
  }
@@ -24290,7 +24751,7 @@ async function runClassifierAgent(common, contextDirAbs, targetFilePathPosix, wo
24290
24751
  }
24291
24752
  let parsed;
24292
24753
  try {
24293
- parsed = JSON.parse(fs44.readFileSync(outAbs, "utf-8"));
24754
+ parsed = JSON.parse(fs45.readFileSync(outAbs, "utf-8"));
24294
24755
  } catch (e) {
24295
24756
  const msg = e instanceof Error ? e.message : String(e);
24296
24757
  lastFailureMessage = `Classifier output not valid JSON: ${msg}`;
@@ -24372,10 +24833,10 @@ var TRIAGE_SCOPE_META = {
24372
24833
  };
24373
24834
  async function runMarkdownReferenceAgent(common, contextDirAbs, targetFilePathPosix, routingSummary, which) {
24374
24835
  const mdBasename = which === "project" ? "project.md" : "architecture.md";
24375
- const mdAbs = path40.join(contextDirAbs, mdBasename);
24836
+ const mdAbs = path41.join(contextDirAbs, mdBasename);
24376
24837
  const agentStem = which === "project" ? ZERO_REF_ADD_REF_PROJECT_AGENT_STEM : ZERO_REF_ADD_REF_ARCH_AGENT_STEM;
24377
- const runDir = path40.join(common.worktreeRoot, ".opencode", "_run");
24378
- fs44.mkdirSync(runDir, { recursive: true });
24838
+ const runDir = path41.join(common.worktreeRoot, ".opencode", "_run");
24839
+ fs45.mkdirSync(runDir, { recursive: true });
24379
24840
  const lines = [
24380
24841
  `# SRS-30 \u2014 Add reference to ${mdBasename}`,
24381
24842
  ``,
@@ -24390,8 +24851,8 @@ async function runMarkdownReferenceAgent(common, contextDirAbs, targetFilePathPo
24390
24851
  `- If the file is short, \`${targetFilePathPosix}:1-<lastLine>\` is acceptable.`,
24391
24852
  `- Do not remove unrelated content; append or extend the most appropriate section.`
24392
24853
  ];
24393
- const promptPath = path40.join(runDir, `zero-ref-md-${which}-${Date.now()}.prompt.txt`);
24394
- fs44.writeFileSync(promptPath, lines.join("\n"), "utf-8");
24854
+ const promptPath = path41.join(runDir, `zero-ref-md-${which}-${Date.now()}.prompt.txt`);
24855
+ fs45.writeFileSync(promptPath, lines.join("\n"), "utf-8");
24395
24856
  const argv = expandArgvTemplate4(common.argvTemplate, {
24396
24857
  promptFile: promptPath,
24397
24858
  agentId: agentStem,
@@ -24418,10 +24879,10 @@ async function runMarkdownReferenceAgent(common, contextDirAbs, targetFilePathPo
24418
24879
  async function runCoordinationTriageAgent(common, contextDirAbs, targetFilePathPosix, routingSummary, workspaceLabel, triageScope) {
24419
24880
  const meta = TRIAGE_SCOPE_META[triageScope];
24420
24881
  const outAbs = stagingPathForTarget(contextDirAbs, "triage", targetFilePathPosix);
24421
- fs44.mkdirSync(path40.dirname(outAbs), { recursive: true });
24422
- const runDir = path40.join(common.worktreeRoot, ".opencode", "_run");
24423
- fs44.mkdirSync(runDir, { recursive: true });
24424
- const outputBasename = path40.basename(outAbs);
24882
+ fs45.mkdirSync(path41.dirname(outAbs), { recursive: true });
24883
+ const runDir = path41.join(common.worktreeRoot, ".opencode", "_run");
24884
+ fs45.mkdirSync(runDir, { recursive: true });
24885
+ const outputBasename = path41.basename(outAbs);
24425
24886
  const listTaskDescription = [
24426
24887
  `Target file: **${targetFilePathPosix}** (${workspaceLabel})`,
24427
24888
  "**Classifier summary:**",
@@ -24451,8 +24912,8 @@ async function runCoordinationTriageAgent(common, contextDirAbs, targetFilePathP
24451
24912
  parentContextBlock: "",
24452
24913
  ...repairAppendix ? { repairAppendix } : {}
24453
24914
  });
24454
- const promptPath = path40.join(runDir, `zero-ref-triage-a${attempt}-${Date.now()}.prompt.txt`);
24455
- fs44.writeFileSync(promptPath, body, "utf-8");
24915
+ const promptPath = path41.join(runDir, `zero-ref-triage-a${attempt}-${Date.now()}.prompt.txt`);
24916
+ fs45.writeFileSync(promptPath, body, "utf-8");
24456
24917
  const argv = expandArgvTemplate4(common.argvTemplate, {
24457
24918
  promptFile: promptPath,
24458
24919
  agentId: ZERO_REF_TRIAGE_COORD_AGENT_STEM,
@@ -24479,7 +24940,7 @@ async function runCoordinationTriageAgent(common, contextDirAbs, targetFilePathP
24479
24940
  const canRetry = attempt < ZERO_REF_STAGING_JSON_TOTAL_ATTEMPTS - 1;
24480
24941
  let st;
24481
24942
  try {
24482
- st = fs44.statSync(outAbs);
24943
+ st = fs45.statSync(outAbs);
24483
24944
  } catch {
24484
24945
  st = void 0;
24485
24946
  }
@@ -24501,7 +24962,7 @@ async function runCoordinationTriageAgent(common, contextDirAbs, targetFilePathP
24501
24962
  }
24502
24963
  let parsed;
24503
24964
  try {
24504
- parsed = JSON.parse(fs44.readFileSync(outAbs, "utf-8"));
24965
+ parsed = JSON.parse(fs45.readFileSync(outAbs, "utf-8"));
24505
24966
  } catch (e) {
24506
24967
  const msg = e instanceof Error ? e.message : String(e);
24507
24968
  lastFailureMessage = `Triage output not valid JSON: ${msg}`;
@@ -24557,7 +25018,7 @@ async function runCoordinationTriageAgent(common, contextDirAbs, targetFilePathP
24557
25018
  return { ok: false, message: lastFailureMessage, stagingPath: outAbs };
24558
25019
  }
24559
25020
  try {
24560
- fs44.writeFileSync(outAbs, `${JSON.stringify(parsed, null, 2)}
25021
+ fs45.writeFileSync(outAbs, `${JSON.stringify(parsed, null, 2)}
24561
25022
  `, "utf-8");
24562
25023
  } catch {
24563
25024
  }
@@ -24566,8 +25027,8 @@ async function runCoordinationTriageAgent(common, contextDirAbs, targetFilePathP
24566
25027
  return { ok: false, message: lastFailureMessage, stagingPath: outAbs };
24567
25028
  }
24568
25029
  async function runOneUnreferencedFilePipeline(p) {
24569
- const routingAbs = path40.join(p.contextDirAbs, ZERO_REF_ROUTING_BASENAME);
24570
- const triageAbs = path40.join(p.contextDirAbs, ZERO_REF_TRIAGE_BASENAME);
25030
+ const routingAbs = path41.join(p.contextDirAbs, ZERO_REF_ROUTING_BASENAME);
25031
+ const triageAbs = path41.join(p.contextDirAbs, ZERO_REF_TRIAGE_BASENAME);
24571
25032
  const key = p.targetFilePathPosix;
24572
25033
  const cr = await runClassifierAgent(p, p.contextDirAbs, key, p.workspaceLabel);
24573
25034
  if (!cr.ok) {
@@ -24575,7 +25036,7 @@ async function runOneUnreferencedFilePipeline(p) {
24575
25036
  }
24576
25037
  let stagingParsed;
24577
25038
  try {
24578
- stagingParsed = JSON.parse(fs44.readFileSync(cr.stagingPath, "utf-8"));
25039
+ stagingParsed = JSON.parse(fs45.readFileSync(cr.stagingPath, "utf-8"));
24579
25040
  } catch (e) {
24580
25041
  return { ok: false, message: String(e) };
24581
25042
  }
@@ -24591,8 +25052,8 @@ async function runOneUnreferencedFilePipeline(p) {
24591
25052
  if (!s.ok) {
24592
25053
  throw new Error(s.errors.join("; "));
24593
25054
  }
24594
- fs44.mkdirSync(path40.dirname(routingAbs), { recursive: true });
24595
- fs44.writeFileSync(routingAbs, s.json, "utf-8");
25055
+ fs45.mkdirSync(path41.dirname(routingAbs), { recursive: true });
25056
+ fs45.writeFileSync(routingAbs, s.json, "utf-8");
24596
25057
  });
24597
25058
  const routing = stagingParsed.routing;
24598
25059
  const routingSummary = typeof stagingParsed.projectRelationSummary === "string" ? stagingParsed.projectRelationSummary : "";
@@ -24623,7 +25084,7 @@ async function runOneUnreferencedFilePipeline(p) {
24623
25084
  }
24624
25085
  let triageParsed;
24625
25086
  try {
24626
- triageParsed = JSON.parse(fs44.readFileSync(tr.stagingPath, "utf-8"));
25087
+ triageParsed = JSON.parse(fs45.readFileSync(tr.stagingPath, "utf-8"));
24627
25088
  } catch (e) {
24628
25089
  return { ok: false, message: String(e) };
24629
25090
  }
@@ -24640,8 +25101,8 @@ async function runOneUnreferencedFilePipeline(p) {
24640
25101
  if (!s.ok) {
24641
25102
  throw new Error(s.errors.join("; "));
24642
25103
  }
24643
- fs44.mkdirSync(path40.dirname(triageAbs), { recursive: true });
24644
- fs44.writeFileSync(triageAbs, s.json, "utf-8");
25104
+ fs45.mkdirSync(path41.dirname(triageAbs), { recursive: true });
25105
+ fs45.writeFileSync(triageAbs, s.json, "utf-8");
24645
25106
  });
24646
25107
  const decision = triageParsed.decision;
24647
25108
  if (decision === "new_item" || decision === "enrich_existing") {
@@ -24668,11 +25129,11 @@ async function runOneUnreferencedFilePipeline(p) {
24668
25129
  return { ok: true, message: `Triage ${decision}.` };
24669
25130
  }
24670
25131
  async function runRemediationPipelineZeroRefPass(p) {
24671
- const contextDirAbs = path40.join(p.worktreeRoot, ".gluecharm", "context");
25132
+ const contextDirAbs = path41.join(p.worktreeRoot, ".gluecharm", "context");
24672
25133
  const covRoot = p.coverageRepositoryRootAbs ?? p.workspaceRootAbs;
24673
25134
  const cov = readNonReferencedFilesFromRepositoryRoot(covRoot);
24674
25135
  const coverageAt = cov.ok ? cov.generatedAt : void 0;
24675
- const workspaceLabel = path40.basename(p.worktreeRoot);
25136
+ const workspaceLabel = path41.basename(p.worktreeRoot);
24676
25137
  const routingMutex = new AsyncMutex();
24677
25138
  const triageMutex = new AsyncMutex();
24678
25139
  const paths = [...p.paths];
@@ -24729,8 +25190,8 @@ async function runRemediationPipelineZeroRefPass(p) {
24729
25190
  }
24730
25191
 
24731
25192
  // src/pipelines/coverage/coverageExecutionReport.ts
24732
- var fs45 = __toESM(require("fs"));
24733
- var path41 = __toESM(require("path"));
25193
+ var fs46 = __toESM(require("fs"));
25194
+ var path42 = __toESM(require("path"));
24734
25195
  var REFERENCE_COVERAGE_EXECUTION_REPORT_BASENAME = "reference-coverage-execution-report.md";
24735
25196
  function inlineMdText(s) {
24736
25197
  const t = s.replace(/\r\n/g, "\n").replace(/\n/g, " ").trim();
@@ -24826,7 +25287,7 @@ function collectNoActionRowsFromRoutingDoc(doc) {
24826
25287
  return rows;
24827
25288
  }
24828
25289
  function readRoutingDocFromDisk(routingAbs) {
24829
- if (!fs45.existsSync(routingAbs)) {
25290
+ if (!fs46.existsSync(routingAbs)) {
24830
25291
  return {
24831
25292
  ok: true,
24832
25293
  doc: { schemaVersion: "1", records: {} }
@@ -24834,7 +25295,7 @@ function readRoutingDocFromDisk(routingAbs) {
24834
25295
  }
24835
25296
  let raw;
24836
25297
  try {
24837
- raw = fs45.readFileSync(routingAbs, "utf-8");
25298
+ raw = fs46.readFileSync(routingAbs, "utf-8");
24838
25299
  } catch (e) {
24839
25300
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
24840
25301
  }
@@ -24854,10 +25315,10 @@ async function runCoverageExecutionReport(p) {
24854
25315
  if (p.abortSignal?.aborted) {
24855
25316
  return { ok: false, error: "Stopped.", cancelled: true };
24856
25317
  }
24857
- const contextDirAbs = path41.join(p.repositoryRootAbs, ".gluecharm", "context");
24858
- const coverageAbs = path41.join(contextDirAbs, "coverage-reference-validation.json");
24859
- const routingAbs = path41.join(contextDirAbs, "zero-reference-routing.json");
24860
- const outAbs = path41.join(contextDirAbs, REFERENCE_COVERAGE_EXECUTION_REPORT_BASENAME);
25318
+ const contextDirAbs = path42.join(p.repositoryRootAbs, ".gluecharm", "context");
25319
+ const coverageAbs = path42.join(contextDirAbs, "coverage-reference-validation.json");
25320
+ const routingAbs = path42.join(contextDirAbs, "zero-reference-routing.json");
25321
+ const outAbs = path42.join(contextDirAbs, REFERENCE_COVERAGE_EXECUTION_REPORT_BASENAME);
24861
25322
  const cov = readAndValidateCoverageReferenceValidationFile(coverageAbs);
24862
25323
  if (!cov.ok) {
24863
25324
  return { ok: false, error: `Coverage JSON: ${cov.errors.join("; ")}` };
@@ -24874,20 +25335,20 @@ async function runCoverageExecutionReport(p) {
24874
25335
  }
24875
25336
  let previous;
24876
25337
  try {
24877
- if (fs45.existsSync(outAbs)) {
24878
- previous = fs45.readFileSync(outAbs, "utf-8");
25338
+ if (fs46.existsSync(outAbs)) {
25339
+ previous = fs46.readFileSync(outAbs, "utf-8");
24879
25340
  }
24880
25341
  } catch {
24881
25342
  previous = void 0;
24882
25343
  }
24883
25344
  try {
24884
- fs45.mkdirSync(path41.dirname(outAbs), { recursive: true });
24885
- fs45.writeFileSync(outAbs, md, "utf-8");
25345
+ fs46.mkdirSync(path42.dirname(outAbs), { recursive: true });
25346
+ fs46.writeFileSync(outAbs, md, "utf-8");
24886
25347
  } catch (e) {
24887
25348
  const msg = e instanceof Error ? e.message : String(e);
24888
25349
  if (previous !== void 0) {
24889
25350
  try {
24890
- fs45.writeFileSync(outAbs, previous, "utf-8");
25351
+ fs46.writeFileSync(outAbs, previous, "utf-8");
24891
25352
  } catch {
24892
25353
  }
24893
25354
  }
@@ -24898,8 +25359,8 @@ async function runCoverageExecutionReport(p) {
24898
25359
  }
24899
25360
 
24900
25361
  // src/gluecharm/minimalGluecharmLayout.ts
24901
- var fs46 = __toESM(require("node:fs"));
24902
- var path42 = __toESM(require("node:path"));
25362
+ var fs47 = __toESM(require("node:fs"));
25363
+ var path43 = __toESM(require("node:path"));
24903
25364
  var MINIMAL_GLUECHARM_RELATIVE_DIRS = [
24904
25365
  [".gluecharm", "docs", "srs"],
24905
25366
  [".gluecharm", "content"],
@@ -24907,11 +25368,11 @@ var MINIMAL_GLUECHARM_RELATIVE_DIRS = [
24907
25368
  [".gluecharm", "context"]
24908
25369
  ];
24909
25370
  function ensureMinimalGluecharmLayoutNode(repoRootAbs) {
24910
- const root = path42.resolve(repoRootAbs);
25371
+ const root = path43.resolve(repoRootAbs);
24911
25372
  for (const segments of MINIMAL_GLUECHARM_RELATIVE_DIRS) {
24912
- const dir = path42.join(root, ...segments);
25373
+ const dir = path43.join(root, ...segments);
24913
25374
  try {
24914
- fs46.mkdirSync(dir, { recursive: true });
25375
+ fs47.mkdirSync(dir, { recursive: true });
24915
25376
  } catch (e) {
24916
25377
  const err = e;
24917
25378
  const msg = e instanceof Error ? e.message : String(e);
@@ -25026,6 +25487,7 @@ function buildFactoryPipelineRegistry(cb) {
25026
25487
  // src/factory/generateContextFactoryHeadlessHost.ts
25027
25488
  function buildFactoryDepsHeadless(input) {
25028
25489
  const { storageContext, repoRoot, agentsDirFs, buildOpenCodeOptions, log, signal, macroConfig } = input;
25490
+ const inPlace = input.inPlace === true;
25029
25491
  let adHocWorktree;
25030
25492
  let macroFinalize;
25031
25493
  let macroSourceBranch;
@@ -25040,7 +25502,7 @@ function buildFactoryDepsHeadless(input) {
25040
25502
  if (!layout.ok) {
25041
25503
  return { ok: false, error: layout.error };
25042
25504
  }
25043
- const ctxDir = path43.join(ar, ".gluecharm", "context");
25505
+ const ctxDir = path44.join(ar, ".gluecharm", "context");
25044
25506
  const snap = readArtefactRunSnapshot(storageContext);
25045
25507
  const rows = listMissingWorkstations(ctxDir, ar, snap);
25046
25508
  if (rows.length === 0) {
@@ -25054,7 +25516,7 @@ function buildFactoryDepsHeadless(input) {
25054
25516
  storageContext,
25055
25517
  repositoryRoot: repoRoot,
25056
25518
  worktreeRoot: ar,
25057
- workspaceLabel: path43.basename(ar),
25519
+ workspaceLabel: path44.basename(ar),
25058
25520
  oc: {
25059
25521
  ...oc,
25060
25522
  aceEnabled: getAceAnalysisEnabledForCheckout(ar),
@@ -25082,7 +25544,7 @@ function buildFactoryDepsHeadless(input) {
25082
25544
  }
25083
25545
  try {
25084
25546
  await startPipelineRun(storageContext, repoRoot);
25085
- const folderName = path43.basename(repoRoot);
25547
+ const folderName = path44.basename(repoRoot);
25086
25548
  const oc = buildOpenCodeOptions(handle.path);
25087
25549
  const result = await runSynthesisPipelineDrainFromPreparedWorktree(
25088
25550
  storageContext,
@@ -25139,7 +25601,7 @@ function buildFactoryDepsHeadless(input) {
25139
25601
  if (!ar) {
25140
25602
  return 0;
25141
25603
  }
25142
- const ctxDir = path43.join(ar, ".gluecharm", "context");
25604
+ const ctxDir = path44.join(ar, ".gluecharm", "context");
25143
25605
  const snap = readArtefactRunSnapshot(storageContext);
25144
25606
  return listMissingWorkstations(ctxDir, ar, snap).length;
25145
25607
  };
@@ -25152,7 +25614,7 @@ function buildFactoryDepsHeadless(input) {
25152
25614
  if (!layout.ok) {
25153
25615
  return { ok: false, message: layout.error };
25154
25616
  }
25155
- const contextDir2 = path43.join(ar, ".gluecharm", "context");
25617
+ const contextDir2 = path44.join(ar, ".gluecharm", "context");
25156
25618
  log(`[factory] reference coverage (worktree) \u2014 ${ar}`);
25157
25619
  const res = runCoveragePipeline({
25158
25620
  repositoryRootAbs: ar,
@@ -25212,7 +25674,7 @@ function buildFactoryDepsHeadless(input) {
25212
25674
  diagnosticLog: log
25213
25675
  });
25214
25676
  if (res.ok) {
25215
- return { ok: true, message: `Report: ${path43.basename(res.outputAbsolutePath)}` };
25677
+ return { ok: true, message: `Report: ${path44.basename(res.outputAbsolutePath)}` };
25216
25678
  }
25217
25679
  if (res.cancelled) {
25218
25680
  return { ok: false, cancelled: true, message: "Report generation stopped." };
@@ -25228,7 +25690,7 @@ function buildFactoryDepsHeadless(input) {
25228
25690
  if (!lmLayout.ok) {
25229
25691
  return { ok: false, message: lmLayout.error };
25230
25692
  }
25231
- const contextDir2 = path43.join(snap.adHocWorktreePath, ".gluecharm", "context");
25693
+ const contextDir2 = path44.join(snap.adHocWorktreePath, ".gluecharm", "context");
25232
25694
  const linkGraph = runLinkMappingPipeline(contextDir2, { log });
25233
25695
  if (!linkGraph.ok) {
25234
25696
  return { ok: false, message: linkGraph.error };
@@ -25244,7 +25706,7 @@ function buildFactoryDepsHeadless(input) {
25244
25706
  if (!idxLayout.ok) {
25245
25707
  return { ok: false, message: idxLayout.error };
25246
25708
  }
25247
- const contextDir2 = path43.join(snap.adHocWorktreePath, ".gluecharm", "context");
25709
+ const contextDir2 = path44.join(snap.adHocWorktreePath, ".gluecharm", "context");
25248
25710
  try {
25249
25711
  writeIndexApplicationContext(contextDir2, void 0, {
25250
25712
  sourceBranchAtWorktreeCreation: snap.adHocSourceBranchAtCreation
@@ -25284,6 +25746,12 @@ function buildFactoryDepsHeadless(input) {
25284
25746
  return {
25285
25747
  signal,
25286
25748
  factoryLog: log,
25749
+ readinessLog: (line) => {
25750
+ process.stderr.write(`${line}
25751
+ `);
25752
+ },
25753
+ ...inPlace ? { analysisInPlace: true } : {},
25754
+ readiness: input.readiness,
25287
25755
  config: { ...macroConfig, ...input.synthesisOnly ? { synthesisOnly: true } : {} },
25288
25756
  sleep: (ms) => sleepUntilAborted(ms, signal),
25289
25757
  post: (payload) => {
@@ -25293,14 +25761,14 @@ function buildFactoryDepsHeadless(input) {
25293
25761
  },
25294
25762
  runPrepareAnalysisWorktree: async (resume) => {
25295
25763
  if (resume) {
25296
- if (adHocWorktree && fs47.existsSync(path43.join(adHocWorktree.path, ".git"))) {
25764
+ if (adHocWorktree && fs48.existsSync(path44.join(adHocWorktree.path, ".git"))) {
25297
25765
  return { ok: true };
25298
25766
  }
25299
25767
  const snap = readAnalysisWorkspaceSnapshot(storageContext);
25300
25768
  const wtPath = snap?.adHocWorktreePath?.trim();
25301
25769
  const repo = snap?.adHocRepositoryRoot?.trim() || repoRoot;
25302
- if (wtPath && fs47.existsSync(path43.join(wtPath, ".git"))) {
25303
- adHocWorktree = attachWorktreeHandle(wtPath, repo);
25770
+ if (wtPath && fs48.existsSync(path44.join(wtPath, ".git"))) {
25771
+ adHocWorktree = resolveAnalysisCheckoutHandle(wtPath, repo);
25304
25772
  macroSourceBranch = snap?.adHocSourceBranchAtCreation;
25305
25773
  macroFinalize = () => {
25306
25774
  try {
@@ -25322,8 +25790,10 @@ function buildFactoryDepsHeadless(input) {
25322
25790
  }
25323
25791
  macroFinalize = void 0;
25324
25792
  macroSourceBranch = void 0;
25325
- log(`[factory] create analysis worktree \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}`);
25326
- const prep = await prepareSynthesisWorktree(storageContext, repoRoot, log);
25793
+ log(
25794
+ inPlace ? `[factory] in-place analysis checkout \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}` : `[factory] create analysis worktree \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}`
25795
+ );
25796
+ const prep = await prepareSynthesisWorktree(storageContext, repoRoot, log, { inPlace });
25327
25797
  if (!prep.ok) {
25328
25798
  prep.finalize?.();
25329
25799
  return { ok: false, error: prep.error };
@@ -25373,9 +25843,6 @@ function buildFactoryDepsHeadless(input) {
25373
25843
 
25374
25844
  // src/cli/failureExitRegistry.ts
25375
25845
  var DRIFT_FACTORY = "context_drift";
25376
- function failureExitIdFromParts(exitCode, minor) {
25377
- return `${String(exitCode)}.${String(minor)}`;
25378
- }
25379
25846
  var DRIFT_META = {
25380
25847
  INVALID_REFERENCE_PATH: {
25381
25848
  phase: "resolve_reference_bundle",
@@ -25391,20 +25858,20 @@ var DRIFT_META = {
25391
25858
  },
25392
25859
  EMPTY_BUNDLE: {
25393
25860
  phase: "resolve_reference_bundle",
25394
- exitCode: ExitCode.validation,
25395
- minor: 10,
25861
+ exitCode: OsExit.driftEmptyBundle,
25862
+ minor: 0,
25396
25863
  title: "Reference bundle was empty or could not be read for drift analysis."
25397
25864
  },
25398
25865
  UNRESOLVED_REFERENCE_ROOT: {
25399
25866
  phase: "resolve_reference_root",
25400
- exitCode: ExitCode.validation,
25401
- minor: 11,
25867
+ exitCode: OsExit.driftUnresolvedReferenceRoot,
25868
+ minor: 0,
25402
25869
  title: "Reference root document could not be resolved. Use --index or ensure an index markdown exists."
25403
25870
  },
25404
25871
  MANIFEST_FAILED: {
25405
25872
  phase: "build_comparison_manifest",
25406
- exitCode: ExitCode.validation,
25407
- minor: 12,
25873
+ exitCode: OsExit.driftManifestFailed,
25874
+ minor: 0,
25408
25875
  title: "Comparison manifest could not be built for drift analysis."
25409
25876
  },
25410
25877
  AGENT_FAILED: {
@@ -25421,14 +25888,14 @@ var DRIFT_META = {
25421
25888
  },
25422
25889
  REPORT_WRITE_FAILED: {
25423
25890
  phase: "validate_and_render_report",
25424
- exitCode: ExitCode.validation,
25425
- minor: 13,
25891
+ exitCode: OsExit.driftReportWriteFailed,
25892
+ minor: 0,
25426
25893
  title: "Drift report markdown could not be written under the analysis worktree."
25427
25894
  },
25428
25895
  INDEX_PATCH_FAILED: {
25429
25896
  phase: "update_reference_index",
25430
- exitCode: ExitCode.validation,
25431
- minor: 14,
25897
+ exitCode: OsExit.driftIndexPatchFailed,
25898
+ minor: 0,
25432
25899
  title: "Reference root markdown could not be updated with the drift report link."
25433
25900
  },
25434
25901
  PROMOTE_FAILED: {
@@ -25484,10 +25951,7 @@ function contextDriftFactoryFailureRow(code, error) {
25484
25951
  title: meta.title,
25485
25952
  detail
25486
25953
  };
25487
- if (meta.exitCode === ExitCode.validation) {
25488
- return { ...base, validationExitId: failureExitId };
25489
- }
25490
- return base;
25954
+ return { ...base, validationExitId: failureExitId };
25491
25955
  }
25492
25956
 
25493
25957
  // src/cli/factoryValidationStderr.ts
@@ -25521,11 +25985,11 @@ function stderrLinesForFactoryFailures(failures, exitCode) {
25521
25985
  }
25522
25986
 
25523
25987
  // src/factory/updateContext/runUpdateContextFactory.ts
25524
- var path48 = __toESM(require("node:path"));
25988
+ var path49 = __toESM(require("node:path"));
25525
25989
 
25526
25990
  // src/factory/updateContext/updateContextBaseline.ts
25527
- var fs48 = __toESM(require("node:fs"));
25528
- var path44 = __toESM(require("node:path"));
25991
+ var fs49 = __toESM(require("node:fs"));
25992
+ var path45 = __toESM(require("node:path"));
25529
25993
  function isValidIso(s) {
25530
25994
  const t = Date.parse(s);
25531
25995
  return Number.isFinite(t);
@@ -25535,17 +25999,17 @@ function maxMtimeRegularFilesUnderDir(dirAbs) {
25535
25999
  const walk = (d) => {
25536
26000
  let entries;
25537
26001
  try {
25538
- entries = fs48.readdirSync(d, { withFileTypes: true });
26002
+ entries = fs49.readdirSync(d, { withFileTypes: true });
25539
26003
  } catch {
25540
26004
  return;
25541
26005
  }
25542
26006
  for (const e of entries) {
25543
- const p = path44.join(d, e.name);
26007
+ const p = path45.join(d, e.name);
25544
26008
  if (e.isDirectory()) {
25545
26009
  walk(p);
25546
26010
  } else if (e.isFile()) {
25547
26011
  try {
25548
- const st = fs48.statSync(p);
26012
+ const st = fs49.statSync(p);
25549
26013
  const m = st.mtimeMs;
25550
26014
  if (best === null || m > best) {
25551
26015
  best = m;
@@ -25566,8 +26030,8 @@ function resolveUpdateContextBaseline(repoRootAbs, repoConfig) {
25566
26030
  if (last.length > 0 && isValidIso(last)) {
25567
26031
  return { baselineIsoUtc: new Date(last).toISOString(), source: "lastRunAt" };
25568
26032
  }
25569
- const ctxDir = path44.join(repoRootAbs, ".gluecharm", "context");
25570
- if (!fs48.existsSync(ctxDir)) {
26033
+ const ctxDir = path45.join(repoRootAbs, ".gluecharm", "context");
26034
+ if (!fs49.existsSync(ctxDir)) {
25571
26035
  return null;
25572
26036
  }
25573
26037
  const maxMs = maxMtimeRegularFilesUnderDir(ctxDir);
@@ -25590,8 +26054,8 @@ function persistUpdateContextLastRunAt(repoRootAbs, isoUtc) {
25590
26054
 
25591
26055
  // src/factory/updateContext/updateContextGitWindow.ts
25592
26056
  var import_node_child_process3 = require("node:child_process");
25593
- var fs49 = __toESM(require("node:fs"));
25594
- var path45 = __toESM(require("node:path"));
26057
+ var fs50 = __toESM(require("node:fs"));
26058
+ var path46 = __toESM(require("node:path"));
25595
26059
  var GIT_ENV = { ...process.env, GIT_TERMINAL_PROMPT: "0" };
25596
26060
  function gitLines(repoRootAbs, args) {
25597
26061
  const r = (0, import_node_child_process3.execFileSync)("git", ["-c", "core.quotepath=false", ...args], {
@@ -25615,8 +26079,8 @@ function parseGitLogIso(line) {
25615
26079
  return { hash, iso };
25616
26080
  }
25617
26081
  function discoverCommitWindowAndTouchedPaths(repoRootAbs, baselineIsoUtc) {
25618
- const root = path45.resolve(repoRootAbs);
25619
- if (!fs49.existsSync(path45.join(root, ".git"))) {
26082
+ const root = path46.resolve(repoRootAbs);
26083
+ if (!fs50.existsSync(path46.join(root, ".git"))) {
25620
26084
  return { ok: false, error: "Not a git repository (missing .git)." };
25621
26085
  }
25622
26086
  const baselineMs = Date.parse(baselineIsoUtc);
@@ -25675,13 +26139,13 @@ function discoverCommitWindowAndTouchedPaths(repoRootAbs, baselineIsoUtc) {
25675
26139
  };
25676
26140
  }
25677
26141
  function filterPathsExistingInWorktree(worktreeRootAbs, pathsPosix) {
25678
- const root = path45.resolve(worktreeRootAbs);
26142
+ const root = path46.resolve(worktreeRootAbs);
25679
26143
  const out = [];
25680
26144
  for (const p of pathsPosix) {
25681
26145
  const rel = p.replace(/\\/g, "/");
25682
- const abs = path45.join(root, ...rel.split("/"));
26146
+ const abs = path46.join(root, ...rel.split("/"));
25683
26147
  try {
25684
- if (fs49.existsSync(abs) && fs49.statSync(abs).isFile()) {
26148
+ if (fs50.existsSync(abs) && fs50.statSync(abs).isFile()) {
25685
26149
  out.push(rel);
25686
26150
  }
25687
26151
  } catch {
@@ -25691,8 +26155,8 @@ function filterPathsExistingInWorktree(worktreeRootAbs, pathsPosix) {
25691
26155
  }
25692
26156
 
25693
26157
  // src/factory/updateContext/updateContextReport.ts
25694
- var fs50 = __toESM(require("node:fs"));
25695
- var path46 = __toESM(require("node:path"));
26158
+ var fs51 = __toESM(require("node:fs"));
26159
+ var path47 = __toESM(require("node:path"));
25696
26160
  var CHANGES_SINCE_DATE_BASENAME = "changes-since-date.md";
25697
26161
  function renderChangesSinceDateMarkdown(p) {
25698
26162
  const lines = [
@@ -25733,9 +26197,9 @@ function renderChangesSinceDateMarkdown(p) {
25733
26197
  }
25734
26198
  function writeChangesSinceDateReport(contextDirAbs, body) {
25735
26199
  try {
25736
- fs50.mkdirSync(contextDirAbs, { recursive: true });
25737
- const target = path46.join(contextDirAbs, CHANGES_SINCE_DATE_BASENAME);
25738
- fs50.writeFileSync(target, body, "utf-8");
26200
+ fs51.mkdirSync(contextDirAbs, { recursive: true });
26201
+ const target = path47.join(contextDirAbs, CHANGES_SINCE_DATE_BASENAME);
26202
+ fs51.writeFileSync(target, body, "utf-8");
25739
26203
  return { ok: true };
25740
26204
  } catch (e) {
25741
26205
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
@@ -25743,13 +26207,13 @@ function writeChangesSinceDateReport(contextDirAbs, body) {
25743
26207
  }
25744
26208
 
25745
26209
  // src/factory/updateContext/updateContextSeedCheck.ts
25746
- var fs51 = __toESM(require("node:fs"));
25747
- var path47 = __toESM(require("node:path"));
26210
+ var fs52 = __toESM(require("node:fs"));
26211
+ var path48 = __toESM(require("node:path"));
25748
26212
  var INDEX_BASENAME = "index-application-context.json";
25749
26213
  var CHANGES_REPORT = "changes-since-date.md";
25750
26214
  function tryParseJsonFile(abs) {
25751
26215
  try {
25752
- const raw = fs51.readFileSync(abs, "utf-8");
26216
+ const raw = fs52.readFileSync(abs, "utf-8");
25753
26217
  JSON.parse(raw);
25754
26218
  return true;
25755
26219
  } catch {
@@ -25757,16 +26221,16 @@ function tryParseJsonFile(abs) {
25757
26221
  }
25758
26222
  }
25759
26223
  function isWorktreeContextSeeded(contextDirAbs) {
25760
- if (!fs51.existsSync(contextDirAbs)) {
26224
+ if (!fs52.existsSync(contextDirAbs)) {
25761
26225
  return false;
25762
26226
  }
25763
- const indexAbs = path47.join(contextDirAbs, INDEX_BASENAME);
25764
- if (fs51.existsSync(indexAbs) && fs51.statSync(indexAbs).isFile() && tryParseJsonFile(indexAbs)) {
26227
+ const indexAbs = path48.join(contextDirAbs, INDEX_BASENAME);
26228
+ if (fs52.existsSync(indexAbs) && fs52.statSync(indexAbs).isFile() && tryParseJsonFile(indexAbs)) {
25765
26229
  return true;
25766
26230
  }
25767
26231
  let names;
25768
26232
  try {
25769
- names = fs51.readdirSync(contextDirAbs);
26233
+ names = fs52.readdirSync(contextDirAbs);
25770
26234
  } catch {
25771
26235
  return false;
25772
26236
  }
@@ -25778,9 +26242,9 @@ function isWorktreeContextSeeded(contextDirAbs) {
25778
26242
  if (!name.endsWith(".md") && !name.endsWith(".json")) {
25779
26243
  continue;
25780
26244
  }
25781
- const p = path47.join(contextDirAbs, name);
26245
+ const p = path48.join(contextDirAbs, name);
25782
26246
  try {
25783
- if (fs51.statSync(p).isFile()) {
26247
+ if (fs52.statSync(p).isFile()) {
25784
26248
  distinct.add(name);
25785
26249
  }
25786
26250
  } catch {
@@ -25792,12 +26256,14 @@ function isWorktreeContextSeeded(contextDirAbs) {
25792
26256
  // src/factory/updateContext/runUpdateContextFactory.ts
25793
26257
  var REMEDIATION_CHUNK_MAX = 40;
25794
26258
  function contextDirUnderRoot(wtRoot) {
25795
- return path48.join(wtRoot, ".gluecharm", "context");
26259
+ return path49.join(wtRoot, ".gluecharm", "context");
25796
26260
  }
25797
26261
  async function runUpdateContextFactory(deps) {
26262
+ const inPlace = deps.inPlace === true;
25798
26263
  const baseMeta = {
25799
26264
  command: "update_context",
25800
- uploadRequested: false
26265
+ uploadRequested: false,
26266
+ ...inPlace ? { analysisInPlace: true } : {}
25801
26267
  };
25802
26268
  const baseline = resolveUpdateContextBaseline(deps.repoRootAbs, deps.repoConfig);
25803
26269
  if (!baseline) {
@@ -25822,8 +26288,42 @@ async function runUpdateContextFactory(deps) {
25822
26288
  };
25823
26289
  }
25824
26290
  const shortNoCommits = gitWin.commitsInOrder.length === 0;
26291
+ const cliVersion = deps.cliVersion?.trim() || "0.0.0";
26292
+ const readinessCtx = {
26293
+ cliVersion,
26294
+ repoRootAbs: deps.repoRootAbs,
26295
+ analysisRootAbs: deps.repoRootAbs,
26296
+ apiBaseUrl: deps.merged.apiBaseUrl,
26297
+ openCodeExecutable: deps.merged.openCodeExecutable,
26298
+ openCodeSkipCredentialsCheck: deps.merged.openCodeSkipCredentialsCheck,
26299
+ providerEnvFromConfig: deps.merged.openCodeChildEnv,
26300
+ repoConfig: deps.repoConfig
26301
+ };
26302
+ const rlog = deps.readinessLog ?? deps.log;
26303
+ const pre = emitCliFactoryReadinessPreflight(rlog, "[factory] update context readiness", readinessCtx);
26304
+ if (!pre.ok) {
26305
+ const g = pre.failure;
26306
+ return {
26307
+ exitOk: false,
26308
+ ok: false,
26309
+ code: "READINESS_FAILED",
26310
+ error: `Factory readiness failed (${g.readinessReasonCode}).`,
26311
+ readinessExitCode: g.exitCode,
26312
+ readinessReasonCode: g.readinessReasonCode,
26313
+ readinessGate: g.gate,
26314
+ openCodeConfigFiles: pre.facts.openCodeConfigFiles,
26315
+ modelConfigured: pre.facts.modelConfigured,
26316
+ baselineDate: baseline.baselineIsoUtc,
26317
+ baselineSource: baseline.source,
26318
+ headCommit: gitWin.headCommit,
26319
+ rangeStartCommit: gitWin.rangeStartCommit,
26320
+ commitsReviewed: gitWin.commitsInOrder.length,
26321
+ ...baseMeta
26322
+ };
26323
+ }
25825
26324
  const prep = await prepareSynthesisWorktree(deps.storage, deps.repoRootAbs, deps.log, {
25826
- clearPriorArtefactRun: true
26325
+ clearPriorArtefactRun: true,
26326
+ inPlace
25827
26327
  });
25828
26328
  if (!prep.ok) {
25829
26329
  prep.finalize?.();
@@ -25844,7 +26344,7 @@ async function runUpdateContextFactory(deps) {
25844
26344
  const finalizeWt = prep.finalize;
25845
26345
  const wsCtxDir = contextDirUnderRoot(deps.repoRootAbs);
25846
26346
  let ctxDirAbs = contextDirUnderRoot(handle.path);
25847
- if (!isWorktreeContextSeeded(ctxDirAbs) && isWorktreeContextSeeded(wsCtxDir)) {
26347
+ if (!inPlace && !isWorktreeContextSeeded(ctxDirAbs) && isWorktreeContextSeeded(wsCtxDir)) {
25848
26348
  deps.log("[update-context] seeding worktree context from workspace .gluecharm/context/");
25849
26349
  promoteContextDirectoryToWorkspaceFs(wsCtxDir, handle.path);
25850
26350
  ctxDirAbs = contextDirUnderRoot(handle.path);
@@ -26023,30 +26523,34 @@ async function runUpdateContextFactory(deps) {
26023
26523
  }
26024
26524
  let promoted = false;
26025
26525
  if (deps.merged.promoteContextToWorkspace && ctxDirAbs) {
26026
- try {
26027
- const { filesCopied } = promoteContextDirectoryToWorkspaceFs(ctxDirAbs, deps.repoRootAbs);
26028
- deps.log(`[update-context] promoted ${String(filesCopied)} file(s) \u2192 ${deps.repoRootAbs}`);
26029
- promoted = filesCopied > 0;
26030
- } catch (e) {
26031
- finalizeWt?.();
26032
- return {
26033
- exitOk: false,
26034
- ok: false,
26035
- code: "PROMOTE_FAILED",
26036
- error: e instanceof Error ? e.message : String(e),
26037
- baselineDate: baseline.baselineIsoUtc,
26038
- baselineSource: baseline.source,
26039
- headCommit: gitWin.headCommit,
26040
- rangeStartCommit: gitWin.rangeStartCommit,
26041
- commitsReviewed: gitWin.commitsInOrder.length,
26042
- filesDetected: inventory.length,
26043
- filesRemediated,
26044
- analysisWorktreeRoot: handle.path,
26045
- changesReportRelativePath: ".gluecharm/context/changes-since-date.md",
26046
- remediationSkipped,
26047
- ...remediationSkipReason ? { skipReason: remediationSkipReason } : {},
26048
- ...baseMeta
26049
- };
26526
+ if (inPlace) {
26527
+ deps.log("[update-context] in-place analysis \u2014 promote skipped (context already at repository root)");
26528
+ } else {
26529
+ try {
26530
+ const { filesCopied } = promoteContextDirectoryToWorkspaceFs(ctxDirAbs, deps.repoRootAbs);
26531
+ deps.log(`[update-context] promoted ${String(filesCopied)} file(s) \u2192 ${deps.repoRootAbs}`);
26532
+ promoted = filesCopied > 0;
26533
+ } catch (e) {
26534
+ finalizeWt?.();
26535
+ return {
26536
+ exitOk: false,
26537
+ ok: false,
26538
+ code: "PROMOTE_FAILED",
26539
+ error: e instanceof Error ? e.message : String(e),
26540
+ baselineDate: baseline.baselineIsoUtc,
26541
+ baselineSource: baseline.source,
26542
+ headCommit: gitWin.headCommit,
26543
+ rangeStartCommit: gitWin.rangeStartCommit,
26544
+ commitsReviewed: gitWin.commitsInOrder.length,
26545
+ filesDetected: inventory.length,
26546
+ filesRemediated,
26547
+ analysisWorktreeRoot: handle.path,
26548
+ changesReportRelativePath: ".gluecharm/context/changes-since-date.md",
26549
+ remediationSkipped,
26550
+ ...remediationSkipReason ? { skipReason: remediationSkipReason } : {},
26551
+ ...baseMeta
26552
+ };
26553
+ }
26050
26554
  }
26051
26555
  }
26052
26556
  const uploadSkipped = true;
@@ -26082,12 +26586,12 @@ async function runUpdateContextFactory(deps) {
26082
26586
  }
26083
26587
 
26084
26588
  // src/factory/contextDrift/runContextDriftFactory.ts
26085
- var fs57 = __toESM(require("node:fs"));
26086
- var path53 = __toESM(require("node:path"));
26589
+ var fs58 = __toESM(require("node:fs"));
26590
+ var path54 = __toESM(require("node:path"));
26087
26591
 
26088
26592
  // src/factory/contextDrift/contextDriftManifest.ts
26089
- var fs52 = __toESM(require("node:fs"));
26090
- var path49 = __toESM(require("node:path"));
26593
+ var fs53 = __toESM(require("node:fs"));
26594
+ var path50 = __toESM(require("node:path"));
26091
26595
  var MAX_REFERENCE_BYTES = 256 * 1024;
26092
26596
  var MAX_EVIDENCE_FILES = 300;
26093
26597
  var MAX_EVIDENCE_READ = 512 * 1024;
@@ -26095,7 +26599,7 @@ var MAX_EXCERPT = 4e3;
26095
26599
  function readFileLimited(abs, maxBytes) {
26096
26600
  let buf;
26097
26601
  try {
26098
- buf = fs52.readFileSync(abs);
26602
+ buf = fs53.readFileSync(abs);
26099
26603
  } catch {
26100
26604
  return { text: "", truncated: false };
26101
26605
  }
@@ -26107,16 +26611,16 @@ function collectEvidencePaths(repoRoot) {
26107
26611
  const out = [];
26108
26612
  const roots = ["src", "test", "tests", "packages", ".gluecharm", "scripts"];
26109
26613
  for (const rel of roots) {
26110
- const abs = path49.join(repoRoot, rel);
26111
- if (!fs52.existsSync(abs)) {
26614
+ const abs = path50.join(repoRoot, rel);
26615
+ if (!fs53.existsSync(abs)) {
26112
26616
  continue;
26113
26617
  }
26114
26618
  walkFiles(abs, repoRoot, out, 0);
26115
26619
  }
26116
26620
  for (const leaf of ["package.json", "tsconfig.json"]) {
26117
- const abs = path49.join(repoRoot, leaf);
26118
- if (fs52.existsSync(abs) && fs52.statSync(abs).isFile()) {
26119
- const r = path49.relative(repoRoot, abs).split(path49.sep).join("/");
26621
+ const abs = path50.join(repoRoot, leaf);
26622
+ if (fs53.existsSync(abs) && fs53.statSync(abs).isFile()) {
26623
+ const r = path50.relative(repoRoot, abs).split(path50.sep).join("/");
26120
26624
  out.push(r);
26121
26625
  }
26122
26626
  }
@@ -26133,7 +26637,7 @@ function walkFiles(dir, repoRoot, out, depth) {
26133
26637
  }
26134
26638
  let entries;
26135
26639
  try {
26136
- entries = fs52.readdirSync(dir, { withFileTypes: true });
26640
+ entries = fs53.readdirSync(dir, { withFileTypes: true });
26137
26641
  } catch {
26138
26642
  return;
26139
26643
  }
@@ -26141,13 +26645,13 @@ function walkFiles(dir, repoRoot, out, depth) {
26141
26645
  if (e.name === "node_modules" || e.name === ".git" || e.name === "dist" || e.name === "out") {
26142
26646
  continue;
26143
26647
  }
26144
- const full = path49.join(dir, e.name);
26648
+ const full = path50.join(dir, e.name);
26145
26649
  if (e.isDirectory()) {
26146
26650
  walkFiles(full, repoRoot, out, depth + 1);
26147
26651
  } else if (e.isFile()) {
26148
- const ext = path49.extname(e.name).toLowerCase();
26652
+ const ext = path50.extname(e.name).toLowerCase();
26149
26653
  if ([".ts", ".tsx", ".js", ".mjs", ".cjs", ".json", ".md", ".yaml", ".yml"].includes(ext) || e.name === "Dockerfile") {
26150
- const rel = path49.relative(repoRoot, full).split(path49.sep).join("/");
26654
+ const rel = path50.relative(repoRoot, full).split(path50.sep).join("/");
26151
26655
  out.push(rel);
26152
26656
  }
26153
26657
  }
@@ -26157,7 +26661,7 @@ function buildComparisonManifest(args) {
26157
26661
  const references = [];
26158
26662
  let referenceTruncated = false;
26159
26663
  for (const abs of args.bundleAbsFiles) {
26160
- const rel = path49.relative(args.worktreeRoot, abs).split(path49.sep).join("/");
26664
+ const rel = path50.relative(args.worktreeRoot, abs).split(path50.sep).join("/");
26161
26665
  const { text, truncated } = readFileLimited(abs, MAX_REFERENCE_BYTES);
26162
26666
  references.push({ path: rel, content: text, truncated });
26163
26667
  if (truncated) {
@@ -26169,8 +26673,8 @@ function buildComparisonManifest(args) {
26169
26673
  const omitted = Math.max(0, allEvidence.length - evidencePathsTrimmed.length);
26170
26674
  const evidenceFiles = [];
26171
26675
  for (const rel of evidencePathsTrimmed) {
26172
- const abs = path49.join(args.worktreeRoot, ...rel.split("/"));
26173
- const st = fs52.existsSync(abs) ? fs52.statSync(abs) : null;
26676
+ const abs = path50.join(args.worktreeRoot, ...rel.split("/"));
26677
+ const st = fs53.existsSync(abs) ? fs53.statSync(abs) : null;
26174
26678
  const size = st && st.isFile() ? st.size : 0;
26175
26679
  const { text, truncated } = readFileLimited(abs, MAX_EVIDENCE_READ);
26176
26680
  const excerpt = truncated ? `${text.slice(0, MAX_EXCERPT)}
@@ -26180,7 +26684,7 @@ function buildComparisonManifest(args) {
26180
26684
  }
26181
26685
  return {
26182
26686
  runDate: args.runDate,
26183
- referenceRelPaths: args.bundleAbsFiles.map((a) => path49.relative(args.worktreeRoot, a).split(path49.sep).join("/")),
26687
+ referenceRelPaths: args.bundleAbsFiles.map((a) => path50.relative(args.worktreeRoot, a).split(path50.sep).join("/")),
26184
26688
  references,
26185
26689
  evidenceFiles,
26186
26690
  evidencePathsOnly: [],
@@ -26192,8 +26696,8 @@ function buildComparisonManifest(args) {
26192
26696
  }
26193
26697
 
26194
26698
  // src/factory/contextDrift/contextDriftAgent.ts
26195
- var fs53 = __toESM(require("node:fs"));
26196
- var path50 = __toESM(require("node:path"));
26699
+ var fs54 = __toESM(require("node:fs"));
26700
+ var path51 = __toESM(require("node:path"));
26197
26701
 
26198
26702
  // src/factory/contextDrift/contextDriftPayload.ts
26199
26703
  function isNonEmptyString2(v) {
@@ -26338,17 +26842,17 @@ function buildDriftPrompt(args) {
26338
26842
  ].join("\n");
26339
26843
  }
26340
26844
  async function runDriftComparisonOpenCode(args) {
26341
- const runDir = path50.join(args.worktreeRoot, ".opencode", "_run");
26342
- fs53.mkdirSync(runDir, { recursive: true });
26343
- const manifestPath = path50.join(runDir, "context-drift-manifest.json");
26344
- const outputPath = path50.join(runDir, "context-drift-payload.json");
26345
- fs53.writeFileSync(manifestPath, `${JSON.stringify(args.manifestObject, null, 2)}
26845
+ const runDir = path51.join(args.worktreeRoot, ".opencode", "_run");
26846
+ fs54.mkdirSync(runDir, { recursive: true });
26847
+ const manifestPath = path51.join(runDir, "context-drift-manifest.json");
26848
+ const outputPath = path51.join(runDir, "context-drift-payload.json");
26849
+ fs54.writeFileSync(manifestPath, `${JSON.stringify(args.manifestObject, null, 2)}
26346
26850
  `, "utf8");
26347
- if (fs53.existsSync(outputPath)) {
26348
- fs53.unlinkSync(outputPath);
26851
+ if (fs54.existsSync(outputPath)) {
26852
+ fs54.unlinkSync(outputPath);
26349
26853
  }
26350
- const promptPath = path50.join(runDir, `context-drift-${Date.now()}.prompt.txt`);
26351
- fs53.writeFileSync(
26854
+ const promptPath = path51.join(runDir, `context-drift-${Date.now()}.prompt.txt`);
26855
+ fs54.writeFileSync(
26352
26856
  promptPath,
26353
26857
  buildDriftPrompt({
26354
26858
  worktreeRoot: args.worktreeRoot,
@@ -26365,7 +26869,7 @@ async function runDriftComparisonOpenCode(args) {
26365
26869
  });
26366
26870
  const title = buildOpenCodeSessionTitle({
26367
26871
  runId: "context-drift",
26368
- workItemId: path50.basename(args.worktreeRoot).slice(0, 24) || "wt",
26872
+ workItemId: path51.basename(args.worktreeRoot).slice(0, 24) || "wt",
26369
26873
  stepLabel: "context-drift"
26370
26874
  });
26371
26875
  const argv = injectPrimaryOpenCodeSessionArgv(expanded, title);
@@ -26390,7 +26894,7 @@ async function runDriftComparisonOpenCode(args) {
26390
26894
  }
26391
26895
  let raw;
26392
26896
  try {
26393
- const txt = fs53.readFileSync(outputPath, "utf8");
26897
+ const txt = fs54.readFileSync(outputPath, "utf8");
26394
26898
  raw = JSON.parse(txt);
26395
26899
  } catch (e) {
26396
26900
  return {
@@ -26407,9 +26911,9 @@ async function runDriftComparisonOpenCode(args) {
26407
26911
 
26408
26912
  // src/factory/contextDrift/contextDriftPaths.ts
26409
26913
  var crypto2 = __toESM(require("node:crypto"));
26410
- var fs54 = __toESM(require("node:fs"));
26411
- var path51 = __toESM(require("node:path"));
26412
- var DRIFT_CONTEXT_SUBDIR = path51.join(".gluecharm", "context", "drift");
26914
+ var fs55 = __toESM(require("node:fs"));
26915
+ var path52 = __toESM(require("node:path"));
26916
+ var DRIFT_CONTEXT_SUBDIR = path52.join(".gluecharm", "context", "drift");
26413
26917
  function sanitizeSlug(raw) {
26414
26918
  const s = raw.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
26415
26919
  return s.length > 0 ? s : "drift";
@@ -26418,9 +26922,9 @@ function utcDateString(d) {
26418
26922
  return d.toISOString().slice(0, 10);
26419
26923
  }
26420
26924
  function resolveInsideRepo(repoRootAbs, userPath) {
26421
- const abs = path51.isAbsolute(userPath) ? path51.normalize(userPath) : path51.resolve(repoRootAbs, userPath);
26422
- const rel = path51.relative(repoRootAbs, abs);
26423
- if (rel.startsWith("..") || path51.isAbsolute(rel)) {
26925
+ const abs = path52.isAbsolute(userPath) ? path52.normalize(userPath) : path52.resolve(repoRootAbs, userPath);
26926
+ const rel = path52.relative(repoRootAbs, abs);
26927
+ if (rel.startsWith("..") || path52.isAbsolute(rel)) {
26424
26928
  return { ok: false };
26425
26929
  }
26426
26930
  return { ok: true, abs };
@@ -26430,7 +26934,7 @@ function computeSlug(args) {
26430
26934
  return sanitizeSlug(args.label.trim());
26431
26935
  }
26432
26936
  const r = resolveInsideRepo(args.repoRootAbs, args.referencePath);
26433
- const base = r.ok ? path51.basename(r.abs) : path51.basename(args.referencePath);
26937
+ const base = r.ok ? path52.basename(r.abs) : path52.basename(args.referencePath);
26434
26938
  return sanitizeSlug(base);
26435
26939
  }
26436
26940
  function driftFilename(slug, runDate) {
@@ -26446,7 +26950,7 @@ function maybeDedupeSlug(slug, referenceRelPosix) {
26446
26950
  function discoverReferenceBundle(worktreeRoot, referenceAbsInWorktree) {
26447
26951
  let st;
26448
26952
  try {
26449
- st = fs54.statSync(referenceAbsInWorktree);
26953
+ st = fs55.statSync(referenceAbsInWorktree);
26450
26954
  } catch {
26451
26955
  return { ok: false, error: `Reference path not found in analysis worktree: ${referenceAbsInWorktree}` };
26452
26956
  }
@@ -26467,12 +26971,12 @@ function discoverReferenceBundle(worktreeRoot, referenceAbsInWorktree) {
26467
26971
  }
26468
26972
  let entries;
26469
26973
  try {
26470
- entries = fs54.readdirSync(dir, { withFileTypes: true });
26974
+ entries = fs55.readdirSync(dir, { withFileTypes: true });
26471
26975
  } catch {
26472
26976
  return;
26473
26977
  }
26474
26978
  for (const e of entries) {
26475
- const full = path51.join(dir, e.name);
26979
+ const full = path52.join(dir, e.name);
26476
26980
  if (e.isDirectory()) {
26477
26981
  if (e.name === "node_modules" || e.name === ".git") {
26478
26982
  continue;
@@ -26492,7 +26996,7 @@ function discoverReferenceBundle(worktreeRoot, referenceAbsInWorktree) {
26492
26996
  }
26493
26997
  function pickReferenceRootDocument(args) {
26494
26998
  if (args.indexOverrideAbs) {
26495
- if (!fs54.existsSync(args.indexOverrideAbs) || !args.indexOverrideAbs.endsWith(".md")) {
26999
+ if (!fs55.existsSync(args.indexOverrideAbs) || !args.indexOverrideAbs.endsWith(".md")) {
26496
27000
  return { ok: false, error: "--index must point to an existing .md file under the repo." };
26497
27001
  }
26498
27002
  return { ok: true, path: args.indexOverrideAbs };
@@ -26502,8 +27006,8 @@ function pickReferenceRootDocument(args) {
26502
27006
  }
26503
27007
  const dir = args.referenceAbsInWorktree;
26504
27008
  for (const name of ["index.md", "README.md"]) {
26505
- const p = path51.join(dir, name);
26506
- if (fs54.existsSync(p) && fs54.statSync(p).isFile()) {
27009
+ const p = path52.join(dir, name);
27010
+ if (fs55.existsSync(p) && fs55.statSync(p).isFile()) {
26507
27011
  return { ok: true, path: p };
26508
27012
  }
26509
27013
  }
@@ -26513,20 +27017,20 @@ function pickReferenceRootDocument(args) {
26513
27017
  };
26514
27018
  }
26515
27019
  function toWorktreeRelative(worktreeRoot, absolute) {
26516
- return path51.relative(worktreeRoot, absolute).split(path51.sep).join("/");
27020
+ return path52.relative(worktreeRoot, absolute).split(path52.sep).join("/");
26517
27021
  }
26518
27022
  function toPosixPath(p) {
26519
- return p.split(path51.sep).join("/");
27023
+ return p.split(path52.sep).join("/");
26520
27024
  }
26521
27025
 
26522
27026
  // src/factory/contextDrift/contextDriftIndex.ts
26523
- var fs55 = __toESM(require("node:fs"));
27027
+ var fs56 = __toESM(require("node:fs"));
26524
27028
  var START = "<!-- easyspecs-drift-links:start -->";
26525
27029
  var END = "<!-- easyspecs-drift-links:end -->";
26526
27030
  function patchReferenceIndexWithDriftLink(args) {
26527
27031
  let body;
26528
27032
  try {
26529
- body = fs55.readFileSync(args.referenceRootAbsolute, "utf8");
27033
+ body = fs56.readFileSync(args.referenceRootAbsolute, "utf8");
26530
27034
  } catch (e) {
26531
27035
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
26532
27036
  }
@@ -26547,7 +27051,7 @@ ${block}
26547
27051
  `;
26548
27052
  }
26549
27053
  try {
26550
- fs55.writeFileSync(args.referenceRootAbsolute, next, "utf8");
27054
+ fs56.writeFileSync(args.referenceRootAbsolute, next, "utf8");
26551
27055
  } catch (e) {
26552
27056
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
26553
27057
  }
@@ -26558,19 +27062,32 @@ function escapeRe(s) {
26558
27062
  }
26559
27063
 
26560
27064
  // src/factory/contextDrift/contextDriftPromote.ts
26561
- var fs56 = __toESM(require("node:fs"));
26562
- var path52 = __toESM(require("node:path"));
27065
+ var fs57 = __toESM(require("node:fs"));
27066
+ var path53 = __toESM(require("node:path"));
26563
27067
  function copyWorktreeFileToWorkspace(args) {
26564
- const src = path52.join(args.worktreeRoot, ...args.relativePosix.split("/"));
26565
- const dest = path52.join(args.workspaceRoot, ...args.relativePosix.split("/"));
26566
- fs56.mkdirSync(path52.dirname(dest), { recursive: true });
26567
- fs56.copyFileSync(src, dest);
27068
+ const wt = path53.resolve(args.worktreeRoot);
27069
+ const ws = path53.resolve(args.workspaceRoot);
27070
+ if (wt === ws) {
27071
+ return;
27072
+ }
27073
+ const src = path53.join(args.worktreeRoot, ...args.relativePosix.split("/"));
27074
+ const dest = path53.join(args.workspaceRoot, ...args.relativePosix.split("/"));
27075
+ if (path53.resolve(src) === path53.resolve(dest)) {
27076
+ return;
27077
+ }
27078
+ fs57.mkdirSync(path53.dirname(dest), { recursive: true });
27079
+ fs57.copyFileSync(src, dest);
26568
27080
  }
26569
27081
 
26570
27082
  // src/factory/contextDrift/runContextDriftFactory.ts
26571
27083
  async function runContextDriftFactory(deps) {
26572
27084
  const runDate = utcDateString(/* @__PURE__ */ new Date());
26573
- const baseMeta = { command: "context_drift", referencePath: deps.referencePathArg };
27085
+ const inPlace = deps.inPlace === true;
27086
+ const baseMeta = {
27087
+ command: "context_drift",
27088
+ referencePath: deps.referencePathArg,
27089
+ ...inPlace ? { analysisInPlace: true } : {}
27090
+ };
26574
27091
  const resolved = resolveInsideRepo(deps.repoRootAbs, deps.referencePathArg);
26575
27092
  if (!resolved.ok) {
26576
27093
  return {
@@ -26583,7 +27100,7 @@ async function runContextDriftFactory(deps) {
26583
27100
  };
26584
27101
  }
26585
27102
  const refAbsWorkspace = resolved.abs;
26586
- if (!fs57.existsSync(refAbsWorkspace)) {
27103
+ if (!fs58.existsSync(refAbsWorkspace)) {
26587
27104
  return {
26588
27105
  exitOk: false,
26589
27106
  ok: false,
@@ -26596,7 +27113,7 @@ async function runContextDriftFactory(deps) {
26596
27113
  let indexOverrideAbsWorkspace;
26597
27114
  if (deps.indexOverrideArg?.trim()) {
26598
27115
  const ir = resolveInsideRepo(deps.repoRootAbs, deps.indexOverrideArg.trim());
26599
- if (!ir.ok || !fs57.existsSync(ir.abs)) {
27116
+ if (!ir.ok || !fs58.existsSync(ir.abs)) {
26600
27117
  return {
26601
27118
  exitOk: false,
26602
27119
  ok: false,
@@ -26614,7 +27131,7 @@ async function runContextDriftFactory(deps) {
26614
27131
  ok: true,
26615
27132
  code: "DRY_RUN",
26616
27133
  ...baseMeta,
26617
- referenceRootDocument: toPosixPath(path53.relative(deps.repoRootAbs, refAbsWorkspace)) + (fs57.statSync(refAbsWorkspace).isDirectory() ? "/" : ""),
27134
+ referenceRootDocument: toPosixPath(path54.relative(deps.repoRootAbs, refAbsWorkspace)) + (fs58.statSync(refAbsWorkspace).isDirectory() ? "/" : ""),
26618
27135
  driftReportPath: null,
26619
27136
  analysisWorktreeRoot: "",
26620
27137
  promoted: false,
@@ -26624,8 +27141,38 @@ async function runContextDriftFactory(deps) {
26624
27141
  dryRun: true
26625
27142
  };
26626
27143
  }
27144
+ const cliVersion = deps.cliVersion?.trim() || "0.0.0";
27145
+ const readinessCtx = {
27146
+ cliVersion,
27147
+ repoRootAbs: deps.repoRootAbs,
27148
+ analysisRootAbs: deps.repoRootAbs,
27149
+ apiBaseUrl: deps.merged.apiBaseUrl,
27150
+ openCodeExecutable: deps.merged.openCodeExecutable,
27151
+ openCodeSkipCredentialsCheck: deps.merged.openCodeSkipCredentialsCheck,
27152
+ providerEnvFromConfig: deps.merged.openCodeChildEnv,
27153
+ repoConfig: deps.repoConfig
27154
+ };
27155
+ const rlog = deps.readinessLog ?? deps.log;
27156
+ const pre = emitCliFactoryReadinessPreflight(rlog, "[factory] context drift readiness", readinessCtx);
27157
+ if (!pre.ok) {
27158
+ const g = pre.failure;
27159
+ return {
27160
+ exitOk: false,
27161
+ ok: false,
27162
+ code: "READINESS_FAILED",
27163
+ error: `Factory readiness failed (${g.readinessReasonCode}).`,
27164
+ readinessExitCode: g.exitCode,
27165
+ readinessReasonCode: g.readinessReasonCode,
27166
+ readinessGate: g.gate,
27167
+ openCodeConfigFiles: pre.facts.openCodeConfigFiles,
27168
+ modelConfigured: pre.facts.modelConfigured,
27169
+ driftReportPath: null,
27170
+ ...baseMeta
27171
+ };
27172
+ }
26627
27173
  const prep = await prepareSynthesisWorktree(deps.storage, deps.repoRootAbs, deps.log, {
26628
- clearPriorArtefactRun: false
27174
+ clearPriorArtefactRun: false,
27175
+ inPlace
26629
27176
  });
26630
27177
  if (!prep.ok) {
26631
27178
  prep.finalize?.();
@@ -26641,8 +27188,8 @@ async function runContextDriftFactory(deps) {
26641
27188
  const handle = prep.handle;
26642
27189
  const finalizeWt = prep.finalize;
26643
27190
  const wt = handle.path;
26644
- const refRel = path53.relative(deps.repoRootAbs, refAbsWorkspace).split(path53.sep).join("/");
26645
- const refAbsWt = path53.join(wt, ...refRel.split("/"));
27191
+ const refRel = path54.relative(deps.repoRootAbs, refAbsWorkspace).split(path54.sep).join("/");
27192
+ const refAbsWt = path54.join(wt, ...refRel.split("/"));
26646
27193
  try {
26647
27194
  materializeOpenCodeAgentsWithAce(deps.agentsDirFs, wt, {
26648
27195
  enabled: getAceAnalysisEnabledForCheckout(wt),
@@ -26681,9 +27228,9 @@ async function runContextDriftFactory(deps) {
26681
27228
  ...baseMeta
26682
27229
  };
26683
27230
  }
26684
- const indexWt = indexOverrideAbsWorkspace ? path53.join(wt, ...path53.relative(deps.repoRootAbs, indexOverrideAbsWorkspace).split(path53.sep)) : void 0;
27231
+ const indexWt = indexOverrideAbsWorkspace ? path54.join(wt, ...path54.relative(deps.repoRootAbs, indexOverrideAbsWorkspace).split(path54.sep)) : void 0;
26685
27232
  const rootPick = pickReferenceRootDocument({
26686
- referencePathIsFile: fs57.statSync(refAbsWt).isFile(),
27233
+ referencePathIsFile: fs58.statSync(refAbsWt).isFile(),
26687
27234
  referenceAbsInWorktree: refAbsWt,
26688
27235
  bundleFiles: bundle.bundleFiles,
26689
27236
  indexOverrideAbs: indexWt
@@ -26709,9 +27256,9 @@ async function runContextDriftFactory(deps) {
26709
27256
  let slug = computeSlug({ label: deps.label, referencePath: deps.referencePathArg, repoRootAbs: deps.repoRootAbs });
26710
27257
  slug = maybeDedupeSlug(slug, refRel);
26711
27258
  const driftBase = driftFilename(slug, runDate);
26712
- const driftDirWt = path53.join(wt, DRIFT_CONTEXT_SUBDIR);
26713
- fs57.mkdirSync(driftDirWt, { recursive: true });
26714
- const driftAbsWt = path53.join(driftDirWt, driftBase);
27259
+ const driftDirWt = path54.join(wt, DRIFT_CONTEXT_SUBDIR);
27260
+ fs58.mkdirSync(driftDirWt, { recursive: true });
27261
+ const driftAbsWt = path54.join(driftDirWt, driftBase);
26715
27262
  let payload;
26716
27263
  if (deps.testOnlyFixturePayload) {
26717
27264
  payload = deps.testOnlyFixturePayload;
@@ -26747,7 +27294,7 @@ async function runContextDriftFactory(deps) {
26747
27294
  manifestTruncation: manifest.truncation
26748
27295
  });
26749
27296
  try {
26750
- fs57.writeFileSync(driftAbsWt, md, "utf8");
27297
+ fs58.writeFileSync(driftAbsWt, md, "utf8");
26751
27298
  } catch (e) {
26752
27299
  finalizeWt?.();
26753
27300
  return {
@@ -26760,7 +27307,7 @@ async function runContextDriftFactory(deps) {
26760
27307
  ...baseMeta
26761
27308
  };
26762
27309
  }
26763
- const driftRelFromRootDir = path53.relative(path53.dirname(refRootAbsWt), driftAbsWt).split(path53.sep).join("/");
27310
+ const driftRelFromRootDir = path54.relative(path54.dirname(refRootAbsWt), driftAbsWt).split(path54.sep).join("/");
26764
27311
  const linkRes = patchReferenceIndexWithDriftLink({
26765
27312
  referenceRootAbsolute: refRootAbsWt,
26766
27313
  relativeLinkFromRootToDrift: driftRelFromRootDir,
@@ -26779,10 +27326,10 @@ async function runContextDriftFactory(deps) {
26779
27326
  ...baseMeta
26780
27327
  };
26781
27328
  }
26782
- const driftRelPosix = toPosixPath(path53.relative(wt, driftAbsWt));
26783
- const rootRelPosix = toPosixPath(path53.relative(wt, refRootAbsWt));
27329
+ const driftRelPosix = toPosixPath(path54.relative(wt, driftAbsWt));
27330
+ const rootRelPosix = toPosixPath(path54.relative(wt, refRootAbsWt));
26784
27331
  const promoteEffective = deps.merged.promoteContextToWorkspace !== false;
26785
- if (promoteEffective) {
27332
+ if (promoteEffective && !inPlace) {
26786
27333
  try {
26787
27334
  copyWorktreeFileToWorkspace({
26788
27335
  worktreeRoot: wt,
@@ -26807,8 +27354,10 @@ async function runContextDriftFactory(deps) {
26807
27354
  ...baseMeta
26808
27355
  };
26809
27356
  }
27357
+ } else if (promoteEffective && inPlace) {
27358
+ deps.log("[context-drift] in-place analysis \u2014 promote skipped (artefacts already under repository root)");
26810
27359
  }
26811
- const driftReportPathFs = promoteEffective ? path53.join(deps.repoRootAbs, ...driftRelPosix.split("/")) : driftAbsWt;
27360
+ const driftReportPathFs = promoteEffective ? path54.join(deps.repoRootAbs, ...driftRelPosix.split("/")) : driftAbsWt;
26812
27361
  return {
26813
27362
  exitOk: true,
26814
27363
  ok: true,
@@ -26817,7 +27366,7 @@ async function runContextDriftFactory(deps) {
26817
27366
  referenceRootDocument: rootRelPosix,
26818
27367
  driftReportPath: driftReportPathFs,
26819
27368
  analysisWorktreeRoot: wt,
26820
- promoted: promoteEffective,
27369
+ promoted: promoteEffective && !inPlace,
26821
27370
  nameOfChangeSlug: slug,
26822
27371
  runDate,
26823
27372
  agentInvoked: !deps.testOnlyFixturePayload,
@@ -26826,8 +27375,8 @@ async function runContextDriftFactory(deps) {
26826
27375
  }
26827
27376
 
26828
27377
  // src/analysis/coordinationDuplicatesDiagnosis.ts
26829
- var fs58 = __toESM(require("fs"));
26830
- var path54 = __toESM(require("path"));
27378
+ var fs59 = __toESM(require("fs"));
27379
+ var path55 = __toESM(require("path"));
26831
27380
  var import__7 = __toESM(require__());
26832
27381
  var COORDINATION_DUPLICATES_REPORT_BASENAME = "coordination-duplicates-report.json";
26833
27382
  var COORDINATION_LIST_SCAN_ENTRIES = [
@@ -26853,7 +27402,7 @@ var RE_MD_DM_FD = /^DM-\d+_FD-\d+-.+\.md$/i;
26853
27402
  var RE_MD_DM = /^DM-\d+-.+\.md$/i;
26854
27403
  var RE_MD_TS = /^TS-\d+-.+\.md$/i;
26855
27404
  function looksLikeCoordinationDetailMarkdownBasename(basename17) {
26856
- if (!basename17 || basename17 !== path54.basename(basename17) || !/\.md$/i.test(basename17)) {
27405
+ if (!basename17 || basename17 !== path55.basename(basename17) || !/\.md$/i.test(basename17)) {
26857
27406
  return false;
26858
27407
  }
26859
27408
  if (STAPLE_CONTEXT_MARKDOWN_BASENAMES.has(basename17)) {
@@ -26862,12 +27411,12 @@ function looksLikeCoordinationDetailMarkdownBasename(basename17) {
26862
27411
  return RE_MD_FE_UC_SC.test(basename17) || RE_MD_FE_UC_SLUG.test(basename17) || RE_MD_FE_UC_PLAIN.test(basename17) || RE_MD_FE_FEATURE.test(basename17) || RE_MD_XP_BH.test(basename17) || RE_MD_XP_VIEW.test(basename17) || RE_MD_SV_ME.test(basename17) || RE_MD_SV.test(basename17) || RE_MD_DM_FD.test(basename17) || RE_MD_DM.test(basename17) || RE_MD_TS.test(basename17);
26863
27412
  }
26864
27413
  function loadRawFeatureRows(contextDirAbs) {
26865
- const p = path54.join(contextDirAbs, "features-list.json");
26866
- if (!fs58.existsSync(p)) {
27414
+ const p = path55.join(contextDirAbs, "features-list.json");
27415
+ if (!fs59.existsSync(p)) {
26867
27416
  return [];
26868
27417
  }
26869
27418
  try {
26870
- const raw = stripUtf8Bom6(fs58.readFileSync(p, "utf-8"));
27419
+ const raw = stripUtf8Bom6(fs59.readFileSync(p, "utf-8"));
26871
27420
  const doc = JSON.parse(raw);
26872
27421
  return Array.isArray(doc.features) ? doc.features : [];
26873
27422
  } catch {
@@ -26902,7 +27451,7 @@ function findOrphanCoordinationMarkdown(contextDirAbs) {
26902
27451
  const featureRows = loadRawFeatureRows(contextDirAbs);
26903
27452
  let dirents;
26904
27453
  try {
26905
- dirents = fs58.readdirSync(contextDirAbs, { withFileTypes: true });
27454
+ dirents = fs59.readdirSync(contextDirAbs, { withFileTypes: true });
26906
27455
  } catch {
26907
27456
  return [];
26908
27457
  }
@@ -27155,14 +27704,14 @@ function buildCoordinationDuplicatesReport(input) {
27155
27704
  const lists = [];
27156
27705
  const duplicateGroups = [];
27157
27706
  for (const entry of COORDINATION_LIST_SCAN_ENTRIES) {
27158
- const filePath = path54.join(input.contextDirAbsolute, entry.basename);
27159
- if (!fs58.existsSync(filePath)) {
27707
+ const filePath = path55.join(input.contextDirAbsolute, entry.basename);
27708
+ if (!fs59.existsSync(filePath)) {
27160
27709
  lists.push({ basename: entry.basename, status: "missing" });
27161
27710
  continue;
27162
27711
  }
27163
27712
  let raw;
27164
27713
  try {
27165
- raw = stripUtf8Bom6(fs58.readFileSync(filePath, "utf-8"));
27714
+ raw = stripUtf8Bom6(fs59.readFileSync(filePath, "utf-8"));
27166
27715
  } catch (e) {
27167
27716
  lists.push({
27168
27717
  basename: entry.basename,
@@ -27210,8 +27759,8 @@ var validateReportCompiled;
27210
27759
  function validateReportData(data) {
27211
27760
  if (!validateReportCompiled) {
27212
27761
  const ajv2 = new import__7.default({ allErrors: true, strict: false });
27213
- const schemaPath = path54.join(resolveContextListSchemasDir(), "coordination-duplicates-report.schema.json");
27214
- const schemaRaw = stripUtf8Bom6(fs58.readFileSync(schemaPath, "utf-8"));
27762
+ const schemaPath = path55.join(resolveContextListSchemasDir(), "coordination-duplicates-report.schema.json");
27763
+ const schemaRaw = stripUtf8Bom6(fs59.readFileSync(schemaPath, "utf-8"));
27215
27764
  validateReportCompiled = ajv2.compile(JSON.parse(schemaRaw));
27216
27765
  }
27217
27766
  if (validateReportCompiled(data)) {
@@ -27229,20 +27778,20 @@ function runCoordinationDuplicatesDiagnosis(input) {
27229
27778
  if (!v.ok) {
27230
27779
  return { ok: false, message: `Report validation failed: ${v.errors.join("; ")}` };
27231
27780
  }
27232
- const outPath = path54.join(input.contextDirAbsolute, COORDINATION_DUPLICATES_REPORT_BASENAME);
27781
+ const outPath = path55.join(input.contextDirAbsolute, COORDINATION_DUPLICATES_REPORT_BASENAME);
27233
27782
  const payload = `${JSON.stringify(report, null, 2)}
27234
27783
  `;
27235
27784
  const tmp = `${outPath}.tmp.${process.pid}`;
27236
27785
  try {
27237
- fs58.writeFileSync(tmp, payload, "utf-8");
27786
+ fs59.writeFileSync(tmp, payload, "utf-8");
27238
27787
  } catch (e) {
27239
27788
  return { ok: false, message: e instanceof Error ? e.message : String(e) };
27240
27789
  }
27241
27790
  try {
27242
- fs58.renameSync(tmp, outPath);
27791
+ fs59.renameSync(tmp, outPath);
27243
27792
  } catch (e) {
27244
27793
  try {
27245
- fs58.unlinkSync(tmp);
27794
+ fs59.unlinkSync(tmp);
27246
27795
  } catch {
27247
27796
  }
27248
27797
  return { ok: false, message: e instanceof Error ? e.message : String(e) };
@@ -27276,8 +27825,8 @@ function runCoordinationDuplicatesDiagnosis(input) {
27276
27825
  }
27277
27826
 
27278
27827
  // src/pipelines/download/downloadPipeline.ts
27279
- var fs59 = __toESM(require("node:fs"));
27280
- var path55 = __toESM(require("node:path"));
27828
+ var fs60 = __toESM(require("node:fs"));
27829
+ var path56 = __toESM(require("node:path"));
27281
27830
  var SRS_DISCOVERY_BATCH_GET_CHUNK_SIZE = 200;
27282
27831
  function isRecord7(v) {
27283
27832
  return Boolean(v) && typeof v === "object" && !Array.isArray(v);
@@ -27367,9 +27916,9 @@ function resolveSafeContextOutputPath(contextDirAbs, nameRaw) {
27367
27916
  return null;
27368
27917
  }
27369
27918
  }
27370
- const resolved = path55.resolve(contextDirAbs, ...segments);
27371
- const rel = path55.relative(contextDirAbs, resolved);
27372
- if (rel.startsWith("..") || path55.isAbsolute(rel)) {
27919
+ const resolved = path56.resolve(contextDirAbs, ...segments);
27920
+ const rel = path56.relative(contextDirAbs, resolved);
27921
+ if (rel.startsWith("..") || path56.isAbsolute(rel)) {
27373
27922
  return null;
27374
27923
  }
27375
27924
  return resolved;
@@ -27382,37 +27931,37 @@ function chunkIds(ids, size) {
27382
27931
  return out;
27383
27932
  }
27384
27933
  function clearContextDirectoryForCloudReplace(contextDirAbs) {
27385
- if (!fs59.existsSync(contextDirAbs) || !fs59.statSync(contextDirAbs).isDirectory()) {
27934
+ if (!fs60.existsSync(contextDirAbs) || !fs60.statSync(contextDirAbs).isDirectory()) {
27386
27935
  return { filesRemoved: 0 };
27387
27936
  }
27388
- const preserveAbs = path55.resolve(contextDirAbs, UPLOAD_TARGET_FILENAME);
27937
+ const preserveAbs = path56.resolve(contextDirAbs, UPLOAD_TARGET_FILENAME);
27389
27938
  const preserveSet = /* @__PURE__ */ new Set();
27390
- if (fs59.existsSync(preserveAbs) && fs59.statSync(preserveAbs).isFile()) {
27939
+ if (fs60.existsSync(preserveAbs) && fs60.statSync(preserveAbs).isFile()) {
27391
27940
  preserveSet.add(preserveAbs);
27392
27941
  }
27393
27942
  let filesRemoved = 0;
27394
27943
  const walkRm = (dir) => {
27395
27944
  let entries;
27396
27945
  try {
27397
- entries = fs59.readdirSync(dir, { withFileTypes: true });
27946
+ entries = fs60.readdirSync(dir, { withFileTypes: true });
27398
27947
  } catch {
27399
27948
  return;
27400
27949
  }
27401
27950
  for (const e of entries) {
27402
- const full = path55.join(dir, e.name);
27951
+ const full = path56.join(dir, e.name);
27403
27952
  if (e.isDirectory()) {
27404
27953
  walkRm(full);
27405
27954
  try {
27406
- fs59.rmdirSync(full);
27955
+ fs60.rmdirSync(full);
27407
27956
  } catch {
27408
27957
  }
27409
27958
  } else if (e.isFile()) {
27410
- const abs = path55.resolve(full);
27959
+ const abs = path56.resolve(full);
27411
27960
  if (preserveSet.has(abs)) {
27412
27961
  continue;
27413
27962
  }
27414
27963
  try {
27415
- fs59.unlinkSync(abs);
27964
+ fs60.unlinkSync(abs);
27416
27965
  filesRemoved += 1;
27417
27966
  } catch {
27418
27967
  }
@@ -27480,7 +28029,7 @@ async function runDownloadPipeline(opts) {
27480
28029
  failed.push({ id, message: "Missing name on srs_discovery node." });
27481
28030
  continue;
27482
28031
  }
27483
- if (name === UPLOAD_TARGET_FILENAME || path55.basename(name) === UPLOAD_TARGET_FILENAME) {
28032
+ if (name === UPLOAD_TARGET_FILENAME || path56.basename(name) === UPLOAD_TARGET_FILENAME) {
27484
28033
  skipped += 1;
27485
28034
  log?.(`[pipeline:download] skip ${name} (upload target row).`);
27486
28035
  continue;
@@ -27491,15 +28040,15 @@ async function runDownloadPipeline(opts) {
27491
28040
  failed.push({ id, name, message: "Unsafe or invalid name for local path." });
27492
28041
  continue;
27493
28042
  }
27494
- fs59.mkdirSync(path55.dirname(outAbs), { recursive: true });
27495
- const exists = fs59.existsSync(outAbs);
28043
+ fs60.mkdirSync(path56.dirname(outAbs), { recursive: true });
28044
+ const exists = fs60.existsSync(outAbs);
27496
28045
  if (exists && !opts.force && !opts.replaceFromCloud) {
27497
28046
  skipped += 1;
27498
28047
  log?.(`[pipeline:download] skip existing ${name} (use --force to overwrite).`);
27499
28048
  continue;
27500
28049
  }
27501
28050
  try {
27502
- fs59.writeFileSync(outAbs, bodyText, "utf8");
28051
+ fs60.writeFileSync(outAbs, bodyText, "utf8");
27503
28052
  downloaded += 1;
27504
28053
  succeededIds[outAbs] = id;
27505
28054
  } catch (e) {
@@ -27574,12 +28123,12 @@ function toFetchErrorMessage(e) {
27574
28123
 
27575
28124
  // src/auth/gluecharmContentNegotiation.ts
27576
28125
  var GLUECHARM_WS_LEGACY_JSON = "application/vnd.gluecharm.v1.ws-legacy+json";
27577
- function pathWithoutQuery(path60) {
27578
- const q = path60.indexOf("?");
27579
- return q === -1 ? path60 : path60.slice(0, q);
28126
+ function pathWithoutQuery(path61) {
28127
+ const q = path61.indexOf("?");
28128
+ return q === -1 ? path61 : path61.slice(0, q);
27580
28129
  }
27581
- function isGluecharmContentApiPath(path60) {
27582
- const p = pathWithoutQuery(path60);
28130
+ function isGluecharmContentApiPath(path61) {
28131
+ const p = pathWithoutQuery(path61);
27583
28132
  return p.startsWith("/api/content/") || p.startsWith("/api/batch/content/");
27584
28133
  }
27585
28134
  function gluecharmContentHeaders(method) {
@@ -27617,7 +28166,7 @@ async function fetchWithTimeout2(url, init, fetchImpl, timeoutMs, externalSignal
27617
28166
  }
27618
28167
  function createAuthenticatedRequestJson(deps) {
27619
28168
  const fetchImpl = deps.fetchImpl ?? fetch;
27620
- async function requestJson(path60, options = {}) {
28169
+ async function requestJson(path61, options = {}) {
27621
28170
  const base = deps.getApiBaseUrl();
27622
28171
  if (!base) {
27623
28172
  const err = { status: 0, message: "easyspecs.apiBaseUrl is not configured." };
@@ -27625,7 +28174,7 @@ function createAuthenticatedRequestJson(deps) {
27625
28174
  }
27626
28175
  const method = options.method ?? "GET";
27627
28176
  const headers = { ...options.headers };
27628
- if (isGluecharmContentApiPath(path60)) {
28177
+ if (isGluecharmContentApiPath(path61)) {
27629
28178
  Object.assign(headers, gluecharmContentHeaders(method));
27630
28179
  } else {
27631
28180
  if (!headers.Accept) {
@@ -27639,7 +28188,7 @@ function createAuthenticatedRequestJson(deps) {
27639
28188
  if (options.withAuth !== false && access) {
27640
28189
  headers.Authorization = `Bearer ${access}`;
27641
28190
  }
27642
- const url = `${base}${path60}`;
28191
+ const url = `${base}${path61}`;
27643
28192
  const timeoutMs = options.timeoutMs ?? API_TIMEOUT_MS;
27644
28193
  const response = await fetchWithTimeout2(
27645
28194
  url,
@@ -27660,7 +28209,7 @@ function createAuthenticatedRequestJson(deps) {
27660
28209
  if (shouldRetryUnauthorized) {
27661
28210
  const refreshed = await deps.refreshSession();
27662
28211
  if (refreshed) {
27663
- return requestJson(path60, { ...options, retryOnUnauthorized: false });
28212
+ return requestJson(path61, { ...options, retryOnUnauthorized: false });
27664
28213
  }
27665
28214
  }
27666
28215
  const fallback = payload == null ? `${response.statusText || "HTTP error"} (response body empty or not JSON)` : "Request failed.";
@@ -27670,15 +28219,15 @@ function createAuthenticatedRequestJson(deps) {
27670
28219
  }
27671
28220
 
27672
28221
  // src/cli/cliSession.ts
27673
- var fs60 = __toESM(require("node:fs"));
27674
- var os6 = __toESM(require("node:os"));
27675
- var path56 = __toESM(require("node:path"));
28222
+ var fs61 = __toESM(require("node:fs"));
28223
+ var os7 = __toESM(require("node:os"));
28224
+ var path57 = __toESM(require("node:path"));
27676
28225
  function defaultSessionPath() {
27677
- return path56.join(os6.homedir(), ".easyspecs", "cli-session.json");
28226
+ return path57.join(os7.homedir(), ".easyspecs", "cli-session.json");
27678
28227
  }
27679
28228
  var configSessionPath;
27680
28229
  function setCliSessionPathFromConfig(absPath) {
27681
- configSessionPath = absPath?.trim() ? path56.resolve(absPath) : void 0;
28230
+ configSessionPath = absPath?.trim() ? path57.resolve(absPath) : void 0;
27682
28231
  }
27683
28232
  function applyCliSessionPathFromRepoConfig(repoRoot, cfg) {
27684
28233
  const raw = cfg.easyspecs?.cliSessionPath?.trim();
@@ -27686,7 +28235,7 @@ function applyCliSessionPathFromRepoConfig(repoRoot, cfg) {
27686
28235
  setCliSessionPathFromConfig(void 0);
27687
28236
  return;
27688
28237
  }
27689
- const abs = path56.isAbsolute(raw) ? raw : path56.join(repoRoot, raw);
28238
+ const abs = path57.isAbsolute(raw) ? raw : path57.join(repoRoot, raw);
27690
28239
  setCliSessionPathFromConfig(abs);
27691
28240
  }
27692
28241
  function normalizeCliSessionPathForConfig(repoRoot, raw) {
@@ -27694,15 +28243,15 @@ function normalizeCliSessionPathForConfig(repoRoot, raw) {
27694
28243
  if (!t) {
27695
28244
  return "";
27696
28245
  }
27697
- const resolvedRepo = path56.resolve(repoRoot);
27698
- const abs = path56.isAbsolute(t) ? path56.normalize(t) : path56.resolve(resolvedRepo, t);
27699
- const rel = path56.relative(resolvedRepo, abs);
28246
+ const resolvedRepo = path57.resolve(repoRoot);
28247
+ const abs = path57.isAbsolute(t) ? path57.normalize(t) : path57.resolve(resolvedRepo, t);
28248
+ const rel = path57.relative(resolvedRepo, abs);
27700
28249
  if (rel === "") {
27701
28250
  return abs;
27702
28251
  }
27703
- const underRepo = !rel.startsWith("..") && !path56.isAbsolute(rel);
28252
+ const underRepo = !rel.startsWith("..") && !path57.isAbsolute(rel);
27704
28253
  if (underRepo) {
27705
- return rel.split(path56.sep).join("/");
28254
+ return rel.split(path57.sep).join("/");
27706
28255
  }
27707
28256
  return abs;
27708
28257
  }
@@ -27715,10 +28264,10 @@ function effectiveCliSessionPath() {
27715
28264
  function readCliSession() {
27716
28265
  const p = effectiveCliSessionPath();
27717
28266
  try {
27718
- if (!fs60.existsSync(p)) {
28267
+ if (!fs61.existsSync(p)) {
27719
28268
  return void 0;
27720
28269
  }
27721
- const j = JSON.parse(fs60.readFileSync(p, "utf8"));
28270
+ const j = JSON.parse(fs61.readFileSync(p, "utf8"));
27722
28271
  const apiBaseUrl = typeof j.apiBaseUrl === "string" ? j.apiBaseUrl.trim() : "";
27723
28272
  const accessToken = typeof j.accessToken === "string" ? j.accessToken : "";
27724
28273
  const refreshToken = typeof j.refreshToken === "string" ? j.refreshToken : "";
@@ -27732,33 +28281,33 @@ function readCliSession() {
27732
28281
  }
27733
28282
  function writeCliSession(s) {
27734
28283
  const p = effectiveCliSessionPath();
27735
- fs60.mkdirSync(path56.dirname(p), { recursive: true });
27736
- fs60.writeFileSync(p, `${JSON.stringify(s, null, 2)}
28284
+ fs61.mkdirSync(path57.dirname(p), { recursive: true });
28285
+ fs61.writeFileSync(p, `${JSON.stringify(s, null, 2)}
27737
28286
  `, "utf8");
27738
28287
  }
27739
28288
  function clearCliSession() {
27740
28289
  const p = effectiveCliSessionPath();
27741
28290
  try {
27742
- fs60.unlinkSync(p);
28291
+ fs61.unlinkSync(p);
27743
28292
  } catch {
27744
28293
  }
27745
28294
  }
27746
28295
 
27747
28296
  // src/analysis/acePendingTraces.ts
27748
- var fs61 = __toESM(require("fs"));
27749
- var path57 = __toESM(require("path"));
28297
+ var fs62 = __toESM(require("fs"));
28298
+ var path58 = __toESM(require("path"));
27750
28299
  function normalizeAceTraceRelativePath(rel) {
27751
28300
  return rel.split(/[/\\]/).join("/");
27752
28301
  }
27753
28302
  function readCompletedTraceRelativePaths(contextDir2) {
27754
28303
  const set = /* @__PURE__ */ new Set();
27755
28304
  const jsonlPath = aceConsolidatedSessionsJsonlPath(contextDir2);
27756
- if (!fs61.existsSync(jsonlPath)) {
28305
+ if (!fs62.existsSync(jsonlPath)) {
27757
28306
  return set;
27758
28307
  }
27759
28308
  let raw;
27760
28309
  try {
27761
- raw = fs61.readFileSync(jsonlPath, "utf8");
28310
+ raw = fs62.readFileSync(jsonlPath, "utf8");
27762
28311
  } catch {
27763
28312
  return set;
27764
28313
  }
@@ -27789,14 +28338,14 @@ function readCompletedTraceRelativePaths(contextDir2) {
27789
28338
  }
27790
28339
  function listPendingAceTraceFiles(contextDir2, worktreeRoot) {
27791
28340
  const traceSchema = opencodeAceSchemaPath(worktreeRoot, ACE_SCHEMA_TRACE);
27792
- if (!fs61.existsSync(traceSchema)) {
28341
+ if (!fs62.existsSync(traceSchema)) {
27793
28342
  return [];
27794
28343
  }
27795
28344
  const completed = readCompletedTraceRelativePaths(contextDir2);
27796
28345
  const allAbs = listAceTraceFiles(contextDir2);
27797
28346
  const pending = [];
27798
28347
  for (const abs of allAbs) {
27799
- const rel = normalizeAceTraceRelativePath(path57.relative(contextDir2, abs));
28348
+ const rel = normalizeAceTraceRelativePath(path58.relative(contextDir2, abs));
27800
28349
  const v = validateAceJsonFile(abs, traceSchema);
27801
28350
  if (!v.ok) {
27802
28351
  continue;
@@ -27811,7 +28360,7 @@ function listPendingAceTraceFiles(contextDir2, worktreeRoot) {
27811
28360
  }
27812
28361
 
27813
28362
  // src/analysis/aceAutoLearnPool.ts
27814
- var path58 = __toESM(require("path"));
28363
+ var path59 = __toESM(require("path"));
27815
28364
  function clampConcurrency2(n) {
27816
28365
  if (!Number.isFinite(n)) {
27817
28366
  return DEFAULT_MAX_CONCURRENT_AI;
@@ -27846,8 +28395,8 @@ async function runAceAutoLearnPool(p) {
27846
28395
  };
27847
28396
  const currentCap = () => Math.min(staticMaxC, adaptiveMax);
27848
28397
  let wake;
27849
- const waitTurn = () => new Promise((resolve20) => {
27850
- wake = resolve20;
28398
+ const waitTurn = () => new Promise((resolve23) => {
28399
+ wake = resolve23;
27851
28400
  });
27852
28401
  const pump = () => {
27853
28402
  wake?.();
@@ -27869,7 +28418,7 @@ async function runAceAutoLearnPool(p) {
27869
28418
  poolAbortListenerRegistered = true;
27870
28419
  }
27871
28420
  }
27872
- const traceRel = (abs) => path58.relative(contextDir2, abs).split(path58.sep).join("/");
28421
+ const traceRel = (abs) => path59.relative(contextDir2, abs).split(path59.sep).join("/");
27873
28422
  const runOne = async (traceAbs) => {
27874
28423
  if (abortSignal?.aborted) {
27875
28424
  active -= 1;
@@ -27961,8 +28510,13 @@ function parseContextDriftTail(tail) {
27961
28510
  let label;
27962
28511
  let index;
27963
28512
  let dryRun = false;
28513
+ let inPlace = false;
27964
28514
  for (let i = 0; i < tail.length; i += 1) {
27965
28515
  const a = tail[i] ?? "";
28516
+ if (a === "--no-worktree" || a === "--noworktree" || a === "--in-place") {
28517
+ inPlace = true;
28518
+ continue;
28519
+ }
27966
28520
  if (a === "--label" && tail[i + 1]) {
27967
28521
  label = tail[i + 1];
27968
28522
  i += 1;
@@ -27979,7 +28533,7 @@ function parseContextDriftTail(tail) {
27979
28533
  }
27980
28534
  rest.push(a);
27981
28535
  }
27982
- return { label, index, dryRun, rest };
28536
+ return { label, index, dryRun, inPlace, rest };
27983
28537
  }
27984
28538
  function stripRootWorktreeTokens(tokens) {
27985
28539
  const out = [...tokens];
@@ -28395,7 +28949,7 @@ function formatCliStderrLine(line, useAnsi) {
28395
28949
  }
28396
28950
 
28397
28951
  // src/cli/main.ts
28398
- var PKG_VERSION = "0.0.28";
28952
+ var PKG_VERSION = "0.2.1";
28399
28953
  function isNonEmptyFactoryFailureArray(x) {
28400
28954
  if (!Array.isArray(x) || x.length === 0) {
28401
28955
  return false;
@@ -28412,6 +28966,12 @@ function isNonEmptyFactoryFailureArray(x) {
28412
28966
  }
28413
28967
  return true;
28414
28968
  }
28969
+ function processExitFromNormalizedFactoryFailures(rows) {
28970
+ return rows?.length ? rows[0].exitCode : OsExit.factoryUnknown;
28971
+ }
28972
+ function isContextDriftSrs70ValidationExit(code) {
28973
+ return code >= OsExit.driftEmptyBundle && code <= OsExit.driftIndexPatchFailed;
28974
+ }
28415
28975
  function isEasyspecsConfigReadError(e) {
28416
28976
  return e instanceof EasyspecsConfigInvalidJsonError || e instanceof EasyspecsConfigSchemaError;
28417
28977
  }
@@ -28478,12 +29038,16 @@ function extractLegacyPositionals(argv) {
28478
29038
  }
28479
29039
  return [];
28480
29040
  }
29041
+ function rewriteArgvForCommanderParse(argv) {
29042
+ return argv.map((t) => t === "--no-worktree" ? "--in-place" : t);
29043
+ }
28481
29044
  function parseCliWithCommander(argv) {
28482
29045
  const program2 = createEasyspecsCliProgram();
28483
29046
  program2.version(PKG_VERSION, "--version", "output the version number");
28484
29047
  program2.exitOverride();
29048
+ const rawArgv = [...argv];
28485
29049
  try {
28486
- program2.parse(argv, { from: "user" });
29050
+ program2.parse(rewriteArgvForCommanderParse(rawArgv), { from: "user" });
28487
29051
  } catch (e) {
28488
29052
  const code = e?.code;
28489
29053
  if (code === "commander.helpDisplayed" || code === "commander.version") {
@@ -28506,7 +29070,7 @@ function parseCliWithCommander(argv) {
28506
29070
  help: false,
28507
29071
  version: false
28508
29072
  };
28509
- const positionals = extractLegacyPositionals(argv);
29073
+ const positionals = extractLegacyPositionals(rawArgv);
28510
29074
  return { flags, positionals };
28511
29075
  }
28512
29076
  function printHelp() {
@@ -28527,23 +29091,23 @@ function resolveAnalysisRoot(repoRoot, rootKind, worktreePath) {
28527
29091
  return repoRoot;
28528
29092
  }
28529
29093
  const wt = worktreePath?.trim();
28530
- if (wt && fs62.existsSync(path59.join(wt, ".git"))) {
28531
- return path59.resolve(wt);
29094
+ if (wt && fs63.existsSync(path60.join(wt, ".git"))) {
29095
+ return path60.resolve(wt);
28532
29096
  }
28533
29097
  throw new Error("worktree mode requires --worktree <path> to an existing analysis checkout.");
28534
29098
  }
28535
29099
  function resolveAdHocCheckoutRoot(_repoRoot, storage, worktreeFlag) {
28536
29100
  const w = worktreeFlag?.trim();
28537
29101
  if (w) {
28538
- const abs = path59.resolve(w);
28539
- if (fs62.existsSync(path59.join(abs, ".git"))) {
29102
+ const abs = path60.resolve(w);
29103
+ if (fs63.existsSync(path60.join(abs, ".git"))) {
28540
29104
  return abs;
28541
29105
  }
28542
29106
  throw new Error(`Invalid --worktree (not a git checkout): ${abs}`);
28543
29107
  }
28544
29108
  const snap = readAnalysisWorkspaceSnapshot(storage);
28545
29109
  const p = snap?.adHocWorktreePath?.trim();
28546
- if (p && fs62.existsSync(path59.join(p, ".git"))) {
29110
+ if (p && fs63.existsSync(path60.join(p, ".git"))) {
28547
29111
  return p;
28548
29112
  }
28549
29113
  throw new Error("No analysis checkout: run `easyspecs-cli run synthesis` first or pass `--worktree <path>`.");
@@ -28570,7 +29134,7 @@ async function runResumeRemediationPool(storage, repoRoot, analysisRoot, merged,
28570
29134
  requireOpenCode(merged, flags);
28571
29135
  const agentsDir = resolveOpenCodeAgentsDir(repoRoot, repoConfig);
28572
29136
  assertAgentsDirExists(agentsDir);
28573
- const ctxDir = path59.join(analysisRoot, ".gluecharm", "context");
29137
+ const ctxDir = path60.join(analysisRoot, ".gluecharm", "context");
28574
29138
  const snap = readArtefactRunSnapshot(storage);
28575
29139
  const rows = listMissingWorkstations(ctxDir, analysisRoot, snap);
28576
29140
  if (rows.length === 0) {
@@ -28588,7 +29152,7 @@ async function runResumeRemediationPool(storage, repoRoot, analysisRoot, merged,
28588
29152
  storageContext: storage,
28589
29153
  repositoryRoot: repoRoot,
28590
29154
  worktreeRoot: analysisRoot,
28591
- workspaceLabel: path59.basename(analysisRoot),
29155
+ workspaceLabel: path60.basename(analysisRoot),
28592
29156
  oc,
28593
29157
  log: (line) => logErr(flags, line),
28594
29158
  abortSignal: void 0,
@@ -28765,17 +29329,17 @@ async function main() {
28765
29329
  { easyspecs: { defaultGitRemoteUrl: url } },
28766
29330
  { warnMigration: (m) => logErr(flags, `[EasySpecs] ${m}`) }
28767
29331
  );
28768
- const path60 = easyspecsConfigPath(repoRoot);
29332
+ const path61 = easyspecsConfigPath(repoRoot);
28769
29333
  if (flags.json) {
28770
29334
  printJsonLine({
28771
29335
  command: "config set-git-remote",
28772
29336
  durationMs: Date.now() - t0,
28773
29337
  ok: true,
28774
- path: path60,
29338
+ path: path61,
28775
29339
  defaultGitRemoteUrl: cfg.easyspecs?.defaultGitRemoteUrl ?? ""
28776
29340
  });
28777
29341
  } else {
28778
- console.log(`Updated ${path60} \u2014 easyspecs.defaultGitRemoteUrl`);
29342
+ console.log(`Updated ${path61} \u2014 easyspecs.defaultGitRemoteUrl`);
28779
29343
  }
28780
29344
  process.exit(ExitCode.ok);
28781
29345
  } catch (e) {
@@ -28808,7 +29372,7 @@ async function main() {
28808
29372
  applyCliSessionPathFromRepoConfig(repoRoot, repoConfig);
28809
29373
  if (flags.sessionPath?.trim()) {
28810
29374
  const sp = flags.sessionPath.trim();
28811
- const abs = path59.isAbsolute(sp) ? path59.normalize(sp) : path59.resolve(repoRoot, sp);
29375
+ const abs = path60.isAbsolute(sp) ? path60.normalize(sp) : path60.resolve(repoRoot, sp);
28812
29376
  setCliSessionPathFromConfig(abs);
28813
29377
  }
28814
29378
  const apiResolved = initApiBaseUrlForCli(repoRoot, flags, repoConfig);
@@ -28865,20 +29429,18 @@ async function main() {
28865
29429
  logExitCodeSummary(ExitCode.usage, flags);
28866
29430
  process.exit(ExitCode.usage);
28867
29431
  }
28868
- const agentsDir = resolveOpenCodeAgentsDir(repoRoot, repoConfig);
28869
- const agentsOk = fs62.existsSync(agentsDir);
28870
- const oc = getOpenCodeReadiness({
28871
- executable: merged.openCodeExecutable,
28872
- skipCredentialsCheck: merged.openCodeSkipCredentialsCheck,
28873
- providerEnvFromConfig: merged.openCodeChildEnv
28874
- });
28875
- const lines = [
28876
- `cliVersion=${PKG_VERSION}`,
28877
- `repoRoot=${repoRoot}`,
28878
- `apiBaseUrl=${apiResolved || "(empty \u2014 stub auth only)"}`,
28879
- `opencode installed=${String(oc.installed)} credentialsReady=${String(oc.credentialsReady)}`,
28880
- `agentsDir=${agentsDir} exists=${String(agentsOk)}`
28881
- ];
29432
+ const readinessCtx = {
29433
+ cliVersion: PKG_VERSION,
29434
+ repoRootAbs: repoRoot,
29435
+ analysisRootAbs: repoRoot,
29436
+ apiBaseUrl: merged.apiBaseUrl,
29437
+ openCodeExecutable: merged.openCodeExecutable,
29438
+ openCodeSkipCredentialsCheck: merged.openCodeSkipCredentialsCheck,
29439
+ providerEnvFromConfig: merged.openCodeChildEnv,
29440
+ repoConfig
29441
+ };
29442
+ const facts = buildReadinessProbeFacts(readinessCtx);
29443
+ const lines = buildReadinessLineBlock(facts, readinessCtx);
28882
29444
  const inspectPayload = buildDoctorInspectPayload(merged, repoConfig);
28883
29445
  if (!flags.json) {
28884
29446
  const parts = [];
@@ -28894,6 +29456,12 @@ async function main() {
28894
29456
  if (modes.readiness) {
28895
29457
  envelope.lines = lines;
28896
29458
  envelope.cliVersion = PKG_VERSION;
29459
+ const jf = buildReadinessJsonFields(facts);
29460
+ envelope.modelConfigured = jf.modelConfigured;
29461
+ envelope.credentialsReady = jf.credentialsReady;
29462
+ envelope.openCodeConfigFiles = jf.openCodeConfigFiles;
29463
+ envelope.agentsDir = jf.agentsDir;
29464
+ envelope.agentsDirExists = jf.agentsDirExists;
28897
29465
  }
28898
29466
  if (modes.inspectConfig) {
28899
29467
  envelope.config = inspectPayload;
@@ -29012,7 +29580,7 @@ async function main() {
29012
29580
  finish(ExitCode.cancelled, { ok: false, error: "Remediation cancelled.", analysisWorktreePath: analysisRoot });
29013
29581
  }
29014
29582
  if (!poolRes.indexOk) {
29015
- finish(ExitCode.validation, {
29583
+ finish(OsExit.resumeSynthesisIndex, {
29016
29584
  ok: false,
29017
29585
  error: poolRes.indexError ?? "Index failed after remediation.",
29018
29586
  analysisWorktreePath: analysisRoot
@@ -29029,7 +29597,7 @@ async function main() {
29029
29597
  finish(ExitCode.cancelled, { ok: false, error: "Remediation cancelled.", analysisWorktreePath: analysisRoot });
29030
29598
  }
29031
29599
  if (!poolRes.indexOk) {
29032
- finish(ExitCode.validation, {
29600
+ finish(OsExit.resumeSynthesisIndex, {
29033
29601
  ok: false,
29034
29602
  error: poolRes.indexError ?? "Index failed after remediation.",
29035
29603
  analysisWorktreePath: analysisRoot
@@ -29045,7 +29613,7 @@ async function main() {
29045
29613
  const result = await runSynthesisPipeline(
29046
29614
  storage,
29047
29615
  repoRoot,
29048
- path59.basename(repoRoot),
29616
+ path60.basename(repoRoot),
29049
29617
  agentsDir,
29050
29618
  {
29051
29619
  ...merged.pipelineOpenCode
@@ -29082,7 +29650,7 @@ async function main() {
29082
29650
  adHocCreatedAtIso: (/* @__PURE__ */ new Date()).toISOString()
29083
29651
  });
29084
29652
  }
29085
- finish(result.cancelled ? ExitCode.cancelled : ExitCode.validation, {
29653
+ finish(result.cancelled ? ExitCode.cancelled : OsExit.runSynthesisPipeline, {
29086
29654
  ok: false,
29087
29655
  error: result.error ?? "run synthesis failed",
29088
29656
  cancelled: result.cancelled === true,
@@ -29100,7 +29668,7 @@ async function main() {
29100
29668
  if (sub === "reference-coverage") {
29101
29669
  const rootAbs = resolveAnalysisRoot(repoRoot, rootKind, worktree);
29102
29670
  requireMinimalGluecharmLayoutAt(rootAbs);
29103
- const contextDir2 = path59.join(rootAbs, ".gluecharm", "context");
29671
+ const contextDir2 = path60.join(rootAbs, ".gluecharm", "context");
29104
29672
  const res = runCoveragePipeline({
29105
29673
  repositoryRootAbs: rootAbs,
29106
29674
  contextDirAbs: contextDir2,
@@ -29110,20 +29678,20 @@ async function main() {
29110
29678
  const d = res.document;
29111
29679
  const maxPct = repoConfig.easyspecs?.diagnose?.zeroReference?.maxPercentNonReferenced;
29112
29680
  if (maxPct !== null && maxPct !== void 0 && Number.isFinite(maxPct) && d.metrics.percentNonReferenced > maxPct) {
29113
- finish(ExitCode.validation, {
29681
+ finish(OsExit.diagnoseReferenceCoverageThreshold, {
29114
29682
  ok: false,
29115
29683
  error: `percentNonReferenced ${String(d.metrics.percentNonReferenced)} > ${String(maxPct)}`
29116
29684
  });
29117
29685
  }
29118
29686
  finish(ExitCode.ok, { ok: true, percentNonReferenced: d.metrics.percentNonReferenced });
29119
29687
  } else {
29120
- finish(ExitCode.validation, { ok: false, error: res.error ?? "coverage failed" });
29688
+ finish(OsExit.diagnoseReferenceCoveragePipeline, { ok: false, error: res.error ?? "coverage failed" });
29121
29689
  }
29122
29690
  }
29123
29691
  if (sub === "coordination-duplicates") {
29124
29692
  const rootAbs = resolveAnalysisRoot(repoRoot, rootKind, worktree);
29125
29693
  requireMinimalGluecharmLayoutAt(rootAbs);
29126
- const contextDir2 = path59.join(rootAbs, ".gluecharm", "context");
29694
+ const contextDir2 = path60.join(rootAbs, ".gluecharm", "context");
29127
29695
  const res = runCoordinationDuplicatesDiagnosis({
29128
29696
  contextDirAbsolute: contextDir2,
29129
29697
  sourceRoot: rootKind === "worktree" ? "worktree" : "workspace"
@@ -29131,7 +29699,7 @@ async function main() {
29131
29699
  if (res.ok) {
29132
29700
  const strict = repoConfig.easyspecs?.diagnose?.coordinationDuplicates?.strict !== false;
29133
29701
  const bad = strict && ((res.groupCount ?? 0) > 0 || (res.orphanMarkdownCount ?? 0) > 0);
29134
- finish(bad ? ExitCode.validation : ExitCode.ok, {
29702
+ finish(bad ? OsExit.diagnoseCoordinationDuplicatesPolicy : ExitCode.ok, {
29135
29703
  ok: !bad,
29136
29704
  groupCount: res.groupCount,
29137
29705
  orphanMarkdownCount: res.orphanMarkdownCount,
@@ -29141,7 +29709,7 @@ async function main() {
29141
29709
  groupsByList: res.groupsByList
29142
29710
  });
29143
29711
  }
29144
- finish(ExitCode.validation, { ok: false, error: res.message ?? "duplicates failed" });
29712
+ finish(OsExit.diagnoseCoordinationDuplicatesEngine, { ok: false, error: res.message ?? "duplicates failed" });
29145
29713
  }
29146
29714
  if (sub === "coverage-report") {
29147
29715
  const rootAbs = resolveAnalysisRoot(repoRoot, rootKind, worktree);
@@ -29153,13 +29721,13 @@ async function main() {
29153
29721
  if (rep.ok) {
29154
29722
  finish(ExitCode.ok, { ok: true, reportPath: rep.outputAbsolutePath });
29155
29723
  } else {
29156
- finish(ExitCode.validation, { ok: false, error: rep.error ?? "report failed" });
29724
+ finish(OsExit.diagnoseCoverageReport, { ok: false, error: rep.error ?? "report failed" });
29157
29725
  }
29158
29726
  }
29159
29727
  if (sub === "missing-artefacts") {
29160
29728
  const rootAbs = resolveAnalysisRoot(repoRoot, rootKind, worktree);
29161
29729
  requireMinimalGluecharmLayoutAt(rootAbs);
29162
- const ctxDir = path59.join(rootAbs, ".gluecharm", "context");
29730
+ const ctxDir = path60.join(rootAbs, ".gluecharm", "context");
29163
29731
  const storage = createFileBackedWorkspaceState(repoRoot);
29164
29732
  const snap = readArtefactRunSnapshot(storage);
29165
29733
  const rows = listMissingWorkstations(ctxDir, rootAbs, snap);
@@ -29183,7 +29751,7 @@ async function main() {
29183
29751
  requireMinimalGluecharmLayoutAt(analysisRoot);
29184
29752
  const cov = readNonReferencedFilesFromRepositoryRoot(analysisRoot);
29185
29753
  if (!cov.ok) {
29186
- finish(ExitCode.validation, { ok: false, error: cov.error });
29754
+ finish(OsExit.diagnoseZeroReferenceReadCoverage, { ok: false, error: cov.error });
29187
29755
  } else {
29188
29756
  const zrPaths = cov.paths;
29189
29757
  if (zrPaths.length === 0) {
@@ -29209,10 +29777,10 @@ async function main() {
29209
29777
  });
29210
29778
  const bad = poolRes.cancelled || poolRes.failures > 0;
29211
29779
  if (!bad) {
29212
- const ctxDir = path59.join(analysisRoot, ".gluecharm", "context");
29780
+ const ctxDir = path60.join(analysisRoot, ".gluecharm", "context");
29213
29781
  const lg = runLinkMappingPipeline(ctxDir, { log: (line) => logErr(flags, line) });
29214
29782
  if (!lg.ok) {
29215
- finish(ExitCode.validation, {
29783
+ finish(OsExit.diagnoseZeroReferenceLinkMapping, {
29216
29784
  ok: false,
29217
29785
  completed: poolRes.completed,
29218
29786
  failures: poolRes.failures,
@@ -29222,7 +29790,7 @@ async function main() {
29222
29790
  });
29223
29791
  }
29224
29792
  }
29225
- finish(bad ? ExitCode.validation : ExitCode.ok, {
29793
+ finish(bad ? OsExit.diagnoseZeroReferencePool : ExitCode.ok, {
29226
29794
  ok: !bad,
29227
29795
  completed: poolRes.completed,
29228
29796
  failures: poolRes.failures,
@@ -29239,12 +29807,12 @@ async function main() {
29239
29807
  const worktree = wtExplicit ?? wtFromRoot;
29240
29808
  const rootAbs = resolveAnalysisRoot(repoRoot, rootKind, worktree);
29241
29809
  requireMinimalGluecharmLayoutAt(rootAbs);
29242
- const contextDir2 = path59.join(rootAbs, ".gluecharm", "context");
29810
+ const contextDir2 = path60.join(rootAbs, ".gluecharm", "context");
29243
29811
  const res = runLinkMappingPipeline(contextDir2, {
29244
29812
  log: (line) => logErr(flags, line)
29245
29813
  });
29246
29814
  if (!res.ok) {
29247
- finish(ExitCode.validation, {
29815
+ finish(OsExit.contextLinkGraph, {
29248
29816
  ok: false,
29249
29817
  contextDir: contextDir2,
29250
29818
  error: res.error,
@@ -29258,10 +29826,19 @@ async function main() {
29258
29826
  if (!refPath) {
29259
29827
  finish(ExitCode.usage, {
29260
29828
  ok: false,
29261
- error: "Usage: easyspecs-cli context drift <referencePath> [--label <slug>] [--index <path>] [--dry-run]"
29829
+ error: "Usage: easyspecs-cli context drift <referencePath> [--label <slug>] [--index <path>] [--dry-run] [--in-place|--no-worktree|--noworktree]"
29262
29830
  });
29263
29831
  }
29264
29832
  const parsedTail = parseContextDriftTail(pos.slice(3));
29833
+ const { rootKind, worktree: wtFromRoot } = parseTailFlags(parsedTail.rest);
29834
+ const { worktree: wtExplicit } = parseWorktreeFlag(parsedTail.rest);
29835
+ const extWorktree = wtExplicit ?? wtFromRoot;
29836
+ if (parsedTail.inPlace && (rootKind === "worktree" || typeof extWorktree === "string" && extWorktree.trim().length > 0)) {
29837
+ finish(ExitCode.usage, {
29838
+ ok: false,
29839
+ error: "`--no-worktree` cannot be combined with `--root worktree` or `--worktree <path>`."
29840
+ });
29841
+ }
29265
29842
  const leftover = stripRootWorktreeTokens(parsedTail.rest);
29266
29843
  if (leftover.length > 0) {
29267
29844
  finish(ExitCode.usage, {
@@ -29270,11 +29847,11 @@ async function main() {
29270
29847
  });
29271
29848
  }
29272
29849
  requireMinimalGluecharmLayoutAt(repoRoot);
29273
- if (!parsedTail.dryRun) {
29274
- requireOpenCode(merged, flags);
29275
- }
29850
+ const readinessLog = (line) => {
29851
+ process.stderr.write(`${line}
29852
+ `);
29853
+ };
29276
29854
  const agentsDir = resolveOpenCodeAgentsDir(repoRoot, repoConfig);
29277
- assertAgentsDirExists(agentsDir);
29278
29855
  const storage = createFileBackedWorkspaceState(repoRoot);
29279
29856
  const ctrl = new AbortController();
29280
29857
  const dres = await runContextDriftFactory({
@@ -29287,8 +29864,11 @@ async function main() {
29287
29864
  label: parsedTail.label,
29288
29865
  indexOverrideArg: parsedTail.index,
29289
29866
  dryRun: parsedTail.dryRun,
29867
+ inPlace: parsedTail.inPlace,
29290
29868
  signal: ctrl.signal,
29291
- log: (line) => logErr(flags, line)
29869
+ log: (line) => logErr(flags, line),
29870
+ cliVersion: PKG_VERSION,
29871
+ readinessLog
29292
29872
  });
29293
29873
  if (dres.exitOk && dres.ok) {
29294
29874
  if (dres.driftReportPath && !flags.json && !dres.dryRun) {
@@ -29298,19 +29878,29 @@ async function main() {
29298
29878
  finish(ExitCode.ok, driftPayload);
29299
29879
  }
29300
29880
  if (dres.ok === false) {
29301
- const row2 = contextDriftFactoryFailureRow(dres.code, dres.error);
29302
- const driftExit = contextDriftExitCodeFor(dres.code, dres.error);
29303
- const { exitOk: _driftOkB, ...driftRest } = dres;
29304
- const envelope = {
29305
- ...driftRest,
29306
- ok: false,
29307
- factoryFailures: [row2],
29308
- error: composeFactoryValidationError(dres.error, [row2])
29309
- };
29310
- if (driftExit === ExitCode.validation) {
29311
- Object.assign(envelope, primaryFailureAliases([row2]));
29881
+ if (dres.code === "READINESS_FAILED") {
29882
+ const ec = dres.readinessExitCode ?? OsExit.readinessOpenCodeCredentials;
29883
+ const { exitOk: _ex, ...driftRest } = dres;
29884
+ finish(ec, {
29885
+ ...driftRest,
29886
+ ok: false,
29887
+ exitCode: ec
29888
+ });
29889
+ } else {
29890
+ const row2 = contextDriftFactoryFailureRow(dres.code, dres.error);
29891
+ const driftExit = contextDriftExitCodeFor(dres.code, dres.error);
29892
+ const { exitOk: _driftOkB, ...driftRest } = dres;
29893
+ const envelope = {
29894
+ ...driftRest,
29895
+ ok: false,
29896
+ factoryFailures: [row2],
29897
+ error: composeFactoryValidationError(dres.error, [row2])
29898
+ };
29899
+ if (isContextDriftSrs70ValidationExit(driftExit)) {
29900
+ Object.assign(envelope, primaryFailureAliases([row2]));
29901
+ }
29902
+ finish(driftExit, envelope);
29312
29903
  }
29313
- finish(driftExit, envelope);
29314
29904
  }
29315
29905
  finish(ExitCode.internal, { ok: false, error: "Unexpected context drift result shape." });
29316
29906
  }
@@ -29319,6 +29909,9 @@ async function main() {
29319
29909
  if (a === "--force-new-context-analysis") {
29320
29910
  continue;
29321
29911
  }
29912
+ if (a === "--no-worktree" || a === "--noworktree" || a === "--in-place") {
29913
+ continue;
29914
+ }
29322
29915
  if (a === "--upload") {
29323
29916
  finish(ExitCode.usage, {
29324
29917
  ok: false,
@@ -29333,10 +29926,11 @@ async function main() {
29333
29926
  }
29334
29927
  finish(ExitCode.usage, {
29335
29928
  ok: false,
29336
- error: `unknown analysis flag: ${a} (allowed: --force-new-context-analysis)`
29929
+ error: `unknown analysis flag: ${a} (allowed: --force-new-context-analysis, --in-place, --no-worktree, --noworktree)`
29337
29930
  });
29338
29931
  }
29339
29932
  const forceNewContextAnalysis = positionals.includes("--force-new-context-analysis");
29933
+ const analysisInPlace = positionals.includes("--no-worktree") || positionals.includes("--noworktree") || positionals.includes("--in-place");
29340
29934
  const cloudCached = readEasyspecsMergedSetting(
29341
29935
  repoConfig.easyspecs,
29342
29936
  "easyspecs.factory.cloudContextAnalyzed"
@@ -29359,11 +29953,19 @@ async function main() {
29359
29953
  });
29360
29954
  }
29361
29955
  requireMinimalGluecharmLayoutAt(repoRoot);
29362
- requireOpenCode(merged, flags);
29363
29956
  const agentsDir = resolveOpenCodeAgentsDir(repoRoot, repoConfig);
29364
- assertAgentsDirExists(agentsDir);
29365
29957
  const storage = createFileBackedWorkspaceState(repoRoot);
29366
29958
  const ctrl = new AbortController();
29959
+ const analysisReadinessCtx = {
29960
+ cliVersion: PKG_VERSION,
29961
+ repoRootAbs: repoRoot,
29962
+ analysisRootAbs: repoRoot,
29963
+ apiBaseUrl: merged.apiBaseUrl,
29964
+ openCodeExecutable: merged.openCodeExecutable,
29965
+ openCodeSkipCredentialsCheck: merged.openCodeSkipCredentialsCheck,
29966
+ providerEnvFromConfig: merged.openCodeChildEnv,
29967
+ repoConfig
29968
+ };
29367
29969
  const deps = buildFactoryDepsHeadless({
29368
29970
  storageContext: storage,
29369
29971
  repoRoot,
@@ -29374,15 +29976,22 @@ async function main() {
29374
29976
  }),
29375
29977
  log: (line) => logErr(flags, line),
29376
29978
  signal: ctrl.signal,
29377
- skipBackendSync: true
29979
+ skipBackendSync: true,
29980
+ inPlace: analysisInPlace,
29981
+ readiness: analysisReadinessCtx
29378
29982
  });
29379
29983
  const res = await runGenerateContextFactory(deps);
29380
29984
  if (res.ok && res.cancelled !== true && flags.promote !== false) {
29381
29985
  const snap = readAnalysisWorkspaceSnapshot(storage);
29382
29986
  const wt = snap?.adHocWorktreePath?.trim();
29383
29987
  if (wt) {
29384
- const sourceCtx = path59.join(wt, ".gluecharm", "context");
29385
- if (fs62.existsSync(sourceCtx)) {
29988
+ const sourceCtx = path60.join(wt, ".gluecharm", "context");
29989
+ if (path60.resolve(wt) === path60.resolve(repoRoot)) {
29990
+ logErr(
29991
+ flags,
29992
+ "[pipeline:analysis] promote skipped (in-place: analysis checkout is the repository root)"
29993
+ );
29994
+ } else if (fs63.existsSync(sourceCtx)) {
29386
29995
  const n = promoteContextDirectoryToWorkspaceFs(sourceCtx, repoRoot);
29387
29996
  logErr(flags, `[pipeline:analysis] promoted ${String(n.filesCopied)} file(s) \u2192 ${repoRoot}`);
29388
29997
  } else {
@@ -29402,16 +30011,24 @@ async function main() {
29402
30011
  ok: res.ok,
29403
30012
  cancelled: res.cancelled,
29404
30013
  totalElapsedMs: res.totalElapsedMs,
29405
- error: res.message
30014
+ error: res.message,
30015
+ ...analysisInPlace ? { analysisInPlace: true } : {}
29406
30016
  };
29407
30017
  if (!res.ok && !res.cancelled && res.factoryFailures && res.factoryFailures.length > 0) {
29408
30018
  analysisEnvelope.factoryFailures = res.factoryFailures;
29409
30019
  Object.assign(analysisEnvelope, primaryFailureAliases(res.factoryFailures));
29410
30020
  analysisEnvelope.error = composeFactoryValidationError(res.message, res.factoryFailures);
29411
30021
  }
29412
- finish(res.ok ? ExitCode.ok : res.cancelled ? ExitCode.cancelled : ExitCode.validation, analysisEnvelope);
30022
+ if (res.readinessFailure) {
30023
+ Object.assign(analysisEnvelope, res.readinessFailure);
30024
+ }
30025
+ finish(
30026
+ res.ok ? ExitCode.ok : res.cancelled ? ExitCode.cancelled : processExitFromNormalizedFactoryFailures(res.factoryFailures),
30027
+ analysisEnvelope
30028
+ );
29413
30029
  }
29414
30030
  if (pos[0] === "update" && pos[1] === "context") {
30031
+ let updateContextInPlace = false;
29415
30032
  for (const a of pos.slice(2)) {
29416
30033
  if (a === "--upload") {
29417
30034
  finish(ExitCode.usage, {
@@ -29419,14 +30036,20 @@ async function main() {
29419
30036
  error: "Removed flag: update context --upload. Run `easyspecs-cli upload context` or `upload republish` after update context completes."
29420
30037
  });
29421
30038
  }
30039
+ if (a === "--no-worktree" || a === "--noworktree" || a === "--in-place") {
30040
+ updateContextInPlace = true;
30041
+ continue;
30042
+ }
29422
30043
  finish(ExitCode.usage, { ok: false, error: `unknown update context flag: ${a}` });
29423
30044
  }
29424
30045
  requireMinimalGluecharmLayoutAt(repoRoot);
29425
- requireOpenCode(merged, flags);
29426
30046
  const agentsDir = resolveOpenCodeAgentsDir(repoRoot, repoConfig);
29427
- assertAgentsDirExists(agentsDir);
29428
30047
  const storage = createFileBackedWorkspaceState(repoRoot);
29429
30048
  const ctrl = new AbortController();
30049
+ const readinessLog = (line) => {
30050
+ process.stderr.write(`${line}
30051
+ `);
30052
+ };
29430
30053
  const ures = await runUpdateContextFactory({
29431
30054
  repoRootAbs: repoRoot,
29432
30055
  repoConfig,
@@ -29434,10 +30057,13 @@ async function main() {
29434
30057
  agentsDirFs: agentsDir,
29435
30058
  storage,
29436
30059
  signal: ctrl.signal,
29437
- log: (line) => logErr(flags, line)
30060
+ log: (line) => logErr(flags, line),
30061
+ inPlace: updateContextInPlace,
30062
+ cliVersion: PKG_VERSION,
30063
+ readinessLog
29438
30064
  });
29439
30065
  const { exitOk, ...payload } = ures;
29440
- const code = exitOk ? ExitCode.ok : ures.code === "MISSING_BASELINE" ? ExitCode.usage : ExitCode.validation;
30066
+ const code = exitOk ? ExitCode.ok : ures.code === "MISSING_BASELINE" ? ExitCode.usage : ures.code === "READINESS_FAILED" && typeof ures.readinessExitCode === "number" ? ures.readinessExitCode : OsExit.updateContextFactory;
29441
30067
  finish(code, payload);
29442
30068
  }
29443
30069
  if (pos[0] === "download" && pos[1] === "context") {
@@ -29462,10 +30088,10 @@ async function main() {
29462
30088
  finish(ExitCode.usage, { ok: false, error: `unknown download context flag: ${a}` });
29463
30089
  }
29464
30090
  requireMinimalGluecharmLayoutAt(repoRoot);
29465
- const ctxDir = path59.resolve(path59.join(repoRoot, ".gluecharm", "context"));
29466
- const gluecharmParent = path59.dirname(ctxDir);
29467
- if (path59.basename(gluecharmParent) === ".gluecharm" && path59.basename(ctxDir) === "context") {
29468
- requireMinimalGluecharmLayoutAt(path59.dirname(gluecharmParent));
30091
+ const ctxDir = path60.resolve(path60.join(repoRoot, ".gluecharm", "context"));
30092
+ const gluecharmParent = path60.dirname(ctxDir);
30093
+ if (path60.basename(gluecharmParent) === ".gluecharm" && path60.basename(ctxDir) === "context") {
30094
+ requireMinimalGluecharmLayoutAt(path60.dirname(gluecharmParent));
29469
30095
  }
29470
30096
  const appIdRaw = getEasyspecsProjectIdFromRepoConfig(repoConfig)?.trim();
29471
30097
  if (!appIdRaw) {
@@ -29548,16 +30174,16 @@ async function main() {
29548
30174
  }
29549
30175
  const sess = sessRaw;
29550
30176
  requireMinimalGluecharmLayoutAt(repoRoot);
29551
- let ctxDir = path59.join(repoRoot, ".gluecharm", "context");
30177
+ let ctxDir = path60.join(repoRoot, ".gluecharm", "context");
29552
30178
  if (pos[1] === "republish") {
29553
30179
  const fromCfg = repoConfig.easyspecs?.upload?.contextDirectory?.trim();
29554
- const resolvedOverride = fromCfg && fromCfg.length > 0 ? path59.isAbsolute(fromCfg) ? path59.normalize(fromCfg) : path59.resolve(repoRoot, fromCfg) : "";
29555
- if (resolvedOverride && fs62.existsSync(path59.join(resolvedOverride, ".."))) {
30180
+ const resolvedOverride = fromCfg && fromCfg.length > 0 ? path60.isAbsolute(fromCfg) ? path60.normalize(fromCfg) : path60.resolve(repoRoot, fromCfg) : "";
30181
+ if (resolvedOverride && fs63.existsSync(path60.join(resolvedOverride, ".."))) {
29556
30182
  ctxDir = resolvedOverride;
29557
30183
  } else {
29558
30184
  const storage = createFileBackedWorkspaceState(repoRoot);
29559
30185
  const snap = readAnalysisWorkspaceSnapshot(storage);
29560
- const wt = snap?.adHocWorktreePath && fs62.existsSync(path59.join(snap.adHocWorktreePath, ".gluecharm", "context")) ? path59.join(snap.adHocWorktreePath, ".gluecharm", "context") : "";
30186
+ const wt = snap?.adHocWorktreePath && fs63.existsSync(path60.join(snap.adHocWorktreePath, ".gluecharm", "context")) ? path60.join(snap.adHocWorktreePath, ".gluecharm", "context") : "";
29561
30187
  if (!wt) {
29562
30188
  finish(ExitCode.misconfiguration, {
29563
30189
  ok: false,
@@ -29567,10 +30193,10 @@ async function main() {
29567
30193
  ctxDir = wt;
29568
30194
  }
29569
30195
  }
29570
- const ctxResolved = path59.resolve(ctxDir);
29571
- const gluecharmParent = path59.dirname(ctxResolved);
29572
- if (path59.basename(gluecharmParent) === ".gluecharm" && path59.basename(ctxResolved) === "context") {
29573
- requireMinimalGluecharmLayoutAt(path59.dirname(gluecharmParent));
30196
+ const ctxResolved = path60.resolve(ctxDir);
30197
+ const gluecharmParent = path60.dirname(ctxResolved);
30198
+ if (path60.basename(gluecharmParent) === ".gluecharm" && path60.basename(ctxResolved) === "context") {
30199
+ requireMinimalGluecharmLayoutAt(path60.dirname(gluecharmParent));
29574
30200
  }
29575
30201
  const appIdRaw = getEasyspecsProjectIdFromRepoConfig(repoConfig)?.trim();
29576
30202
  if (!appIdRaw) {
@@ -29674,18 +30300,18 @@ async function main() {
29674
30300
  finish(failed ? ExitCode.upload : ExitCode.ok, primary);
29675
30301
  }
29676
30302
  if (pos[0] === "ace" && pos[1] === "clear") {
29677
- const learnings = path59.join(repoRoot, ".gluecharm", "context", "learnings");
29678
- if (!fs62.existsSync(learnings)) {
30303
+ const learnings = path60.join(repoRoot, ".gluecharm", "context", "learnings");
30304
+ if (!fs63.existsSync(learnings)) {
29679
30305
  finish(ExitCode.ok, { ok: true, message: "nothing to clear" });
29680
30306
  }
29681
- fs62.rmSync(learnings, { recursive: true, force: true });
30307
+ fs63.rmSync(learnings, { recursive: true, force: true });
29682
30308
  finish(ExitCode.ok, { ok: true, message: `cleared ${learnings}` });
29683
30309
  }
29684
30310
  if (pos[0] === "ace" && pos[1] === "learn") {
29685
30311
  requireOpenCode(merged, flags);
29686
30312
  const { worktree } = parseWorktreeFlag(pos.slice(2));
29687
- const root = worktree && fs62.existsSync(path59.join(worktree, ".opencode", "schemas", "ace")) ? worktree : repoRoot;
29688
- const contextDir2 = path59.join(root, ".gluecharm", "context");
30313
+ const root = worktree && fs63.existsSync(path60.join(worktree, ".opencode", "schemas", "ace")) ? worktree : repoRoot;
30314
+ const contextDir2 = path60.join(root, ".gluecharm", "context");
29689
30315
  const traces = listAceTraceFiles(contextDir2);
29690
30316
  if (traces.length === 0) {
29691
30317
  finish(ExitCode.ok, { ok: true, message: "no traces", traceCount: 0 });
@@ -29700,7 +30326,7 @@ async function main() {
29700
30326
  diagnosticLog: (line) => logErr(flags, line)
29701
30327
  });
29702
30328
  if (!res.ok) {
29703
- finish(ExitCode.validation, { ok: false, error: res.message });
30329
+ finish(OsExit.aceLearnTrace, { ok: false, error: res.message });
29704
30330
  }
29705
30331
  okCount += 1;
29706
30332
  }
@@ -29709,8 +30335,8 @@ async function main() {
29709
30335
  if (pos[0] === "ace" && pos[1] === "auto-learn") {
29710
30336
  requireOpenCode(merged, flags);
29711
30337
  const { worktree } = parseWorktreeFlag(pos.slice(2));
29712
- const root = worktree && fs62.existsSync(path59.join(worktree, ".git")) ? worktree : repoRoot;
29713
- const contextDir2 = path59.join(root, ".gluecharm", "context");
30338
+ const root = worktree && fs63.existsSync(path60.join(worktree, ".git")) ? worktree : repoRoot;
30339
+ const contextDir2 = path60.join(root, ".gluecharm", "context");
29714
30340
  const pending = listPendingAceTraceFiles(contextDir2, root);
29715
30341
  if (pending.length === 0) {
29716
30342
  finish(ExitCode.ok, { ok: true, pending: 0 });
@@ -29726,7 +30352,7 @@ async function main() {
29726
30352
  diagnosticLog: (line) => logErr(flags, line)
29727
30353
  }
29728
30354
  });
29729
- finish(pool.failed ? ExitCode.validation : ExitCode.ok, {
30355
+ finish(pool.failed ? OsExit.aceAutoLearnPool : ExitCode.ok, {
29730
30356
  ok: pool.failed === 0,
29731
30357
  completed: pool.completed,
29732
30358
  failed: pool.failed,