@gluecharm-lab/easyspecs-cli 0.1.1 → 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,8 +10636,8 @@ 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
10643
  var OsExit = {
@@ -10672,7 +10672,15 @@ var OsExit = {
10672
10672
  runSynthesisPipeline: 80,
10673
10673
  aceLearnTrace: 81,
10674
10674
  aceAutoLearnPool: 82,
10675
- updateContextFactory: 83
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
10676
10684
  };
10677
10685
  var ExitCode = {
10678
10686
  ok: 0,
@@ -10765,6 +10773,14 @@ function describeExitCode(code) {
10765
10773
  return "ace auto-learn: one or more learn runs failed.";
10766
10774
  case OsExit.updateContextFactory:
10767
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.";
10768
10784
  default:
10769
10785
  return `Non-zero exit (${String(code)}) \u2014 see stderr and any JSON \`error\` field for detail.`;
10770
10786
  }
@@ -10794,6 +10810,12 @@ var {
10794
10810
  } = import_index.default;
10795
10811
 
10796
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
+ }
10797
10819
  function createEasyspecsCliProgram() {
10798
10820
  const program2 = new Command();
10799
10821
  program2.name("easyspecs-cli").allowExcessArguments(false).enablePositionalOptions();
@@ -10811,7 +10833,9 @@ function createEasyspecsCliProgram() {
10811
10833
  const runSynthesis = run.command("synthesis").description("Run synthesis pipeline");
10812
10834
  runSynthesis.command("resume-missing").description("Resume remediation pool for missing artefacts").option("--worktree <path>", "Path to an analysis checkout");
10813
10835
  runSynthesis.command("resume-synthesis").description("Resume synthesis pipeline").option("--worktree <path>", "Path to an analysis checkout");
10814
- 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);
10815
10839
  const diagnose = program2.command("diagnose").description("Deterministic diagnostics");
10816
10840
  const addRootAndWorktree = (c) => c.option("--root <root>", "workspace|worktree").option("--worktree <path>", "Path to an analysis checkout");
10817
10841
  addRootAndWorktree(diagnose.command("reference-coverage").description("Compute reference coverage"));
@@ -10821,11 +10845,12 @@ function createEasyspecsCliProgram() {
10821
10845
  diagnose.command("zero-reference").description("Run zero-reference remediation").option("--worktree <path>", "Path to an analysis checkout");
10822
10846
  const context = program2.command("context").description("Context operations");
10823
10847
  addRootAndWorktree(context.command("link-graph").description("Validate EasySpecs navigation links in context markdown"));
10824
- addRootAndWorktree(
10825
- 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")
10826
- );
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);
10827
10851
  const update = program2.command("update").description("Incremental context refresh");
10828
- 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);
10829
10854
  const download = program2.command("download").description("Download resources");
10830
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");
10831
10856
  const upload = program2.command("upload").description("Upload resources");
@@ -12662,7 +12687,7 @@ function stringifyForSrs13Debug(value) {
12662
12687
  return truncateForSrs13DebugLog(String(value));
12663
12688
  }
12664
12689
  }
12665
- function logSrs13HttpDebug(log, path60, method, requestBody, error) {
12690
+ function logSrs13HttpDebug(log, path61, method, requestBody, error) {
12666
12691
  if (!log) {
12667
12692
  return;
12668
12693
  }
@@ -12672,7 +12697,7 @@ function logSrs13HttpDebug(log, path60, method, requestBody, error) {
12672
12697
  } catch {
12673
12698
  bodyBytes = 0;
12674
12699
  }
12675
- 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):`);
12676
12701
  log(stringifyForSrs13Debug(requestBody));
12677
12702
  const raw = httpApiResponseBody(error);
12678
12703
  const status = error && typeof error === "object" && "status" in error ? Number(error.status) : void 0;
@@ -14369,9 +14394,9 @@ function parsePsRssDarwinKilobytes(stdout) {
14369
14394
  return n;
14370
14395
  }
14371
14396
  function readLinuxPidRssBytes(pid) {
14372
- const path60 = `/proc/${pid}/status`;
14397
+ const path61 = `/proc/${pid}/status`;
14373
14398
  try {
14374
- const content = fs18.readFileSync(path60, "utf8");
14399
+ const content = fs18.readFileSync(path61, "utf8");
14375
14400
  const kb = parseVmRssKilobytesFromProcStatus(content);
14376
14401
  if (kb === null) {
14377
14402
  return { kind: "unknown", reason: "VmRSS_missing" };
@@ -14559,9 +14584,9 @@ function runOpenCodeAgent(cwd, args, options) {
14559
14584
  log?.(`${procTag} command: ${formatCliCommandForLog(cmd, args)}`);
14560
14585
  log?.(`${procTag} cwd: ${JSON.stringify(cwd)}`);
14561
14586
  log?.(`${procTag} argv: ${JSON.stringify(args)}`);
14562
- return new Promise((resolve20) => {
14587
+ return new Promise((resolve23) => {
14563
14588
  if (sig?.aborted) {
14564
- resolve20({ ok: false, message: "Stopped by user.", cancelled: true });
14589
+ resolve23({ ok: false, message: "Stopped by user.", cancelled: true });
14565
14590
  return;
14566
14591
  }
14567
14592
  const spawnEnv = options?.childEnv && Object.keys(options.childEnv).length > 0 ? { ...process.env, ...options.childEnv } : process.env;
@@ -14656,7 +14681,7 @@ ${truncateForDiag(outBody, DIAG_STDOUT_MAX)}`);
14656
14681
  if (diag) {
14657
14682
  finishDiag(diag.label, diag.code, diag.dumpStreams);
14658
14683
  }
14659
- resolve20(result);
14684
+ resolve23(result);
14660
14685
  };
14661
14686
  let onAbort;
14662
14687
  const clearAbortHandler = () => {
@@ -19091,6 +19116,23 @@ function readHeadBranchShort(repoRoot) {
19091
19116
  const b = (r.stdout ?? "").trim();
19092
19117
  return b.length > 0 ? b : void 0;
19093
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
+ }
19094
19136
  function attachWorktreeHandle(worktreePath, repositoryRoot) {
19095
19137
  const wt = path27.resolve(worktreePath);
19096
19138
  const repo = path27.resolve(repositoryRoot);
@@ -21363,8 +21405,8 @@ async function drainWorkstationPool(p) {
21363
21405
  const artefactRunId = readArtefactRunSnapshot(storageContext)?.runId ?? "unknown-run";
21364
21406
  let active = 0;
21365
21407
  let wake;
21366
- const waitTurn = () => new Promise((resolve20) => {
21367
- wake = resolve20;
21408
+ const waitTurn = () => new Promise((resolve23) => {
21409
+ wake = resolve23;
21368
21410
  });
21369
21411
  const persist = async () => {
21370
21412
  const items = {};
@@ -21533,6 +21575,26 @@ async function prepareSynthesisWorktree(storageContext, repoRoot, log, options)
21533
21575
  if (options?.clearPriorArtefactRun !== false) {
21534
21576
  await clearArtefactRun(storageContext);
21535
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
+ }
21536
21598
  const wt = createAnalysisWorktree(repoRoot, { log });
21537
21599
  if (!wt.ok) {
21538
21600
  return { ok: false, error: wt.error };
@@ -21691,6 +21753,7 @@ function promoteContextDirectoryToWorkspaceFs(sourceContextDir, workspaceRootFs)
21691
21753
 
21692
21754
  // src/shared/factoryPipelineExitConditions.ts
21693
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).",
21694
21757
  create_analysis_worktree: "Git analysis checkout exists under the configured temp parent (SRS-8); ready for agent materialization.",
21695
21758
  materialize_opencode_agents: "Bundled OpenCode agent definitions are copied into the analysis worktree (`.opencode/` tree).",
21696
21759
  synthesis_convergence: "Missing artefact count is 0. May run again after remediation (R5) if a refreshed check finds new expected outputs.",
@@ -21702,6 +21765,208 @@ var FACTORY_PIPELINE_EXIT_CONDITIONS = {
21702
21765
  backend_context_sync: "Context upload finished with no failures (quiet SRS-13 path; or cancel)."
21703
21766
  };
21704
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
+
21705
21970
  // src/factory/factoryValidationFailures.ts
21706
21971
  function factoryFailureDisplayId(row2) {
21707
21972
  return row2.failureExitId;
@@ -21732,6 +21997,7 @@ function normalizeFactoryFailureRow(r) {
21732
21997
  return { ...base, validationExitId: r.validationExitId ?? failureExitId };
21733
21998
  }
21734
21999
  var FACTORY_VALIDATION_PHASE_ORDER = [
22000
+ "diagnose_readiness",
21735
22001
  "create_analysis_worktree",
21736
22002
  "materialize_opencode_agents",
21737
22003
  "synthesis_convergence",
@@ -21747,6 +22013,7 @@ var ERROR_JOIN_MAX = 900;
21747
22013
  var ADDITIONAL_APPEND_MAX = 200;
21748
22014
  var PHASE_TO_OS_EXIT = {
21749
22015
  unknown_factory_phase: OsExit.factoryUnknown,
22016
+ diagnose_readiness: OsExit.readinessOpenCodeModel,
21750
22017
  create_analysis_worktree: OsExit.createAnalysisWorktree,
21751
22018
  materialize_opencode_agents: OsExit.materializeOpenCodeAgents,
21752
22019
  synthesis_convergence: OsExit.synthesisConvergence,
@@ -21759,6 +22026,7 @@ var PHASE_TO_OS_EXIT = {
21759
22026
  };
21760
22027
  var TITLE_BY_PHASE = {
21761
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.",
21762
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.",
21763
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.",
21764
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.",
@@ -21770,6 +22038,7 @@ var TITLE_BY_PHASE = {
21770
22038
  backend_context_sync: "Upload / cloud sync after analysis did not succeed. Check auth, project id, network, and upload error details."
21771
22039
  };
21772
22040
  var READABLE_PHASE_LABEL = {
22041
+ diagnose_readiness: "Diagnose readiness",
21773
22042
  create_analysis_worktree: "Analysis worktree",
21774
22043
  materialize_opencode_agents: "OpenCode agents",
21775
22044
  synthesis_convergence: "Synthesis",
@@ -21835,13 +22104,13 @@ function buildFactoryFailuresFromRows(phases) {
21835
22104
  const failed = phases.filter((p) => p.status === "failed");
21836
22105
  failed.sort((a, b) => phaseIndex(a.key) - phaseIndex(b.key));
21837
22106
  const semantic = failed.map((p) => {
21838
- const os7 = phaseToSemanticOsExitForGenerateContext(p.key);
22107
+ const os8 = phaseToSemanticOsExitForGenerateContext(p.key);
21839
22108
  const sub = inferValidationSubcode(p.key, p.detail);
21840
- const fid = failureExitIdFromParts(os7, 0);
22109
+ const fid = failureExitIdFromParts(os8, 0);
21841
22110
  return {
21842
22111
  factory: "generate_context",
21843
22112
  phase: p.key,
21844
- exitCode: os7,
22113
+ exitCode: os8,
21845
22114
  failureExitId: fid,
21846
22115
  validationExitId: fid,
21847
22116
  title: titleForGenerateContextPhase(p.key),
@@ -21906,6 +22175,7 @@ function composeFactoryValidationError(orchestratorMessage, failures) {
21906
22175
 
21907
22176
  // src/factory/generateContextFactory.ts
21908
22177
  var FACTORY_PIPELINE_KEYS = [
22178
+ "diagnose_readiness",
21909
22179
  "create_analysis_worktree",
21910
22180
  "materialize_opencode_agents",
21911
22181
  "synthesis_convergence",
@@ -21934,7 +22204,7 @@ function sleepUntilAborted(ms, signal) {
21934
22204
  if (signal.aborted) {
21935
22205
  return Promise.reject(new DOMException("The operation was aborted.", "AbortError"));
21936
22206
  }
21937
- return new Promise((resolve20, reject) => {
22207
+ return new Promise((resolve23, reject) => {
21938
22208
  const onAbort = () => {
21939
22209
  clearTimeout(t);
21940
22210
  signal.removeEventListener("abort", onAbort);
@@ -21942,7 +22212,7 @@ function sleepUntilAborted(ms, signal) {
21942
22212
  };
21943
22213
  const t = setTimeout(() => {
21944
22214
  signal.removeEventListener("abort", onAbort);
21945
- resolve20();
22215
+ resolve23();
21946
22216
  }, ms);
21947
22217
  signal.addEventListener("abort", onAbort, { once: true });
21948
22218
  });
@@ -22041,6 +22311,59 @@ async function runGenerateContextFactory(deps) {
22041
22311
  };
22042
22312
  let pingPong = 0;
22043
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
+ }
22044
22367
  outer: while (true) {
22045
22368
  if (isAborted(signal)) {
22046
22369
  setRowTimed("synthesis_convergence", "cancelled", "Stopped.");
@@ -22057,7 +22380,15 @@ async function runGenerateContextFactory(deps) {
22057
22380
  return fin({ ok: false, cancelled: true, message: "Factory stopped.", totalElapsedMs: macroEnd() });
22058
22381
  }
22059
22382
  if (!resumeSynthesis) {
22060
- 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
+ }
22061
22392
  await post();
22062
22393
  const wtRes = await deps.runPrepareAnalysisWorktree(false);
22063
22394
  if (!wtRes.ok) {
@@ -22065,7 +22396,15 @@ async function runGenerateContextFactory(deps) {
22065
22396
  await post();
22066
22397
  return fail(wtRes.error ?? "Worktree creation failed.");
22067
22398
  }
22068
- 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
+ }
22069
22408
  await post();
22070
22409
  if (isAborted(signal)) {
22071
22410
  setRowTimed("materialize_opencode_agents", "cancelled");
@@ -22371,8 +22710,8 @@ async function runGenerateContextFactory(deps) {
22371
22710
  }
22372
22711
 
22373
22712
  // src/factory/generateContextFactoryHeadlessHost.ts
22374
- var fs47 = __toESM(require("node:fs"));
22375
- var path43 = __toESM(require("node:path"));
22713
+ var fs48 = __toESM(require("node:fs"));
22714
+ var path44 = __toESM(require("node:path"));
22376
22715
 
22377
22716
  // src/stores/pipelineRunStore.ts
22378
22717
  var STORAGE_KEY2 = SRS53_PIPELINE_RUN_KEY_V2;
@@ -22472,12 +22811,12 @@ async function noteAgentsMaterialized(context) {
22472
22811
  }
22473
22812
 
22474
22813
  // src/pipelines/remediation/missingWorkstations.ts
22475
- var fs40 = __toESM(require("fs"));
22476
- var path35 = __toESM(require("path"));
22814
+ var fs41 = __toESM(require("fs"));
22815
+ var path36 = __toESM(require("path"));
22477
22816
 
22478
22817
  // src/analysis/analysisDetailMarkdownDiscovery.ts
22479
- var fs39 = __toESM(require("fs"));
22480
- var path34 = __toESM(require("path"));
22818
+ var fs40 = __toESM(require("fs"));
22819
+ var path35 = __toESM(require("path"));
22481
22820
  var SLUG4 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
22482
22821
  var FE2 = /^FE-\d+$/;
22483
22822
  var UC2 = /^UC-\d+$/;
@@ -22498,7 +22837,7 @@ var STEM_TO_AGENT = {
22498
22837
  };
22499
22838
  function readJson5(filePath) {
22500
22839
  try {
22501
- let raw = fs39.readFileSync(filePath, "utf-8");
22840
+ let raw = fs40.readFileSync(filePath, "utf-8");
22502
22841
  if (raw.length > 0 && raw.charCodeAt(0) === 65279) {
22503
22842
  raw = raw.slice(1);
22504
22843
  }
@@ -22539,7 +22878,7 @@ function expectedFeatureDetailBasenameFromRow(row2) {
22539
22878
  return `${code}-${slug}.md`;
22540
22879
  }
22541
22880
  function ctxPath(contextDir2, basename17) {
22542
- return path34.join(contextDir2, basename17);
22881
+ return path35.join(contextDir2, basename17);
22543
22882
  }
22544
22883
  function pushTarget(targets, stem, outputBasename, taskDescription, contextDir2) {
22545
22884
  const meta = STEM_TO_AGENT[stem];
@@ -22555,7 +22894,7 @@ function pushTarget(targets, stem, outputBasename, taskDescription, contextDir2)
22555
22894
  function discoverDetailMarkdownGroups(contextDir2) {
22556
22895
  const groups = [];
22557
22896
  const featureTargets = [];
22558
- const flPath = path34.join(contextDir2, "features-list.json");
22897
+ const flPath = path35.join(contextDir2, "features-list.json");
22559
22898
  const fl = readJson5(flPath);
22560
22899
  const features = Array.isArray(fl?.features) ? fl.features : [];
22561
22900
  for (const row2 of features) {
@@ -22585,7 +22924,7 @@ function discoverDetailMarkdownGroups(contextDir2) {
22585
22924
  if (!FE2.test(feCode)) {
22586
22925
  continue;
22587
22926
  }
22588
- const ucListPath = path34.join(contextDir2, `${feCode}-use-cases-list.json`);
22927
+ const ucListPath = path35.join(contextDir2, `${feCode}-use-cases-list.json`);
22589
22928
  const ucFile = readJson5(ucListPath);
22590
22929
  const ucs = Array.isArray(ucFile?.useCases) ? ucFile.useCases : [];
22591
22930
  for (const ucRow of ucs) {
@@ -22605,7 +22944,7 @@ function discoverDetailMarkdownGroups(contextDir2) {
22605
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.`,
22606
22945
  contextDir2
22607
22946
  );
22608
- const scPath = path34.join(contextDir2, `${feCode}_${ucCode}-scenarios-list.json`);
22947
+ const scPath = path35.join(contextDir2, `${feCode}_${ucCode}-scenarios-list.json`);
22609
22948
  const scFile = readJson5(scPath);
22610
22949
  const scs = Array.isArray(scFile?.scenarios) ? scFile.scenarios : [];
22611
22950
  for (const scRow of scs) {
@@ -22676,7 +23015,7 @@ Follow bundled agent **agent-md-use-case-detail**: include **## Data inputs and
22676
23015
  groups.push({ id: "detail-services", label: "Detail markdown \u2014 Services", targets: svcTargets });
22677
23016
  groups.push({ id: "detail-methods", label: "Detail markdown \u2014 Methods", targets: meTargets });
22678
23017
  const entTargets = [];
22679
- const dmPath = path34.join(contextDir2, "data-model-list.json");
23018
+ const dmPath = path35.join(contextDir2, "data-model-list.json");
22680
23019
  const dmFile = readJson5(dmPath);
22681
23020
  const ents = Array.isArray(dmFile?.entities) ? dmFile.entities : [];
22682
23021
  for (const erow of ents) {
@@ -22705,7 +23044,7 @@ Follow bundled agent **agent-md-use-case-detail**: include **## Data inputs and
22705
23044
  if (!DM2.test(dmCode)) {
22706
23045
  continue;
22707
23046
  }
22708
- const flPath2 = path34.join(contextDir2, `${dmCode}-fields-list.json`);
23047
+ const flPath2 = path35.join(contextDir2, `${dmCode}-fields-list.json`);
22709
23048
  const flFile = readJson5(flPath2);
22710
23049
  const flds = Array.isArray(flFile?.fields) ? flFile.fields : [];
22711
23050
  for (const frow of flds) {
@@ -22764,9 +23103,9 @@ function fileAndValidationFromKind(kind) {
22764
23103
  return { filePresentYesNo: "no", validationYesNo: "na" };
22765
23104
  }
22766
23105
  function classifyMissingWorkstationOutputFileStatus(row2, contextDir2, worktreeRoot) {
22767
- const abs = path35.join(contextDir2, row2.relativePath);
23106
+ const abs = path36.join(contextDir2, row2.relativePath);
22768
23107
  try {
22769
- const st = fs40.statSync(abs);
23108
+ const st = fs41.statSync(abs);
22770
23109
  if (!st.isFile()) {
22771
23110
  return { kind: "absent", detail: "Path exists but is not a regular file." };
22772
23111
  }
@@ -22803,8 +23142,8 @@ function classifyMissingWorkstationOutputFileStatus(row2, contextDir2, worktreeR
22803
23142
  detail: "Unknown coordination list basename \u2014 no JSON Schema mapping."
22804
23143
  };
22805
23144
  }
22806
- const schemaAbs = path35.join(worktreeRoot, ".opencode", "schemas", "context-lists", schemaBn);
22807
- if (!fs40.existsSync(schemaAbs)) {
23145
+ const schemaAbs = path36.join(worktreeRoot, ".opencode", "schemas", "context-lists", schemaBn);
23146
+ if (!fs41.existsSync(schemaAbs)) {
22808
23147
  return {
22809
23148
  kind: "invalid",
22810
23149
  detail: `Schema not found (${schemaBn}). Run **Materialize agents** on this checkout.`
@@ -22833,7 +23172,7 @@ function classifyWorkstationOutputOnDisk(item, contextDir2, worktreeRoot) {
22833
23172
  return classifyMissingWorkstationOutputFileStatus(row2, contextDir2, worktreeRoot).kind;
22834
23173
  }
22835
23174
  function isWorkstationRunSnapshotForWorktree(snapshot, worktreeRoot) {
22836
- 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));
22837
23176
  }
22838
23177
  function expectedBasenameForCoordPayload(p) {
22839
23178
  const { step, listTarget } = p;
@@ -22907,10 +23246,10 @@ function labelContextForCoordPayload(p) {
22907
23246
  }
22908
23247
  function contextPathForWorkItem(item, contextDir2) {
22909
23248
  if (item.kind === "markdown") {
22910
- return path35.join(contextDir2, item.payload.outputBasename);
23249
+ return path36.join(contextDir2, item.payload.outputBasename);
22911
23250
  }
22912
23251
  const bn = expectedBasenameForCoordPayload(item.payload);
22913
- return bn ? path35.join(contextDir2, bn) : null;
23252
+ return bn ? path36.join(contextDir2, bn) : null;
22914
23253
  }
22915
23254
  function syntheticRunnerId(key) {
22916
23255
  return `remediation:${key}`;
@@ -22920,7 +23259,7 @@ function rowFromSkippedItem(item, contextDir2) {
22920
23259
  return null;
22921
23260
  }
22922
23261
  const abs = contextPathForWorkItem(item, contextDir2);
22923
- 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;
22924
23263
  if (abs && nonEmptyContextFile(abs)) {
22925
23264
  return null;
22926
23265
  }
@@ -23040,7 +23379,7 @@ function listMissingWorkstations(contextDir2, worktreeRoot, snapshot) {
23040
23379
  }
23041
23380
  }
23042
23381
  }
23043
- if (!fs40.existsSync(contextDir2)) {
23382
+ if (!fs41.existsSync(contextDir2)) {
23044
23383
  return [...map.values()].sort((a, b) => a.key.localeCompare(b.key));
23045
23384
  }
23046
23385
  const dynamic = discoverDynamicAnalysisTestSteps(contextDir2);
@@ -23095,7 +23434,7 @@ function toMissingWorkstationUiRows(rows, contextDir2, worktreeRoot) {
23095
23434
  }
23096
23435
 
23097
23436
  // src/pipelines/remediation/missingWorkstationsPool.ts
23098
- var path36 = __toESM(require("path"));
23437
+ var path37 = __toESM(require("path"));
23099
23438
  function reconcileSkippedWorkItemsWithDisk(byId, contextDir2, worktreeRoot) {
23100
23439
  for (const item of byId.values()) {
23101
23440
  if (item.status !== "skipped") {
@@ -23155,7 +23494,7 @@ async function runRemediationPipelineMissingPass(p) {
23155
23494
  onItemComplete,
23156
23495
  sourceBranchAtWorktreeCreation
23157
23496
  } = p;
23158
- const contextDir2 = path36.join(worktreeRoot, ".gluecharm", "context");
23497
+ const contextDir2 = path37.join(worktreeRoot, ".gluecharm", "context");
23159
23498
  const snap = readArtefactRunSnapshot(storageContext);
23160
23499
  const snapOk = isWorkstationRunSnapshotForWorktree(snap, worktreeRoot);
23161
23500
  let byId;
@@ -23221,18 +23560,18 @@ async function runRemediationPipelineMissingPass(p) {
23221
23560
 
23222
23561
  // src/pipelines/coverage/coveragePipeline.ts
23223
23562
  var import_child_process5 = require("child_process");
23224
- var fs42 = __toESM(require("fs"));
23225
- var path38 = __toESM(require("path"));
23563
+ var fs43 = __toESM(require("fs"));
23564
+ var path39 = __toESM(require("path"));
23226
23565
 
23227
23566
  // src/analysis/coverageReferenceValidationSchemaValidate.ts
23228
- var fs41 = __toESM(require("fs"));
23229
- var path37 = __toESM(require("path"));
23567
+ var fs42 = __toESM(require("fs"));
23568
+ var path38 = __toESM(require("path"));
23230
23569
  var import__5 = __toESM(require__());
23231
23570
  function stripUtf8Bom4(s) {
23232
23571
  return s.length > 0 && s.charCodeAt(0) === 65279 ? s.slice(1) : s;
23233
23572
  }
23234
23573
  function bundledCoverageReferenceValidationSchemaPath() {
23235
- return path37.join(
23574
+ return path38.join(
23236
23575
  resolveRepoResourcesRoot(),
23237
23576
  "schemas",
23238
23577
  "context-lists",
@@ -23255,7 +23594,7 @@ function getValidate() {
23255
23594
  return compiledValidate;
23256
23595
  }
23257
23596
  const schemaPath = bundledCoverageReferenceValidationSchemaPath();
23258
- const schemaRaw = stripUtf8Bom4(fs41.readFileSync(schemaPath, "utf-8"));
23597
+ const schemaRaw = stripUtf8Bom4(fs42.readFileSync(schemaPath, "utf-8"));
23259
23598
  const schema = JSON.parse(schemaRaw);
23260
23599
  const ajv2 = new import__5.default({ allErrors: true, strict: false });
23261
23600
  compiledValidate = ajv2.compile(schema);
@@ -23271,7 +23610,7 @@ function validateCoverageReferenceValidationData(data) {
23271
23610
  function readAndValidateCoverageReferenceValidationFile(jsonAbsolutePath) {
23272
23611
  let raw;
23273
23612
  try {
23274
- raw = stripUtf8Bom4(fs41.readFileSync(jsonAbsolutePath, "utf-8"));
23613
+ raw = stripUtf8Bom4(fs42.readFileSync(jsonAbsolutePath, "utf-8"));
23275
23614
  } catch (e) {
23276
23615
  return {
23277
23616
  ok: false,
@@ -23312,8 +23651,8 @@ var DEFAULT_IGNORE_DIR_BASENAMES = [
23312
23651
  ];
23313
23652
  var GIT_LS_FILES_MAX_BUFFER = 64 * 1024 * 1024;
23314
23653
  function tryLoadGitNonIgnoredPathSet(repositoryRootAbs) {
23315
- const root = path38.resolve(repositoryRootAbs);
23316
- if (!fs42.existsSync(path38.join(root, ".git"))) {
23654
+ const root = path39.resolve(repositoryRootAbs);
23655
+ if (!fs43.existsSync(path39.join(root, ".git"))) {
23317
23656
  return null;
23318
23657
  }
23319
23658
  const env = { ...process.env, GIT_TERMINAL_PROMPT: "0" };
@@ -23381,12 +23720,12 @@ var REFERENCE_COVERAGE_IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
23381
23720
  ".emf"
23382
23721
  ]);
23383
23722
  function isReferenceCoverageExcludedImagePath(relPosix) {
23384
- const ext = path38.extname(relPosix).toLowerCase();
23723
+ const ext = path39.extname(relPosix).toLowerCase();
23385
23724
  return ext.length > 0 && REFERENCE_COVERAGE_IMAGE_EXTENSIONS.has(ext);
23386
23725
  }
23387
23726
  var REFERENCE_COVERAGE_EXCLUDED_FILE_BASENAMES = /* @__PURE__ */ new Set([".gitignore"]);
23388
23727
  function isReferenceCoverageExcludedDefaultBasename(relPosix) {
23389
- const base = path38.basename(relPosix.replace(/\\/g, "/")).toLowerCase();
23728
+ const base = path39.basename(relPosix.replace(/\\/g, "/")).toLowerCase();
23390
23729
  return REFERENCE_COVERAGE_EXCLUDED_FILE_BASENAMES.has(base);
23391
23730
  }
23392
23731
  function decodeBufferForLineCount(buf) {
@@ -23423,12 +23762,12 @@ function normalizeRepoRelativePath(repoRoot, raw) {
23423
23762
  if (!trimmed || trimmed.includes("\0")) {
23424
23763
  return null;
23425
23764
  }
23426
- const abs = path38.resolve(repoRoot, trimmed);
23427
- const rel = path38.relative(repoRoot, abs);
23428
- 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)) {
23429
23768
  return null;
23430
23769
  }
23431
- return rel.split(path38.sep).join("/");
23770
+ return rel.split(path39.sep).join("/");
23432
23771
  }
23433
23772
  function collectJsonSourceReferences(node, out) {
23434
23773
  if (node === null || typeof node !== "object") {
@@ -23468,12 +23807,12 @@ function extractEvidenceIndexPathCitations(body) {
23468
23807
  function listContextFilesRecursive(dir, acc) {
23469
23808
  let entries;
23470
23809
  try {
23471
- entries = fs42.readdirSync(dir, { withFileTypes: true });
23810
+ entries = fs43.readdirSync(dir, { withFileTypes: true });
23472
23811
  } catch {
23473
23812
  return;
23474
23813
  }
23475
23814
  for (const e of entries) {
23476
- const full = path38.join(dir, e.name);
23815
+ const full = path39.join(dir, e.name);
23477
23816
  if (e.isDirectory()) {
23478
23817
  listContextFilesRecursive(full, acc);
23479
23818
  } else if (e.isFile()) {
@@ -23486,7 +23825,7 @@ function walkRepositoryFiles(repoRoot, ignoreBasenames, maxBytes, excludedOut, g
23486
23825
  const walk = (dir) => {
23487
23826
  let entries;
23488
23827
  try {
23489
- entries = fs42.readdirSync(dir, { withFileTypes: true });
23828
+ entries = fs43.readdirSync(dir, { withFileTypes: true });
23490
23829
  } catch {
23491
23830
  return;
23492
23831
  }
@@ -23494,8 +23833,8 @@ function walkRepositoryFiles(repoRoot, ignoreBasenames, maxBytes, excludedOut, g
23494
23833
  if (ignoreBasenames.has(e.name)) {
23495
23834
  continue;
23496
23835
  }
23497
- const full = path38.join(dir, e.name);
23498
- 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("/");
23499
23838
  if (rel.startsWith("..")) {
23500
23839
  continue;
23501
23840
  }
@@ -23516,7 +23855,7 @@ function walkRepositoryFiles(repoRoot, ignoreBasenames, maxBytes, excludedOut, g
23516
23855
  }
23517
23856
  let st;
23518
23857
  try {
23519
- st = fs42.statSync(full);
23858
+ st = fs43.statSync(full);
23520
23859
  } catch {
23521
23860
  continue;
23522
23861
  }
@@ -23526,7 +23865,7 @@ function walkRepositoryFiles(repoRoot, ignoreBasenames, maxBytes, excludedOut, g
23526
23865
  }
23527
23866
  let buf;
23528
23867
  try {
23529
- buf = fs42.readFileSync(full);
23868
+ buf = fs43.readFileSync(full);
23530
23869
  } catch {
23531
23870
  excludedOut.push({ path: rel, reason: "read error" });
23532
23871
  continue;
@@ -23546,23 +23885,23 @@ function walkRepositoryFiles(repoRoot, ignoreBasenames, maxBytes, excludedOut, g
23546
23885
  }
23547
23886
  function collectReferencesFromContext(contextDirAbs, repositoryRootAbs, warnings) {
23548
23887
  const references = [];
23549
- if (!fs42.existsSync(contextDirAbs)) {
23888
+ if (!fs43.existsSync(contextDirAbs)) {
23550
23889
  warnings.push(`Context directory missing: ${contextDirAbs}`);
23551
23890
  return references;
23552
23891
  }
23553
23892
  const allFiles = [];
23554
23893
  listContextFilesRecursive(contextDirAbs, allFiles);
23555
23894
  for (const abs of allFiles) {
23556
- const ext = path38.extname(abs).toLowerCase();
23557
- const base = path38.basename(abs);
23558
- 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("/");
23559
23898
  if (ext === ".json") {
23560
23899
  if (SKIP_CONTEXT_JSON.has(base)) {
23561
23900
  continue;
23562
23901
  }
23563
23902
  let raw;
23564
23903
  try {
23565
- raw = fs42.readFileSync(abs, "utf-8");
23904
+ raw = fs43.readFileSync(abs, "utf-8");
23566
23905
  } catch (e) {
23567
23906
  warnings.push(`Skip JSON (read error): ${sourceArtefact} \u2014 ${e instanceof Error ? e.message : String(e)}`);
23568
23907
  continue;
@@ -23593,7 +23932,7 @@ function collectReferencesFromContext(contextDirAbs, repositoryRootAbs, warnings
23593
23932
  if (ext === ".md") {
23594
23933
  let text;
23595
23934
  try {
23596
- const buf = fs42.readFileSync(abs);
23935
+ const buf = fs43.readFileSync(abs);
23597
23936
  text = decodeBufferForLineCount(buf);
23598
23937
  } catch (e) {
23599
23938
  warnings.push(`Skip markdown (read/decode error): ${sourceArtefact} \u2014 ${e instanceof Error ? e.message : String(e)}`);
@@ -23637,12 +23976,12 @@ function sortReferenceRows(a, b) {
23637
23976
  return (a.startLine ?? 0) - (b.startLine ?? 0);
23638
23977
  }
23639
23978
  function buildCoverageReferenceValidationDocument(repositoryRootAbs, contextDirAbs, options) {
23640
- const repoRoot = path38.resolve(repositoryRootAbs);
23979
+ const repoRoot = path39.resolve(repositoryRootAbs);
23641
23980
  const warnings = [];
23642
23981
  const ignoreDirs = [...DEFAULT_IGNORE_DIR_BASENAMES];
23643
23982
  const ignoreSet = new Set(ignoreDirs);
23644
23983
  const maxBytes = options?.maxFileBytes ?? MAX_FILE_BYTES;
23645
- const references = collectReferencesFromContext(path38.resolve(contextDirAbs), repoRoot, warnings);
23984
+ const references = collectReferencesFromContext(path39.resolve(contextDirAbs), repoRoot, warnings);
23646
23985
  references.sort(sortReferenceRows);
23647
23986
  const referencedSet = /* @__PURE__ */ new Set();
23648
23987
  for (const r of references) {
@@ -23650,7 +23989,7 @@ function buildCoverageReferenceValidationDocument(repositoryRootAbs, contextDirA
23650
23989
  }
23651
23990
  const excludedFiles = [];
23652
23991
  const gitNonIgnoredPaths = tryLoadGitNonIgnoredPathSet(repoRoot);
23653
- if (fs42.existsSync(path38.join(repoRoot, ".git")) && gitNonIgnoredPaths === null) {
23992
+ if (fs43.existsSync(path39.join(repoRoot, ".git")) && gitNonIgnoredPaths === null) {
23654
23993
  warnings.push(
23655
23994
  "Repository has .git but git ls-files failed or git is unavailable; .gitignore / exclude-standard not applied."
23656
23995
  );
@@ -23699,12 +24038,12 @@ function buildCoverageReferenceValidationDocument(repositoryRootAbs, contextDirA
23699
24038
  return { document: doc, warnings };
23700
24039
  }
23701
24040
  function runCoveragePipeline(opts) {
23702
- const repoRoot = path38.resolve(opts.repositoryRootAbs);
23703
- const contextDir2 = path38.resolve(opts.contextDirAbs);
23704
- if (!fs42.existsSync(repoRoot)) {
24041
+ const repoRoot = path39.resolve(opts.repositoryRootAbs);
24042
+ const contextDir2 = path39.resolve(opts.contextDirAbs);
24043
+ if (!fs43.existsSync(repoRoot)) {
23705
24044
  return { ok: false, error: `Repository root does not exist: ${repoRoot}` };
23706
24045
  }
23707
- if (!fs42.existsSync(contextDir2)) {
24046
+ if (!fs43.existsSync(contextDir2)) {
23708
24047
  return {
23709
24048
  ok: false,
23710
24049
  error: `Missing .gluecharm/context: ${contextDir2}`
@@ -23722,11 +24061,11 @@ ${schemaCheck.errors.join("\n")}`,
23722
24061
  warnings
23723
24062
  };
23724
24063
  }
23725
- const outPath = path38.join(contextDir2, COVERAGE_REFERENCE_VALIDATION_BASENAME);
24064
+ const outPath = path39.join(contextDir2, COVERAGE_REFERENCE_VALIDATION_BASENAME);
23726
24065
  if (opts.write) {
23727
24066
  try {
23728
24067
  const payload = stableStringifyCoverageDocument(document);
23729
- fs42.writeFileSync(outPath, payload, "utf-8");
24068
+ fs43.writeFileSync(outPath, payload, "utf-8");
23730
24069
  } catch (e) {
23731
24070
  return {
23732
24071
  ok: false,
@@ -23740,12 +24079,12 @@ ${schemaCheck.errors.join("\n")}`,
23740
24079
 
23741
24080
  // src/pipelines/remediation/zeroReferenceWorkstationChain.ts
23742
24081
  var crypto = __toESM(require("crypto"));
23743
- var fs44 = __toESM(require("fs"));
23744
- var path40 = __toESM(require("path"));
24082
+ var fs45 = __toESM(require("fs"));
24083
+ var path41 = __toESM(require("path"));
23745
24084
 
23746
24085
  // src/analysis/zeroReferenceRemediationSchemaValidate.ts
23747
- var fs43 = __toESM(require("fs"));
23748
- var path39 = __toESM(require("path"));
24086
+ var fs44 = __toESM(require("fs"));
24087
+ var path40 = __toESM(require("path"));
23749
24088
  var import__6 = __toESM(require__());
23750
24089
  function stripUtf8Bom5(s) {
23751
24090
  return s.length > 0 && s.charCodeAt(0) === 65279 ? s.slice(1) : s;
@@ -23765,8 +24104,8 @@ function formatAjvErrors6(errors) {
23765
24104
  }
23766
24105
  var ajv = new import__6.default({ allErrors: true, strict: false });
23767
24106
  function compileSchema(basename17) {
23768
- const schemaPath = path39.join(schemasDir(), basename17);
23769
- const schemaRaw = stripUtf8Bom5(fs43.readFileSync(schemaPath, "utf-8"));
24107
+ const schemaPath = path40.join(schemasDir(), basename17);
24108
+ const schemaRaw = stripUtf8Bom5(fs44.readFileSync(schemaPath, "utf-8"));
23770
24109
  const schema = JSON.parse(schemaRaw);
23771
24110
  return ajv.compile(schema);
23772
24111
  }
@@ -23810,7 +24149,7 @@ var ZERO_REF_STAGING_JSON_TOTAL_ATTEMPTS = 5;
23810
24149
  var ZERO_REF_STAGING_FILE_PREVIEW_MAX_CHARS = 6e3;
23811
24150
  function readStagingOutputPreview(outAbs) {
23812
24151
  try {
23813
- const s = fs44.readFileSync(outAbs, "utf-8");
24152
+ const s = fs45.readFileSync(outAbs, "utf-8");
23814
24153
  if (s.length <= ZERO_REF_STAGING_FILE_PREVIEW_MAX_CHARS) {
23815
24154
  return s;
23816
24155
  }
@@ -24060,17 +24399,17 @@ function expandArgvTemplate4(template, vars) {
24060
24399
  });
24061
24400
  }
24062
24401
  function schemaRef2(worktreeRoot, schemaBasename) {
24063
- return path40.join(worktreeRoot, ".opencode", "schemas", "context-lists", schemaBasename);
24402
+ return path41.join(worktreeRoot, ".opencode", "schemas", "context-lists", schemaBasename);
24064
24403
  }
24065
24404
  function stagingDir(contextDirAbs) {
24066
- return path40.join(contextDirAbs, "_zero-ref-staging");
24405
+ return path41.join(contextDirAbs, "_zero-ref-staging");
24067
24406
  }
24068
24407
  function stagingPathForTarget(contextDirAbs, kind, targetFilePathPosix) {
24069
24408
  const h = crypto.createHash("sha256").update(targetFilePathPosix, "utf8").digest("hex").slice(0, 16);
24070
- return path40.join(stagingDir(contextDirAbs), `${kind}-${h}.json`);
24409
+ return path41.join(stagingDir(contextDirAbs), `${kind}-${h}.json`);
24071
24410
  }
24072
24411
  function readNonReferencedFilesFromRepositoryRoot(repositoryRootAbs) {
24073
- const p = path40.join(repositoryRootAbs, ".gluecharm", "context", "coverage-reference-validation.json");
24412
+ const p = path41.join(repositoryRootAbs, ".gluecharm", "context", "coverage-reference-validation.json");
24074
24413
  const r = readAndValidateCoverageReferenceValidationFile(p);
24075
24414
  if (!r.ok) {
24076
24415
  return { ok: false, error: r.errors.join("; ") };
@@ -24093,14 +24432,14 @@ function readNonReferencedFilesFromRepositoryRoot(repositoryRootAbs) {
24093
24432
  return { ok: true, paths, ...generatedAt ? { generatedAt } : {} };
24094
24433
  }
24095
24434
  function readOrInitRoutingDoc(routingAbs, coverageReferenceGeneratedAt) {
24096
- if (!fs44.existsSync(routingAbs)) {
24435
+ if (!fs45.existsSync(routingAbs)) {
24097
24436
  return {
24098
24437
  schemaVersion: ROUTING_SCHEMA_VERSION,
24099
24438
  ...coverageReferenceGeneratedAt ? { coverageReferenceGeneratedAt } : {},
24100
24439
  records: {}
24101
24440
  };
24102
24441
  }
24103
- const raw = fs44.readFileSync(routingAbs, "utf-8");
24442
+ const raw = fs45.readFileSync(routingAbs, "utf-8");
24104
24443
  const data = JSON.parse(raw);
24105
24444
  if (!data.records || typeof data.records !== "object") {
24106
24445
  return {
@@ -24112,10 +24451,10 @@ function readOrInitRoutingDoc(routingAbs, coverageReferenceGeneratedAt) {
24112
24451
  return data;
24113
24452
  }
24114
24453
  function readOrInitTriageDoc(triageAbs) {
24115
- if (!fs44.existsSync(triageAbs)) {
24454
+ if (!fs45.existsSync(triageAbs)) {
24116
24455
  return { schemaVersion: TRIAGE_SCHEMA_VERSION, records: {} };
24117
24456
  }
24118
- const raw = fs44.readFileSync(triageAbs, "utf-8");
24457
+ const raw = fs45.readFileSync(triageAbs, "utf-8");
24119
24458
  const data = JSON.parse(raw);
24120
24459
  if (!data.records || typeof data.records !== "object") {
24121
24460
  return { schemaVersion: TRIAGE_SCHEMA_VERSION, records: {} };
@@ -24163,10 +24502,10 @@ function slugifyFeatureLabel(s) {
24163
24502
  return t.length > 0 ? t : "feature";
24164
24503
  }
24165
24504
  function lineCountRepoFile(worktreeRootAbs, relPosix) {
24166
- const abs = path40.join(worktreeRootAbs, ...relPosix.split("/"));
24505
+ const abs = path41.join(worktreeRootAbs, ...relPosix.split("/"));
24167
24506
  let buf;
24168
24507
  try {
24169
- buf = fs44.readFileSync(abs);
24508
+ buf = fs45.readFileSync(abs);
24170
24509
  } catch {
24171
24510
  return 1;
24172
24511
  }
@@ -24218,9 +24557,9 @@ var LIST_STEP_HINT = {
24218
24557
  };
24219
24558
  async function applyCoordinationListTriageMerge(input) {
24220
24559
  const cfg = LIST_MERGE_CFG[input.listKind];
24221
- const listPath = path40.join(input.contextDirAbs, cfg.listBasename);
24222
- const schemaPath = path40.join(resolveContextListSchemasDir(), cfg.schemaBasename);
24223
- 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)) {
24224
24563
  return {
24225
24564
  ok: false,
24226
24565
  message: `${cfg.listBasename} not found \u2014 run coordination step ${LIST_STEP_HINT[input.listKind]} first.`
@@ -24231,7 +24570,7 @@ async function applyCoordinationListTriageMerge(input) {
24231
24570
  return withCoordinationListFileLock(listPath, {}, async () => {
24232
24571
  let raw;
24233
24572
  try {
24234
- raw = fs44.readFileSync(listPath, "utf-8");
24573
+ raw = fs45.readFileSync(listPath, "utf-8");
24235
24574
  } catch (e) {
24236
24575
  return { ok: false, message: e instanceof Error ? e.message : String(e) };
24237
24576
  }
@@ -24299,7 +24638,7 @@ async function applyCoordinationListTriageMerge(input) {
24299
24638
  });
24300
24639
  const tmp = `${listPath}.tmp.${process.pid}`;
24301
24640
  try {
24302
- fs44.writeFileSync(tmp, `${JSON.stringify(doc, null, 2)}
24641
+ fs45.writeFileSync(tmp, `${JSON.stringify(doc, null, 2)}
24303
24642
  `, "utf-8");
24304
24643
  } catch (e) {
24305
24644
  return { ok: false, message: e instanceof Error ? e.message : String(e) };
@@ -24307,13 +24646,13 @@ async function applyCoordinationListTriageMerge(input) {
24307
24646
  const v = validateCoordinationListJson(tmp, schemaPath);
24308
24647
  if (!v.ok) {
24309
24648
  try {
24310
- fs44.unlinkSync(tmp);
24649
+ fs45.unlinkSync(tmp);
24311
24650
  } catch {
24312
24651
  }
24313
24652
  return { ok: false, message: `${cfg.listBasename} validation failed: ${JSON.stringify(v.failure)}` };
24314
24653
  }
24315
24654
  try {
24316
- fs44.renameSync(tmp, listPath);
24655
+ fs45.renameSync(tmp, listPath);
24317
24656
  } catch (e) {
24318
24657
  return { ok: false, message: e instanceof Error ? e.message : String(e) };
24319
24658
  }
@@ -24323,10 +24662,10 @@ async function applyCoordinationListTriageMerge(input) {
24323
24662
  }
24324
24663
  async function runClassifierAgent(common, contextDirAbs, targetFilePathPosix, workspaceLabel) {
24325
24664
  const outAbs = stagingPathForTarget(contextDirAbs, "classifier", targetFilePathPosix);
24326
- fs44.mkdirSync(path40.dirname(outAbs), { recursive: true });
24327
- const runDir = path40.join(common.worktreeRoot, ".opencode", "_run");
24328
- fs44.mkdirSync(runDir, { recursive: true });
24329
- 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);
24330
24669
  const listTaskDescription = [
24331
24670
  `Target file (repo-relative, POSIX): **${targetFilePathPosix}**`,
24332
24671
  `Workspace label hint: **${workspaceLabel}**.`,
@@ -24362,8 +24701,8 @@ async function runClassifierAgent(common, contextDirAbs, targetFilePathPosix, wo
24362
24701
  parentContextBlock: "",
24363
24702
  ...repairAppendix ? { repairAppendix } : {}
24364
24703
  });
24365
- const promptPath = path40.join(runDir, `zero-ref-classify-a${attempt}-${Date.now()}.prompt.txt`);
24366
- 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");
24367
24706
  const argv = expandArgvTemplate4(common.argvTemplate, {
24368
24707
  promptFile: promptPath,
24369
24708
  agentId: ZERO_REF_CLASSIFY_AGENT_STEM,
@@ -24390,7 +24729,7 @@ async function runClassifierAgent(common, contextDirAbs, targetFilePathPosix, wo
24390
24729
  const canRetry = attempt < ZERO_REF_STAGING_JSON_TOTAL_ATTEMPTS - 1;
24391
24730
  let st;
24392
24731
  try {
24393
- st = fs44.statSync(outAbs);
24732
+ st = fs45.statSync(outAbs);
24394
24733
  } catch {
24395
24734
  st = void 0;
24396
24735
  }
@@ -24412,7 +24751,7 @@ async function runClassifierAgent(common, contextDirAbs, targetFilePathPosix, wo
24412
24751
  }
24413
24752
  let parsed;
24414
24753
  try {
24415
- parsed = JSON.parse(fs44.readFileSync(outAbs, "utf-8"));
24754
+ parsed = JSON.parse(fs45.readFileSync(outAbs, "utf-8"));
24416
24755
  } catch (e) {
24417
24756
  const msg = e instanceof Error ? e.message : String(e);
24418
24757
  lastFailureMessage = `Classifier output not valid JSON: ${msg}`;
@@ -24494,10 +24833,10 @@ var TRIAGE_SCOPE_META = {
24494
24833
  };
24495
24834
  async function runMarkdownReferenceAgent(common, contextDirAbs, targetFilePathPosix, routingSummary, which) {
24496
24835
  const mdBasename = which === "project" ? "project.md" : "architecture.md";
24497
- const mdAbs = path40.join(contextDirAbs, mdBasename);
24836
+ const mdAbs = path41.join(contextDirAbs, mdBasename);
24498
24837
  const agentStem = which === "project" ? ZERO_REF_ADD_REF_PROJECT_AGENT_STEM : ZERO_REF_ADD_REF_ARCH_AGENT_STEM;
24499
- const runDir = path40.join(common.worktreeRoot, ".opencode", "_run");
24500
- fs44.mkdirSync(runDir, { recursive: true });
24838
+ const runDir = path41.join(common.worktreeRoot, ".opencode", "_run");
24839
+ fs45.mkdirSync(runDir, { recursive: true });
24501
24840
  const lines = [
24502
24841
  `# SRS-30 \u2014 Add reference to ${mdBasename}`,
24503
24842
  ``,
@@ -24512,8 +24851,8 @@ async function runMarkdownReferenceAgent(common, contextDirAbs, targetFilePathPo
24512
24851
  `- If the file is short, \`${targetFilePathPosix}:1-<lastLine>\` is acceptable.`,
24513
24852
  `- Do not remove unrelated content; append or extend the most appropriate section.`
24514
24853
  ];
24515
- const promptPath = path40.join(runDir, `zero-ref-md-${which}-${Date.now()}.prompt.txt`);
24516
- 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");
24517
24856
  const argv = expandArgvTemplate4(common.argvTemplate, {
24518
24857
  promptFile: promptPath,
24519
24858
  agentId: agentStem,
@@ -24540,10 +24879,10 @@ async function runMarkdownReferenceAgent(common, contextDirAbs, targetFilePathPo
24540
24879
  async function runCoordinationTriageAgent(common, contextDirAbs, targetFilePathPosix, routingSummary, workspaceLabel, triageScope) {
24541
24880
  const meta = TRIAGE_SCOPE_META[triageScope];
24542
24881
  const outAbs = stagingPathForTarget(contextDirAbs, "triage", targetFilePathPosix);
24543
- fs44.mkdirSync(path40.dirname(outAbs), { recursive: true });
24544
- const runDir = path40.join(common.worktreeRoot, ".opencode", "_run");
24545
- fs44.mkdirSync(runDir, { recursive: true });
24546
- 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);
24547
24886
  const listTaskDescription = [
24548
24887
  `Target file: **${targetFilePathPosix}** (${workspaceLabel})`,
24549
24888
  "**Classifier summary:**",
@@ -24573,8 +24912,8 @@ async function runCoordinationTriageAgent(common, contextDirAbs, targetFilePathP
24573
24912
  parentContextBlock: "",
24574
24913
  ...repairAppendix ? { repairAppendix } : {}
24575
24914
  });
24576
- const promptPath = path40.join(runDir, `zero-ref-triage-a${attempt}-${Date.now()}.prompt.txt`);
24577
- 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");
24578
24917
  const argv = expandArgvTemplate4(common.argvTemplate, {
24579
24918
  promptFile: promptPath,
24580
24919
  agentId: ZERO_REF_TRIAGE_COORD_AGENT_STEM,
@@ -24601,7 +24940,7 @@ async function runCoordinationTriageAgent(common, contextDirAbs, targetFilePathP
24601
24940
  const canRetry = attempt < ZERO_REF_STAGING_JSON_TOTAL_ATTEMPTS - 1;
24602
24941
  let st;
24603
24942
  try {
24604
- st = fs44.statSync(outAbs);
24943
+ st = fs45.statSync(outAbs);
24605
24944
  } catch {
24606
24945
  st = void 0;
24607
24946
  }
@@ -24623,7 +24962,7 @@ async function runCoordinationTriageAgent(common, contextDirAbs, targetFilePathP
24623
24962
  }
24624
24963
  let parsed;
24625
24964
  try {
24626
- parsed = JSON.parse(fs44.readFileSync(outAbs, "utf-8"));
24965
+ parsed = JSON.parse(fs45.readFileSync(outAbs, "utf-8"));
24627
24966
  } catch (e) {
24628
24967
  const msg = e instanceof Error ? e.message : String(e);
24629
24968
  lastFailureMessage = `Triage output not valid JSON: ${msg}`;
@@ -24679,7 +25018,7 @@ async function runCoordinationTriageAgent(common, contextDirAbs, targetFilePathP
24679
25018
  return { ok: false, message: lastFailureMessage, stagingPath: outAbs };
24680
25019
  }
24681
25020
  try {
24682
- fs44.writeFileSync(outAbs, `${JSON.stringify(parsed, null, 2)}
25021
+ fs45.writeFileSync(outAbs, `${JSON.stringify(parsed, null, 2)}
24683
25022
  `, "utf-8");
24684
25023
  } catch {
24685
25024
  }
@@ -24688,8 +25027,8 @@ async function runCoordinationTriageAgent(common, contextDirAbs, targetFilePathP
24688
25027
  return { ok: false, message: lastFailureMessage, stagingPath: outAbs };
24689
25028
  }
24690
25029
  async function runOneUnreferencedFilePipeline(p) {
24691
- const routingAbs = path40.join(p.contextDirAbs, ZERO_REF_ROUTING_BASENAME);
24692
- 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);
24693
25032
  const key = p.targetFilePathPosix;
24694
25033
  const cr = await runClassifierAgent(p, p.contextDirAbs, key, p.workspaceLabel);
24695
25034
  if (!cr.ok) {
@@ -24697,7 +25036,7 @@ async function runOneUnreferencedFilePipeline(p) {
24697
25036
  }
24698
25037
  let stagingParsed;
24699
25038
  try {
24700
- stagingParsed = JSON.parse(fs44.readFileSync(cr.stagingPath, "utf-8"));
25039
+ stagingParsed = JSON.parse(fs45.readFileSync(cr.stagingPath, "utf-8"));
24701
25040
  } catch (e) {
24702
25041
  return { ok: false, message: String(e) };
24703
25042
  }
@@ -24713,8 +25052,8 @@ async function runOneUnreferencedFilePipeline(p) {
24713
25052
  if (!s.ok) {
24714
25053
  throw new Error(s.errors.join("; "));
24715
25054
  }
24716
- fs44.mkdirSync(path40.dirname(routingAbs), { recursive: true });
24717
- fs44.writeFileSync(routingAbs, s.json, "utf-8");
25055
+ fs45.mkdirSync(path41.dirname(routingAbs), { recursive: true });
25056
+ fs45.writeFileSync(routingAbs, s.json, "utf-8");
24718
25057
  });
24719
25058
  const routing = stagingParsed.routing;
24720
25059
  const routingSummary = typeof stagingParsed.projectRelationSummary === "string" ? stagingParsed.projectRelationSummary : "";
@@ -24745,7 +25084,7 @@ async function runOneUnreferencedFilePipeline(p) {
24745
25084
  }
24746
25085
  let triageParsed;
24747
25086
  try {
24748
- triageParsed = JSON.parse(fs44.readFileSync(tr.stagingPath, "utf-8"));
25087
+ triageParsed = JSON.parse(fs45.readFileSync(tr.stagingPath, "utf-8"));
24749
25088
  } catch (e) {
24750
25089
  return { ok: false, message: String(e) };
24751
25090
  }
@@ -24762,8 +25101,8 @@ async function runOneUnreferencedFilePipeline(p) {
24762
25101
  if (!s.ok) {
24763
25102
  throw new Error(s.errors.join("; "));
24764
25103
  }
24765
- fs44.mkdirSync(path40.dirname(triageAbs), { recursive: true });
24766
- fs44.writeFileSync(triageAbs, s.json, "utf-8");
25104
+ fs45.mkdirSync(path41.dirname(triageAbs), { recursive: true });
25105
+ fs45.writeFileSync(triageAbs, s.json, "utf-8");
24767
25106
  });
24768
25107
  const decision = triageParsed.decision;
24769
25108
  if (decision === "new_item" || decision === "enrich_existing") {
@@ -24790,11 +25129,11 @@ async function runOneUnreferencedFilePipeline(p) {
24790
25129
  return { ok: true, message: `Triage ${decision}.` };
24791
25130
  }
24792
25131
  async function runRemediationPipelineZeroRefPass(p) {
24793
- const contextDirAbs = path40.join(p.worktreeRoot, ".gluecharm", "context");
25132
+ const contextDirAbs = path41.join(p.worktreeRoot, ".gluecharm", "context");
24794
25133
  const covRoot = p.coverageRepositoryRootAbs ?? p.workspaceRootAbs;
24795
25134
  const cov = readNonReferencedFilesFromRepositoryRoot(covRoot);
24796
25135
  const coverageAt = cov.ok ? cov.generatedAt : void 0;
24797
- const workspaceLabel = path40.basename(p.worktreeRoot);
25136
+ const workspaceLabel = path41.basename(p.worktreeRoot);
24798
25137
  const routingMutex = new AsyncMutex();
24799
25138
  const triageMutex = new AsyncMutex();
24800
25139
  const paths = [...p.paths];
@@ -24851,8 +25190,8 @@ async function runRemediationPipelineZeroRefPass(p) {
24851
25190
  }
24852
25191
 
24853
25192
  // src/pipelines/coverage/coverageExecutionReport.ts
24854
- var fs45 = __toESM(require("fs"));
24855
- var path41 = __toESM(require("path"));
25193
+ var fs46 = __toESM(require("fs"));
25194
+ var path42 = __toESM(require("path"));
24856
25195
  var REFERENCE_COVERAGE_EXECUTION_REPORT_BASENAME = "reference-coverage-execution-report.md";
24857
25196
  function inlineMdText(s) {
24858
25197
  const t = s.replace(/\r\n/g, "\n").replace(/\n/g, " ").trim();
@@ -24948,7 +25287,7 @@ function collectNoActionRowsFromRoutingDoc(doc) {
24948
25287
  return rows;
24949
25288
  }
24950
25289
  function readRoutingDocFromDisk(routingAbs) {
24951
- if (!fs45.existsSync(routingAbs)) {
25290
+ if (!fs46.existsSync(routingAbs)) {
24952
25291
  return {
24953
25292
  ok: true,
24954
25293
  doc: { schemaVersion: "1", records: {} }
@@ -24956,7 +25295,7 @@ function readRoutingDocFromDisk(routingAbs) {
24956
25295
  }
24957
25296
  let raw;
24958
25297
  try {
24959
- raw = fs45.readFileSync(routingAbs, "utf-8");
25298
+ raw = fs46.readFileSync(routingAbs, "utf-8");
24960
25299
  } catch (e) {
24961
25300
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
24962
25301
  }
@@ -24976,10 +25315,10 @@ async function runCoverageExecutionReport(p) {
24976
25315
  if (p.abortSignal?.aborted) {
24977
25316
  return { ok: false, error: "Stopped.", cancelled: true };
24978
25317
  }
24979
- const contextDirAbs = path41.join(p.repositoryRootAbs, ".gluecharm", "context");
24980
- const coverageAbs = path41.join(contextDirAbs, "coverage-reference-validation.json");
24981
- const routingAbs = path41.join(contextDirAbs, "zero-reference-routing.json");
24982
- 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);
24983
25322
  const cov = readAndValidateCoverageReferenceValidationFile(coverageAbs);
24984
25323
  if (!cov.ok) {
24985
25324
  return { ok: false, error: `Coverage JSON: ${cov.errors.join("; ")}` };
@@ -24996,20 +25335,20 @@ async function runCoverageExecutionReport(p) {
24996
25335
  }
24997
25336
  let previous;
24998
25337
  try {
24999
- if (fs45.existsSync(outAbs)) {
25000
- previous = fs45.readFileSync(outAbs, "utf-8");
25338
+ if (fs46.existsSync(outAbs)) {
25339
+ previous = fs46.readFileSync(outAbs, "utf-8");
25001
25340
  }
25002
25341
  } catch {
25003
25342
  previous = void 0;
25004
25343
  }
25005
25344
  try {
25006
- fs45.mkdirSync(path41.dirname(outAbs), { recursive: true });
25007
- fs45.writeFileSync(outAbs, md, "utf-8");
25345
+ fs46.mkdirSync(path42.dirname(outAbs), { recursive: true });
25346
+ fs46.writeFileSync(outAbs, md, "utf-8");
25008
25347
  } catch (e) {
25009
25348
  const msg = e instanceof Error ? e.message : String(e);
25010
25349
  if (previous !== void 0) {
25011
25350
  try {
25012
- fs45.writeFileSync(outAbs, previous, "utf-8");
25351
+ fs46.writeFileSync(outAbs, previous, "utf-8");
25013
25352
  } catch {
25014
25353
  }
25015
25354
  }
@@ -25020,8 +25359,8 @@ async function runCoverageExecutionReport(p) {
25020
25359
  }
25021
25360
 
25022
25361
  // src/gluecharm/minimalGluecharmLayout.ts
25023
- var fs46 = __toESM(require("node:fs"));
25024
- var path42 = __toESM(require("node:path"));
25362
+ var fs47 = __toESM(require("node:fs"));
25363
+ var path43 = __toESM(require("node:path"));
25025
25364
  var MINIMAL_GLUECHARM_RELATIVE_DIRS = [
25026
25365
  [".gluecharm", "docs", "srs"],
25027
25366
  [".gluecharm", "content"],
@@ -25029,11 +25368,11 @@ var MINIMAL_GLUECHARM_RELATIVE_DIRS = [
25029
25368
  [".gluecharm", "context"]
25030
25369
  ];
25031
25370
  function ensureMinimalGluecharmLayoutNode(repoRootAbs) {
25032
- const root = path42.resolve(repoRootAbs);
25371
+ const root = path43.resolve(repoRootAbs);
25033
25372
  for (const segments of MINIMAL_GLUECHARM_RELATIVE_DIRS) {
25034
- const dir = path42.join(root, ...segments);
25373
+ const dir = path43.join(root, ...segments);
25035
25374
  try {
25036
- fs46.mkdirSync(dir, { recursive: true });
25375
+ fs47.mkdirSync(dir, { recursive: true });
25037
25376
  } catch (e) {
25038
25377
  const err = e;
25039
25378
  const msg = e instanceof Error ? e.message : String(e);
@@ -25148,6 +25487,7 @@ function buildFactoryPipelineRegistry(cb) {
25148
25487
  // src/factory/generateContextFactoryHeadlessHost.ts
25149
25488
  function buildFactoryDepsHeadless(input) {
25150
25489
  const { storageContext, repoRoot, agentsDirFs, buildOpenCodeOptions, log, signal, macroConfig } = input;
25490
+ const inPlace = input.inPlace === true;
25151
25491
  let adHocWorktree;
25152
25492
  let macroFinalize;
25153
25493
  let macroSourceBranch;
@@ -25162,7 +25502,7 @@ function buildFactoryDepsHeadless(input) {
25162
25502
  if (!layout.ok) {
25163
25503
  return { ok: false, error: layout.error };
25164
25504
  }
25165
- const ctxDir = path43.join(ar, ".gluecharm", "context");
25505
+ const ctxDir = path44.join(ar, ".gluecharm", "context");
25166
25506
  const snap = readArtefactRunSnapshot(storageContext);
25167
25507
  const rows = listMissingWorkstations(ctxDir, ar, snap);
25168
25508
  if (rows.length === 0) {
@@ -25176,7 +25516,7 @@ function buildFactoryDepsHeadless(input) {
25176
25516
  storageContext,
25177
25517
  repositoryRoot: repoRoot,
25178
25518
  worktreeRoot: ar,
25179
- workspaceLabel: path43.basename(ar),
25519
+ workspaceLabel: path44.basename(ar),
25180
25520
  oc: {
25181
25521
  ...oc,
25182
25522
  aceEnabled: getAceAnalysisEnabledForCheckout(ar),
@@ -25204,7 +25544,7 @@ function buildFactoryDepsHeadless(input) {
25204
25544
  }
25205
25545
  try {
25206
25546
  await startPipelineRun(storageContext, repoRoot);
25207
- const folderName = path43.basename(repoRoot);
25547
+ const folderName = path44.basename(repoRoot);
25208
25548
  const oc = buildOpenCodeOptions(handle.path);
25209
25549
  const result = await runSynthesisPipelineDrainFromPreparedWorktree(
25210
25550
  storageContext,
@@ -25261,7 +25601,7 @@ function buildFactoryDepsHeadless(input) {
25261
25601
  if (!ar) {
25262
25602
  return 0;
25263
25603
  }
25264
- const ctxDir = path43.join(ar, ".gluecharm", "context");
25604
+ const ctxDir = path44.join(ar, ".gluecharm", "context");
25265
25605
  const snap = readArtefactRunSnapshot(storageContext);
25266
25606
  return listMissingWorkstations(ctxDir, ar, snap).length;
25267
25607
  };
@@ -25274,7 +25614,7 @@ function buildFactoryDepsHeadless(input) {
25274
25614
  if (!layout.ok) {
25275
25615
  return { ok: false, message: layout.error };
25276
25616
  }
25277
- const contextDir2 = path43.join(ar, ".gluecharm", "context");
25617
+ const contextDir2 = path44.join(ar, ".gluecharm", "context");
25278
25618
  log(`[factory] reference coverage (worktree) \u2014 ${ar}`);
25279
25619
  const res = runCoveragePipeline({
25280
25620
  repositoryRootAbs: ar,
@@ -25334,7 +25674,7 @@ function buildFactoryDepsHeadless(input) {
25334
25674
  diagnosticLog: log
25335
25675
  });
25336
25676
  if (res.ok) {
25337
- return { ok: true, message: `Report: ${path43.basename(res.outputAbsolutePath)}` };
25677
+ return { ok: true, message: `Report: ${path44.basename(res.outputAbsolutePath)}` };
25338
25678
  }
25339
25679
  if (res.cancelled) {
25340
25680
  return { ok: false, cancelled: true, message: "Report generation stopped." };
@@ -25350,7 +25690,7 @@ function buildFactoryDepsHeadless(input) {
25350
25690
  if (!lmLayout.ok) {
25351
25691
  return { ok: false, message: lmLayout.error };
25352
25692
  }
25353
- const contextDir2 = path43.join(snap.adHocWorktreePath, ".gluecharm", "context");
25693
+ const contextDir2 = path44.join(snap.adHocWorktreePath, ".gluecharm", "context");
25354
25694
  const linkGraph = runLinkMappingPipeline(contextDir2, { log });
25355
25695
  if (!linkGraph.ok) {
25356
25696
  return { ok: false, message: linkGraph.error };
@@ -25366,7 +25706,7 @@ function buildFactoryDepsHeadless(input) {
25366
25706
  if (!idxLayout.ok) {
25367
25707
  return { ok: false, message: idxLayout.error };
25368
25708
  }
25369
- const contextDir2 = path43.join(snap.adHocWorktreePath, ".gluecharm", "context");
25709
+ const contextDir2 = path44.join(snap.adHocWorktreePath, ".gluecharm", "context");
25370
25710
  try {
25371
25711
  writeIndexApplicationContext(contextDir2, void 0, {
25372
25712
  sourceBranchAtWorktreeCreation: snap.adHocSourceBranchAtCreation
@@ -25406,6 +25746,12 @@ function buildFactoryDepsHeadless(input) {
25406
25746
  return {
25407
25747
  signal,
25408
25748
  factoryLog: log,
25749
+ readinessLog: (line) => {
25750
+ process.stderr.write(`${line}
25751
+ `);
25752
+ },
25753
+ ...inPlace ? { analysisInPlace: true } : {},
25754
+ readiness: input.readiness,
25409
25755
  config: { ...macroConfig, ...input.synthesisOnly ? { synthesisOnly: true } : {} },
25410
25756
  sleep: (ms) => sleepUntilAborted(ms, signal),
25411
25757
  post: (payload) => {
@@ -25415,14 +25761,14 @@ function buildFactoryDepsHeadless(input) {
25415
25761
  },
25416
25762
  runPrepareAnalysisWorktree: async (resume) => {
25417
25763
  if (resume) {
25418
- if (adHocWorktree && fs47.existsSync(path43.join(adHocWorktree.path, ".git"))) {
25764
+ if (adHocWorktree && fs48.existsSync(path44.join(adHocWorktree.path, ".git"))) {
25419
25765
  return { ok: true };
25420
25766
  }
25421
25767
  const snap = readAnalysisWorkspaceSnapshot(storageContext);
25422
25768
  const wtPath = snap?.adHocWorktreePath?.trim();
25423
25769
  const repo = snap?.adHocRepositoryRoot?.trim() || repoRoot;
25424
- if (wtPath && fs47.existsSync(path43.join(wtPath, ".git"))) {
25425
- adHocWorktree = attachWorktreeHandle(wtPath, repo);
25770
+ if (wtPath && fs48.existsSync(path44.join(wtPath, ".git"))) {
25771
+ adHocWorktree = resolveAnalysisCheckoutHandle(wtPath, repo);
25426
25772
  macroSourceBranch = snap?.adHocSourceBranchAtCreation;
25427
25773
  macroFinalize = () => {
25428
25774
  try {
@@ -25444,8 +25790,10 @@ function buildFactoryDepsHeadless(input) {
25444
25790
  }
25445
25791
  macroFinalize = void 0;
25446
25792
  macroSourceBranch = void 0;
25447
- log(`[factory] create analysis worktree \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}`);
25448
- 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 });
25449
25797
  if (!prep.ok) {
25450
25798
  prep.finalize?.();
25451
25799
  return { ok: false, error: prep.error };
@@ -25637,11 +25985,11 @@ function stderrLinesForFactoryFailures(failures, exitCode) {
25637
25985
  }
25638
25986
 
25639
25987
  // src/factory/updateContext/runUpdateContextFactory.ts
25640
- var path48 = __toESM(require("node:path"));
25988
+ var path49 = __toESM(require("node:path"));
25641
25989
 
25642
25990
  // src/factory/updateContext/updateContextBaseline.ts
25643
- var fs48 = __toESM(require("node:fs"));
25644
- var path44 = __toESM(require("node:path"));
25991
+ var fs49 = __toESM(require("node:fs"));
25992
+ var path45 = __toESM(require("node:path"));
25645
25993
  function isValidIso(s) {
25646
25994
  const t = Date.parse(s);
25647
25995
  return Number.isFinite(t);
@@ -25651,17 +25999,17 @@ function maxMtimeRegularFilesUnderDir(dirAbs) {
25651
25999
  const walk = (d) => {
25652
26000
  let entries;
25653
26001
  try {
25654
- entries = fs48.readdirSync(d, { withFileTypes: true });
26002
+ entries = fs49.readdirSync(d, { withFileTypes: true });
25655
26003
  } catch {
25656
26004
  return;
25657
26005
  }
25658
26006
  for (const e of entries) {
25659
- const p = path44.join(d, e.name);
26007
+ const p = path45.join(d, e.name);
25660
26008
  if (e.isDirectory()) {
25661
26009
  walk(p);
25662
26010
  } else if (e.isFile()) {
25663
26011
  try {
25664
- const st = fs48.statSync(p);
26012
+ const st = fs49.statSync(p);
25665
26013
  const m = st.mtimeMs;
25666
26014
  if (best === null || m > best) {
25667
26015
  best = m;
@@ -25682,8 +26030,8 @@ function resolveUpdateContextBaseline(repoRootAbs, repoConfig) {
25682
26030
  if (last.length > 0 && isValidIso(last)) {
25683
26031
  return { baselineIsoUtc: new Date(last).toISOString(), source: "lastRunAt" };
25684
26032
  }
25685
- const ctxDir = path44.join(repoRootAbs, ".gluecharm", "context");
25686
- if (!fs48.existsSync(ctxDir)) {
26033
+ const ctxDir = path45.join(repoRootAbs, ".gluecharm", "context");
26034
+ if (!fs49.existsSync(ctxDir)) {
25687
26035
  return null;
25688
26036
  }
25689
26037
  const maxMs = maxMtimeRegularFilesUnderDir(ctxDir);
@@ -25706,8 +26054,8 @@ function persistUpdateContextLastRunAt(repoRootAbs, isoUtc) {
25706
26054
 
25707
26055
  // src/factory/updateContext/updateContextGitWindow.ts
25708
26056
  var import_node_child_process3 = require("node:child_process");
25709
- var fs49 = __toESM(require("node:fs"));
25710
- var path45 = __toESM(require("node:path"));
26057
+ var fs50 = __toESM(require("node:fs"));
26058
+ var path46 = __toESM(require("node:path"));
25711
26059
  var GIT_ENV = { ...process.env, GIT_TERMINAL_PROMPT: "0" };
25712
26060
  function gitLines(repoRootAbs, args) {
25713
26061
  const r = (0, import_node_child_process3.execFileSync)("git", ["-c", "core.quotepath=false", ...args], {
@@ -25731,8 +26079,8 @@ function parseGitLogIso(line) {
25731
26079
  return { hash, iso };
25732
26080
  }
25733
26081
  function discoverCommitWindowAndTouchedPaths(repoRootAbs, baselineIsoUtc) {
25734
- const root = path45.resolve(repoRootAbs);
25735
- if (!fs49.existsSync(path45.join(root, ".git"))) {
26082
+ const root = path46.resolve(repoRootAbs);
26083
+ if (!fs50.existsSync(path46.join(root, ".git"))) {
25736
26084
  return { ok: false, error: "Not a git repository (missing .git)." };
25737
26085
  }
25738
26086
  const baselineMs = Date.parse(baselineIsoUtc);
@@ -25791,13 +26139,13 @@ function discoverCommitWindowAndTouchedPaths(repoRootAbs, baselineIsoUtc) {
25791
26139
  };
25792
26140
  }
25793
26141
  function filterPathsExistingInWorktree(worktreeRootAbs, pathsPosix) {
25794
- const root = path45.resolve(worktreeRootAbs);
26142
+ const root = path46.resolve(worktreeRootAbs);
25795
26143
  const out = [];
25796
26144
  for (const p of pathsPosix) {
25797
26145
  const rel = p.replace(/\\/g, "/");
25798
- const abs = path45.join(root, ...rel.split("/"));
26146
+ const abs = path46.join(root, ...rel.split("/"));
25799
26147
  try {
25800
- if (fs49.existsSync(abs) && fs49.statSync(abs).isFile()) {
26148
+ if (fs50.existsSync(abs) && fs50.statSync(abs).isFile()) {
25801
26149
  out.push(rel);
25802
26150
  }
25803
26151
  } catch {
@@ -25807,8 +26155,8 @@ function filterPathsExistingInWorktree(worktreeRootAbs, pathsPosix) {
25807
26155
  }
25808
26156
 
25809
26157
  // src/factory/updateContext/updateContextReport.ts
25810
- var fs50 = __toESM(require("node:fs"));
25811
- var path46 = __toESM(require("node:path"));
26158
+ var fs51 = __toESM(require("node:fs"));
26159
+ var path47 = __toESM(require("node:path"));
25812
26160
  var CHANGES_SINCE_DATE_BASENAME = "changes-since-date.md";
25813
26161
  function renderChangesSinceDateMarkdown(p) {
25814
26162
  const lines = [
@@ -25849,9 +26197,9 @@ function renderChangesSinceDateMarkdown(p) {
25849
26197
  }
25850
26198
  function writeChangesSinceDateReport(contextDirAbs, body) {
25851
26199
  try {
25852
- fs50.mkdirSync(contextDirAbs, { recursive: true });
25853
- const target = path46.join(contextDirAbs, CHANGES_SINCE_DATE_BASENAME);
25854
- 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");
25855
26203
  return { ok: true };
25856
26204
  } catch (e) {
25857
26205
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
@@ -25859,13 +26207,13 @@ function writeChangesSinceDateReport(contextDirAbs, body) {
25859
26207
  }
25860
26208
 
25861
26209
  // src/factory/updateContext/updateContextSeedCheck.ts
25862
- var fs51 = __toESM(require("node:fs"));
25863
- var path47 = __toESM(require("node:path"));
26210
+ var fs52 = __toESM(require("node:fs"));
26211
+ var path48 = __toESM(require("node:path"));
25864
26212
  var INDEX_BASENAME = "index-application-context.json";
25865
26213
  var CHANGES_REPORT = "changes-since-date.md";
25866
26214
  function tryParseJsonFile(abs) {
25867
26215
  try {
25868
- const raw = fs51.readFileSync(abs, "utf-8");
26216
+ const raw = fs52.readFileSync(abs, "utf-8");
25869
26217
  JSON.parse(raw);
25870
26218
  return true;
25871
26219
  } catch {
@@ -25873,16 +26221,16 @@ function tryParseJsonFile(abs) {
25873
26221
  }
25874
26222
  }
25875
26223
  function isWorktreeContextSeeded(contextDirAbs) {
25876
- if (!fs51.existsSync(contextDirAbs)) {
26224
+ if (!fs52.existsSync(contextDirAbs)) {
25877
26225
  return false;
25878
26226
  }
25879
- const indexAbs = path47.join(contextDirAbs, INDEX_BASENAME);
25880
- 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)) {
25881
26229
  return true;
25882
26230
  }
25883
26231
  let names;
25884
26232
  try {
25885
- names = fs51.readdirSync(contextDirAbs);
26233
+ names = fs52.readdirSync(contextDirAbs);
25886
26234
  } catch {
25887
26235
  return false;
25888
26236
  }
@@ -25894,9 +26242,9 @@ function isWorktreeContextSeeded(contextDirAbs) {
25894
26242
  if (!name.endsWith(".md") && !name.endsWith(".json")) {
25895
26243
  continue;
25896
26244
  }
25897
- const p = path47.join(contextDirAbs, name);
26245
+ const p = path48.join(contextDirAbs, name);
25898
26246
  try {
25899
- if (fs51.statSync(p).isFile()) {
26247
+ if (fs52.statSync(p).isFile()) {
25900
26248
  distinct.add(name);
25901
26249
  }
25902
26250
  } catch {
@@ -25908,12 +26256,14 @@ function isWorktreeContextSeeded(contextDirAbs) {
25908
26256
  // src/factory/updateContext/runUpdateContextFactory.ts
25909
26257
  var REMEDIATION_CHUNK_MAX = 40;
25910
26258
  function contextDirUnderRoot(wtRoot) {
25911
- return path48.join(wtRoot, ".gluecharm", "context");
26259
+ return path49.join(wtRoot, ".gluecharm", "context");
25912
26260
  }
25913
26261
  async function runUpdateContextFactory(deps) {
26262
+ const inPlace = deps.inPlace === true;
25914
26263
  const baseMeta = {
25915
26264
  command: "update_context",
25916
- uploadRequested: false
26265
+ uploadRequested: false,
26266
+ ...inPlace ? { analysisInPlace: true } : {}
25917
26267
  };
25918
26268
  const baseline = resolveUpdateContextBaseline(deps.repoRootAbs, deps.repoConfig);
25919
26269
  if (!baseline) {
@@ -25938,8 +26288,42 @@ async function runUpdateContextFactory(deps) {
25938
26288
  };
25939
26289
  }
25940
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
+ }
25941
26324
  const prep = await prepareSynthesisWorktree(deps.storage, deps.repoRootAbs, deps.log, {
25942
- clearPriorArtefactRun: true
26325
+ clearPriorArtefactRun: true,
26326
+ inPlace
25943
26327
  });
25944
26328
  if (!prep.ok) {
25945
26329
  prep.finalize?.();
@@ -25960,7 +26344,7 @@ async function runUpdateContextFactory(deps) {
25960
26344
  const finalizeWt = prep.finalize;
25961
26345
  const wsCtxDir = contextDirUnderRoot(deps.repoRootAbs);
25962
26346
  let ctxDirAbs = contextDirUnderRoot(handle.path);
25963
- if (!isWorktreeContextSeeded(ctxDirAbs) && isWorktreeContextSeeded(wsCtxDir)) {
26347
+ if (!inPlace && !isWorktreeContextSeeded(ctxDirAbs) && isWorktreeContextSeeded(wsCtxDir)) {
25964
26348
  deps.log("[update-context] seeding worktree context from workspace .gluecharm/context/");
25965
26349
  promoteContextDirectoryToWorkspaceFs(wsCtxDir, handle.path);
25966
26350
  ctxDirAbs = contextDirUnderRoot(handle.path);
@@ -26139,30 +26523,34 @@ async function runUpdateContextFactory(deps) {
26139
26523
  }
26140
26524
  let promoted = false;
26141
26525
  if (deps.merged.promoteContextToWorkspace && ctxDirAbs) {
26142
- try {
26143
- const { filesCopied } = promoteContextDirectoryToWorkspaceFs(ctxDirAbs, deps.repoRootAbs);
26144
- deps.log(`[update-context] promoted ${String(filesCopied)} file(s) \u2192 ${deps.repoRootAbs}`);
26145
- promoted = filesCopied > 0;
26146
- } catch (e) {
26147
- finalizeWt?.();
26148
- return {
26149
- exitOk: false,
26150
- ok: false,
26151
- code: "PROMOTE_FAILED",
26152
- error: e instanceof Error ? e.message : String(e),
26153
- baselineDate: baseline.baselineIsoUtc,
26154
- baselineSource: baseline.source,
26155
- headCommit: gitWin.headCommit,
26156
- rangeStartCommit: gitWin.rangeStartCommit,
26157
- commitsReviewed: gitWin.commitsInOrder.length,
26158
- filesDetected: inventory.length,
26159
- filesRemediated,
26160
- analysisWorktreeRoot: handle.path,
26161
- changesReportRelativePath: ".gluecharm/context/changes-since-date.md",
26162
- remediationSkipped,
26163
- ...remediationSkipReason ? { skipReason: remediationSkipReason } : {},
26164
- ...baseMeta
26165
- };
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
+ }
26166
26554
  }
26167
26555
  }
26168
26556
  const uploadSkipped = true;
@@ -26198,12 +26586,12 @@ async function runUpdateContextFactory(deps) {
26198
26586
  }
26199
26587
 
26200
26588
  // src/factory/contextDrift/runContextDriftFactory.ts
26201
- var fs57 = __toESM(require("node:fs"));
26202
- var path53 = __toESM(require("node:path"));
26589
+ var fs58 = __toESM(require("node:fs"));
26590
+ var path54 = __toESM(require("node:path"));
26203
26591
 
26204
26592
  // src/factory/contextDrift/contextDriftManifest.ts
26205
- var fs52 = __toESM(require("node:fs"));
26206
- var path49 = __toESM(require("node:path"));
26593
+ var fs53 = __toESM(require("node:fs"));
26594
+ var path50 = __toESM(require("node:path"));
26207
26595
  var MAX_REFERENCE_BYTES = 256 * 1024;
26208
26596
  var MAX_EVIDENCE_FILES = 300;
26209
26597
  var MAX_EVIDENCE_READ = 512 * 1024;
@@ -26211,7 +26599,7 @@ var MAX_EXCERPT = 4e3;
26211
26599
  function readFileLimited(abs, maxBytes) {
26212
26600
  let buf;
26213
26601
  try {
26214
- buf = fs52.readFileSync(abs);
26602
+ buf = fs53.readFileSync(abs);
26215
26603
  } catch {
26216
26604
  return { text: "", truncated: false };
26217
26605
  }
@@ -26223,16 +26611,16 @@ function collectEvidencePaths(repoRoot) {
26223
26611
  const out = [];
26224
26612
  const roots = ["src", "test", "tests", "packages", ".gluecharm", "scripts"];
26225
26613
  for (const rel of roots) {
26226
- const abs = path49.join(repoRoot, rel);
26227
- if (!fs52.existsSync(abs)) {
26614
+ const abs = path50.join(repoRoot, rel);
26615
+ if (!fs53.existsSync(abs)) {
26228
26616
  continue;
26229
26617
  }
26230
26618
  walkFiles(abs, repoRoot, out, 0);
26231
26619
  }
26232
26620
  for (const leaf of ["package.json", "tsconfig.json"]) {
26233
- const abs = path49.join(repoRoot, leaf);
26234
- if (fs52.existsSync(abs) && fs52.statSync(abs).isFile()) {
26235
- 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("/");
26236
26624
  out.push(r);
26237
26625
  }
26238
26626
  }
@@ -26249,7 +26637,7 @@ function walkFiles(dir, repoRoot, out, depth) {
26249
26637
  }
26250
26638
  let entries;
26251
26639
  try {
26252
- entries = fs52.readdirSync(dir, { withFileTypes: true });
26640
+ entries = fs53.readdirSync(dir, { withFileTypes: true });
26253
26641
  } catch {
26254
26642
  return;
26255
26643
  }
@@ -26257,13 +26645,13 @@ function walkFiles(dir, repoRoot, out, depth) {
26257
26645
  if (e.name === "node_modules" || e.name === ".git" || e.name === "dist" || e.name === "out") {
26258
26646
  continue;
26259
26647
  }
26260
- const full = path49.join(dir, e.name);
26648
+ const full = path50.join(dir, e.name);
26261
26649
  if (e.isDirectory()) {
26262
26650
  walkFiles(full, repoRoot, out, depth + 1);
26263
26651
  } else if (e.isFile()) {
26264
- const ext = path49.extname(e.name).toLowerCase();
26652
+ const ext = path50.extname(e.name).toLowerCase();
26265
26653
  if ([".ts", ".tsx", ".js", ".mjs", ".cjs", ".json", ".md", ".yaml", ".yml"].includes(ext) || e.name === "Dockerfile") {
26266
- const rel = path49.relative(repoRoot, full).split(path49.sep).join("/");
26654
+ const rel = path50.relative(repoRoot, full).split(path50.sep).join("/");
26267
26655
  out.push(rel);
26268
26656
  }
26269
26657
  }
@@ -26273,7 +26661,7 @@ function buildComparisonManifest(args) {
26273
26661
  const references = [];
26274
26662
  let referenceTruncated = false;
26275
26663
  for (const abs of args.bundleAbsFiles) {
26276
- const rel = path49.relative(args.worktreeRoot, abs).split(path49.sep).join("/");
26664
+ const rel = path50.relative(args.worktreeRoot, abs).split(path50.sep).join("/");
26277
26665
  const { text, truncated } = readFileLimited(abs, MAX_REFERENCE_BYTES);
26278
26666
  references.push({ path: rel, content: text, truncated });
26279
26667
  if (truncated) {
@@ -26285,8 +26673,8 @@ function buildComparisonManifest(args) {
26285
26673
  const omitted = Math.max(0, allEvidence.length - evidencePathsTrimmed.length);
26286
26674
  const evidenceFiles = [];
26287
26675
  for (const rel of evidencePathsTrimmed) {
26288
- const abs = path49.join(args.worktreeRoot, ...rel.split("/"));
26289
- 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;
26290
26678
  const size = st && st.isFile() ? st.size : 0;
26291
26679
  const { text, truncated } = readFileLimited(abs, MAX_EVIDENCE_READ);
26292
26680
  const excerpt = truncated ? `${text.slice(0, MAX_EXCERPT)}
@@ -26296,7 +26684,7 @@ function buildComparisonManifest(args) {
26296
26684
  }
26297
26685
  return {
26298
26686
  runDate: args.runDate,
26299
- 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("/")),
26300
26688
  references,
26301
26689
  evidenceFiles,
26302
26690
  evidencePathsOnly: [],
@@ -26308,8 +26696,8 @@ function buildComparisonManifest(args) {
26308
26696
  }
26309
26697
 
26310
26698
  // src/factory/contextDrift/contextDriftAgent.ts
26311
- var fs53 = __toESM(require("node:fs"));
26312
- var path50 = __toESM(require("node:path"));
26699
+ var fs54 = __toESM(require("node:fs"));
26700
+ var path51 = __toESM(require("node:path"));
26313
26701
 
26314
26702
  // src/factory/contextDrift/contextDriftPayload.ts
26315
26703
  function isNonEmptyString2(v) {
@@ -26454,17 +26842,17 @@ function buildDriftPrompt(args) {
26454
26842
  ].join("\n");
26455
26843
  }
26456
26844
  async function runDriftComparisonOpenCode(args) {
26457
- const runDir = path50.join(args.worktreeRoot, ".opencode", "_run");
26458
- fs53.mkdirSync(runDir, { recursive: true });
26459
- const manifestPath = path50.join(runDir, "context-drift-manifest.json");
26460
- const outputPath = path50.join(runDir, "context-drift-payload.json");
26461
- 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)}
26462
26850
  `, "utf8");
26463
- if (fs53.existsSync(outputPath)) {
26464
- fs53.unlinkSync(outputPath);
26851
+ if (fs54.existsSync(outputPath)) {
26852
+ fs54.unlinkSync(outputPath);
26465
26853
  }
26466
- const promptPath = path50.join(runDir, `context-drift-${Date.now()}.prompt.txt`);
26467
- fs53.writeFileSync(
26854
+ const promptPath = path51.join(runDir, `context-drift-${Date.now()}.prompt.txt`);
26855
+ fs54.writeFileSync(
26468
26856
  promptPath,
26469
26857
  buildDriftPrompt({
26470
26858
  worktreeRoot: args.worktreeRoot,
@@ -26481,7 +26869,7 @@ async function runDriftComparisonOpenCode(args) {
26481
26869
  });
26482
26870
  const title = buildOpenCodeSessionTitle({
26483
26871
  runId: "context-drift",
26484
- workItemId: path50.basename(args.worktreeRoot).slice(0, 24) || "wt",
26872
+ workItemId: path51.basename(args.worktreeRoot).slice(0, 24) || "wt",
26485
26873
  stepLabel: "context-drift"
26486
26874
  });
26487
26875
  const argv = injectPrimaryOpenCodeSessionArgv(expanded, title);
@@ -26506,7 +26894,7 @@ async function runDriftComparisonOpenCode(args) {
26506
26894
  }
26507
26895
  let raw;
26508
26896
  try {
26509
- const txt = fs53.readFileSync(outputPath, "utf8");
26897
+ const txt = fs54.readFileSync(outputPath, "utf8");
26510
26898
  raw = JSON.parse(txt);
26511
26899
  } catch (e) {
26512
26900
  return {
@@ -26523,9 +26911,9 @@ async function runDriftComparisonOpenCode(args) {
26523
26911
 
26524
26912
  // src/factory/contextDrift/contextDriftPaths.ts
26525
26913
  var crypto2 = __toESM(require("node:crypto"));
26526
- var fs54 = __toESM(require("node:fs"));
26527
- var path51 = __toESM(require("node:path"));
26528
- 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");
26529
26917
  function sanitizeSlug(raw) {
26530
26918
  const s = raw.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
26531
26919
  return s.length > 0 ? s : "drift";
@@ -26534,9 +26922,9 @@ function utcDateString(d) {
26534
26922
  return d.toISOString().slice(0, 10);
26535
26923
  }
26536
26924
  function resolveInsideRepo(repoRootAbs, userPath) {
26537
- const abs = path51.isAbsolute(userPath) ? path51.normalize(userPath) : path51.resolve(repoRootAbs, userPath);
26538
- const rel = path51.relative(repoRootAbs, abs);
26539
- 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)) {
26540
26928
  return { ok: false };
26541
26929
  }
26542
26930
  return { ok: true, abs };
@@ -26546,7 +26934,7 @@ function computeSlug(args) {
26546
26934
  return sanitizeSlug(args.label.trim());
26547
26935
  }
26548
26936
  const r = resolveInsideRepo(args.repoRootAbs, args.referencePath);
26549
- 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);
26550
26938
  return sanitizeSlug(base);
26551
26939
  }
26552
26940
  function driftFilename(slug, runDate) {
@@ -26562,7 +26950,7 @@ function maybeDedupeSlug(slug, referenceRelPosix) {
26562
26950
  function discoverReferenceBundle(worktreeRoot, referenceAbsInWorktree) {
26563
26951
  let st;
26564
26952
  try {
26565
- st = fs54.statSync(referenceAbsInWorktree);
26953
+ st = fs55.statSync(referenceAbsInWorktree);
26566
26954
  } catch {
26567
26955
  return { ok: false, error: `Reference path not found in analysis worktree: ${referenceAbsInWorktree}` };
26568
26956
  }
@@ -26583,12 +26971,12 @@ function discoverReferenceBundle(worktreeRoot, referenceAbsInWorktree) {
26583
26971
  }
26584
26972
  let entries;
26585
26973
  try {
26586
- entries = fs54.readdirSync(dir, { withFileTypes: true });
26974
+ entries = fs55.readdirSync(dir, { withFileTypes: true });
26587
26975
  } catch {
26588
26976
  return;
26589
26977
  }
26590
26978
  for (const e of entries) {
26591
- const full = path51.join(dir, e.name);
26979
+ const full = path52.join(dir, e.name);
26592
26980
  if (e.isDirectory()) {
26593
26981
  if (e.name === "node_modules" || e.name === ".git") {
26594
26982
  continue;
@@ -26608,7 +26996,7 @@ function discoverReferenceBundle(worktreeRoot, referenceAbsInWorktree) {
26608
26996
  }
26609
26997
  function pickReferenceRootDocument(args) {
26610
26998
  if (args.indexOverrideAbs) {
26611
- if (!fs54.existsSync(args.indexOverrideAbs) || !args.indexOverrideAbs.endsWith(".md")) {
26999
+ if (!fs55.existsSync(args.indexOverrideAbs) || !args.indexOverrideAbs.endsWith(".md")) {
26612
27000
  return { ok: false, error: "--index must point to an existing .md file under the repo." };
26613
27001
  }
26614
27002
  return { ok: true, path: args.indexOverrideAbs };
@@ -26618,8 +27006,8 @@ function pickReferenceRootDocument(args) {
26618
27006
  }
26619
27007
  const dir = args.referenceAbsInWorktree;
26620
27008
  for (const name of ["index.md", "README.md"]) {
26621
- const p = path51.join(dir, name);
26622
- if (fs54.existsSync(p) && fs54.statSync(p).isFile()) {
27009
+ const p = path52.join(dir, name);
27010
+ if (fs55.existsSync(p) && fs55.statSync(p).isFile()) {
26623
27011
  return { ok: true, path: p };
26624
27012
  }
26625
27013
  }
@@ -26629,20 +27017,20 @@ function pickReferenceRootDocument(args) {
26629
27017
  };
26630
27018
  }
26631
27019
  function toWorktreeRelative(worktreeRoot, absolute) {
26632
- return path51.relative(worktreeRoot, absolute).split(path51.sep).join("/");
27020
+ return path52.relative(worktreeRoot, absolute).split(path52.sep).join("/");
26633
27021
  }
26634
27022
  function toPosixPath(p) {
26635
- return p.split(path51.sep).join("/");
27023
+ return p.split(path52.sep).join("/");
26636
27024
  }
26637
27025
 
26638
27026
  // src/factory/contextDrift/contextDriftIndex.ts
26639
- var fs55 = __toESM(require("node:fs"));
27027
+ var fs56 = __toESM(require("node:fs"));
26640
27028
  var START = "<!-- easyspecs-drift-links:start -->";
26641
27029
  var END = "<!-- easyspecs-drift-links:end -->";
26642
27030
  function patchReferenceIndexWithDriftLink(args) {
26643
27031
  let body;
26644
27032
  try {
26645
- body = fs55.readFileSync(args.referenceRootAbsolute, "utf8");
27033
+ body = fs56.readFileSync(args.referenceRootAbsolute, "utf8");
26646
27034
  } catch (e) {
26647
27035
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
26648
27036
  }
@@ -26663,7 +27051,7 @@ ${block}
26663
27051
  `;
26664
27052
  }
26665
27053
  try {
26666
- fs55.writeFileSync(args.referenceRootAbsolute, next, "utf8");
27054
+ fs56.writeFileSync(args.referenceRootAbsolute, next, "utf8");
26667
27055
  } catch (e) {
26668
27056
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
26669
27057
  }
@@ -26674,19 +27062,32 @@ function escapeRe(s) {
26674
27062
  }
26675
27063
 
26676
27064
  // src/factory/contextDrift/contextDriftPromote.ts
26677
- var fs56 = __toESM(require("node:fs"));
26678
- var path52 = __toESM(require("node:path"));
27065
+ var fs57 = __toESM(require("node:fs"));
27066
+ var path53 = __toESM(require("node:path"));
26679
27067
  function copyWorktreeFileToWorkspace(args) {
26680
- const src = path52.join(args.worktreeRoot, ...args.relativePosix.split("/"));
26681
- const dest = path52.join(args.workspaceRoot, ...args.relativePosix.split("/"));
26682
- fs56.mkdirSync(path52.dirname(dest), { recursive: true });
26683
- 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);
26684
27080
  }
26685
27081
 
26686
27082
  // src/factory/contextDrift/runContextDriftFactory.ts
26687
27083
  async function runContextDriftFactory(deps) {
26688
27084
  const runDate = utcDateString(/* @__PURE__ */ new Date());
26689
- 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
+ };
26690
27091
  const resolved = resolveInsideRepo(deps.repoRootAbs, deps.referencePathArg);
26691
27092
  if (!resolved.ok) {
26692
27093
  return {
@@ -26699,7 +27100,7 @@ async function runContextDriftFactory(deps) {
26699
27100
  };
26700
27101
  }
26701
27102
  const refAbsWorkspace = resolved.abs;
26702
- if (!fs57.existsSync(refAbsWorkspace)) {
27103
+ if (!fs58.existsSync(refAbsWorkspace)) {
26703
27104
  return {
26704
27105
  exitOk: false,
26705
27106
  ok: false,
@@ -26712,7 +27113,7 @@ async function runContextDriftFactory(deps) {
26712
27113
  let indexOverrideAbsWorkspace;
26713
27114
  if (deps.indexOverrideArg?.trim()) {
26714
27115
  const ir = resolveInsideRepo(deps.repoRootAbs, deps.indexOverrideArg.trim());
26715
- if (!ir.ok || !fs57.existsSync(ir.abs)) {
27116
+ if (!ir.ok || !fs58.existsSync(ir.abs)) {
26716
27117
  return {
26717
27118
  exitOk: false,
26718
27119
  ok: false,
@@ -26730,7 +27131,7 @@ async function runContextDriftFactory(deps) {
26730
27131
  ok: true,
26731
27132
  code: "DRY_RUN",
26732
27133
  ...baseMeta,
26733
- referenceRootDocument: toPosixPath(path53.relative(deps.repoRootAbs, refAbsWorkspace)) + (fs57.statSync(refAbsWorkspace).isDirectory() ? "/" : ""),
27134
+ referenceRootDocument: toPosixPath(path54.relative(deps.repoRootAbs, refAbsWorkspace)) + (fs58.statSync(refAbsWorkspace).isDirectory() ? "/" : ""),
26734
27135
  driftReportPath: null,
26735
27136
  analysisWorktreeRoot: "",
26736
27137
  promoted: false,
@@ -26740,8 +27141,38 @@ async function runContextDriftFactory(deps) {
26740
27141
  dryRun: true
26741
27142
  };
26742
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
+ }
26743
27173
  const prep = await prepareSynthesisWorktree(deps.storage, deps.repoRootAbs, deps.log, {
26744
- clearPriorArtefactRun: false
27174
+ clearPriorArtefactRun: false,
27175
+ inPlace
26745
27176
  });
26746
27177
  if (!prep.ok) {
26747
27178
  prep.finalize?.();
@@ -26757,8 +27188,8 @@ async function runContextDriftFactory(deps) {
26757
27188
  const handle = prep.handle;
26758
27189
  const finalizeWt = prep.finalize;
26759
27190
  const wt = handle.path;
26760
- const refRel = path53.relative(deps.repoRootAbs, refAbsWorkspace).split(path53.sep).join("/");
26761
- 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("/"));
26762
27193
  try {
26763
27194
  materializeOpenCodeAgentsWithAce(deps.agentsDirFs, wt, {
26764
27195
  enabled: getAceAnalysisEnabledForCheckout(wt),
@@ -26797,9 +27228,9 @@ async function runContextDriftFactory(deps) {
26797
27228
  ...baseMeta
26798
27229
  };
26799
27230
  }
26800
- 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;
26801
27232
  const rootPick = pickReferenceRootDocument({
26802
- referencePathIsFile: fs57.statSync(refAbsWt).isFile(),
27233
+ referencePathIsFile: fs58.statSync(refAbsWt).isFile(),
26803
27234
  referenceAbsInWorktree: refAbsWt,
26804
27235
  bundleFiles: bundle.bundleFiles,
26805
27236
  indexOverrideAbs: indexWt
@@ -26825,9 +27256,9 @@ async function runContextDriftFactory(deps) {
26825
27256
  let slug = computeSlug({ label: deps.label, referencePath: deps.referencePathArg, repoRootAbs: deps.repoRootAbs });
26826
27257
  slug = maybeDedupeSlug(slug, refRel);
26827
27258
  const driftBase = driftFilename(slug, runDate);
26828
- const driftDirWt = path53.join(wt, DRIFT_CONTEXT_SUBDIR);
26829
- fs57.mkdirSync(driftDirWt, { recursive: true });
26830
- 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);
26831
27262
  let payload;
26832
27263
  if (deps.testOnlyFixturePayload) {
26833
27264
  payload = deps.testOnlyFixturePayload;
@@ -26863,7 +27294,7 @@ async function runContextDriftFactory(deps) {
26863
27294
  manifestTruncation: manifest.truncation
26864
27295
  });
26865
27296
  try {
26866
- fs57.writeFileSync(driftAbsWt, md, "utf8");
27297
+ fs58.writeFileSync(driftAbsWt, md, "utf8");
26867
27298
  } catch (e) {
26868
27299
  finalizeWt?.();
26869
27300
  return {
@@ -26876,7 +27307,7 @@ async function runContextDriftFactory(deps) {
26876
27307
  ...baseMeta
26877
27308
  };
26878
27309
  }
26879
- 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("/");
26880
27311
  const linkRes = patchReferenceIndexWithDriftLink({
26881
27312
  referenceRootAbsolute: refRootAbsWt,
26882
27313
  relativeLinkFromRootToDrift: driftRelFromRootDir,
@@ -26895,10 +27326,10 @@ async function runContextDriftFactory(deps) {
26895
27326
  ...baseMeta
26896
27327
  };
26897
27328
  }
26898
- const driftRelPosix = toPosixPath(path53.relative(wt, driftAbsWt));
26899
- const rootRelPosix = toPosixPath(path53.relative(wt, refRootAbsWt));
27329
+ const driftRelPosix = toPosixPath(path54.relative(wt, driftAbsWt));
27330
+ const rootRelPosix = toPosixPath(path54.relative(wt, refRootAbsWt));
26900
27331
  const promoteEffective = deps.merged.promoteContextToWorkspace !== false;
26901
- if (promoteEffective) {
27332
+ if (promoteEffective && !inPlace) {
26902
27333
  try {
26903
27334
  copyWorktreeFileToWorkspace({
26904
27335
  worktreeRoot: wt,
@@ -26923,8 +27354,10 @@ async function runContextDriftFactory(deps) {
26923
27354
  ...baseMeta
26924
27355
  };
26925
27356
  }
27357
+ } else if (promoteEffective && inPlace) {
27358
+ deps.log("[context-drift] in-place analysis \u2014 promote skipped (artefacts already under repository root)");
26926
27359
  }
26927
- const driftReportPathFs = promoteEffective ? path53.join(deps.repoRootAbs, ...driftRelPosix.split("/")) : driftAbsWt;
27360
+ const driftReportPathFs = promoteEffective ? path54.join(deps.repoRootAbs, ...driftRelPosix.split("/")) : driftAbsWt;
26928
27361
  return {
26929
27362
  exitOk: true,
26930
27363
  ok: true,
@@ -26933,7 +27366,7 @@ async function runContextDriftFactory(deps) {
26933
27366
  referenceRootDocument: rootRelPosix,
26934
27367
  driftReportPath: driftReportPathFs,
26935
27368
  analysisWorktreeRoot: wt,
26936
- promoted: promoteEffective,
27369
+ promoted: promoteEffective && !inPlace,
26937
27370
  nameOfChangeSlug: slug,
26938
27371
  runDate,
26939
27372
  agentInvoked: !deps.testOnlyFixturePayload,
@@ -26942,8 +27375,8 @@ async function runContextDriftFactory(deps) {
26942
27375
  }
26943
27376
 
26944
27377
  // src/analysis/coordinationDuplicatesDiagnosis.ts
26945
- var fs58 = __toESM(require("fs"));
26946
- var path54 = __toESM(require("path"));
27378
+ var fs59 = __toESM(require("fs"));
27379
+ var path55 = __toESM(require("path"));
26947
27380
  var import__7 = __toESM(require__());
26948
27381
  var COORDINATION_DUPLICATES_REPORT_BASENAME = "coordination-duplicates-report.json";
26949
27382
  var COORDINATION_LIST_SCAN_ENTRIES = [
@@ -26969,7 +27402,7 @@ var RE_MD_DM_FD = /^DM-\d+_FD-\d+-.+\.md$/i;
26969
27402
  var RE_MD_DM = /^DM-\d+-.+\.md$/i;
26970
27403
  var RE_MD_TS = /^TS-\d+-.+\.md$/i;
26971
27404
  function looksLikeCoordinationDetailMarkdownBasename(basename17) {
26972
- if (!basename17 || basename17 !== path54.basename(basename17) || !/\.md$/i.test(basename17)) {
27405
+ if (!basename17 || basename17 !== path55.basename(basename17) || !/\.md$/i.test(basename17)) {
26973
27406
  return false;
26974
27407
  }
26975
27408
  if (STAPLE_CONTEXT_MARKDOWN_BASENAMES.has(basename17)) {
@@ -26978,12 +27411,12 @@ function looksLikeCoordinationDetailMarkdownBasename(basename17) {
26978
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);
26979
27412
  }
26980
27413
  function loadRawFeatureRows(contextDirAbs) {
26981
- const p = path54.join(contextDirAbs, "features-list.json");
26982
- if (!fs58.existsSync(p)) {
27414
+ const p = path55.join(contextDirAbs, "features-list.json");
27415
+ if (!fs59.existsSync(p)) {
26983
27416
  return [];
26984
27417
  }
26985
27418
  try {
26986
- const raw = stripUtf8Bom6(fs58.readFileSync(p, "utf-8"));
27419
+ const raw = stripUtf8Bom6(fs59.readFileSync(p, "utf-8"));
26987
27420
  const doc = JSON.parse(raw);
26988
27421
  return Array.isArray(doc.features) ? doc.features : [];
26989
27422
  } catch {
@@ -27018,7 +27451,7 @@ function findOrphanCoordinationMarkdown(contextDirAbs) {
27018
27451
  const featureRows = loadRawFeatureRows(contextDirAbs);
27019
27452
  let dirents;
27020
27453
  try {
27021
- dirents = fs58.readdirSync(contextDirAbs, { withFileTypes: true });
27454
+ dirents = fs59.readdirSync(contextDirAbs, { withFileTypes: true });
27022
27455
  } catch {
27023
27456
  return [];
27024
27457
  }
@@ -27271,14 +27704,14 @@ function buildCoordinationDuplicatesReport(input) {
27271
27704
  const lists = [];
27272
27705
  const duplicateGroups = [];
27273
27706
  for (const entry of COORDINATION_LIST_SCAN_ENTRIES) {
27274
- const filePath = path54.join(input.contextDirAbsolute, entry.basename);
27275
- if (!fs58.existsSync(filePath)) {
27707
+ const filePath = path55.join(input.contextDirAbsolute, entry.basename);
27708
+ if (!fs59.existsSync(filePath)) {
27276
27709
  lists.push({ basename: entry.basename, status: "missing" });
27277
27710
  continue;
27278
27711
  }
27279
27712
  let raw;
27280
27713
  try {
27281
- raw = stripUtf8Bom6(fs58.readFileSync(filePath, "utf-8"));
27714
+ raw = stripUtf8Bom6(fs59.readFileSync(filePath, "utf-8"));
27282
27715
  } catch (e) {
27283
27716
  lists.push({
27284
27717
  basename: entry.basename,
@@ -27326,8 +27759,8 @@ var validateReportCompiled;
27326
27759
  function validateReportData(data) {
27327
27760
  if (!validateReportCompiled) {
27328
27761
  const ajv2 = new import__7.default({ allErrors: true, strict: false });
27329
- const schemaPath = path54.join(resolveContextListSchemasDir(), "coordination-duplicates-report.schema.json");
27330
- 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"));
27331
27764
  validateReportCompiled = ajv2.compile(JSON.parse(schemaRaw));
27332
27765
  }
27333
27766
  if (validateReportCompiled(data)) {
@@ -27345,20 +27778,20 @@ function runCoordinationDuplicatesDiagnosis(input) {
27345
27778
  if (!v.ok) {
27346
27779
  return { ok: false, message: `Report validation failed: ${v.errors.join("; ")}` };
27347
27780
  }
27348
- const outPath = path54.join(input.contextDirAbsolute, COORDINATION_DUPLICATES_REPORT_BASENAME);
27781
+ const outPath = path55.join(input.contextDirAbsolute, COORDINATION_DUPLICATES_REPORT_BASENAME);
27349
27782
  const payload = `${JSON.stringify(report, null, 2)}
27350
27783
  `;
27351
27784
  const tmp = `${outPath}.tmp.${process.pid}`;
27352
27785
  try {
27353
- fs58.writeFileSync(tmp, payload, "utf-8");
27786
+ fs59.writeFileSync(tmp, payload, "utf-8");
27354
27787
  } catch (e) {
27355
27788
  return { ok: false, message: e instanceof Error ? e.message : String(e) };
27356
27789
  }
27357
27790
  try {
27358
- fs58.renameSync(tmp, outPath);
27791
+ fs59.renameSync(tmp, outPath);
27359
27792
  } catch (e) {
27360
27793
  try {
27361
- fs58.unlinkSync(tmp);
27794
+ fs59.unlinkSync(tmp);
27362
27795
  } catch {
27363
27796
  }
27364
27797
  return { ok: false, message: e instanceof Error ? e.message : String(e) };
@@ -27392,8 +27825,8 @@ function runCoordinationDuplicatesDiagnosis(input) {
27392
27825
  }
27393
27826
 
27394
27827
  // src/pipelines/download/downloadPipeline.ts
27395
- var fs59 = __toESM(require("node:fs"));
27396
- var path55 = __toESM(require("node:path"));
27828
+ var fs60 = __toESM(require("node:fs"));
27829
+ var path56 = __toESM(require("node:path"));
27397
27830
  var SRS_DISCOVERY_BATCH_GET_CHUNK_SIZE = 200;
27398
27831
  function isRecord7(v) {
27399
27832
  return Boolean(v) && typeof v === "object" && !Array.isArray(v);
@@ -27483,9 +27916,9 @@ function resolveSafeContextOutputPath(contextDirAbs, nameRaw) {
27483
27916
  return null;
27484
27917
  }
27485
27918
  }
27486
- const resolved = path55.resolve(contextDirAbs, ...segments);
27487
- const rel = path55.relative(contextDirAbs, resolved);
27488
- 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)) {
27489
27922
  return null;
27490
27923
  }
27491
27924
  return resolved;
@@ -27498,37 +27931,37 @@ function chunkIds(ids, size) {
27498
27931
  return out;
27499
27932
  }
27500
27933
  function clearContextDirectoryForCloudReplace(contextDirAbs) {
27501
- if (!fs59.existsSync(contextDirAbs) || !fs59.statSync(contextDirAbs).isDirectory()) {
27934
+ if (!fs60.existsSync(contextDirAbs) || !fs60.statSync(contextDirAbs).isDirectory()) {
27502
27935
  return { filesRemoved: 0 };
27503
27936
  }
27504
- const preserveAbs = path55.resolve(contextDirAbs, UPLOAD_TARGET_FILENAME);
27937
+ const preserveAbs = path56.resolve(contextDirAbs, UPLOAD_TARGET_FILENAME);
27505
27938
  const preserveSet = /* @__PURE__ */ new Set();
27506
- if (fs59.existsSync(preserveAbs) && fs59.statSync(preserveAbs).isFile()) {
27939
+ if (fs60.existsSync(preserveAbs) && fs60.statSync(preserveAbs).isFile()) {
27507
27940
  preserveSet.add(preserveAbs);
27508
27941
  }
27509
27942
  let filesRemoved = 0;
27510
27943
  const walkRm = (dir) => {
27511
27944
  let entries;
27512
27945
  try {
27513
- entries = fs59.readdirSync(dir, { withFileTypes: true });
27946
+ entries = fs60.readdirSync(dir, { withFileTypes: true });
27514
27947
  } catch {
27515
27948
  return;
27516
27949
  }
27517
27950
  for (const e of entries) {
27518
- const full = path55.join(dir, e.name);
27951
+ const full = path56.join(dir, e.name);
27519
27952
  if (e.isDirectory()) {
27520
27953
  walkRm(full);
27521
27954
  try {
27522
- fs59.rmdirSync(full);
27955
+ fs60.rmdirSync(full);
27523
27956
  } catch {
27524
27957
  }
27525
27958
  } else if (e.isFile()) {
27526
- const abs = path55.resolve(full);
27959
+ const abs = path56.resolve(full);
27527
27960
  if (preserveSet.has(abs)) {
27528
27961
  continue;
27529
27962
  }
27530
27963
  try {
27531
- fs59.unlinkSync(abs);
27964
+ fs60.unlinkSync(abs);
27532
27965
  filesRemoved += 1;
27533
27966
  } catch {
27534
27967
  }
@@ -27596,7 +28029,7 @@ async function runDownloadPipeline(opts) {
27596
28029
  failed.push({ id, message: "Missing name on srs_discovery node." });
27597
28030
  continue;
27598
28031
  }
27599
- if (name === UPLOAD_TARGET_FILENAME || path55.basename(name) === UPLOAD_TARGET_FILENAME) {
28032
+ if (name === UPLOAD_TARGET_FILENAME || path56.basename(name) === UPLOAD_TARGET_FILENAME) {
27600
28033
  skipped += 1;
27601
28034
  log?.(`[pipeline:download] skip ${name} (upload target row).`);
27602
28035
  continue;
@@ -27607,15 +28040,15 @@ async function runDownloadPipeline(opts) {
27607
28040
  failed.push({ id, name, message: "Unsafe or invalid name for local path." });
27608
28041
  continue;
27609
28042
  }
27610
- fs59.mkdirSync(path55.dirname(outAbs), { recursive: true });
27611
- const exists = fs59.existsSync(outAbs);
28043
+ fs60.mkdirSync(path56.dirname(outAbs), { recursive: true });
28044
+ const exists = fs60.existsSync(outAbs);
27612
28045
  if (exists && !opts.force && !opts.replaceFromCloud) {
27613
28046
  skipped += 1;
27614
28047
  log?.(`[pipeline:download] skip existing ${name} (use --force to overwrite).`);
27615
28048
  continue;
27616
28049
  }
27617
28050
  try {
27618
- fs59.writeFileSync(outAbs, bodyText, "utf8");
28051
+ fs60.writeFileSync(outAbs, bodyText, "utf8");
27619
28052
  downloaded += 1;
27620
28053
  succeededIds[outAbs] = id;
27621
28054
  } catch (e) {
@@ -27690,12 +28123,12 @@ function toFetchErrorMessage(e) {
27690
28123
 
27691
28124
  // src/auth/gluecharmContentNegotiation.ts
27692
28125
  var GLUECHARM_WS_LEGACY_JSON = "application/vnd.gluecharm.v1.ws-legacy+json";
27693
- function pathWithoutQuery(path60) {
27694
- const q = path60.indexOf("?");
27695
- 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);
27696
28129
  }
27697
- function isGluecharmContentApiPath(path60) {
27698
- const p = pathWithoutQuery(path60);
28130
+ function isGluecharmContentApiPath(path61) {
28131
+ const p = pathWithoutQuery(path61);
27699
28132
  return p.startsWith("/api/content/") || p.startsWith("/api/batch/content/");
27700
28133
  }
27701
28134
  function gluecharmContentHeaders(method) {
@@ -27733,7 +28166,7 @@ async function fetchWithTimeout2(url, init, fetchImpl, timeoutMs, externalSignal
27733
28166
  }
27734
28167
  function createAuthenticatedRequestJson(deps) {
27735
28168
  const fetchImpl = deps.fetchImpl ?? fetch;
27736
- async function requestJson(path60, options = {}) {
28169
+ async function requestJson(path61, options = {}) {
27737
28170
  const base = deps.getApiBaseUrl();
27738
28171
  if (!base) {
27739
28172
  const err = { status: 0, message: "easyspecs.apiBaseUrl is not configured." };
@@ -27741,7 +28174,7 @@ function createAuthenticatedRequestJson(deps) {
27741
28174
  }
27742
28175
  const method = options.method ?? "GET";
27743
28176
  const headers = { ...options.headers };
27744
- if (isGluecharmContentApiPath(path60)) {
28177
+ if (isGluecharmContentApiPath(path61)) {
27745
28178
  Object.assign(headers, gluecharmContentHeaders(method));
27746
28179
  } else {
27747
28180
  if (!headers.Accept) {
@@ -27755,7 +28188,7 @@ function createAuthenticatedRequestJson(deps) {
27755
28188
  if (options.withAuth !== false && access) {
27756
28189
  headers.Authorization = `Bearer ${access}`;
27757
28190
  }
27758
- const url = `${base}${path60}`;
28191
+ const url = `${base}${path61}`;
27759
28192
  const timeoutMs = options.timeoutMs ?? API_TIMEOUT_MS;
27760
28193
  const response = await fetchWithTimeout2(
27761
28194
  url,
@@ -27776,7 +28209,7 @@ function createAuthenticatedRequestJson(deps) {
27776
28209
  if (shouldRetryUnauthorized) {
27777
28210
  const refreshed = await deps.refreshSession();
27778
28211
  if (refreshed) {
27779
- return requestJson(path60, { ...options, retryOnUnauthorized: false });
28212
+ return requestJson(path61, { ...options, retryOnUnauthorized: false });
27780
28213
  }
27781
28214
  }
27782
28215
  const fallback = payload == null ? `${response.statusText || "HTTP error"} (response body empty or not JSON)` : "Request failed.";
@@ -27786,15 +28219,15 @@ function createAuthenticatedRequestJson(deps) {
27786
28219
  }
27787
28220
 
27788
28221
  // src/cli/cliSession.ts
27789
- var fs60 = __toESM(require("node:fs"));
27790
- var os6 = __toESM(require("node:os"));
27791
- 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"));
27792
28225
  function defaultSessionPath() {
27793
- return path56.join(os6.homedir(), ".easyspecs", "cli-session.json");
28226
+ return path57.join(os7.homedir(), ".easyspecs", "cli-session.json");
27794
28227
  }
27795
28228
  var configSessionPath;
27796
28229
  function setCliSessionPathFromConfig(absPath) {
27797
- configSessionPath = absPath?.trim() ? path56.resolve(absPath) : void 0;
28230
+ configSessionPath = absPath?.trim() ? path57.resolve(absPath) : void 0;
27798
28231
  }
27799
28232
  function applyCliSessionPathFromRepoConfig(repoRoot, cfg) {
27800
28233
  const raw = cfg.easyspecs?.cliSessionPath?.trim();
@@ -27802,7 +28235,7 @@ function applyCliSessionPathFromRepoConfig(repoRoot, cfg) {
27802
28235
  setCliSessionPathFromConfig(void 0);
27803
28236
  return;
27804
28237
  }
27805
- const abs = path56.isAbsolute(raw) ? raw : path56.join(repoRoot, raw);
28238
+ const abs = path57.isAbsolute(raw) ? raw : path57.join(repoRoot, raw);
27806
28239
  setCliSessionPathFromConfig(abs);
27807
28240
  }
27808
28241
  function normalizeCliSessionPathForConfig(repoRoot, raw) {
@@ -27810,15 +28243,15 @@ function normalizeCliSessionPathForConfig(repoRoot, raw) {
27810
28243
  if (!t) {
27811
28244
  return "";
27812
28245
  }
27813
- const resolvedRepo = path56.resolve(repoRoot);
27814
- const abs = path56.isAbsolute(t) ? path56.normalize(t) : path56.resolve(resolvedRepo, t);
27815
- 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);
27816
28249
  if (rel === "") {
27817
28250
  return abs;
27818
28251
  }
27819
- const underRepo = !rel.startsWith("..") && !path56.isAbsolute(rel);
28252
+ const underRepo = !rel.startsWith("..") && !path57.isAbsolute(rel);
27820
28253
  if (underRepo) {
27821
- return rel.split(path56.sep).join("/");
28254
+ return rel.split(path57.sep).join("/");
27822
28255
  }
27823
28256
  return abs;
27824
28257
  }
@@ -27831,10 +28264,10 @@ function effectiveCliSessionPath() {
27831
28264
  function readCliSession() {
27832
28265
  const p = effectiveCliSessionPath();
27833
28266
  try {
27834
- if (!fs60.existsSync(p)) {
28267
+ if (!fs61.existsSync(p)) {
27835
28268
  return void 0;
27836
28269
  }
27837
- const j = JSON.parse(fs60.readFileSync(p, "utf8"));
28270
+ const j = JSON.parse(fs61.readFileSync(p, "utf8"));
27838
28271
  const apiBaseUrl = typeof j.apiBaseUrl === "string" ? j.apiBaseUrl.trim() : "";
27839
28272
  const accessToken = typeof j.accessToken === "string" ? j.accessToken : "";
27840
28273
  const refreshToken = typeof j.refreshToken === "string" ? j.refreshToken : "";
@@ -27848,33 +28281,33 @@ function readCliSession() {
27848
28281
  }
27849
28282
  function writeCliSession(s) {
27850
28283
  const p = effectiveCliSessionPath();
27851
- fs60.mkdirSync(path56.dirname(p), { recursive: true });
27852
- 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)}
27853
28286
  `, "utf8");
27854
28287
  }
27855
28288
  function clearCliSession() {
27856
28289
  const p = effectiveCliSessionPath();
27857
28290
  try {
27858
- fs60.unlinkSync(p);
28291
+ fs61.unlinkSync(p);
27859
28292
  } catch {
27860
28293
  }
27861
28294
  }
27862
28295
 
27863
28296
  // src/analysis/acePendingTraces.ts
27864
- var fs61 = __toESM(require("fs"));
27865
- var path57 = __toESM(require("path"));
28297
+ var fs62 = __toESM(require("fs"));
28298
+ var path58 = __toESM(require("path"));
27866
28299
  function normalizeAceTraceRelativePath(rel) {
27867
28300
  return rel.split(/[/\\]/).join("/");
27868
28301
  }
27869
28302
  function readCompletedTraceRelativePaths(contextDir2) {
27870
28303
  const set = /* @__PURE__ */ new Set();
27871
28304
  const jsonlPath = aceConsolidatedSessionsJsonlPath(contextDir2);
27872
- if (!fs61.existsSync(jsonlPath)) {
28305
+ if (!fs62.existsSync(jsonlPath)) {
27873
28306
  return set;
27874
28307
  }
27875
28308
  let raw;
27876
28309
  try {
27877
- raw = fs61.readFileSync(jsonlPath, "utf8");
28310
+ raw = fs62.readFileSync(jsonlPath, "utf8");
27878
28311
  } catch {
27879
28312
  return set;
27880
28313
  }
@@ -27905,14 +28338,14 @@ function readCompletedTraceRelativePaths(contextDir2) {
27905
28338
  }
27906
28339
  function listPendingAceTraceFiles(contextDir2, worktreeRoot) {
27907
28340
  const traceSchema = opencodeAceSchemaPath(worktreeRoot, ACE_SCHEMA_TRACE);
27908
- if (!fs61.existsSync(traceSchema)) {
28341
+ if (!fs62.existsSync(traceSchema)) {
27909
28342
  return [];
27910
28343
  }
27911
28344
  const completed = readCompletedTraceRelativePaths(contextDir2);
27912
28345
  const allAbs = listAceTraceFiles(contextDir2);
27913
28346
  const pending = [];
27914
28347
  for (const abs of allAbs) {
27915
- const rel = normalizeAceTraceRelativePath(path57.relative(contextDir2, abs));
28348
+ const rel = normalizeAceTraceRelativePath(path58.relative(contextDir2, abs));
27916
28349
  const v = validateAceJsonFile(abs, traceSchema);
27917
28350
  if (!v.ok) {
27918
28351
  continue;
@@ -27927,7 +28360,7 @@ function listPendingAceTraceFiles(contextDir2, worktreeRoot) {
27927
28360
  }
27928
28361
 
27929
28362
  // src/analysis/aceAutoLearnPool.ts
27930
- var path58 = __toESM(require("path"));
28363
+ var path59 = __toESM(require("path"));
27931
28364
  function clampConcurrency2(n) {
27932
28365
  if (!Number.isFinite(n)) {
27933
28366
  return DEFAULT_MAX_CONCURRENT_AI;
@@ -27962,8 +28395,8 @@ async function runAceAutoLearnPool(p) {
27962
28395
  };
27963
28396
  const currentCap = () => Math.min(staticMaxC, adaptiveMax);
27964
28397
  let wake;
27965
- const waitTurn = () => new Promise((resolve20) => {
27966
- wake = resolve20;
28398
+ const waitTurn = () => new Promise((resolve23) => {
28399
+ wake = resolve23;
27967
28400
  });
27968
28401
  const pump = () => {
27969
28402
  wake?.();
@@ -27985,7 +28418,7 @@ async function runAceAutoLearnPool(p) {
27985
28418
  poolAbortListenerRegistered = true;
27986
28419
  }
27987
28420
  }
27988
- const traceRel = (abs) => path58.relative(contextDir2, abs).split(path58.sep).join("/");
28421
+ const traceRel = (abs) => path59.relative(contextDir2, abs).split(path59.sep).join("/");
27989
28422
  const runOne = async (traceAbs) => {
27990
28423
  if (abortSignal?.aborted) {
27991
28424
  active -= 1;
@@ -28077,8 +28510,13 @@ function parseContextDriftTail(tail) {
28077
28510
  let label;
28078
28511
  let index;
28079
28512
  let dryRun = false;
28513
+ let inPlace = false;
28080
28514
  for (let i = 0; i < tail.length; i += 1) {
28081
28515
  const a = tail[i] ?? "";
28516
+ if (a === "--no-worktree" || a === "--noworktree" || a === "--in-place") {
28517
+ inPlace = true;
28518
+ continue;
28519
+ }
28082
28520
  if (a === "--label" && tail[i + 1]) {
28083
28521
  label = tail[i + 1];
28084
28522
  i += 1;
@@ -28095,7 +28533,7 @@ function parseContextDriftTail(tail) {
28095
28533
  }
28096
28534
  rest.push(a);
28097
28535
  }
28098
- return { label, index, dryRun, rest };
28536
+ return { label, index, dryRun, inPlace, rest };
28099
28537
  }
28100
28538
  function stripRootWorktreeTokens(tokens) {
28101
28539
  const out = [...tokens];
@@ -28511,7 +28949,7 @@ function formatCliStderrLine(line, useAnsi) {
28511
28949
  }
28512
28950
 
28513
28951
  // src/cli/main.ts
28514
- var PKG_VERSION = "0.1.1";
28952
+ var PKG_VERSION = "0.2.1";
28515
28953
  function isNonEmptyFactoryFailureArray(x) {
28516
28954
  if (!Array.isArray(x) || x.length === 0) {
28517
28955
  return false;
@@ -28600,12 +29038,16 @@ function extractLegacyPositionals(argv) {
28600
29038
  }
28601
29039
  return [];
28602
29040
  }
29041
+ function rewriteArgvForCommanderParse(argv) {
29042
+ return argv.map((t) => t === "--no-worktree" ? "--in-place" : t);
29043
+ }
28603
29044
  function parseCliWithCommander(argv) {
28604
29045
  const program2 = createEasyspecsCliProgram();
28605
29046
  program2.version(PKG_VERSION, "--version", "output the version number");
28606
29047
  program2.exitOverride();
29048
+ const rawArgv = [...argv];
28607
29049
  try {
28608
- program2.parse(argv, { from: "user" });
29050
+ program2.parse(rewriteArgvForCommanderParse(rawArgv), { from: "user" });
28609
29051
  } catch (e) {
28610
29052
  const code = e?.code;
28611
29053
  if (code === "commander.helpDisplayed" || code === "commander.version") {
@@ -28628,7 +29070,7 @@ function parseCliWithCommander(argv) {
28628
29070
  help: false,
28629
29071
  version: false
28630
29072
  };
28631
- const positionals = extractLegacyPositionals(argv);
29073
+ const positionals = extractLegacyPositionals(rawArgv);
28632
29074
  return { flags, positionals };
28633
29075
  }
28634
29076
  function printHelp() {
@@ -28649,23 +29091,23 @@ function resolveAnalysisRoot(repoRoot, rootKind, worktreePath) {
28649
29091
  return repoRoot;
28650
29092
  }
28651
29093
  const wt = worktreePath?.trim();
28652
- if (wt && fs62.existsSync(path59.join(wt, ".git"))) {
28653
- return path59.resolve(wt);
29094
+ if (wt && fs63.existsSync(path60.join(wt, ".git"))) {
29095
+ return path60.resolve(wt);
28654
29096
  }
28655
29097
  throw new Error("worktree mode requires --worktree <path> to an existing analysis checkout.");
28656
29098
  }
28657
29099
  function resolveAdHocCheckoutRoot(_repoRoot, storage, worktreeFlag) {
28658
29100
  const w = worktreeFlag?.trim();
28659
29101
  if (w) {
28660
- const abs = path59.resolve(w);
28661
- if (fs62.existsSync(path59.join(abs, ".git"))) {
29102
+ const abs = path60.resolve(w);
29103
+ if (fs63.existsSync(path60.join(abs, ".git"))) {
28662
29104
  return abs;
28663
29105
  }
28664
29106
  throw new Error(`Invalid --worktree (not a git checkout): ${abs}`);
28665
29107
  }
28666
29108
  const snap = readAnalysisWorkspaceSnapshot(storage);
28667
29109
  const p = snap?.adHocWorktreePath?.trim();
28668
- if (p && fs62.existsSync(path59.join(p, ".git"))) {
29110
+ if (p && fs63.existsSync(path60.join(p, ".git"))) {
28669
29111
  return p;
28670
29112
  }
28671
29113
  throw new Error("No analysis checkout: run `easyspecs-cli run synthesis` first or pass `--worktree <path>`.");
@@ -28692,7 +29134,7 @@ async function runResumeRemediationPool(storage, repoRoot, analysisRoot, merged,
28692
29134
  requireOpenCode(merged, flags);
28693
29135
  const agentsDir = resolveOpenCodeAgentsDir(repoRoot, repoConfig);
28694
29136
  assertAgentsDirExists(agentsDir);
28695
- const ctxDir = path59.join(analysisRoot, ".gluecharm", "context");
29137
+ const ctxDir = path60.join(analysisRoot, ".gluecharm", "context");
28696
29138
  const snap = readArtefactRunSnapshot(storage);
28697
29139
  const rows = listMissingWorkstations(ctxDir, analysisRoot, snap);
28698
29140
  if (rows.length === 0) {
@@ -28710,7 +29152,7 @@ async function runResumeRemediationPool(storage, repoRoot, analysisRoot, merged,
28710
29152
  storageContext: storage,
28711
29153
  repositoryRoot: repoRoot,
28712
29154
  worktreeRoot: analysisRoot,
28713
- workspaceLabel: path59.basename(analysisRoot),
29155
+ workspaceLabel: path60.basename(analysisRoot),
28714
29156
  oc,
28715
29157
  log: (line) => logErr(flags, line),
28716
29158
  abortSignal: void 0,
@@ -28887,17 +29329,17 @@ async function main() {
28887
29329
  { easyspecs: { defaultGitRemoteUrl: url } },
28888
29330
  { warnMigration: (m) => logErr(flags, `[EasySpecs] ${m}`) }
28889
29331
  );
28890
- const path60 = easyspecsConfigPath(repoRoot);
29332
+ const path61 = easyspecsConfigPath(repoRoot);
28891
29333
  if (flags.json) {
28892
29334
  printJsonLine({
28893
29335
  command: "config set-git-remote",
28894
29336
  durationMs: Date.now() - t0,
28895
29337
  ok: true,
28896
- path: path60,
29338
+ path: path61,
28897
29339
  defaultGitRemoteUrl: cfg.easyspecs?.defaultGitRemoteUrl ?? ""
28898
29340
  });
28899
29341
  } else {
28900
- console.log(`Updated ${path60} \u2014 easyspecs.defaultGitRemoteUrl`);
29342
+ console.log(`Updated ${path61} \u2014 easyspecs.defaultGitRemoteUrl`);
28901
29343
  }
28902
29344
  process.exit(ExitCode.ok);
28903
29345
  } catch (e) {
@@ -28930,7 +29372,7 @@ async function main() {
28930
29372
  applyCliSessionPathFromRepoConfig(repoRoot, repoConfig);
28931
29373
  if (flags.sessionPath?.trim()) {
28932
29374
  const sp = flags.sessionPath.trim();
28933
- 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);
28934
29376
  setCliSessionPathFromConfig(abs);
28935
29377
  }
28936
29378
  const apiResolved = initApiBaseUrlForCli(repoRoot, flags, repoConfig);
@@ -28987,20 +29429,18 @@ async function main() {
28987
29429
  logExitCodeSummary(ExitCode.usage, flags);
28988
29430
  process.exit(ExitCode.usage);
28989
29431
  }
28990
- const agentsDir = resolveOpenCodeAgentsDir(repoRoot, repoConfig);
28991
- const agentsOk = fs62.existsSync(agentsDir);
28992
- const oc = getOpenCodeReadiness({
28993
- executable: merged.openCodeExecutable,
28994
- skipCredentialsCheck: merged.openCodeSkipCredentialsCheck,
28995
- providerEnvFromConfig: merged.openCodeChildEnv
28996
- });
28997
- const lines = [
28998
- `cliVersion=${PKG_VERSION}`,
28999
- `repoRoot=${repoRoot}`,
29000
- `apiBaseUrl=${apiResolved || "(empty \u2014 stub auth only)"}`,
29001
- `opencode installed=${String(oc.installed)} credentialsReady=${String(oc.credentialsReady)}`,
29002
- `agentsDir=${agentsDir} exists=${String(agentsOk)}`
29003
- ];
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);
29004
29444
  const inspectPayload = buildDoctorInspectPayload(merged, repoConfig);
29005
29445
  if (!flags.json) {
29006
29446
  const parts = [];
@@ -29016,6 +29456,12 @@ async function main() {
29016
29456
  if (modes.readiness) {
29017
29457
  envelope.lines = lines;
29018
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;
29019
29465
  }
29020
29466
  if (modes.inspectConfig) {
29021
29467
  envelope.config = inspectPayload;
@@ -29167,7 +29613,7 @@ async function main() {
29167
29613
  const result = await runSynthesisPipeline(
29168
29614
  storage,
29169
29615
  repoRoot,
29170
- path59.basename(repoRoot),
29616
+ path60.basename(repoRoot),
29171
29617
  agentsDir,
29172
29618
  {
29173
29619
  ...merged.pipelineOpenCode
@@ -29222,7 +29668,7 @@ async function main() {
29222
29668
  if (sub === "reference-coverage") {
29223
29669
  const rootAbs = resolveAnalysisRoot(repoRoot, rootKind, worktree);
29224
29670
  requireMinimalGluecharmLayoutAt(rootAbs);
29225
- const contextDir2 = path59.join(rootAbs, ".gluecharm", "context");
29671
+ const contextDir2 = path60.join(rootAbs, ".gluecharm", "context");
29226
29672
  const res = runCoveragePipeline({
29227
29673
  repositoryRootAbs: rootAbs,
29228
29674
  contextDirAbs: contextDir2,
@@ -29245,7 +29691,7 @@ async function main() {
29245
29691
  if (sub === "coordination-duplicates") {
29246
29692
  const rootAbs = resolveAnalysisRoot(repoRoot, rootKind, worktree);
29247
29693
  requireMinimalGluecharmLayoutAt(rootAbs);
29248
- const contextDir2 = path59.join(rootAbs, ".gluecharm", "context");
29694
+ const contextDir2 = path60.join(rootAbs, ".gluecharm", "context");
29249
29695
  const res = runCoordinationDuplicatesDiagnosis({
29250
29696
  contextDirAbsolute: contextDir2,
29251
29697
  sourceRoot: rootKind === "worktree" ? "worktree" : "workspace"
@@ -29281,7 +29727,7 @@ async function main() {
29281
29727
  if (sub === "missing-artefacts") {
29282
29728
  const rootAbs = resolveAnalysisRoot(repoRoot, rootKind, worktree);
29283
29729
  requireMinimalGluecharmLayoutAt(rootAbs);
29284
- const ctxDir = path59.join(rootAbs, ".gluecharm", "context");
29730
+ const ctxDir = path60.join(rootAbs, ".gluecharm", "context");
29285
29731
  const storage = createFileBackedWorkspaceState(repoRoot);
29286
29732
  const snap = readArtefactRunSnapshot(storage);
29287
29733
  const rows = listMissingWorkstations(ctxDir, rootAbs, snap);
@@ -29331,7 +29777,7 @@ async function main() {
29331
29777
  });
29332
29778
  const bad = poolRes.cancelled || poolRes.failures > 0;
29333
29779
  if (!bad) {
29334
- const ctxDir = path59.join(analysisRoot, ".gluecharm", "context");
29780
+ const ctxDir = path60.join(analysisRoot, ".gluecharm", "context");
29335
29781
  const lg = runLinkMappingPipeline(ctxDir, { log: (line) => logErr(flags, line) });
29336
29782
  if (!lg.ok) {
29337
29783
  finish(OsExit.diagnoseZeroReferenceLinkMapping, {
@@ -29361,7 +29807,7 @@ async function main() {
29361
29807
  const worktree = wtExplicit ?? wtFromRoot;
29362
29808
  const rootAbs = resolveAnalysisRoot(repoRoot, rootKind, worktree);
29363
29809
  requireMinimalGluecharmLayoutAt(rootAbs);
29364
- const contextDir2 = path59.join(rootAbs, ".gluecharm", "context");
29810
+ const contextDir2 = path60.join(rootAbs, ".gluecharm", "context");
29365
29811
  const res = runLinkMappingPipeline(contextDir2, {
29366
29812
  log: (line) => logErr(flags, line)
29367
29813
  });
@@ -29380,10 +29826,19 @@ async function main() {
29380
29826
  if (!refPath) {
29381
29827
  finish(ExitCode.usage, {
29382
29828
  ok: false,
29383
- 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]"
29384
29830
  });
29385
29831
  }
29386
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
+ }
29387
29842
  const leftover = stripRootWorktreeTokens(parsedTail.rest);
29388
29843
  if (leftover.length > 0) {
29389
29844
  finish(ExitCode.usage, {
@@ -29392,11 +29847,11 @@ async function main() {
29392
29847
  });
29393
29848
  }
29394
29849
  requireMinimalGluecharmLayoutAt(repoRoot);
29395
- if (!parsedTail.dryRun) {
29396
- requireOpenCode(merged, flags);
29397
- }
29850
+ const readinessLog = (line) => {
29851
+ process.stderr.write(`${line}
29852
+ `);
29853
+ };
29398
29854
  const agentsDir = resolveOpenCodeAgentsDir(repoRoot, repoConfig);
29399
- assertAgentsDirExists(agentsDir);
29400
29855
  const storage = createFileBackedWorkspaceState(repoRoot);
29401
29856
  const ctrl = new AbortController();
29402
29857
  const dres = await runContextDriftFactory({
@@ -29409,8 +29864,11 @@ async function main() {
29409
29864
  label: parsedTail.label,
29410
29865
  indexOverrideArg: parsedTail.index,
29411
29866
  dryRun: parsedTail.dryRun,
29867
+ inPlace: parsedTail.inPlace,
29412
29868
  signal: ctrl.signal,
29413
- log: (line) => logErr(flags, line)
29869
+ log: (line) => logErr(flags, line),
29870
+ cliVersion: PKG_VERSION,
29871
+ readinessLog
29414
29872
  });
29415
29873
  if (dres.exitOk && dres.ok) {
29416
29874
  if (dres.driftReportPath && !flags.json && !dres.dryRun) {
@@ -29420,19 +29878,29 @@ async function main() {
29420
29878
  finish(ExitCode.ok, driftPayload);
29421
29879
  }
29422
29880
  if (dres.ok === false) {
29423
- const row2 = contextDriftFactoryFailureRow(dres.code, dres.error);
29424
- const driftExit = contextDriftExitCodeFor(dres.code, dres.error);
29425
- const { exitOk: _driftOkB, ...driftRest } = dres;
29426
- const envelope = {
29427
- ...driftRest,
29428
- ok: false,
29429
- factoryFailures: [row2],
29430
- error: composeFactoryValidationError(dres.error, [row2])
29431
- };
29432
- if (isContextDriftSrs70ValidationExit(driftExit)) {
29433
- 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);
29434
29903
  }
29435
- finish(driftExit, envelope);
29436
29904
  }
29437
29905
  finish(ExitCode.internal, { ok: false, error: "Unexpected context drift result shape." });
29438
29906
  }
@@ -29441,6 +29909,9 @@ async function main() {
29441
29909
  if (a === "--force-new-context-analysis") {
29442
29910
  continue;
29443
29911
  }
29912
+ if (a === "--no-worktree" || a === "--noworktree" || a === "--in-place") {
29913
+ continue;
29914
+ }
29444
29915
  if (a === "--upload") {
29445
29916
  finish(ExitCode.usage, {
29446
29917
  ok: false,
@@ -29455,10 +29926,11 @@ async function main() {
29455
29926
  }
29456
29927
  finish(ExitCode.usage, {
29457
29928
  ok: false,
29458
- 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)`
29459
29930
  });
29460
29931
  }
29461
29932
  const forceNewContextAnalysis = positionals.includes("--force-new-context-analysis");
29933
+ const analysisInPlace = positionals.includes("--no-worktree") || positionals.includes("--noworktree") || positionals.includes("--in-place");
29462
29934
  const cloudCached = readEasyspecsMergedSetting(
29463
29935
  repoConfig.easyspecs,
29464
29936
  "easyspecs.factory.cloudContextAnalyzed"
@@ -29481,11 +29953,19 @@ async function main() {
29481
29953
  });
29482
29954
  }
29483
29955
  requireMinimalGluecharmLayoutAt(repoRoot);
29484
- requireOpenCode(merged, flags);
29485
29956
  const agentsDir = resolveOpenCodeAgentsDir(repoRoot, repoConfig);
29486
- assertAgentsDirExists(agentsDir);
29487
29957
  const storage = createFileBackedWorkspaceState(repoRoot);
29488
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
+ };
29489
29969
  const deps = buildFactoryDepsHeadless({
29490
29970
  storageContext: storage,
29491
29971
  repoRoot,
@@ -29496,15 +29976,22 @@ async function main() {
29496
29976
  }),
29497
29977
  log: (line) => logErr(flags, line),
29498
29978
  signal: ctrl.signal,
29499
- skipBackendSync: true
29979
+ skipBackendSync: true,
29980
+ inPlace: analysisInPlace,
29981
+ readiness: analysisReadinessCtx
29500
29982
  });
29501
29983
  const res = await runGenerateContextFactory(deps);
29502
29984
  if (res.ok && res.cancelled !== true && flags.promote !== false) {
29503
29985
  const snap = readAnalysisWorkspaceSnapshot(storage);
29504
29986
  const wt = snap?.adHocWorktreePath?.trim();
29505
29987
  if (wt) {
29506
- const sourceCtx = path59.join(wt, ".gluecharm", "context");
29507
- 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)) {
29508
29995
  const n = promoteContextDirectoryToWorkspaceFs(sourceCtx, repoRoot);
29509
29996
  logErr(flags, `[pipeline:analysis] promoted ${String(n.filesCopied)} file(s) \u2192 ${repoRoot}`);
29510
29997
  } else {
@@ -29524,19 +30011,24 @@ async function main() {
29524
30011
  ok: res.ok,
29525
30012
  cancelled: res.cancelled,
29526
30013
  totalElapsedMs: res.totalElapsedMs,
29527
- error: res.message
30014
+ error: res.message,
30015
+ ...analysisInPlace ? { analysisInPlace: true } : {}
29528
30016
  };
29529
30017
  if (!res.ok && !res.cancelled && res.factoryFailures && res.factoryFailures.length > 0) {
29530
30018
  analysisEnvelope.factoryFailures = res.factoryFailures;
29531
30019
  Object.assign(analysisEnvelope, primaryFailureAliases(res.factoryFailures));
29532
30020
  analysisEnvelope.error = composeFactoryValidationError(res.message, res.factoryFailures);
29533
30021
  }
30022
+ if (res.readinessFailure) {
30023
+ Object.assign(analysisEnvelope, res.readinessFailure);
30024
+ }
29534
30025
  finish(
29535
30026
  res.ok ? ExitCode.ok : res.cancelled ? ExitCode.cancelled : processExitFromNormalizedFactoryFailures(res.factoryFailures),
29536
30027
  analysisEnvelope
29537
30028
  );
29538
30029
  }
29539
30030
  if (pos[0] === "update" && pos[1] === "context") {
30031
+ let updateContextInPlace = false;
29540
30032
  for (const a of pos.slice(2)) {
29541
30033
  if (a === "--upload") {
29542
30034
  finish(ExitCode.usage, {
@@ -29544,14 +30036,20 @@ async function main() {
29544
30036
  error: "Removed flag: update context --upload. Run `easyspecs-cli upload context` or `upload republish` after update context completes."
29545
30037
  });
29546
30038
  }
30039
+ if (a === "--no-worktree" || a === "--noworktree" || a === "--in-place") {
30040
+ updateContextInPlace = true;
30041
+ continue;
30042
+ }
29547
30043
  finish(ExitCode.usage, { ok: false, error: `unknown update context flag: ${a}` });
29548
30044
  }
29549
30045
  requireMinimalGluecharmLayoutAt(repoRoot);
29550
- requireOpenCode(merged, flags);
29551
30046
  const agentsDir = resolveOpenCodeAgentsDir(repoRoot, repoConfig);
29552
- assertAgentsDirExists(agentsDir);
29553
30047
  const storage = createFileBackedWorkspaceState(repoRoot);
29554
30048
  const ctrl = new AbortController();
30049
+ const readinessLog = (line) => {
30050
+ process.stderr.write(`${line}
30051
+ `);
30052
+ };
29555
30053
  const ures = await runUpdateContextFactory({
29556
30054
  repoRootAbs: repoRoot,
29557
30055
  repoConfig,
@@ -29559,10 +30057,13 @@ async function main() {
29559
30057
  agentsDirFs: agentsDir,
29560
30058
  storage,
29561
30059
  signal: ctrl.signal,
29562
- log: (line) => logErr(flags, line)
30060
+ log: (line) => logErr(flags, line),
30061
+ inPlace: updateContextInPlace,
30062
+ cliVersion: PKG_VERSION,
30063
+ readinessLog
29563
30064
  });
29564
30065
  const { exitOk, ...payload } = ures;
29565
- const code = exitOk ? ExitCode.ok : ures.code === "MISSING_BASELINE" ? ExitCode.usage : OsExit.updateContextFactory;
30066
+ const code = exitOk ? ExitCode.ok : ures.code === "MISSING_BASELINE" ? ExitCode.usage : ures.code === "READINESS_FAILED" && typeof ures.readinessExitCode === "number" ? ures.readinessExitCode : OsExit.updateContextFactory;
29566
30067
  finish(code, payload);
29567
30068
  }
29568
30069
  if (pos[0] === "download" && pos[1] === "context") {
@@ -29587,10 +30088,10 @@ async function main() {
29587
30088
  finish(ExitCode.usage, { ok: false, error: `unknown download context flag: ${a}` });
29588
30089
  }
29589
30090
  requireMinimalGluecharmLayoutAt(repoRoot);
29590
- const ctxDir = path59.resolve(path59.join(repoRoot, ".gluecharm", "context"));
29591
- const gluecharmParent = path59.dirname(ctxDir);
29592
- if (path59.basename(gluecharmParent) === ".gluecharm" && path59.basename(ctxDir) === "context") {
29593
- 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));
29594
30095
  }
29595
30096
  const appIdRaw = getEasyspecsProjectIdFromRepoConfig(repoConfig)?.trim();
29596
30097
  if (!appIdRaw) {
@@ -29673,16 +30174,16 @@ async function main() {
29673
30174
  }
29674
30175
  const sess = sessRaw;
29675
30176
  requireMinimalGluecharmLayoutAt(repoRoot);
29676
- let ctxDir = path59.join(repoRoot, ".gluecharm", "context");
30177
+ let ctxDir = path60.join(repoRoot, ".gluecharm", "context");
29677
30178
  if (pos[1] === "republish") {
29678
30179
  const fromCfg = repoConfig.easyspecs?.upload?.contextDirectory?.trim();
29679
- const resolvedOverride = fromCfg && fromCfg.length > 0 ? path59.isAbsolute(fromCfg) ? path59.normalize(fromCfg) : path59.resolve(repoRoot, fromCfg) : "";
29680
- 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, ".."))) {
29681
30182
  ctxDir = resolvedOverride;
29682
30183
  } else {
29683
30184
  const storage = createFileBackedWorkspaceState(repoRoot);
29684
30185
  const snap = readAnalysisWorkspaceSnapshot(storage);
29685
- 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") : "";
29686
30187
  if (!wt) {
29687
30188
  finish(ExitCode.misconfiguration, {
29688
30189
  ok: false,
@@ -29692,10 +30193,10 @@ async function main() {
29692
30193
  ctxDir = wt;
29693
30194
  }
29694
30195
  }
29695
- const ctxResolved = path59.resolve(ctxDir);
29696
- const gluecharmParent = path59.dirname(ctxResolved);
29697
- if (path59.basename(gluecharmParent) === ".gluecharm" && path59.basename(ctxResolved) === "context") {
29698
- 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));
29699
30200
  }
29700
30201
  const appIdRaw = getEasyspecsProjectIdFromRepoConfig(repoConfig)?.trim();
29701
30202
  if (!appIdRaw) {
@@ -29799,18 +30300,18 @@ async function main() {
29799
30300
  finish(failed ? ExitCode.upload : ExitCode.ok, primary);
29800
30301
  }
29801
30302
  if (pos[0] === "ace" && pos[1] === "clear") {
29802
- const learnings = path59.join(repoRoot, ".gluecharm", "context", "learnings");
29803
- if (!fs62.existsSync(learnings)) {
30303
+ const learnings = path60.join(repoRoot, ".gluecharm", "context", "learnings");
30304
+ if (!fs63.existsSync(learnings)) {
29804
30305
  finish(ExitCode.ok, { ok: true, message: "nothing to clear" });
29805
30306
  }
29806
- fs62.rmSync(learnings, { recursive: true, force: true });
30307
+ fs63.rmSync(learnings, { recursive: true, force: true });
29807
30308
  finish(ExitCode.ok, { ok: true, message: `cleared ${learnings}` });
29808
30309
  }
29809
30310
  if (pos[0] === "ace" && pos[1] === "learn") {
29810
30311
  requireOpenCode(merged, flags);
29811
30312
  const { worktree } = parseWorktreeFlag(pos.slice(2));
29812
- const root = worktree && fs62.existsSync(path59.join(worktree, ".opencode", "schemas", "ace")) ? worktree : repoRoot;
29813
- 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");
29814
30315
  const traces = listAceTraceFiles(contextDir2);
29815
30316
  if (traces.length === 0) {
29816
30317
  finish(ExitCode.ok, { ok: true, message: "no traces", traceCount: 0 });
@@ -29834,8 +30335,8 @@ async function main() {
29834
30335
  if (pos[0] === "ace" && pos[1] === "auto-learn") {
29835
30336
  requireOpenCode(merged, flags);
29836
30337
  const { worktree } = parseWorktreeFlag(pos.slice(2));
29837
- const root = worktree && fs62.existsSync(path59.join(worktree, ".git")) ? worktree : repoRoot;
29838
- 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");
29839
30340
  const pending = listPendingAceTraceFiles(contextDir2, root);
29840
30341
  if (pending.length === 0) {
29841
30342
  finish(ExitCode.ok, { ok: true, pending: 0 });