@gluecharm-lab/easyspecs-cli 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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 path62 = 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 = path62.resolve(baseDir, baseName);
1896
+ if (fs64.existsSync(localBin)) return localBin;
1897
+ if (sourceExt.includes(path62.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 = path62.resolve(
1916
+ path62.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 = path62.basename(
1924
1924
  this._scriptPath,
1925
- path60.extname(this._scriptPath)
1925
+ path62.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(path62.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 = path62.basename(filename, path62.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(path63) {
2791
+ if (path63 === void 0) return this._executableDir;
2792
+ this._executableDir = path63;
2793
2793
  return this;
2794
2794
  }
2795
2795
  /**
@@ -5244,8 +5244,8 @@ var require_resolve = __commonJS({
5244
5244
  }
5245
5245
  return count;
5246
5246
  }
5247
- function getFullPath(resolver, id = "", normalize8) {
5248
- if (normalize8 !== false)
5247
+ function getFullPath(resolver, id = "", normalize9) {
5248
+ if (normalize9 !== false)
5249
5249
  id = normalizeId(id);
5250
5250
  const p = resolver.parse(id);
5251
5251
  return _getFullPath(resolver, p);
@@ -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 = resolve24.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 resolve24(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(path62) {
6239
+ let input = path62;
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 [path62, query] = wsComponent.resourceName.split("?");
6439
+ wsComponent.path = path62 && path62 !== "/" ? path62 : void 0;
6440
6440
  wsComponent.query = query;
6441
6441
  wsComponent.resourceName = void 0;
6442
6442
  }
@@ -6585,7 +6585,7 @@ var require_fast_uri = __commonJS({
6585
6585
  "use strict";
6586
6586
  var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizeComponentEncoding, isIPv4, nonSimpleDomain } = require_utils();
6587
6587
  var { SCHEMES, getSchemeHandler } = require_schemes();
6588
- function normalize8(uri, options) {
6588
+ function normalize9(uri, options) {
6589
6589
  if (typeof uri === "string") {
6590
6590
  uri = /** @type {T} */
6591
6591
  serialize(parse(uri, options), options);
@@ -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 resolve24(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;
@@ -6821,8 +6821,8 @@ var require_fast_uri = __commonJS({
6821
6821
  }
6822
6822
  var fastUri = {
6823
6823
  SCHEMES,
6824
- normalize: normalize8,
6825
- resolve: resolve20,
6824
+ normalize: normalize9,
6825
+ resolve: resolve24,
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 path61 = __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 `model` (or equivalent) in repo `opencode.json` / `opencode.jsonc`, global `~/.config/opencode/opencode.json`, `OPENCODE_CONFIG` / `OPENCODE_CONFIG_DIR`, managed config (see OpenCode docs), or `easyspecs.openCodeRuntime.providers`.";
10782
+ case OsExit.readinessOpenCodeMandatoryConfig:
10783
+ return "Readiness gate (d) reserved \u2014 repo-root `opencode.json` is optional when OpenCode is installed, credentials are ready, and a model is configured.";
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, path62, 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} ${path62} \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 path62 = `/proc/${pid}/status`;
14373
14398
  try {
14374
- const content = fs18.readFileSync(path60, "utf8");
14399
+ const content = fs18.readFileSync(path62, "utf8");
14375
14400
  const kb = parseVmRssKilobytesFromProcStatus(content);
14376
14401
  if (kb === null) {
14377
14402
  return { kind: "unknown", reason: "VmRSS_missing" };
@@ -14472,7 +14497,16 @@ var PROVIDER_ENV_KEYS = [
14472
14497
  "OPENAI_API_KEY",
14473
14498
  "OPENROUTER_API_KEY",
14474
14499
  "GOOGLE_API_KEY",
14475
- "OPENCODE_API_KEY"
14500
+ "GEMINI_API_KEY",
14501
+ "GOOGLE_GENERATIVE_AI_API_KEY",
14502
+ "OPENCODE_API_KEY",
14503
+ "MISTRAL_API_KEY",
14504
+ "GROQ_API_KEY",
14505
+ "COHERE_API_KEY",
14506
+ "XAI_API_KEY",
14507
+ "DEEPSEEK_API_KEY",
14508
+ "AZURE_OPENAI_API_KEY",
14509
+ "AWS_BEARER_TOKEN_BEDROCK"
14476
14510
  ];
14477
14511
  function hasProviderEnvConfigured() {
14478
14512
  for (const k of PROVIDER_ENV_KEYS) {
@@ -14559,9 +14593,9 @@ function runOpenCodeAgent(cwd, args, options) {
14559
14593
  log?.(`${procTag} command: ${formatCliCommandForLog(cmd, args)}`);
14560
14594
  log?.(`${procTag} cwd: ${JSON.stringify(cwd)}`);
14561
14595
  log?.(`${procTag} argv: ${JSON.stringify(args)}`);
14562
- return new Promise((resolve20) => {
14596
+ return new Promise((resolve24) => {
14563
14597
  if (sig?.aborted) {
14564
- resolve20({ ok: false, message: "Stopped by user.", cancelled: true });
14598
+ resolve24({ ok: false, message: "Stopped by user.", cancelled: true });
14565
14599
  return;
14566
14600
  }
14567
14601
  const spawnEnv = options?.childEnv && Object.keys(options.childEnv).length > 0 ? { ...process.env, ...options.childEnv } : process.env;
@@ -14656,7 +14690,7 @@ ${truncateForDiag(outBody, DIAG_STDOUT_MAX)}`);
14656
14690
  if (diag) {
14657
14691
  finishDiag(diag.label, diag.code, diag.dumpStreams);
14658
14692
  }
14659
- resolve20(result);
14693
+ resolve24(result);
14660
14694
  };
14661
14695
  let onAbort;
14662
14696
  const clearAbortHandler = () => {
@@ -19091,6 +19125,23 @@ function readHeadBranchShort(repoRoot) {
19091
19125
  const b = (r.stdout ?? "").trim();
19092
19126
  return b.length > 0 ? b : void 0;
19093
19127
  }
19128
+ function createInPlaceWorktreeHandle(repositoryRootAbs) {
19129
+ const root = path27.resolve(repositoryRootAbs);
19130
+ return {
19131
+ path: root,
19132
+ repoRoot: root,
19133
+ remove() {
19134
+ }
19135
+ };
19136
+ }
19137
+ function resolveAnalysisCheckoutHandle(worktreePath, repositoryRoot) {
19138
+ const wt = path27.resolve(worktreePath);
19139
+ const repo = path27.resolve(repositoryRoot);
19140
+ if (wt === repo) {
19141
+ return createInPlaceWorktreeHandle(repo);
19142
+ }
19143
+ return attachWorktreeHandle(worktreePath, repositoryRoot);
19144
+ }
19094
19145
  function attachWorktreeHandle(worktreePath, repositoryRoot) {
19095
19146
  const wt = path27.resolve(worktreePath);
19096
19147
  const repo = path27.resolve(repositoryRoot);
@@ -21363,8 +21414,8 @@ async function drainWorkstationPool(p) {
21363
21414
  const artefactRunId = readArtefactRunSnapshot(storageContext)?.runId ?? "unknown-run";
21364
21415
  let active = 0;
21365
21416
  let wake;
21366
- const waitTurn = () => new Promise((resolve20) => {
21367
- wake = resolve20;
21417
+ const waitTurn = () => new Promise((resolve24) => {
21418
+ wake = resolve24;
21368
21419
  });
21369
21420
  const persist = async () => {
21370
21421
  const items = {};
@@ -21533,6 +21584,26 @@ async function prepareSynthesisWorktree(storageContext, repoRoot, log, options)
21533
21584
  if (options?.clearPriorArtefactRun !== false) {
21534
21585
  await clearArtefactRun(storageContext);
21535
21586
  }
21587
+ if (options?.inPlace === true) {
21588
+ const repoResolved = path32.resolve(repoRoot);
21589
+ log(`[worktree] in-place analysis \u2014 using repository root ${repoResolved}`);
21590
+ const handle2 = createInPlaceWorktreeHandle(repoResolved);
21591
+ const sourceBranchAtCreation = readHeadBranchShort(repoResolved);
21592
+ let finalized2 = false;
21593
+ const finalize2 = () => {
21594
+ if (finalized2) {
21595
+ return;
21596
+ }
21597
+ finalized2 = true;
21598
+ log(`[worktree] in-place mode \u2014 no teardown`);
21599
+ };
21600
+ return {
21601
+ ok: true,
21602
+ handle: handle2,
21603
+ finalize: finalize2,
21604
+ ...sourceBranchAtCreation ? { sourceBranchAtCreation } : {}
21605
+ };
21606
+ }
21536
21607
  const wt = createAnalysisWorktree(repoRoot, { log });
21537
21608
  if (!wt.ok) {
21538
21609
  return { ok: false, error: wt.error };
@@ -21691,6 +21762,7 @@ function promoteContextDirectoryToWorkspaceFs(sourceContextDir, workspaceRootFs)
21691
21762
 
21692
21763
  // src/shared/factoryPipelineExitConditions.ts
21693
21764
  var FACTORY_PIPELINE_EXIT_CONDITIONS = {
21765
+ diagnose_readiness: "OpenCode CLI, credentials, default model, and mandatory project `opencode.json` are ready before worktree / agent work (SRS-72).",
21694
21766
  create_analysis_worktree: "Git analysis checkout exists under the configured temp parent (SRS-8); ready for agent materialization.",
21695
21767
  materialize_opencode_agents: "Bundled OpenCode agent definitions are copied into the analysis worktree (`.opencode/` tree).",
21696
21768
  synthesis_convergence: "Missing artefact count is 0. May run again after remediation (R5) if a refreshed check finds new expected outputs.",
@@ -21702,6 +21774,286 @@ var FACTORY_PIPELINE_EXIT_CONDITIONS = {
21702
21774
  backend_context_sync: "Context upload finished with no failures (quiet SRS-13 path; or cancel)."
21703
21775
  };
21704
21776
 
21777
+ // src/readiness/factoryReadiness.ts
21778
+ var fs39 = __toESM(require("node:fs"));
21779
+ var path35 = __toESM(require("node:path"));
21780
+
21781
+ // src/readiness/openCodeConfigCandidates.ts
21782
+ var os6 = __toESM(require("node:os"));
21783
+ var path34 = __toESM(require("node:path"));
21784
+ function openCodeUserConfigDir() {
21785
+ if (process.platform === "win32") {
21786
+ const base = process.env.APPDATA || path34.join(os6.homedir(), "AppData", "Roaming");
21787
+ return path34.join(base, "opencode");
21788
+ }
21789
+ const xdg = process.env.XDG_CONFIG_HOME?.trim();
21790
+ const cfgRoot = xdg && xdg.length > 0 ? xdg : path34.join(os6.homedir(), ".config");
21791
+ return path34.join(cfgRoot, "opencode");
21792
+ }
21793
+ function managedOpenCodeConfigDir() {
21794
+ if (process.platform === "darwin") {
21795
+ return "/Library/Application Support/opencode";
21796
+ }
21797
+ if (process.platform === "linux") {
21798
+ return path34.join("/etc", "opencode");
21799
+ }
21800
+ if (process.platform === "win32") {
21801
+ const pd = process.env.ProgramData?.trim() || "C:\\ProgramData";
21802
+ return path34.join(pd, "opencode");
21803
+ }
21804
+ return void 0;
21805
+ }
21806
+ function pushConfigBasenames(out, dir) {
21807
+ const d = path34.normalize(dir);
21808
+ out.push(path34.join(d, "opencode.json"));
21809
+ out.push(path34.join(d, "opencode.jsonc"));
21810
+ out.push(path34.join(d, "config.json"));
21811
+ }
21812
+ function dedupeStablePaths(paths) {
21813
+ const seen = /* @__PURE__ */ new Set();
21814
+ const out = [];
21815
+ for (const p of paths) {
21816
+ const n = path34.normalize(p.trim());
21817
+ if (n.length === 0 || seen.has(n)) {
21818
+ continue;
21819
+ }
21820
+ seen.add(n);
21821
+ out.push(n);
21822
+ }
21823
+ return out;
21824
+ }
21825
+ function openCodeJsonModelFileCandidates(analysisRootAbs) {
21826
+ const root = path34.resolve(analysisRootAbs);
21827
+ const acc = [];
21828
+ const oc = process.env.OPENCODE_CONFIG?.trim();
21829
+ if (oc) {
21830
+ acc.push(path34.resolve(oc));
21831
+ }
21832
+ pushConfigBasenames(acc, root);
21833
+ pushConfigBasenames(acc, path34.join(root, ".opencode"));
21834
+ const ocd = process.env.OPENCODE_CONFIG_DIR?.trim();
21835
+ if (ocd) {
21836
+ pushConfigBasenames(acc, path34.resolve(ocd));
21837
+ }
21838
+ pushConfigBasenames(acc, openCodeUserConfigDir());
21839
+ pushConfigBasenames(acc, path34.join(os6.homedir(), ".opencode"));
21840
+ const managed = managedOpenCodeConfigDir();
21841
+ if (managed) {
21842
+ pushConfigBasenames(acc, managed);
21843
+ }
21844
+ return dedupeStablePaths(acc);
21845
+ }
21846
+
21847
+ // src/readiness/factoryReadiness.ts
21848
+ var MANDATORY_OPEN_CODE_CONFIG_REL_PATHS = ["opencode.json"];
21849
+ var READINESS_OPENCODE_NOT_INSTALLED = "READINESS_OPENCODE_NOT_INSTALLED";
21850
+ var READINESS_OPENCODE_CREDENTIALS = "READINESS_OPENCODE_CREDENTIALS";
21851
+ var READINESS_OPENCODE_MODEL = "READINESS_OPENCODE_MODEL";
21852
+ function buildOpenCodeConfigInventory(analysisRootAbs) {
21853
+ return openCodeJsonModelFileCandidates(analysisRootAbs).map((p) => ({ path: p, exists: fs39.existsSync(p) }));
21854
+ }
21855
+ function defaultModelFromEasyspecsConfig(cfg) {
21856
+ const providers = cfg.easyspecs?.openCodeRuntime?.providers;
21857
+ if (!providers || typeof providers !== "object") {
21858
+ return void 0;
21859
+ }
21860
+ for (const rec of Object.values(providers)) {
21861
+ const dm = rec?.defaultModel?.trim();
21862
+ if (dm) {
21863
+ return dm;
21864
+ }
21865
+ }
21866
+ return void 0;
21867
+ }
21868
+ function pickString(v) {
21869
+ return typeof v === "string" && v.trim().length > 0 ? v.trim() : void 0;
21870
+ }
21871
+ function extractModelFromOpenCodeJson(data) {
21872
+ if (!data || typeof data !== "object") {
21873
+ return void 0;
21874
+ }
21875
+ const o = data;
21876
+ const direct = pickString(o.model) ?? pickString(o.defaultModel);
21877
+ if (direct) {
21878
+ return direct;
21879
+ }
21880
+ const models = o.models;
21881
+ if (models && typeof models === "object") {
21882
+ const m = models;
21883
+ const def = pickString(m.default) ?? pickString(m.defaultModel);
21884
+ if (def) {
21885
+ return def;
21886
+ }
21887
+ }
21888
+ const agent = o.agent;
21889
+ if (agent && typeof agent === "object") {
21890
+ const a = agent;
21891
+ const am = pickString(a.model) ?? pickString(a.defaultModel);
21892
+ if (am) {
21893
+ return am;
21894
+ }
21895
+ }
21896
+ return void 0;
21897
+ }
21898
+ function parseOpenCodeConfigText(raw) {
21899
+ const t = raw.trim();
21900
+ if (!t) {
21901
+ return void 0;
21902
+ }
21903
+ try {
21904
+ return JSON.parse(t);
21905
+ } catch {
21906
+ const noBlock = t.replace(/\/\*[\s\S]*?\*\//g, "");
21907
+ const noLine = noBlock.replace(/^\s*\/\/[^\n\r]*/gm, "");
21908
+ try {
21909
+ return JSON.parse(noLine);
21910
+ } catch {
21911
+ return void 0;
21912
+ }
21913
+ }
21914
+ }
21915
+ function modelFromOpencodeConfigContentEnv() {
21916
+ const v = process.env.OPENCODE_CONFIG_CONTENT?.trim();
21917
+ if (!v) {
21918
+ return void 0;
21919
+ }
21920
+ const data = parseOpenCodeConfigText(v);
21921
+ return data !== void 0 ? extractModelFromOpenCodeJson(data) : void 0;
21922
+ }
21923
+ function tryModelFromConfigFile(absPath) {
21924
+ try {
21925
+ const txt = fs39.readFileSync(absPath, "utf-8");
21926
+ const data = parseOpenCodeConfigText(txt);
21927
+ return data !== void 0 ? extractModelFromOpenCodeJson(data) : void 0;
21928
+ } catch {
21929
+ return void 0;
21930
+ }
21931
+ }
21932
+ function sanitizeModelSummary(raw) {
21933
+ const t = raw.trim();
21934
+ if (!t) {
21935
+ return "(not configured)";
21936
+ }
21937
+ if (t.length > 160) {
21938
+ return `${t.slice(0, 157)}\u2026`;
21939
+ }
21940
+ const lower = t.toLowerCase();
21941
+ if (lower.includes("bearer ") || lower.includes("authorization:") || lower.startsWith("sk-")) {
21942
+ return "(redacted)";
21943
+ }
21944
+ return t;
21945
+ }
21946
+ function resolveModelFromContext(ctx) {
21947
+ const fromCfg = defaultModelFromEasyspecsConfig(ctx.repoConfig);
21948
+ if (fromCfg) {
21949
+ return { configured: true, summary: sanitizeModelSummary(fromCfg) };
21950
+ }
21951
+ const fromInline = modelFromOpencodeConfigContentEnv();
21952
+ if (fromInline) {
21953
+ return { configured: true, summary: sanitizeModelSummary(fromInline) };
21954
+ }
21955
+ for (const p of openCodeJsonModelFileCandidates(ctx.analysisRootAbs)) {
21956
+ const m = tryModelFromConfigFile(p);
21957
+ if (m) {
21958
+ return { configured: true, summary: sanitizeModelSummary(m) };
21959
+ }
21960
+ }
21961
+ return { configured: false, summary: "(not configured)" };
21962
+ }
21963
+ function buildReadinessProbeFacts(ctx) {
21964
+ const oc = ctx.__testOnlyOpenCodeReadiness?.() ?? getOpenCodeReadiness({
21965
+ executable: ctx.openCodeExecutable,
21966
+ skipCredentialsCheck: ctx.openCodeSkipCredentialsCheck,
21967
+ providerEnvFromConfig: ctx.providerEnvFromConfig
21968
+ });
21969
+ const openCodeConfigFiles = buildOpenCodeConfigInventory(ctx.analysisRootAbs);
21970
+ const mandatoryOk = MANDATORY_OPEN_CODE_CONFIG_REL_PATHS.every((rel) => {
21971
+ const abs = path35.join(path35.resolve(ctx.analysisRootAbs), rel);
21972
+ return fs39.existsSync(abs);
21973
+ });
21974
+ const model = resolveModelFromContext(ctx);
21975
+ const agentsDir = resolveOpenCodeAgentsDir(ctx.repoRootAbs, ctx.repoConfig);
21976
+ return {
21977
+ installed: oc.installed,
21978
+ credentialsReady: oc.credentialsReady,
21979
+ skipCredentialsCheck: ctx.openCodeSkipCredentialsCheck === true,
21980
+ modelConfigured: model.configured,
21981
+ modelSummary: model.summary,
21982
+ mandatoryConfigPathsOk: mandatoryOk,
21983
+ openCodeConfigFiles,
21984
+ agentsDir,
21985
+ agentsDirExists: fs39.existsSync(agentsDir)
21986
+ };
21987
+ }
21988
+ function buildReadinessLineBlock(facts, ctx) {
21989
+ const apiDisp = ctx.apiBaseUrl.trim().length > 0 ? ctx.apiBaseUrl : "(empty \u2014 stub auth only)";
21990
+ const lines = [
21991
+ `cliVersion=${ctx.cliVersion}`,
21992
+ `repoRoot=${ctx.repoRootAbs}`,
21993
+ `apiBaseUrl=${apiDisp}`,
21994
+ `opencode installed=${String(facts.installed)} credentialsReady=${String(facts.credentialsReady)}`,
21995
+ `opencode modelConfigured=${String(facts.modelConfigured)} modelSummary=${facts.modelSummary}`,
21996
+ `mandatoryRepoOpenCodeJsonPathsOk=${String(facts.mandatoryConfigPathsOk)} (informational)`
21997
+ ];
21998
+ for (const e of facts.openCodeConfigFiles) {
21999
+ lines.push(`opencodeConfigFile ${e.path} exists=${String(e.exists)}`);
22000
+ }
22001
+ lines.push(`agentsDir=${facts.agentsDir} exists=${String(facts.agentsDirExists)}`);
22002
+ return lines;
22003
+ }
22004
+ function evaluateReadinessGates(facts) {
22005
+ if (!facts.installed) {
22006
+ return {
22007
+ ok: false,
22008
+ gate: "a",
22009
+ exitCode: OsExit.readinessOpenCodeNotInstalled,
22010
+ readinessReasonCode: READINESS_OPENCODE_NOT_INSTALLED
22011
+ };
22012
+ }
22013
+ if (!facts.credentialsReady && !facts.skipCredentialsCheck) {
22014
+ return {
22015
+ ok: false,
22016
+ gate: "b",
22017
+ exitCode: OsExit.readinessOpenCodeCredentials,
22018
+ readinessReasonCode: READINESS_OPENCODE_CREDENTIALS
22019
+ };
22020
+ }
22021
+ if (!facts.modelConfigured) {
22022
+ return {
22023
+ ok: false,
22024
+ gate: "c",
22025
+ exitCode: OsExit.readinessOpenCodeModel,
22026
+ readinessReasonCode: READINESS_OPENCODE_MODEL
22027
+ };
22028
+ }
22029
+ return { ok: true };
22030
+ }
22031
+ function buildReadinessJsonFields(facts) {
22032
+ return {
22033
+ modelConfigured: facts.modelConfigured,
22034
+ credentialsReady: facts.credentialsReady,
22035
+ openCodeConfigFiles: facts.openCodeConfigFiles,
22036
+ agentsDir: facts.agentsDir,
22037
+ agentsDirExists: facts.agentsDirExists
22038
+ };
22039
+ }
22040
+ function emitCliFactoryReadinessPreflight(log, bannerPrefix, ctx) {
22041
+ const facts = buildReadinessProbeFacts(ctx);
22042
+ const lines = buildReadinessLineBlock(facts, ctx);
22043
+ log(`${bannerPrefix} \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}`);
22044
+ for (const ln of lines) {
22045
+ log(ln);
22046
+ }
22047
+ const gateRes = evaluateReadinessGates(facts);
22048
+ if (!gateRes.ok) {
22049
+ log(`${bannerPrefix} \u2014 failed (readinessReasonCode=${gateRes.readinessReasonCode})`);
22050
+ log(`Exit ${String(gateRes.exitCode)} \u2014 ${describeExitCode(gateRes.exitCode)}`);
22051
+ return { ok: false, facts, failure: gateRes };
22052
+ }
22053
+ log(`${bannerPrefix} \u2014 succeeded (detail: all checks ok)`);
22054
+ return { ok: true, facts };
22055
+ }
22056
+
21705
22057
  // src/factory/factoryValidationFailures.ts
21706
22058
  function factoryFailureDisplayId(row2) {
21707
22059
  return row2.failureExitId;
@@ -21732,6 +22084,7 @@ function normalizeFactoryFailureRow(r) {
21732
22084
  return { ...base, validationExitId: r.validationExitId ?? failureExitId };
21733
22085
  }
21734
22086
  var FACTORY_VALIDATION_PHASE_ORDER = [
22087
+ "diagnose_readiness",
21735
22088
  "create_analysis_worktree",
21736
22089
  "materialize_opencode_agents",
21737
22090
  "synthesis_convergence",
@@ -21747,6 +22100,7 @@ var ERROR_JOIN_MAX = 900;
21747
22100
  var ADDITIONAL_APPEND_MAX = 200;
21748
22101
  var PHASE_TO_OS_EXIT = {
21749
22102
  unknown_factory_phase: OsExit.factoryUnknown,
22103
+ diagnose_readiness: OsExit.readinessOpenCodeModel,
21750
22104
  create_analysis_worktree: OsExit.createAnalysisWorktree,
21751
22105
  materialize_opencode_agents: OsExit.materializeOpenCodeAgents,
21752
22106
  synthesis_convergence: OsExit.synthesisConvergence,
@@ -21759,6 +22113,7 @@ var PHASE_TO_OS_EXIT = {
21759
22113
  };
21760
22114
  var TITLE_BY_PHASE = {
21761
22115
  unknown_factory_phase: "EasySpecs stopped: the failing pipeline phase could not be identified. Retry with --verbose; report this outcome if it persists.",
22116
+ 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
22117
  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
22118
  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
22119
  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 +22125,7 @@ var TITLE_BY_PHASE = {
21770
22125
  backend_context_sync: "Upload / cloud sync after analysis did not succeed. Check auth, project id, network, and upload error details."
21771
22126
  };
21772
22127
  var READABLE_PHASE_LABEL = {
22128
+ diagnose_readiness: "Diagnose readiness",
21773
22129
  create_analysis_worktree: "Analysis worktree",
21774
22130
  materialize_opencode_agents: "OpenCode agents",
21775
22131
  synthesis_convergence: "Synthesis",
@@ -21835,13 +22191,13 @@ function buildFactoryFailuresFromRows(phases) {
21835
22191
  const failed = phases.filter((p) => p.status === "failed");
21836
22192
  failed.sort((a, b) => phaseIndex(a.key) - phaseIndex(b.key));
21837
22193
  const semantic = failed.map((p) => {
21838
- const os7 = phaseToSemanticOsExitForGenerateContext(p.key);
22194
+ const os8 = phaseToSemanticOsExitForGenerateContext(p.key);
21839
22195
  const sub = inferValidationSubcode(p.key, p.detail);
21840
- const fid = failureExitIdFromParts(os7, 0);
22196
+ const fid = failureExitIdFromParts(os8, 0);
21841
22197
  return {
21842
22198
  factory: "generate_context",
21843
22199
  phase: p.key,
21844
- exitCode: os7,
22200
+ exitCode: os8,
21845
22201
  failureExitId: fid,
21846
22202
  validationExitId: fid,
21847
22203
  title: titleForGenerateContextPhase(p.key),
@@ -21906,6 +22262,7 @@ function composeFactoryValidationError(orchestratorMessage, failures) {
21906
22262
 
21907
22263
  // src/factory/generateContextFactory.ts
21908
22264
  var FACTORY_PIPELINE_KEYS = [
22265
+ "diagnose_readiness",
21909
22266
  "create_analysis_worktree",
21910
22267
  "materialize_opencode_agents",
21911
22268
  "synthesis_convergence",
@@ -21934,7 +22291,7 @@ function sleepUntilAborted(ms, signal) {
21934
22291
  if (signal.aborted) {
21935
22292
  return Promise.reject(new DOMException("The operation was aborted.", "AbortError"));
21936
22293
  }
21937
- return new Promise((resolve20, reject) => {
22294
+ return new Promise((resolve24, reject) => {
21938
22295
  const onAbort = () => {
21939
22296
  clearTimeout(t);
21940
22297
  signal.removeEventListener("abort", onAbort);
@@ -21942,7 +22299,7 @@ function sleepUntilAborted(ms, signal) {
21942
22299
  };
21943
22300
  const t = setTimeout(() => {
21944
22301
  signal.removeEventListener("abort", onAbort);
21945
- resolve20();
22302
+ resolve24();
21946
22303
  }, ms);
21947
22304
  signal.addEventListener("abort", onAbort, { once: true });
21948
22305
  });
@@ -22041,6 +22398,59 @@ async function runGenerateContextFactory(deps) {
22041
22398
  };
22042
22399
  let pingPong = 0;
22043
22400
  try {
22401
+ if (!deps.readiness) {
22402
+ setRowTimed("diagnose_readiness", "succeeded", "Readiness context omitted (narrow unit test).");
22403
+ await post();
22404
+ } else {
22405
+ setRowTimed("diagnose_readiness", "running", "Running diagnose readiness preflight\u2026");
22406
+ await post();
22407
+ const facts = buildReadinessProbeFacts(deps.readiness);
22408
+ const lines = buildReadinessLineBlock(facts, deps.readiness);
22409
+ const gateRes = evaluateReadinessGates(facts);
22410
+ const stamp = (/* @__PURE__ */ new Date()).toISOString();
22411
+ const rlog = deps.readinessLog ?? deps.factoryLog;
22412
+ rlog?.(`[factory] diagnose readiness \u2014 ${stamp}`);
22413
+ for (const ln of lines) {
22414
+ rlog?.(ln);
22415
+ }
22416
+ if (!gateRes.ok) {
22417
+ rlog?.(
22418
+ `[factory] diagnose readiness \u2014 failed (readinessReasonCode=${gateRes.readinessReasonCode})`
22419
+ );
22420
+ rlog?.(`Exit ${String(gateRes.exitCode)} \u2014 ${describeExitCode(gateRes.exitCode)}`);
22421
+ const detail = `${gateRes.readinessReasonCode} (gate ${gateRes.gate})`;
22422
+ setRowTimed("diagnose_readiness", "failed", detail);
22423
+ await post();
22424
+ const fr = {
22425
+ factory: "generate_context",
22426
+ phase: "diagnose_readiness",
22427
+ exitCode: gateRes.exitCode,
22428
+ failureExitId: failureExitIdFromParts(gateRes.exitCode, 0),
22429
+ validationExitId: failureExitIdFromParts(gateRes.exitCode, 0),
22430
+ title: titleForGenerateContextPhase("diagnose_readiness"),
22431
+ detail: detail.length > 600 ? `${detail.slice(0, 597)}\u2026` : detail
22432
+ };
22433
+ const ff = finalizeFactoryFailuresForProcessExit([fr]);
22434
+ const msg = `Readiness failed: ${gateRes.readinessReasonCode}`;
22435
+ const r = {
22436
+ ok: false,
22437
+ message: msg,
22438
+ totalElapsedMs: macroEnd(),
22439
+ factoryFailures: ff,
22440
+ readinessFailure: {
22441
+ exitCode: gateRes.exitCode,
22442
+ readinessReasonCode: gateRes.readinessReasonCode,
22443
+ readinessGate: gateRes.gate
22444
+ }
22445
+ };
22446
+ logFactoryEnd(r);
22447
+ return r;
22448
+ }
22449
+ const joined = lines.join(" | ");
22450
+ const okDetail = joined.length > 600 ? `${lines[0] ?? "ok"} | \u2026 (${String(lines.length)} lines)` : joined;
22451
+ setRowTimed("diagnose_readiness", "succeeded", okDetail);
22452
+ await post();
22453
+ }
22044
22454
  outer: while (true) {
22045
22455
  if (isAborted(signal)) {
22046
22456
  setRowTimed("synthesis_convergence", "cancelled", "Stopped.");
@@ -22057,7 +22467,15 @@ async function runGenerateContextFactory(deps) {
22057
22467
  return fin({ ok: false, cancelled: true, message: "Factory stopped.", totalElapsedMs: macroEnd() });
22058
22468
  }
22059
22469
  if (!resumeSynthesis) {
22060
- setRowTimed("create_analysis_worktree", "running", "Creating git analysis worktree\u2026");
22470
+ if (deps.analysisInPlace === true) {
22471
+ setRowTimed(
22472
+ "create_analysis_worktree",
22473
+ "running",
22474
+ "In-place analysis \u2014 preparing repository root (no temp worktree)\u2026"
22475
+ );
22476
+ } else {
22477
+ setRowTimed("create_analysis_worktree", "running", "Creating git analysis worktree\u2026");
22478
+ }
22061
22479
  await post();
22062
22480
  const wtRes = await deps.runPrepareAnalysisWorktree(false);
22063
22481
  if (!wtRes.ok) {
@@ -22065,7 +22483,15 @@ async function runGenerateContextFactory(deps) {
22065
22483
  await post();
22066
22484
  return fail(wtRes.error ?? "Worktree creation failed.");
22067
22485
  }
22068
- setRowTimed("create_analysis_worktree", "succeeded", "Analysis checkout ready.");
22486
+ if (deps.analysisInPlace === true) {
22487
+ setRowTimed(
22488
+ "create_analysis_worktree",
22489
+ "skipped",
22490
+ "In-place analysis \u2014 using repository root (no detached checkout)."
22491
+ );
22492
+ } else {
22493
+ setRowTimed("create_analysis_worktree", "succeeded", "Analysis checkout ready.");
22494
+ }
22069
22495
  await post();
22070
22496
  if (isAborted(signal)) {
22071
22497
  setRowTimed("materialize_opencode_agents", "cancelled");
@@ -22371,8 +22797,8 @@ async function runGenerateContextFactory(deps) {
22371
22797
  }
22372
22798
 
22373
22799
  // src/factory/generateContextFactoryHeadlessHost.ts
22374
- var fs47 = __toESM(require("node:fs"));
22375
- var path43 = __toESM(require("node:path"));
22800
+ var fs48 = __toESM(require("node:fs"));
22801
+ var path45 = __toESM(require("node:path"));
22376
22802
 
22377
22803
  // src/stores/pipelineRunStore.ts
22378
22804
  var STORAGE_KEY2 = SRS53_PIPELINE_RUN_KEY_V2;
@@ -22472,12 +22898,12 @@ async function noteAgentsMaterialized(context) {
22472
22898
  }
22473
22899
 
22474
22900
  // src/pipelines/remediation/missingWorkstations.ts
22475
- var fs40 = __toESM(require("fs"));
22476
- var path35 = __toESM(require("path"));
22901
+ var fs41 = __toESM(require("fs"));
22902
+ var path37 = __toESM(require("path"));
22477
22903
 
22478
22904
  // src/analysis/analysisDetailMarkdownDiscovery.ts
22479
- var fs39 = __toESM(require("fs"));
22480
- var path34 = __toESM(require("path"));
22905
+ var fs40 = __toESM(require("fs"));
22906
+ var path36 = __toESM(require("path"));
22481
22907
  var SLUG4 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
22482
22908
  var FE2 = /^FE-\d+$/;
22483
22909
  var UC2 = /^UC-\d+$/;
@@ -22498,7 +22924,7 @@ var STEM_TO_AGENT = {
22498
22924
  };
22499
22925
  function readJson5(filePath) {
22500
22926
  try {
22501
- let raw = fs39.readFileSync(filePath, "utf-8");
22927
+ let raw = fs40.readFileSync(filePath, "utf-8");
22502
22928
  if (raw.length > 0 && raw.charCodeAt(0) === 65279) {
22503
22929
  raw = raw.slice(1);
22504
22930
  }
@@ -22539,7 +22965,7 @@ function expectedFeatureDetailBasenameFromRow(row2) {
22539
22965
  return `${code}-${slug}.md`;
22540
22966
  }
22541
22967
  function ctxPath(contextDir2, basename17) {
22542
- return path34.join(contextDir2, basename17);
22968
+ return path36.join(contextDir2, basename17);
22543
22969
  }
22544
22970
  function pushTarget(targets, stem, outputBasename, taskDescription, contextDir2) {
22545
22971
  const meta = STEM_TO_AGENT[stem];
@@ -22555,7 +22981,7 @@ function pushTarget(targets, stem, outputBasename, taskDescription, contextDir2)
22555
22981
  function discoverDetailMarkdownGroups(contextDir2) {
22556
22982
  const groups = [];
22557
22983
  const featureTargets = [];
22558
- const flPath = path34.join(contextDir2, "features-list.json");
22984
+ const flPath = path36.join(contextDir2, "features-list.json");
22559
22985
  const fl = readJson5(flPath);
22560
22986
  const features = Array.isArray(fl?.features) ? fl.features : [];
22561
22987
  for (const row2 of features) {
@@ -22585,7 +23011,7 @@ function discoverDetailMarkdownGroups(contextDir2) {
22585
23011
  if (!FE2.test(feCode)) {
22586
23012
  continue;
22587
23013
  }
22588
- const ucListPath = path34.join(contextDir2, `${feCode}-use-cases-list.json`);
23014
+ const ucListPath = path36.join(contextDir2, `${feCode}-use-cases-list.json`);
22589
23015
  const ucFile = readJson5(ucListPath);
22590
23016
  const ucs = Array.isArray(ucFile?.useCases) ? ucFile.useCases : [];
22591
23017
  for (const ucRow of ucs) {
@@ -22605,7 +23031,7 @@ function discoverDetailMarkdownGroups(contextDir2) {
22605
23031
  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
23032
  contextDir2
22607
23033
  );
22608
- const scPath = path34.join(contextDir2, `${feCode}_${ucCode}-scenarios-list.json`);
23034
+ const scPath = path36.join(contextDir2, `${feCode}_${ucCode}-scenarios-list.json`);
22609
23035
  const scFile = readJson5(scPath);
22610
23036
  const scs = Array.isArray(scFile?.scenarios) ? scFile.scenarios : [];
22611
23037
  for (const scRow of scs) {
@@ -22676,7 +23102,7 @@ Follow bundled agent **agent-md-use-case-detail**: include **## Data inputs and
22676
23102
  groups.push({ id: "detail-services", label: "Detail markdown \u2014 Services", targets: svcTargets });
22677
23103
  groups.push({ id: "detail-methods", label: "Detail markdown \u2014 Methods", targets: meTargets });
22678
23104
  const entTargets = [];
22679
- const dmPath = path34.join(contextDir2, "data-model-list.json");
23105
+ const dmPath = path36.join(contextDir2, "data-model-list.json");
22680
23106
  const dmFile = readJson5(dmPath);
22681
23107
  const ents = Array.isArray(dmFile?.entities) ? dmFile.entities : [];
22682
23108
  for (const erow of ents) {
@@ -22705,7 +23131,7 @@ Follow bundled agent **agent-md-use-case-detail**: include **## Data inputs and
22705
23131
  if (!DM2.test(dmCode)) {
22706
23132
  continue;
22707
23133
  }
22708
- const flPath2 = path34.join(contextDir2, `${dmCode}-fields-list.json`);
23134
+ const flPath2 = path36.join(contextDir2, `${dmCode}-fields-list.json`);
22709
23135
  const flFile = readJson5(flPath2);
22710
23136
  const flds = Array.isArray(flFile?.fields) ? flFile.fields : [];
22711
23137
  for (const frow of flds) {
@@ -22764,9 +23190,9 @@ function fileAndValidationFromKind(kind) {
22764
23190
  return { filePresentYesNo: "no", validationYesNo: "na" };
22765
23191
  }
22766
23192
  function classifyMissingWorkstationOutputFileStatus(row2, contextDir2, worktreeRoot) {
22767
- const abs = path35.join(contextDir2, row2.relativePath);
23193
+ const abs = path37.join(contextDir2, row2.relativePath);
22768
23194
  try {
22769
- const st = fs40.statSync(abs);
23195
+ const st = fs41.statSync(abs);
22770
23196
  if (!st.isFile()) {
22771
23197
  return { kind: "absent", detail: "Path exists but is not a regular file." };
22772
23198
  }
@@ -22803,8 +23229,8 @@ function classifyMissingWorkstationOutputFileStatus(row2, contextDir2, worktreeR
22803
23229
  detail: "Unknown coordination list basename \u2014 no JSON Schema mapping."
22804
23230
  };
22805
23231
  }
22806
- const schemaAbs = path35.join(worktreeRoot, ".opencode", "schemas", "context-lists", schemaBn);
22807
- if (!fs40.existsSync(schemaAbs)) {
23232
+ const schemaAbs = path37.join(worktreeRoot, ".opencode", "schemas", "context-lists", schemaBn);
23233
+ if (!fs41.existsSync(schemaAbs)) {
22808
23234
  return {
22809
23235
  kind: "invalid",
22810
23236
  detail: `Schema not found (${schemaBn}). Run **Materialize agents** on this checkout.`
@@ -22833,7 +23259,7 @@ function classifyWorkstationOutputOnDisk(item, contextDir2, worktreeRoot) {
22833
23259
  return classifyMissingWorkstationOutputFileStatus(row2, contextDir2, worktreeRoot).kind;
22834
23260
  }
22835
23261
  function isWorkstationRunSnapshotForWorktree(snapshot, worktreeRoot) {
22836
- return !!(snapshot && snapshot.overallStatus !== "running" && snapshot.overallStatus !== "idle" && path35.resolve(snapshot.analysisRoot) === path35.resolve(worktreeRoot));
23262
+ return !!(snapshot && snapshot.overallStatus !== "running" && snapshot.overallStatus !== "idle" && path37.resolve(snapshot.analysisRoot) === path37.resolve(worktreeRoot));
22837
23263
  }
22838
23264
  function expectedBasenameForCoordPayload(p) {
22839
23265
  const { step, listTarget } = p;
@@ -22907,10 +23333,10 @@ function labelContextForCoordPayload(p) {
22907
23333
  }
22908
23334
  function contextPathForWorkItem(item, contextDir2) {
22909
23335
  if (item.kind === "markdown") {
22910
- return path35.join(contextDir2, item.payload.outputBasename);
23336
+ return path37.join(contextDir2, item.payload.outputBasename);
22911
23337
  }
22912
23338
  const bn = expectedBasenameForCoordPayload(item.payload);
22913
- return bn ? path35.join(contextDir2, bn) : null;
23339
+ return bn ? path37.join(contextDir2, bn) : null;
22914
23340
  }
22915
23341
  function syntheticRunnerId(key) {
22916
23342
  return `remediation:${key}`;
@@ -22920,7 +23346,7 @@ function rowFromSkippedItem(item, contextDir2) {
22920
23346
  return null;
22921
23347
  }
22922
23348
  const abs = contextPathForWorkItem(item, contextDir2);
22923
- const rel = abs ? path35.basename(abs) : item.kind === "markdown" ? item.payload.outputBasename : item.id;
23349
+ const rel = abs ? path37.basename(abs) : item.kind === "markdown" ? item.payload.outputBasename : item.id;
22924
23350
  if (abs && nonEmptyContextFile(abs)) {
22925
23351
  return null;
22926
23352
  }
@@ -23040,7 +23466,7 @@ function listMissingWorkstations(contextDir2, worktreeRoot, snapshot) {
23040
23466
  }
23041
23467
  }
23042
23468
  }
23043
- if (!fs40.existsSync(contextDir2)) {
23469
+ if (!fs41.existsSync(contextDir2)) {
23044
23470
  return [...map.values()].sort((a, b) => a.key.localeCompare(b.key));
23045
23471
  }
23046
23472
  const dynamic = discoverDynamicAnalysisTestSteps(contextDir2);
@@ -23095,7 +23521,7 @@ function toMissingWorkstationUiRows(rows, contextDir2, worktreeRoot) {
23095
23521
  }
23096
23522
 
23097
23523
  // src/pipelines/remediation/missingWorkstationsPool.ts
23098
- var path36 = __toESM(require("path"));
23524
+ var path38 = __toESM(require("path"));
23099
23525
  function reconcileSkippedWorkItemsWithDisk(byId, contextDir2, worktreeRoot) {
23100
23526
  for (const item of byId.values()) {
23101
23527
  if (item.status !== "skipped") {
@@ -23155,7 +23581,7 @@ async function runRemediationPipelineMissingPass(p) {
23155
23581
  onItemComplete,
23156
23582
  sourceBranchAtWorktreeCreation
23157
23583
  } = p;
23158
- const contextDir2 = path36.join(worktreeRoot, ".gluecharm", "context");
23584
+ const contextDir2 = path38.join(worktreeRoot, ".gluecharm", "context");
23159
23585
  const snap = readArtefactRunSnapshot(storageContext);
23160
23586
  const snapOk = isWorkstationRunSnapshotForWorktree(snap, worktreeRoot);
23161
23587
  let byId;
@@ -23221,18 +23647,18 @@ async function runRemediationPipelineMissingPass(p) {
23221
23647
 
23222
23648
  // src/pipelines/coverage/coveragePipeline.ts
23223
23649
  var import_child_process5 = require("child_process");
23224
- var fs42 = __toESM(require("fs"));
23225
- var path38 = __toESM(require("path"));
23650
+ var fs43 = __toESM(require("fs"));
23651
+ var path40 = __toESM(require("path"));
23226
23652
 
23227
23653
  // src/analysis/coverageReferenceValidationSchemaValidate.ts
23228
- var fs41 = __toESM(require("fs"));
23229
- var path37 = __toESM(require("path"));
23654
+ var fs42 = __toESM(require("fs"));
23655
+ var path39 = __toESM(require("path"));
23230
23656
  var import__5 = __toESM(require__());
23231
23657
  function stripUtf8Bom4(s) {
23232
23658
  return s.length > 0 && s.charCodeAt(0) === 65279 ? s.slice(1) : s;
23233
23659
  }
23234
23660
  function bundledCoverageReferenceValidationSchemaPath() {
23235
- return path37.join(
23661
+ return path39.join(
23236
23662
  resolveRepoResourcesRoot(),
23237
23663
  "schemas",
23238
23664
  "context-lists",
@@ -23255,7 +23681,7 @@ function getValidate() {
23255
23681
  return compiledValidate;
23256
23682
  }
23257
23683
  const schemaPath = bundledCoverageReferenceValidationSchemaPath();
23258
- const schemaRaw = stripUtf8Bom4(fs41.readFileSync(schemaPath, "utf-8"));
23684
+ const schemaRaw = stripUtf8Bom4(fs42.readFileSync(schemaPath, "utf-8"));
23259
23685
  const schema = JSON.parse(schemaRaw);
23260
23686
  const ajv2 = new import__5.default({ allErrors: true, strict: false });
23261
23687
  compiledValidate = ajv2.compile(schema);
@@ -23271,7 +23697,7 @@ function validateCoverageReferenceValidationData(data) {
23271
23697
  function readAndValidateCoverageReferenceValidationFile(jsonAbsolutePath) {
23272
23698
  let raw;
23273
23699
  try {
23274
- raw = stripUtf8Bom4(fs41.readFileSync(jsonAbsolutePath, "utf-8"));
23700
+ raw = stripUtf8Bom4(fs42.readFileSync(jsonAbsolutePath, "utf-8"));
23275
23701
  } catch (e) {
23276
23702
  return {
23277
23703
  ok: false,
@@ -23312,8 +23738,8 @@ var DEFAULT_IGNORE_DIR_BASENAMES = [
23312
23738
  ];
23313
23739
  var GIT_LS_FILES_MAX_BUFFER = 64 * 1024 * 1024;
23314
23740
  function tryLoadGitNonIgnoredPathSet(repositoryRootAbs) {
23315
- const root = path38.resolve(repositoryRootAbs);
23316
- if (!fs42.existsSync(path38.join(root, ".git"))) {
23741
+ const root = path40.resolve(repositoryRootAbs);
23742
+ if (!fs43.existsSync(path40.join(root, ".git"))) {
23317
23743
  return null;
23318
23744
  }
23319
23745
  const env = { ...process.env, GIT_TERMINAL_PROMPT: "0" };
@@ -23381,12 +23807,12 @@ var REFERENCE_COVERAGE_IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
23381
23807
  ".emf"
23382
23808
  ]);
23383
23809
  function isReferenceCoverageExcludedImagePath(relPosix) {
23384
- const ext = path38.extname(relPosix).toLowerCase();
23810
+ const ext = path40.extname(relPosix).toLowerCase();
23385
23811
  return ext.length > 0 && REFERENCE_COVERAGE_IMAGE_EXTENSIONS.has(ext);
23386
23812
  }
23387
23813
  var REFERENCE_COVERAGE_EXCLUDED_FILE_BASENAMES = /* @__PURE__ */ new Set([".gitignore"]);
23388
23814
  function isReferenceCoverageExcludedDefaultBasename(relPosix) {
23389
- const base = path38.basename(relPosix.replace(/\\/g, "/")).toLowerCase();
23815
+ const base = path40.basename(relPosix.replace(/\\/g, "/")).toLowerCase();
23390
23816
  return REFERENCE_COVERAGE_EXCLUDED_FILE_BASENAMES.has(base);
23391
23817
  }
23392
23818
  function decodeBufferForLineCount(buf) {
@@ -23423,12 +23849,12 @@ function normalizeRepoRelativePath(repoRoot, raw) {
23423
23849
  if (!trimmed || trimmed.includes("\0")) {
23424
23850
  return null;
23425
23851
  }
23426
- const abs = path38.resolve(repoRoot, trimmed);
23427
- const rel = path38.relative(repoRoot, abs);
23428
- if (rel.startsWith("..") || path38.isAbsolute(rel)) {
23852
+ const abs = path40.resolve(repoRoot, trimmed);
23853
+ const rel = path40.relative(repoRoot, abs);
23854
+ if (rel.startsWith("..") || path40.isAbsolute(rel)) {
23429
23855
  return null;
23430
23856
  }
23431
- return rel.split(path38.sep).join("/");
23857
+ return rel.split(path40.sep).join("/");
23432
23858
  }
23433
23859
  function collectJsonSourceReferences(node, out) {
23434
23860
  if (node === null || typeof node !== "object") {
@@ -23468,12 +23894,12 @@ function extractEvidenceIndexPathCitations(body) {
23468
23894
  function listContextFilesRecursive(dir, acc) {
23469
23895
  let entries;
23470
23896
  try {
23471
- entries = fs42.readdirSync(dir, { withFileTypes: true });
23897
+ entries = fs43.readdirSync(dir, { withFileTypes: true });
23472
23898
  } catch {
23473
23899
  return;
23474
23900
  }
23475
23901
  for (const e of entries) {
23476
- const full = path38.join(dir, e.name);
23902
+ const full = path40.join(dir, e.name);
23477
23903
  if (e.isDirectory()) {
23478
23904
  listContextFilesRecursive(full, acc);
23479
23905
  } else if (e.isFile()) {
@@ -23486,7 +23912,7 @@ function walkRepositoryFiles(repoRoot, ignoreBasenames, maxBytes, excludedOut, g
23486
23912
  const walk = (dir) => {
23487
23913
  let entries;
23488
23914
  try {
23489
- entries = fs42.readdirSync(dir, { withFileTypes: true });
23915
+ entries = fs43.readdirSync(dir, { withFileTypes: true });
23490
23916
  } catch {
23491
23917
  return;
23492
23918
  }
@@ -23494,8 +23920,8 @@ function walkRepositoryFiles(repoRoot, ignoreBasenames, maxBytes, excludedOut, g
23494
23920
  if (ignoreBasenames.has(e.name)) {
23495
23921
  continue;
23496
23922
  }
23497
- const full = path38.join(dir, e.name);
23498
- const rel = path38.relative(repoRoot, full).split(path38.sep).join("/");
23923
+ const full = path40.join(dir, e.name);
23924
+ const rel = path40.relative(repoRoot, full).split(path40.sep).join("/");
23499
23925
  if (rel.startsWith("..")) {
23500
23926
  continue;
23501
23927
  }
@@ -23516,7 +23942,7 @@ function walkRepositoryFiles(repoRoot, ignoreBasenames, maxBytes, excludedOut, g
23516
23942
  }
23517
23943
  let st;
23518
23944
  try {
23519
- st = fs42.statSync(full);
23945
+ st = fs43.statSync(full);
23520
23946
  } catch {
23521
23947
  continue;
23522
23948
  }
@@ -23526,7 +23952,7 @@ function walkRepositoryFiles(repoRoot, ignoreBasenames, maxBytes, excludedOut, g
23526
23952
  }
23527
23953
  let buf;
23528
23954
  try {
23529
- buf = fs42.readFileSync(full);
23955
+ buf = fs43.readFileSync(full);
23530
23956
  } catch {
23531
23957
  excludedOut.push({ path: rel, reason: "read error" });
23532
23958
  continue;
@@ -23546,23 +23972,23 @@ function walkRepositoryFiles(repoRoot, ignoreBasenames, maxBytes, excludedOut, g
23546
23972
  }
23547
23973
  function collectReferencesFromContext(contextDirAbs, repositoryRootAbs, warnings) {
23548
23974
  const references = [];
23549
- if (!fs42.existsSync(contextDirAbs)) {
23975
+ if (!fs43.existsSync(contextDirAbs)) {
23550
23976
  warnings.push(`Context directory missing: ${contextDirAbs}`);
23551
23977
  return references;
23552
23978
  }
23553
23979
  const allFiles = [];
23554
23980
  listContextFilesRecursive(contextDirAbs, allFiles);
23555
23981
  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("/");
23982
+ const ext = path40.extname(abs).toLowerCase();
23983
+ const base = path40.basename(abs);
23984
+ const sourceArtefact = path40.relative(contextDirAbs, abs).split(path40.sep).join("/");
23559
23985
  if (ext === ".json") {
23560
23986
  if (SKIP_CONTEXT_JSON.has(base)) {
23561
23987
  continue;
23562
23988
  }
23563
23989
  let raw;
23564
23990
  try {
23565
- raw = fs42.readFileSync(abs, "utf-8");
23991
+ raw = fs43.readFileSync(abs, "utf-8");
23566
23992
  } catch (e) {
23567
23993
  warnings.push(`Skip JSON (read error): ${sourceArtefact} \u2014 ${e instanceof Error ? e.message : String(e)}`);
23568
23994
  continue;
@@ -23593,7 +24019,7 @@ function collectReferencesFromContext(contextDirAbs, repositoryRootAbs, warnings
23593
24019
  if (ext === ".md") {
23594
24020
  let text;
23595
24021
  try {
23596
- const buf = fs42.readFileSync(abs);
24022
+ const buf = fs43.readFileSync(abs);
23597
24023
  text = decodeBufferForLineCount(buf);
23598
24024
  } catch (e) {
23599
24025
  warnings.push(`Skip markdown (read/decode error): ${sourceArtefact} \u2014 ${e instanceof Error ? e.message : String(e)}`);
@@ -23637,12 +24063,12 @@ function sortReferenceRows(a, b) {
23637
24063
  return (a.startLine ?? 0) - (b.startLine ?? 0);
23638
24064
  }
23639
24065
  function buildCoverageReferenceValidationDocument(repositoryRootAbs, contextDirAbs, options) {
23640
- const repoRoot = path38.resolve(repositoryRootAbs);
24066
+ const repoRoot = path40.resolve(repositoryRootAbs);
23641
24067
  const warnings = [];
23642
24068
  const ignoreDirs = [...DEFAULT_IGNORE_DIR_BASENAMES];
23643
24069
  const ignoreSet = new Set(ignoreDirs);
23644
24070
  const maxBytes = options?.maxFileBytes ?? MAX_FILE_BYTES;
23645
- const references = collectReferencesFromContext(path38.resolve(contextDirAbs), repoRoot, warnings);
24071
+ const references = collectReferencesFromContext(path40.resolve(contextDirAbs), repoRoot, warnings);
23646
24072
  references.sort(sortReferenceRows);
23647
24073
  const referencedSet = /* @__PURE__ */ new Set();
23648
24074
  for (const r of references) {
@@ -23650,7 +24076,7 @@ function buildCoverageReferenceValidationDocument(repositoryRootAbs, contextDirA
23650
24076
  }
23651
24077
  const excludedFiles = [];
23652
24078
  const gitNonIgnoredPaths = tryLoadGitNonIgnoredPathSet(repoRoot);
23653
- if (fs42.existsSync(path38.join(repoRoot, ".git")) && gitNonIgnoredPaths === null) {
24079
+ if (fs43.existsSync(path40.join(repoRoot, ".git")) && gitNonIgnoredPaths === null) {
23654
24080
  warnings.push(
23655
24081
  "Repository has .git but git ls-files failed or git is unavailable; .gitignore / exclude-standard not applied."
23656
24082
  );
@@ -23699,12 +24125,12 @@ function buildCoverageReferenceValidationDocument(repositoryRootAbs, contextDirA
23699
24125
  return { document: doc, warnings };
23700
24126
  }
23701
24127
  function runCoveragePipeline(opts) {
23702
- const repoRoot = path38.resolve(opts.repositoryRootAbs);
23703
- const contextDir2 = path38.resolve(opts.contextDirAbs);
23704
- if (!fs42.existsSync(repoRoot)) {
24128
+ const repoRoot = path40.resolve(opts.repositoryRootAbs);
24129
+ const contextDir2 = path40.resolve(opts.contextDirAbs);
24130
+ if (!fs43.existsSync(repoRoot)) {
23705
24131
  return { ok: false, error: `Repository root does not exist: ${repoRoot}` };
23706
24132
  }
23707
- if (!fs42.existsSync(contextDir2)) {
24133
+ if (!fs43.existsSync(contextDir2)) {
23708
24134
  return {
23709
24135
  ok: false,
23710
24136
  error: `Missing .gluecharm/context: ${contextDir2}`
@@ -23722,11 +24148,11 @@ ${schemaCheck.errors.join("\n")}`,
23722
24148
  warnings
23723
24149
  };
23724
24150
  }
23725
- const outPath = path38.join(contextDir2, COVERAGE_REFERENCE_VALIDATION_BASENAME);
24151
+ const outPath = path40.join(contextDir2, COVERAGE_REFERENCE_VALIDATION_BASENAME);
23726
24152
  if (opts.write) {
23727
24153
  try {
23728
24154
  const payload = stableStringifyCoverageDocument(document);
23729
- fs42.writeFileSync(outPath, payload, "utf-8");
24155
+ fs43.writeFileSync(outPath, payload, "utf-8");
23730
24156
  } catch (e) {
23731
24157
  return {
23732
24158
  ok: false,
@@ -23740,12 +24166,12 @@ ${schemaCheck.errors.join("\n")}`,
23740
24166
 
23741
24167
  // src/pipelines/remediation/zeroReferenceWorkstationChain.ts
23742
24168
  var crypto = __toESM(require("crypto"));
23743
- var fs44 = __toESM(require("fs"));
23744
- var path40 = __toESM(require("path"));
24169
+ var fs45 = __toESM(require("fs"));
24170
+ var path42 = __toESM(require("path"));
23745
24171
 
23746
24172
  // src/analysis/zeroReferenceRemediationSchemaValidate.ts
23747
- var fs43 = __toESM(require("fs"));
23748
- var path39 = __toESM(require("path"));
24173
+ var fs44 = __toESM(require("fs"));
24174
+ var path41 = __toESM(require("path"));
23749
24175
  var import__6 = __toESM(require__());
23750
24176
  function stripUtf8Bom5(s) {
23751
24177
  return s.length > 0 && s.charCodeAt(0) === 65279 ? s.slice(1) : s;
@@ -23765,8 +24191,8 @@ function formatAjvErrors6(errors) {
23765
24191
  }
23766
24192
  var ajv = new import__6.default({ allErrors: true, strict: false });
23767
24193
  function compileSchema(basename17) {
23768
- const schemaPath = path39.join(schemasDir(), basename17);
23769
- const schemaRaw = stripUtf8Bom5(fs43.readFileSync(schemaPath, "utf-8"));
24194
+ const schemaPath = path41.join(schemasDir(), basename17);
24195
+ const schemaRaw = stripUtf8Bom5(fs44.readFileSync(schemaPath, "utf-8"));
23770
24196
  const schema = JSON.parse(schemaRaw);
23771
24197
  return ajv.compile(schema);
23772
24198
  }
@@ -23810,7 +24236,7 @@ var ZERO_REF_STAGING_JSON_TOTAL_ATTEMPTS = 5;
23810
24236
  var ZERO_REF_STAGING_FILE_PREVIEW_MAX_CHARS = 6e3;
23811
24237
  function readStagingOutputPreview(outAbs) {
23812
24238
  try {
23813
- const s = fs44.readFileSync(outAbs, "utf-8");
24239
+ const s = fs45.readFileSync(outAbs, "utf-8");
23814
24240
  if (s.length <= ZERO_REF_STAGING_FILE_PREVIEW_MAX_CHARS) {
23815
24241
  return s;
23816
24242
  }
@@ -24060,17 +24486,17 @@ function expandArgvTemplate4(template, vars) {
24060
24486
  });
24061
24487
  }
24062
24488
  function schemaRef2(worktreeRoot, schemaBasename) {
24063
- return path40.join(worktreeRoot, ".opencode", "schemas", "context-lists", schemaBasename);
24489
+ return path42.join(worktreeRoot, ".opencode", "schemas", "context-lists", schemaBasename);
24064
24490
  }
24065
24491
  function stagingDir(contextDirAbs) {
24066
- return path40.join(contextDirAbs, "_zero-ref-staging");
24492
+ return path42.join(contextDirAbs, "_zero-ref-staging");
24067
24493
  }
24068
24494
  function stagingPathForTarget(contextDirAbs, kind, targetFilePathPosix) {
24069
24495
  const h = crypto.createHash("sha256").update(targetFilePathPosix, "utf8").digest("hex").slice(0, 16);
24070
- return path40.join(stagingDir(contextDirAbs), `${kind}-${h}.json`);
24496
+ return path42.join(stagingDir(contextDirAbs), `${kind}-${h}.json`);
24071
24497
  }
24072
24498
  function readNonReferencedFilesFromRepositoryRoot(repositoryRootAbs) {
24073
- const p = path40.join(repositoryRootAbs, ".gluecharm", "context", "coverage-reference-validation.json");
24499
+ const p = path42.join(repositoryRootAbs, ".gluecharm", "context", "coverage-reference-validation.json");
24074
24500
  const r = readAndValidateCoverageReferenceValidationFile(p);
24075
24501
  if (!r.ok) {
24076
24502
  return { ok: false, error: r.errors.join("; ") };
@@ -24093,14 +24519,14 @@ function readNonReferencedFilesFromRepositoryRoot(repositoryRootAbs) {
24093
24519
  return { ok: true, paths, ...generatedAt ? { generatedAt } : {} };
24094
24520
  }
24095
24521
  function readOrInitRoutingDoc(routingAbs, coverageReferenceGeneratedAt) {
24096
- if (!fs44.existsSync(routingAbs)) {
24522
+ if (!fs45.existsSync(routingAbs)) {
24097
24523
  return {
24098
24524
  schemaVersion: ROUTING_SCHEMA_VERSION,
24099
24525
  ...coverageReferenceGeneratedAt ? { coverageReferenceGeneratedAt } : {},
24100
24526
  records: {}
24101
24527
  };
24102
24528
  }
24103
- const raw = fs44.readFileSync(routingAbs, "utf-8");
24529
+ const raw = fs45.readFileSync(routingAbs, "utf-8");
24104
24530
  const data = JSON.parse(raw);
24105
24531
  if (!data.records || typeof data.records !== "object") {
24106
24532
  return {
@@ -24112,10 +24538,10 @@ function readOrInitRoutingDoc(routingAbs, coverageReferenceGeneratedAt) {
24112
24538
  return data;
24113
24539
  }
24114
24540
  function readOrInitTriageDoc(triageAbs) {
24115
- if (!fs44.existsSync(triageAbs)) {
24541
+ if (!fs45.existsSync(triageAbs)) {
24116
24542
  return { schemaVersion: TRIAGE_SCHEMA_VERSION, records: {} };
24117
24543
  }
24118
- const raw = fs44.readFileSync(triageAbs, "utf-8");
24544
+ const raw = fs45.readFileSync(triageAbs, "utf-8");
24119
24545
  const data = JSON.parse(raw);
24120
24546
  if (!data.records || typeof data.records !== "object") {
24121
24547
  return { schemaVersion: TRIAGE_SCHEMA_VERSION, records: {} };
@@ -24163,10 +24589,10 @@ function slugifyFeatureLabel(s) {
24163
24589
  return t.length > 0 ? t : "feature";
24164
24590
  }
24165
24591
  function lineCountRepoFile(worktreeRootAbs, relPosix) {
24166
- const abs = path40.join(worktreeRootAbs, ...relPosix.split("/"));
24592
+ const abs = path42.join(worktreeRootAbs, ...relPosix.split("/"));
24167
24593
  let buf;
24168
24594
  try {
24169
- buf = fs44.readFileSync(abs);
24595
+ buf = fs45.readFileSync(abs);
24170
24596
  } catch {
24171
24597
  return 1;
24172
24598
  }
@@ -24218,9 +24644,9 @@ var LIST_STEP_HINT = {
24218
24644
  };
24219
24645
  async function applyCoordinationListTriageMerge(input) {
24220
24646
  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)) {
24647
+ const listPath = path42.join(input.contextDirAbs, cfg.listBasename);
24648
+ const schemaPath = path42.join(resolveContextListSchemasDir(), cfg.schemaBasename);
24649
+ if (!fs45.existsSync(listPath)) {
24224
24650
  return {
24225
24651
  ok: false,
24226
24652
  message: `${cfg.listBasename} not found \u2014 run coordination step ${LIST_STEP_HINT[input.listKind]} first.`
@@ -24231,7 +24657,7 @@ async function applyCoordinationListTriageMerge(input) {
24231
24657
  return withCoordinationListFileLock(listPath, {}, async () => {
24232
24658
  let raw;
24233
24659
  try {
24234
- raw = fs44.readFileSync(listPath, "utf-8");
24660
+ raw = fs45.readFileSync(listPath, "utf-8");
24235
24661
  } catch (e) {
24236
24662
  return { ok: false, message: e instanceof Error ? e.message : String(e) };
24237
24663
  }
@@ -24299,7 +24725,7 @@ async function applyCoordinationListTriageMerge(input) {
24299
24725
  });
24300
24726
  const tmp = `${listPath}.tmp.${process.pid}`;
24301
24727
  try {
24302
- fs44.writeFileSync(tmp, `${JSON.stringify(doc, null, 2)}
24728
+ fs45.writeFileSync(tmp, `${JSON.stringify(doc, null, 2)}
24303
24729
  `, "utf-8");
24304
24730
  } catch (e) {
24305
24731
  return { ok: false, message: e instanceof Error ? e.message : String(e) };
@@ -24307,13 +24733,13 @@ async function applyCoordinationListTriageMerge(input) {
24307
24733
  const v = validateCoordinationListJson(tmp, schemaPath);
24308
24734
  if (!v.ok) {
24309
24735
  try {
24310
- fs44.unlinkSync(tmp);
24736
+ fs45.unlinkSync(tmp);
24311
24737
  } catch {
24312
24738
  }
24313
24739
  return { ok: false, message: `${cfg.listBasename} validation failed: ${JSON.stringify(v.failure)}` };
24314
24740
  }
24315
24741
  try {
24316
- fs44.renameSync(tmp, listPath);
24742
+ fs45.renameSync(tmp, listPath);
24317
24743
  } catch (e) {
24318
24744
  return { ok: false, message: e instanceof Error ? e.message : String(e) };
24319
24745
  }
@@ -24323,10 +24749,10 @@ async function applyCoordinationListTriageMerge(input) {
24323
24749
  }
24324
24750
  async function runClassifierAgent(common, contextDirAbs, targetFilePathPosix, workspaceLabel) {
24325
24751
  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);
24752
+ fs45.mkdirSync(path42.dirname(outAbs), { recursive: true });
24753
+ const runDir = path42.join(common.worktreeRoot, ".opencode", "_run");
24754
+ fs45.mkdirSync(runDir, { recursive: true });
24755
+ const outputBasename = path42.basename(outAbs);
24330
24756
  const listTaskDescription = [
24331
24757
  `Target file (repo-relative, POSIX): **${targetFilePathPosix}**`,
24332
24758
  `Workspace label hint: **${workspaceLabel}**.`,
@@ -24362,8 +24788,8 @@ async function runClassifierAgent(common, contextDirAbs, targetFilePathPosix, wo
24362
24788
  parentContextBlock: "",
24363
24789
  ...repairAppendix ? { repairAppendix } : {}
24364
24790
  });
24365
- const promptPath = path40.join(runDir, `zero-ref-classify-a${attempt}-${Date.now()}.prompt.txt`);
24366
- fs44.writeFileSync(promptPath, body, "utf-8");
24791
+ const promptPath = path42.join(runDir, `zero-ref-classify-a${attempt}-${Date.now()}.prompt.txt`);
24792
+ fs45.writeFileSync(promptPath, body, "utf-8");
24367
24793
  const argv = expandArgvTemplate4(common.argvTemplate, {
24368
24794
  promptFile: promptPath,
24369
24795
  agentId: ZERO_REF_CLASSIFY_AGENT_STEM,
@@ -24390,7 +24816,7 @@ async function runClassifierAgent(common, contextDirAbs, targetFilePathPosix, wo
24390
24816
  const canRetry = attempt < ZERO_REF_STAGING_JSON_TOTAL_ATTEMPTS - 1;
24391
24817
  let st;
24392
24818
  try {
24393
- st = fs44.statSync(outAbs);
24819
+ st = fs45.statSync(outAbs);
24394
24820
  } catch {
24395
24821
  st = void 0;
24396
24822
  }
@@ -24412,7 +24838,7 @@ async function runClassifierAgent(common, contextDirAbs, targetFilePathPosix, wo
24412
24838
  }
24413
24839
  let parsed;
24414
24840
  try {
24415
- parsed = JSON.parse(fs44.readFileSync(outAbs, "utf-8"));
24841
+ parsed = JSON.parse(fs45.readFileSync(outAbs, "utf-8"));
24416
24842
  } catch (e) {
24417
24843
  const msg = e instanceof Error ? e.message : String(e);
24418
24844
  lastFailureMessage = `Classifier output not valid JSON: ${msg}`;
@@ -24494,10 +24920,10 @@ var TRIAGE_SCOPE_META = {
24494
24920
  };
24495
24921
  async function runMarkdownReferenceAgent(common, contextDirAbs, targetFilePathPosix, routingSummary, which) {
24496
24922
  const mdBasename = which === "project" ? "project.md" : "architecture.md";
24497
- const mdAbs = path40.join(contextDirAbs, mdBasename);
24923
+ const mdAbs = path42.join(contextDirAbs, mdBasename);
24498
24924
  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 });
24925
+ const runDir = path42.join(common.worktreeRoot, ".opencode", "_run");
24926
+ fs45.mkdirSync(runDir, { recursive: true });
24501
24927
  const lines = [
24502
24928
  `# SRS-30 \u2014 Add reference to ${mdBasename}`,
24503
24929
  ``,
@@ -24512,8 +24938,8 @@ async function runMarkdownReferenceAgent(common, contextDirAbs, targetFilePathPo
24512
24938
  `- If the file is short, \`${targetFilePathPosix}:1-<lastLine>\` is acceptable.`,
24513
24939
  `- Do not remove unrelated content; append or extend the most appropriate section.`
24514
24940
  ];
24515
- const promptPath = path40.join(runDir, `zero-ref-md-${which}-${Date.now()}.prompt.txt`);
24516
- fs44.writeFileSync(promptPath, lines.join("\n"), "utf-8");
24941
+ const promptPath = path42.join(runDir, `zero-ref-md-${which}-${Date.now()}.prompt.txt`);
24942
+ fs45.writeFileSync(promptPath, lines.join("\n"), "utf-8");
24517
24943
  const argv = expandArgvTemplate4(common.argvTemplate, {
24518
24944
  promptFile: promptPath,
24519
24945
  agentId: agentStem,
@@ -24540,10 +24966,10 @@ async function runMarkdownReferenceAgent(common, contextDirAbs, targetFilePathPo
24540
24966
  async function runCoordinationTriageAgent(common, contextDirAbs, targetFilePathPosix, routingSummary, workspaceLabel, triageScope) {
24541
24967
  const meta = TRIAGE_SCOPE_META[triageScope];
24542
24968
  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);
24969
+ fs45.mkdirSync(path42.dirname(outAbs), { recursive: true });
24970
+ const runDir = path42.join(common.worktreeRoot, ".opencode", "_run");
24971
+ fs45.mkdirSync(runDir, { recursive: true });
24972
+ const outputBasename = path42.basename(outAbs);
24547
24973
  const listTaskDescription = [
24548
24974
  `Target file: **${targetFilePathPosix}** (${workspaceLabel})`,
24549
24975
  "**Classifier summary:**",
@@ -24573,8 +24999,8 @@ async function runCoordinationTriageAgent(common, contextDirAbs, targetFilePathP
24573
24999
  parentContextBlock: "",
24574
25000
  ...repairAppendix ? { repairAppendix } : {}
24575
25001
  });
24576
- const promptPath = path40.join(runDir, `zero-ref-triage-a${attempt}-${Date.now()}.prompt.txt`);
24577
- fs44.writeFileSync(promptPath, body, "utf-8");
25002
+ const promptPath = path42.join(runDir, `zero-ref-triage-a${attempt}-${Date.now()}.prompt.txt`);
25003
+ fs45.writeFileSync(promptPath, body, "utf-8");
24578
25004
  const argv = expandArgvTemplate4(common.argvTemplate, {
24579
25005
  promptFile: promptPath,
24580
25006
  agentId: ZERO_REF_TRIAGE_COORD_AGENT_STEM,
@@ -24601,7 +25027,7 @@ async function runCoordinationTriageAgent(common, contextDirAbs, targetFilePathP
24601
25027
  const canRetry = attempt < ZERO_REF_STAGING_JSON_TOTAL_ATTEMPTS - 1;
24602
25028
  let st;
24603
25029
  try {
24604
- st = fs44.statSync(outAbs);
25030
+ st = fs45.statSync(outAbs);
24605
25031
  } catch {
24606
25032
  st = void 0;
24607
25033
  }
@@ -24623,7 +25049,7 @@ async function runCoordinationTriageAgent(common, contextDirAbs, targetFilePathP
24623
25049
  }
24624
25050
  let parsed;
24625
25051
  try {
24626
- parsed = JSON.parse(fs44.readFileSync(outAbs, "utf-8"));
25052
+ parsed = JSON.parse(fs45.readFileSync(outAbs, "utf-8"));
24627
25053
  } catch (e) {
24628
25054
  const msg = e instanceof Error ? e.message : String(e);
24629
25055
  lastFailureMessage = `Triage output not valid JSON: ${msg}`;
@@ -24679,7 +25105,7 @@ async function runCoordinationTriageAgent(common, contextDirAbs, targetFilePathP
24679
25105
  return { ok: false, message: lastFailureMessage, stagingPath: outAbs };
24680
25106
  }
24681
25107
  try {
24682
- fs44.writeFileSync(outAbs, `${JSON.stringify(parsed, null, 2)}
25108
+ fs45.writeFileSync(outAbs, `${JSON.stringify(parsed, null, 2)}
24683
25109
  `, "utf-8");
24684
25110
  } catch {
24685
25111
  }
@@ -24688,8 +25114,8 @@ async function runCoordinationTriageAgent(common, contextDirAbs, targetFilePathP
24688
25114
  return { ok: false, message: lastFailureMessage, stagingPath: outAbs };
24689
25115
  }
24690
25116
  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);
25117
+ const routingAbs = path42.join(p.contextDirAbs, ZERO_REF_ROUTING_BASENAME);
25118
+ const triageAbs = path42.join(p.contextDirAbs, ZERO_REF_TRIAGE_BASENAME);
24693
25119
  const key = p.targetFilePathPosix;
24694
25120
  const cr = await runClassifierAgent(p, p.contextDirAbs, key, p.workspaceLabel);
24695
25121
  if (!cr.ok) {
@@ -24697,7 +25123,7 @@ async function runOneUnreferencedFilePipeline(p) {
24697
25123
  }
24698
25124
  let stagingParsed;
24699
25125
  try {
24700
- stagingParsed = JSON.parse(fs44.readFileSync(cr.stagingPath, "utf-8"));
25126
+ stagingParsed = JSON.parse(fs45.readFileSync(cr.stagingPath, "utf-8"));
24701
25127
  } catch (e) {
24702
25128
  return { ok: false, message: String(e) };
24703
25129
  }
@@ -24713,8 +25139,8 @@ async function runOneUnreferencedFilePipeline(p) {
24713
25139
  if (!s.ok) {
24714
25140
  throw new Error(s.errors.join("; "));
24715
25141
  }
24716
- fs44.mkdirSync(path40.dirname(routingAbs), { recursive: true });
24717
- fs44.writeFileSync(routingAbs, s.json, "utf-8");
25142
+ fs45.mkdirSync(path42.dirname(routingAbs), { recursive: true });
25143
+ fs45.writeFileSync(routingAbs, s.json, "utf-8");
24718
25144
  });
24719
25145
  const routing = stagingParsed.routing;
24720
25146
  const routingSummary = typeof stagingParsed.projectRelationSummary === "string" ? stagingParsed.projectRelationSummary : "";
@@ -24745,7 +25171,7 @@ async function runOneUnreferencedFilePipeline(p) {
24745
25171
  }
24746
25172
  let triageParsed;
24747
25173
  try {
24748
- triageParsed = JSON.parse(fs44.readFileSync(tr.stagingPath, "utf-8"));
25174
+ triageParsed = JSON.parse(fs45.readFileSync(tr.stagingPath, "utf-8"));
24749
25175
  } catch (e) {
24750
25176
  return { ok: false, message: String(e) };
24751
25177
  }
@@ -24762,8 +25188,8 @@ async function runOneUnreferencedFilePipeline(p) {
24762
25188
  if (!s.ok) {
24763
25189
  throw new Error(s.errors.join("; "));
24764
25190
  }
24765
- fs44.mkdirSync(path40.dirname(triageAbs), { recursive: true });
24766
- fs44.writeFileSync(triageAbs, s.json, "utf-8");
25191
+ fs45.mkdirSync(path42.dirname(triageAbs), { recursive: true });
25192
+ fs45.writeFileSync(triageAbs, s.json, "utf-8");
24767
25193
  });
24768
25194
  const decision = triageParsed.decision;
24769
25195
  if (decision === "new_item" || decision === "enrich_existing") {
@@ -24790,11 +25216,11 @@ async function runOneUnreferencedFilePipeline(p) {
24790
25216
  return { ok: true, message: `Triage ${decision}.` };
24791
25217
  }
24792
25218
  async function runRemediationPipelineZeroRefPass(p) {
24793
- const contextDirAbs = path40.join(p.worktreeRoot, ".gluecharm", "context");
25219
+ const contextDirAbs = path42.join(p.worktreeRoot, ".gluecharm", "context");
24794
25220
  const covRoot = p.coverageRepositoryRootAbs ?? p.workspaceRootAbs;
24795
25221
  const cov = readNonReferencedFilesFromRepositoryRoot(covRoot);
24796
25222
  const coverageAt = cov.ok ? cov.generatedAt : void 0;
24797
- const workspaceLabel = path40.basename(p.worktreeRoot);
25223
+ const workspaceLabel = path42.basename(p.worktreeRoot);
24798
25224
  const routingMutex = new AsyncMutex();
24799
25225
  const triageMutex = new AsyncMutex();
24800
25226
  const paths = [...p.paths];
@@ -24851,8 +25277,8 @@ async function runRemediationPipelineZeroRefPass(p) {
24851
25277
  }
24852
25278
 
24853
25279
  // src/pipelines/coverage/coverageExecutionReport.ts
24854
- var fs45 = __toESM(require("fs"));
24855
- var path41 = __toESM(require("path"));
25280
+ var fs46 = __toESM(require("fs"));
25281
+ var path43 = __toESM(require("path"));
24856
25282
  var REFERENCE_COVERAGE_EXECUTION_REPORT_BASENAME = "reference-coverage-execution-report.md";
24857
25283
  function inlineMdText(s) {
24858
25284
  const t = s.replace(/\r\n/g, "\n").replace(/\n/g, " ").trim();
@@ -24948,7 +25374,7 @@ function collectNoActionRowsFromRoutingDoc(doc) {
24948
25374
  return rows;
24949
25375
  }
24950
25376
  function readRoutingDocFromDisk(routingAbs) {
24951
- if (!fs45.existsSync(routingAbs)) {
25377
+ if (!fs46.existsSync(routingAbs)) {
24952
25378
  return {
24953
25379
  ok: true,
24954
25380
  doc: { schemaVersion: "1", records: {} }
@@ -24956,7 +25382,7 @@ function readRoutingDocFromDisk(routingAbs) {
24956
25382
  }
24957
25383
  let raw;
24958
25384
  try {
24959
- raw = fs45.readFileSync(routingAbs, "utf-8");
25385
+ raw = fs46.readFileSync(routingAbs, "utf-8");
24960
25386
  } catch (e) {
24961
25387
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
24962
25388
  }
@@ -24976,10 +25402,10 @@ async function runCoverageExecutionReport(p) {
24976
25402
  if (p.abortSignal?.aborted) {
24977
25403
  return { ok: false, error: "Stopped.", cancelled: true };
24978
25404
  }
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);
25405
+ const contextDirAbs = path43.join(p.repositoryRootAbs, ".gluecharm", "context");
25406
+ const coverageAbs = path43.join(contextDirAbs, "coverage-reference-validation.json");
25407
+ const routingAbs = path43.join(contextDirAbs, "zero-reference-routing.json");
25408
+ const outAbs = path43.join(contextDirAbs, REFERENCE_COVERAGE_EXECUTION_REPORT_BASENAME);
24983
25409
  const cov = readAndValidateCoverageReferenceValidationFile(coverageAbs);
24984
25410
  if (!cov.ok) {
24985
25411
  return { ok: false, error: `Coverage JSON: ${cov.errors.join("; ")}` };
@@ -24996,20 +25422,20 @@ async function runCoverageExecutionReport(p) {
24996
25422
  }
24997
25423
  let previous;
24998
25424
  try {
24999
- if (fs45.existsSync(outAbs)) {
25000
- previous = fs45.readFileSync(outAbs, "utf-8");
25425
+ if (fs46.existsSync(outAbs)) {
25426
+ previous = fs46.readFileSync(outAbs, "utf-8");
25001
25427
  }
25002
25428
  } catch {
25003
25429
  previous = void 0;
25004
25430
  }
25005
25431
  try {
25006
- fs45.mkdirSync(path41.dirname(outAbs), { recursive: true });
25007
- fs45.writeFileSync(outAbs, md, "utf-8");
25432
+ fs46.mkdirSync(path43.dirname(outAbs), { recursive: true });
25433
+ fs46.writeFileSync(outAbs, md, "utf-8");
25008
25434
  } catch (e) {
25009
25435
  const msg = e instanceof Error ? e.message : String(e);
25010
25436
  if (previous !== void 0) {
25011
25437
  try {
25012
- fs45.writeFileSync(outAbs, previous, "utf-8");
25438
+ fs46.writeFileSync(outAbs, previous, "utf-8");
25013
25439
  } catch {
25014
25440
  }
25015
25441
  }
@@ -25020,8 +25446,8 @@ async function runCoverageExecutionReport(p) {
25020
25446
  }
25021
25447
 
25022
25448
  // src/gluecharm/minimalGluecharmLayout.ts
25023
- var fs46 = __toESM(require("node:fs"));
25024
- var path42 = __toESM(require("node:path"));
25449
+ var fs47 = __toESM(require("node:fs"));
25450
+ var path44 = __toESM(require("node:path"));
25025
25451
  var MINIMAL_GLUECHARM_RELATIVE_DIRS = [
25026
25452
  [".gluecharm", "docs", "srs"],
25027
25453
  [".gluecharm", "content"],
@@ -25029,11 +25455,11 @@ var MINIMAL_GLUECHARM_RELATIVE_DIRS = [
25029
25455
  [".gluecharm", "context"]
25030
25456
  ];
25031
25457
  function ensureMinimalGluecharmLayoutNode(repoRootAbs) {
25032
- const root = path42.resolve(repoRootAbs);
25458
+ const root = path44.resolve(repoRootAbs);
25033
25459
  for (const segments of MINIMAL_GLUECHARM_RELATIVE_DIRS) {
25034
- const dir = path42.join(root, ...segments);
25460
+ const dir = path44.join(root, ...segments);
25035
25461
  try {
25036
- fs46.mkdirSync(dir, { recursive: true });
25462
+ fs47.mkdirSync(dir, { recursive: true });
25037
25463
  } catch (e) {
25038
25464
  const err = e;
25039
25465
  const msg = e instanceof Error ? e.message : String(e);
@@ -25148,6 +25574,7 @@ function buildFactoryPipelineRegistry(cb) {
25148
25574
  // src/factory/generateContextFactoryHeadlessHost.ts
25149
25575
  function buildFactoryDepsHeadless(input) {
25150
25576
  const { storageContext, repoRoot, agentsDirFs, buildOpenCodeOptions, log, signal, macroConfig } = input;
25577
+ const inPlace = input.inPlace === true;
25151
25578
  let adHocWorktree;
25152
25579
  let macroFinalize;
25153
25580
  let macroSourceBranch;
@@ -25162,7 +25589,7 @@ function buildFactoryDepsHeadless(input) {
25162
25589
  if (!layout.ok) {
25163
25590
  return { ok: false, error: layout.error };
25164
25591
  }
25165
- const ctxDir = path43.join(ar, ".gluecharm", "context");
25592
+ const ctxDir = path45.join(ar, ".gluecharm", "context");
25166
25593
  const snap = readArtefactRunSnapshot(storageContext);
25167
25594
  const rows = listMissingWorkstations(ctxDir, ar, snap);
25168
25595
  if (rows.length === 0) {
@@ -25176,7 +25603,7 @@ function buildFactoryDepsHeadless(input) {
25176
25603
  storageContext,
25177
25604
  repositoryRoot: repoRoot,
25178
25605
  worktreeRoot: ar,
25179
- workspaceLabel: path43.basename(ar),
25606
+ workspaceLabel: path45.basename(ar),
25180
25607
  oc: {
25181
25608
  ...oc,
25182
25609
  aceEnabled: getAceAnalysisEnabledForCheckout(ar),
@@ -25204,7 +25631,7 @@ function buildFactoryDepsHeadless(input) {
25204
25631
  }
25205
25632
  try {
25206
25633
  await startPipelineRun(storageContext, repoRoot);
25207
- const folderName = path43.basename(repoRoot);
25634
+ const folderName = path45.basename(repoRoot);
25208
25635
  const oc = buildOpenCodeOptions(handle.path);
25209
25636
  const result = await runSynthesisPipelineDrainFromPreparedWorktree(
25210
25637
  storageContext,
@@ -25261,7 +25688,7 @@ function buildFactoryDepsHeadless(input) {
25261
25688
  if (!ar) {
25262
25689
  return 0;
25263
25690
  }
25264
- const ctxDir = path43.join(ar, ".gluecharm", "context");
25691
+ const ctxDir = path45.join(ar, ".gluecharm", "context");
25265
25692
  const snap = readArtefactRunSnapshot(storageContext);
25266
25693
  return listMissingWorkstations(ctxDir, ar, snap).length;
25267
25694
  };
@@ -25274,7 +25701,7 @@ function buildFactoryDepsHeadless(input) {
25274
25701
  if (!layout.ok) {
25275
25702
  return { ok: false, message: layout.error };
25276
25703
  }
25277
- const contextDir2 = path43.join(ar, ".gluecharm", "context");
25704
+ const contextDir2 = path45.join(ar, ".gluecharm", "context");
25278
25705
  log(`[factory] reference coverage (worktree) \u2014 ${ar}`);
25279
25706
  const res = runCoveragePipeline({
25280
25707
  repositoryRootAbs: ar,
@@ -25334,7 +25761,7 @@ function buildFactoryDepsHeadless(input) {
25334
25761
  diagnosticLog: log
25335
25762
  });
25336
25763
  if (res.ok) {
25337
- return { ok: true, message: `Report: ${path43.basename(res.outputAbsolutePath)}` };
25764
+ return { ok: true, message: `Report: ${path45.basename(res.outputAbsolutePath)}` };
25338
25765
  }
25339
25766
  if (res.cancelled) {
25340
25767
  return { ok: false, cancelled: true, message: "Report generation stopped." };
@@ -25350,7 +25777,7 @@ function buildFactoryDepsHeadless(input) {
25350
25777
  if (!lmLayout.ok) {
25351
25778
  return { ok: false, message: lmLayout.error };
25352
25779
  }
25353
- const contextDir2 = path43.join(snap.adHocWorktreePath, ".gluecharm", "context");
25780
+ const contextDir2 = path45.join(snap.adHocWorktreePath, ".gluecharm", "context");
25354
25781
  const linkGraph = runLinkMappingPipeline(contextDir2, { log });
25355
25782
  if (!linkGraph.ok) {
25356
25783
  return { ok: false, message: linkGraph.error };
@@ -25366,7 +25793,7 @@ function buildFactoryDepsHeadless(input) {
25366
25793
  if (!idxLayout.ok) {
25367
25794
  return { ok: false, message: idxLayout.error };
25368
25795
  }
25369
- const contextDir2 = path43.join(snap.adHocWorktreePath, ".gluecharm", "context");
25796
+ const contextDir2 = path45.join(snap.adHocWorktreePath, ".gluecharm", "context");
25370
25797
  try {
25371
25798
  writeIndexApplicationContext(contextDir2, void 0, {
25372
25799
  sourceBranchAtWorktreeCreation: snap.adHocSourceBranchAtCreation
@@ -25406,6 +25833,12 @@ function buildFactoryDepsHeadless(input) {
25406
25833
  return {
25407
25834
  signal,
25408
25835
  factoryLog: log,
25836
+ readinessLog: (line) => {
25837
+ process.stderr.write(`${line}
25838
+ `);
25839
+ },
25840
+ ...inPlace ? { analysisInPlace: true } : {},
25841
+ readiness: input.readiness,
25409
25842
  config: { ...macroConfig, ...input.synthesisOnly ? { synthesisOnly: true } : {} },
25410
25843
  sleep: (ms) => sleepUntilAborted(ms, signal),
25411
25844
  post: (payload) => {
@@ -25415,14 +25848,14 @@ function buildFactoryDepsHeadless(input) {
25415
25848
  },
25416
25849
  runPrepareAnalysisWorktree: async (resume) => {
25417
25850
  if (resume) {
25418
- if (adHocWorktree && fs47.existsSync(path43.join(adHocWorktree.path, ".git"))) {
25851
+ if (adHocWorktree && fs48.existsSync(path45.join(adHocWorktree.path, ".git"))) {
25419
25852
  return { ok: true };
25420
25853
  }
25421
25854
  const snap = readAnalysisWorkspaceSnapshot(storageContext);
25422
25855
  const wtPath = snap?.adHocWorktreePath?.trim();
25423
25856
  const repo = snap?.adHocRepositoryRoot?.trim() || repoRoot;
25424
- if (wtPath && fs47.existsSync(path43.join(wtPath, ".git"))) {
25425
- adHocWorktree = attachWorktreeHandle(wtPath, repo);
25857
+ if (wtPath && fs48.existsSync(path45.join(wtPath, ".git"))) {
25858
+ adHocWorktree = resolveAnalysisCheckoutHandle(wtPath, repo);
25426
25859
  macroSourceBranch = snap?.adHocSourceBranchAtCreation;
25427
25860
  macroFinalize = () => {
25428
25861
  try {
@@ -25444,8 +25877,10 @@ function buildFactoryDepsHeadless(input) {
25444
25877
  }
25445
25878
  macroFinalize = void 0;
25446
25879
  macroSourceBranch = void 0;
25447
- log(`[factory] create analysis worktree \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}`);
25448
- const prep = await prepareSynthesisWorktree(storageContext, repoRoot, log);
25880
+ log(
25881
+ inPlace ? `[factory] in-place analysis checkout \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}` : `[factory] create analysis worktree \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}`
25882
+ );
25883
+ const prep = await prepareSynthesisWorktree(storageContext, repoRoot, log, { inPlace });
25449
25884
  if (!prep.ok) {
25450
25885
  prep.finalize?.();
25451
25886
  return { ok: false, error: prep.error };
@@ -25637,11 +26072,11 @@ function stderrLinesForFactoryFailures(failures, exitCode) {
25637
26072
  }
25638
26073
 
25639
26074
  // src/factory/updateContext/runUpdateContextFactory.ts
25640
- var path48 = __toESM(require("node:path"));
26075
+ var path50 = __toESM(require("node:path"));
25641
26076
 
25642
26077
  // src/factory/updateContext/updateContextBaseline.ts
25643
- var fs48 = __toESM(require("node:fs"));
25644
- var path44 = __toESM(require("node:path"));
26078
+ var fs49 = __toESM(require("node:fs"));
26079
+ var path46 = __toESM(require("node:path"));
25645
26080
  function isValidIso(s) {
25646
26081
  const t = Date.parse(s);
25647
26082
  return Number.isFinite(t);
@@ -25651,17 +26086,17 @@ function maxMtimeRegularFilesUnderDir(dirAbs) {
25651
26086
  const walk = (d) => {
25652
26087
  let entries;
25653
26088
  try {
25654
- entries = fs48.readdirSync(d, { withFileTypes: true });
26089
+ entries = fs49.readdirSync(d, { withFileTypes: true });
25655
26090
  } catch {
25656
26091
  return;
25657
26092
  }
25658
26093
  for (const e of entries) {
25659
- const p = path44.join(d, e.name);
26094
+ const p = path46.join(d, e.name);
25660
26095
  if (e.isDirectory()) {
25661
26096
  walk(p);
25662
26097
  } else if (e.isFile()) {
25663
26098
  try {
25664
- const st = fs48.statSync(p);
26099
+ const st = fs49.statSync(p);
25665
26100
  const m = st.mtimeMs;
25666
26101
  if (best === null || m > best) {
25667
26102
  best = m;
@@ -25682,8 +26117,8 @@ function resolveUpdateContextBaseline(repoRootAbs, repoConfig) {
25682
26117
  if (last.length > 0 && isValidIso(last)) {
25683
26118
  return { baselineIsoUtc: new Date(last).toISOString(), source: "lastRunAt" };
25684
26119
  }
25685
- const ctxDir = path44.join(repoRootAbs, ".gluecharm", "context");
25686
- if (!fs48.existsSync(ctxDir)) {
26120
+ const ctxDir = path46.join(repoRootAbs, ".gluecharm", "context");
26121
+ if (!fs49.existsSync(ctxDir)) {
25687
26122
  return null;
25688
26123
  }
25689
26124
  const maxMs = maxMtimeRegularFilesUnderDir(ctxDir);
@@ -25706,8 +26141,8 @@ function persistUpdateContextLastRunAt(repoRootAbs, isoUtc) {
25706
26141
 
25707
26142
  // src/factory/updateContext/updateContextGitWindow.ts
25708
26143
  var import_node_child_process3 = require("node:child_process");
25709
- var fs49 = __toESM(require("node:fs"));
25710
- var path45 = __toESM(require("node:path"));
26144
+ var fs50 = __toESM(require("node:fs"));
26145
+ var path47 = __toESM(require("node:path"));
25711
26146
  var GIT_ENV = { ...process.env, GIT_TERMINAL_PROMPT: "0" };
25712
26147
  function gitLines(repoRootAbs, args) {
25713
26148
  const r = (0, import_node_child_process3.execFileSync)("git", ["-c", "core.quotepath=false", ...args], {
@@ -25731,8 +26166,8 @@ function parseGitLogIso(line) {
25731
26166
  return { hash, iso };
25732
26167
  }
25733
26168
  function discoverCommitWindowAndTouchedPaths(repoRootAbs, baselineIsoUtc) {
25734
- const root = path45.resolve(repoRootAbs);
25735
- if (!fs49.existsSync(path45.join(root, ".git"))) {
26169
+ const root = path47.resolve(repoRootAbs);
26170
+ if (!fs50.existsSync(path47.join(root, ".git"))) {
25736
26171
  return { ok: false, error: "Not a git repository (missing .git)." };
25737
26172
  }
25738
26173
  const baselineMs = Date.parse(baselineIsoUtc);
@@ -25791,13 +26226,13 @@ function discoverCommitWindowAndTouchedPaths(repoRootAbs, baselineIsoUtc) {
25791
26226
  };
25792
26227
  }
25793
26228
  function filterPathsExistingInWorktree(worktreeRootAbs, pathsPosix) {
25794
- const root = path45.resolve(worktreeRootAbs);
26229
+ const root = path47.resolve(worktreeRootAbs);
25795
26230
  const out = [];
25796
26231
  for (const p of pathsPosix) {
25797
26232
  const rel = p.replace(/\\/g, "/");
25798
- const abs = path45.join(root, ...rel.split("/"));
26233
+ const abs = path47.join(root, ...rel.split("/"));
25799
26234
  try {
25800
- if (fs49.existsSync(abs) && fs49.statSync(abs).isFile()) {
26235
+ if (fs50.existsSync(abs) && fs50.statSync(abs).isFile()) {
25801
26236
  out.push(rel);
25802
26237
  }
25803
26238
  } catch {
@@ -25807,8 +26242,8 @@ function filterPathsExistingInWorktree(worktreeRootAbs, pathsPosix) {
25807
26242
  }
25808
26243
 
25809
26244
  // src/factory/updateContext/updateContextReport.ts
25810
- var fs50 = __toESM(require("node:fs"));
25811
- var path46 = __toESM(require("node:path"));
26245
+ var fs51 = __toESM(require("node:fs"));
26246
+ var path48 = __toESM(require("node:path"));
25812
26247
  var CHANGES_SINCE_DATE_BASENAME = "changes-since-date.md";
25813
26248
  function renderChangesSinceDateMarkdown(p) {
25814
26249
  const lines = [
@@ -25849,9 +26284,9 @@ function renderChangesSinceDateMarkdown(p) {
25849
26284
  }
25850
26285
  function writeChangesSinceDateReport(contextDirAbs, body) {
25851
26286
  try {
25852
- fs50.mkdirSync(contextDirAbs, { recursive: true });
25853
- const target = path46.join(contextDirAbs, CHANGES_SINCE_DATE_BASENAME);
25854
- fs50.writeFileSync(target, body, "utf-8");
26287
+ fs51.mkdirSync(contextDirAbs, { recursive: true });
26288
+ const target = path48.join(contextDirAbs, CHANGES_SINCE_DATE_BASENAME);
26289
+ fs51.writeFileSync(target, body, "utf-8");
25855
26290
  return { ok: true };
25856
26291
  } catch (e) {
25857
26292
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
@@ -25859,13 +26294,13 @@ function writeChangesSinceDateReport(contextDirAbs, body) {
25859
26294
  }
25860
26295
 
25861
26296
  // src/factory/updateContext/updateContextSeedCheck.ts
25862
- var fs51 = __toESM(require("node:fs"));
25863
- var path47 = __toESM(require("node:path"));
26297
+ var fs52 = __toESM(require("node:fs"));
26298
+ var path49 = __toESM(require("node:path"));
25864
26299
  var INDEX_BASENAME = "index-application-context.json";
25865
26300
  var CHANGES_REPORT = "changes-since-date.md";
25866
26301
  function tryParseJsonFile(abs) {
25867
26302
  try {
25868
- const raw = fs51.readFileSync(abs, "utf-8");
26303
+ const raw = fs52.readFileSync(abs, "utf-8");
25869
26304
  JSON.parse(raw);
25870
26305
  return true;
25871
26306
  } catch {
@@ -25873,16 +26308,16 @@ function tryParseJsonFile(abs) {
25873
26308
  }
25874
26309
  }
25875
26310
  function isWorktreeContextSeeded(contextDirAbs) {
25876
- if (!fs51.existsSync(contextDirAbs)) {
26311
+ if (!fs52.existsSync(contextDirAbs)) {
25877
26312
  return false;
25878
26313
  }
25879
- const indexAbs = path47.join(contextDirAbs, INDEX_BASENAME);
25880
- if (fs51.existsSync(indexAbs) && fs51.statSync(indexAbs).isFile() && tryParseJsonFile(indexAbs)) {
26314
+ const indexAbs = path49.join(contextDirAbs, INDEX_BASENAME);
26315
+ if (fs52.existsSync(indexAbs) && fs52.statSync(indexAbs).isFile() && tryParseJsonFile(indexAbs)) {
25881
26316
  return true;
25882
26317
  }
25883
26318
  let names;
25884
26319
  try {
25885
- names = fs51.readdirSync(contextDirAbs);
26320
+ names = fs52.readdirSync(contextDirAbs);
25886
26321
  } catch {
25887
26322
  return false;
25888
26323
  }
@@ -25894,9 +26329,9 @@ function isWorktreeContextSeeded(contextDirAbs) {
25894
26329
  if (!name.endsWith(".md") && !name.endsWith(".json")) {
25895
26330
  continue;
25896
26331
  }
25897
- const p = path47.join(contextDirAbs, name);
26332
+ const p = path49.join(contextDirAbs, name);
25898
26333
  try {
25899
- if (fs51.statSync(p).isFile()) {
26334
+ if (fs52.statSync(p).isFile()) {
25900
26335
  distinct.add(name);
25901
26336
  }
25902
26337
  } catch {
@@ -25908,12 +26343,14 @@ function isWorktreeContextSeeded(contextDirAbs) {
25908
26343
  // src/factory/updateContext/runUpdateContextFactory.ts
25909
26344
  var REMEDIATION_CHUNK_MAX = 40;
25910
26345
  function contextDirUnderRoot(wtRoot) {
25911
- return path48.join(wtRoot, ".gluecharm", "context");
26346
+ return path50.join(wtRoot, ".gluecharm", "context");
25912
26347
  }
25913
26348
  async function runUpdateContextFactory(deps) {
26349
+ const inPlace = deps.inPlace === true;
25914
26350
  const baseMeta = {
25915
26351
  command: "update_context",
25916
- uploadRequested: false
26352
+ uploadRequested: false,
26353
+ ...inPlace ? { analysisInPlace: true } : {}
25917
26354
  };
25918
26355
  const baseline = resolveUpdateContextBaseline(deps.repoRootAbs, deps.repoConfig);
25919
26356
  if (!baseline) {
@@ -25938,8 +26375,42 @@ async function runUpdateContextFactory(deps) {
25938
26375
  };
25939
26376
  }
25940
26377
  const shortNoCommits = gitWin.commitsInOrder.length === 0;
26378
+ const cliVersion = deps.cliVersion?.trim() || "0.0.0";
26379
+ const readinessCtx = {
26380
+ cliVersion,
26381
+ repoRootAbs: deps.repoRootAbs,
26382
+ analysisRootAbs: deps.repoRootAbs,
26383
+ apiBaseUrl: deps.merged.apiBaseUrl,
26384
+ openCodeExecutable: deps.merged.openCodeExecutable,
26385
+ openCodeSkipCredentialsCheck: deps.merged.openCodeSkipCredentialsCheck,
26386
+ providerEnvFromConfig: deps.merged.openCodeChildEnv,
26387
+ repoConfig: deps.repoConfig
26388
+ };
26389
+ const rlog = deps.readinessLog ?? deps.log;
26390
+ const pre = emitCliFactoryReadinessPreflight(rlog, "[factory] update context readiness", readinessCtx);
26391
+ if (!pre.ok) {
26392
+ const g = pre.failure;
26393
+ return {
26394
+ exitOk: false,
26395
+ ok: false,
26396
+ code: "READINESS_FAILED",
26397
+ error: `Factory readiness failed (${g.readinessReasonCode}).`,
26398
+ readinessExitCode: g.exitCode,
26399
+ readinessReasonCode: g.readinessReasonCode,
26400
+ readinessGate: g.gate,
26401
+ openCodeConfigFiles: pre.facts.openCodeConfigFiles,
26402
+ modelConfigured: pre.facts.modelConfigured,
26403
+ baselineDate: baseline.baselineIsoUtc,
26404
+ baselineSource: baseline.source,
26405
+ headCommit: gitWin.headCommit,
26406
+ rangeStartCommit: gitWin.rangeStartCommit,
26407
+ commitsReviewed: gitWin.commitsInOrder.length,
26408
+ ...baseMeta
26409
+ };
26410
+ }
25941
26411
  const prep = await prepareSynthesisWorktree(deps.storage, deps.repoRootAbs, deps.log, {
25942
- clearPriorArtefactRun: true
26412
+ clearPriorArtefactRun: true,
26413
+ inPlace
25943
26414
  });
25944
26415
  if (!prep.ok) {
25945
26416
  prep.finalize?.();
@@ -25960,7 +26431,7 @@ async function runUpdateContextFactory(deps) {
25960
26431
  const finalizeWt = prep.finalize;
25961
26432
  const wsCtxDir = contextDirUnderRoot(deps.repoRootAbs);
25962
26433
  let ctxDirAbs = contextDirUnderRoot(handle.path);
25963
- if (!isWorktreeContextSeeded(ctxDirAbs) && isWorktreeContextSeeded(wsCtxDir)) {
26434
+ if (!inPlace && !isWorktreeContextSeeded(ctxDirAbs) && isWorktreeContextSeeded(wsCtxDir)) {
25964
26435
  deps.log("[update-context] seeding worktree context from workspace .gluecharm/context/");
25965
26436
  promoteContextDirectoryToWorkspaceFs(wsCtxDir, handle.path);
25966
26437
  ctxDirAbs = contextDirUnderRoot(handle.path);
@@ -26139,30 +26610,34 @@ async function runUpdateContextFactory(deps) {
26139
26610
  }
26140
26611
  let promoted = false;
26141
26612
  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
- };
26613
+ if (inPlace) {
26614
+ deps.log("[update-context] in-place analysis \u2014 promote skipped (context already at repository root)");
26615
+ } else {
26616
+ try {
26617
+ const { filesCopied } = promoteContextDirectoryToWorkspaceFs(ctxDirAbs, deps.repoRootAbs);
26618
+ deps.log(`[update-context] promoted ${String(filesCopied)} file(s) \u2192 ${deps.repoRootAbs}`);
26619
+ promoted = filesCopied > 0;
26620
+ } catch (e) {
26621
+ finalizeWt?.();
26622
+ return {
26623
+ exitOk: false,
26624
+ ok: false,
26625
+ code: "PROMOTE_FAILED",
26626
+ error: e instanceof Error ? e.message : String(e),
26627
+ baselineDate: baseline.baselineIsoUtc,
26628
+ baselineSource: baseline.source,
26629
+ headCommit: gitWin.headCommit,
26630
+ rangeStartCommit: gitWin.rangeStartCommit,
26631
+ commitsReviewed: gitWin.commitsInOrder.length,
26632
+ filesDetected: inventory.length,
26633
+ filesRemediated,
26634
+ analysisWorktreeRoot: handle.path,
26635
+ changesReportRelativePath: ".gluecharm/context/changes-since-date.md",
26636
+ remediationSkipped,
26637
+ ...remediationSkipReason ? { skipReason: remediationSkipReason } : {},
26638
+ ...baseMeta
26639
+ };
26640
+ }
26166
26641
  }
26167
26642
  }
26168
26643
  const uploadSkipped = true;
@@ -26198,12 +26673,12 @@ async function runUpdateContextFactory(deps) {
26198
26673
  }
26199
26674
 
26200
26675
  // src/factory/contextDrift/runContextDriftFactory.ts
26201
- var fs57 = __toESM(require("node:fs"));
26202
- var path53 = __toESM(require("node:path"));
26676
+ var fs58 = __toESM(require("node:fs"));
26677
+ var path55 = __toESM(require("node:path"));
26203
26678
 
26204
26679
  // src/factory/contextDrift/contextDriftManifest.ts
26205
- var fs52 = __toESM(require("node:fs"));
26206
- var path49 = __toESM(require("node:path"));
26680
+ var fs53 = __toESM(require("node:fs"));
26681
+ var path51 = __toESM(require("node:path"));
26207
26682
  var MAX_REFERENCE_BYTES = 256 * 1024;
26208
26683
  var MAX_EVIDENCE_FILES = 300;
26209
26684
  var MAX_EVIDENCE_READ = 512 * 1024;
@@ -26211,7 +26686,7 @@ var MAX_EXCERPT = 4e3;
26211
26686
  function readFileLimited(abs, maxBytes) {
26212
26687
  let buf;
26213
26688
  try {
26214
- buf = fs52.readFileSync(abs);
26689
+ buf = fs53.readFileSync(abs);
26215
26690
  } catch {
26216
26691
  return { text: "", truncated: false };
26217
26692
  }
@@ -26223,16 +26698,16 @@ function collectEvidencePaths(repoRoot) {
26223
26698
  const out = [];
26224
26699
  const roots = ["src", "test", "tests", "packages", ".gluecharm", "scripts"];
26225
26700
  for (const rel of roots) {
26226
- const abs = path49.join(repoRoot, rel);
26227
- if (!fs52.existsSync(abs)) {
26701
+ const abs = path51.join(repoRoot, rel);
26702
+ if (!fs53.existsSync(abs)) {
26228
26703
  continue;
26229
26704
  }
26230
26705
  walkFiles(abs, repoRoot, out, 0);
26231
26706
  }
26232
26707
  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("/");
26708
+ const abs = path51.join(repoRoot, leaf);
26709
+ if (fs53.existsSync(abs) && fs53.statSync(abs).isFile()) {
26710
+ const r = path51.relative(repoRoot, abs).split(path51.sep).join("/");
26236
26711
  out.push(r);
26237
26712
  }
26238
26713
  }
@@ -26249,7 +26724,7 @@ function walkFiles(dir, repoRoot, out, depth) {
26249
26724
  }
26250
26725
  let entries;
26251
26726
  try {
26252
- entries = fs52.readdirSync(dir, { withFileTypes: true });
26727
+ entries = fs53.readdirSync(dir, { withFileTypes: true });
26253
26728
  } catch {
26254
26729
  return;
26255
26730
  }
@@ -26257,13 +26732,13 @@ function walkFiles(dir, repoRoot, out, depth) {
26257
26732
  if (e.name === "node_modules" || e.name === ".git" || e.name === "dist" || e.name === "out") {
26258
26733
  continue;
26259
26734
  }
26260
- const full = path49.join(dir, e.name);
26735
+ const full = path51.join(dir, e.name);
26261
26736
  if (e.isDirectory()) {
26262
26737
  walkFiles(full, repoRoot, out, depth + 1);
26263
26738
  } else if (e.isFile()) {
26264
- const ext = path49.extname(e.name).toLowerCase();
26739
+ const ext = path51.extname(e.name).toLowerCase();
26265
26740
  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("/");
26741
+ const rel = path51.relative(repoRoot, full).split(path51.sep).join("/");
26267
26742
  out.push(rel);
26268
26743
  }
26269
26744
  }
@@ -26273,7 +26748,7 @@ function buildComparisonManifest(args) {
26273
26748
  const references = [];
26274
26749
  let referenceTruncated = false;
26275
26750
  for (const abs of args.bundleAbsFiles) {
26276
- const rel = path49.relative(args.worktreeRoot, abs).split(path49.sep).join("/");
26751
+ const rel = path51.relative(args.worktreeRoot, abs).split(path51.sep).join("/");
26277
26752
  const { text, truncated } = readFileLimited(abs, MAX_REFERENCE_BYTES);
26278
26753
  references.push({ path: rel, content: text, truncated });
26279
26754
  if (truncated) {
@@ -26285,8 +26760,8 @@ function buildComparisonManifest(args) {
26285
26760
  const omitted = Math.max(0, allEvidence.length - evidencePathsTrimmed.length);
26286
26761
  const evidenceFiles = [];
26287
26762
  for (const rel of evidencePathsTrimmed) {
26288
- const abs = path49.join(args.worktreeRoot, ...rel.split("/"));
26289
- const st = fs52.existsSync(abs) ? fs52.statSync(abs) : null;
26763
+ const abs = path51.join(args.worktreeRoot, ...rel.split("/"));
26764
+ const st = fs53.existsSync(abs) ? fs53.statSync(abs) : null;
26290
26765
  const size = st && st.isFile() ? st.size : 0;
26291
26766
  const { text, truncated } = readFileLimited(abs, MAX_EVIDENCE_READ);
26292
26767
  const excerpt = truncated ? `${text.slice(0, MAX_EXCERPT)}
@@ -26296,7 +26771,7 @@ function buildComparisonManifest(args) {
26296
26771
  }
26297
26772
  return {
26298
26773
  runDate: args.runDate,
26299
- referenceRelPaths: args.bundleAbsFiles.map((a) => path49.relative(args.worktreeRoot, a).split(path49.sep).join("/")),
26774
+ referenceRelPaths: args.bundleAbsFiles.map((a) => path51.relative(args.worktreeRoot, a).split(path51.sep).join("/")),
26300
26775
  references,
26301
26776
  evidenceFiles,
26302
26777
  evidencePathsOnly: [],
@@ -26308,8 +26783,8 @@ function buildComparisonManifest(args) {
26308
26783
  }
26309
26784
 
26310
26785
  // src/factory/contextDrift/contextDriftAgent.ts
26311
- var fs53 = __toESM(require("node:fs"));
26312
- var path50 = __toESM(require("node:path"));
26786
+ var fs54 = __toESM(require("node:fs"));
26787
+ var path52 = __toESM(require("node:path"));
26313
26788
 
26314
26789
  // src/factory/contextDrift/contextDriftPayload.ts
26315
26790
  function isNonEmptyString2(v) {
@@ -26454,17 +26929,17 @@ function buildDriftPrompt(args) {
26454
26929
  ].join("\n");
26455
26930
  }
26456
26931
  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)}
26932
+ const runDir = path52.join(args.worktreeRoot, ".opencode", "_run");
26933
+ fs54.mkdirSync(runDir, { recursive: true });
26934
+ const manifestPath = path52.join(runDir, "context-drift-manifest.json");
26935
+ const outputPath = path52.join(runDir, "context-drift-payload.json");
26936
+ fs54.writeFileSync(manifestPath, `${JSON.stringify(args.manifestObject, null, 2)}
26462
26937
  `, "utf8");
26463
- if (fs53.existsSync(outputPath)) {
26464
- fs53.unlinkSync(outputPath);
26938
+ if (fs54.existsSync(outputPath)) {
26939
+ fs54.unlinkSync(outputPath);
26465
26940
  }
26466
- const promptPath = path50.join(runDir, `context-drift-${Date.now()}.prompt.txt`);
26467
- fs53.writeFileSync(
26941
+ const promptPath = path52.join(runDir, `context-drift-${Date.now()}.prompt.txt`);
26942
+ fs54.writeFileSync(
26468
26943
  promptPath,
26469
26944
  buildDriftPrompt({
26470
26945
  worktreeRoot: args.worktreeRoot,
@@ -26481,7 +26956,7 @@ async function runDriftComparisonOpenCode(args) {
26481
26956
  });
26482
26957
  const title = buildOpenCodeSessionTitle({
26483
26958
  runId: "context-drift",
26484
- workItemId: path50.basename(args.worktreeRoot).slice(0, 24) || "wt",
26959
+ workItemId: path52.basename(args.worktreeRoot).slice(0, 24) || "wt",
26485
26960
  stepLabel: "context-drift"
26486
26961
  });
26487
26962
  const argv = injectPrimaryOpenCodeSessionArgv(expanded, title);
@@ -26506,7 +26981,7 @@ async function runDriftComparisonOpenCode(args) {
26506
26981
  }
26507
26982
  let raw;
26508
26983
  try {
26509
- const txt = fs53.readFileSync(outputPath, "utf8");
26984
+ const txt = fs54.readFileSync(outputPath, "utf8");
26510
26985
  raw = JSON.parse(txt);
26511
26986
  } catch (e) {
26512
26987
  return {
@@ -26523,9 +26998,9 @@ async function runDriftComparisonOpenCode(args) {
26523
26998
 
26524
26999
  // src/factory/contextDrift/contextDriftPaths.ts
26525
27000
  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");
27001
+ var fs55 = __toESM(require("node:fs"));
27002
+ var path53 = __toESM(require("node:path"));
27003
+ var DRIFT_CONTEXT_SUBDIR = path53.join(".gluecharm", "context", "drift");
26529
27004
  function sanitizeSlug(raw) {
26530
27005
  const s = raw.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
26531
27006
  return s.length > 0 ? s : "drift";
@@ -26534,9 +27009,9 @@ function utcDateString(d) {
26534
27009
  return d.toISOString().slice(0, 10);
26535
27010
  }
26536
27011
  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)) {
27012
+ const abs = path53.isAbsolute(userPath) ? path53.normalize(userPath) : path53.resolve(repoRootAbs, userPath);
27013
+ const rel = path53.relative(repoRootAbs, abs);
27014
+ if (rel.startsWith("..") || path53.isAbsolute(rel)) {
26540
27015
  return { ok: false };
26541
27016
  }
26542
27017
  return { ok: true, abs };
@@ -26546,7 +27021,7 @@ function computeSlug(args) {
26546
27021
  return sanitizeSlug(args.label.trim());
26547
27022
  }
26548
27023
  const r = resolveInsideRepo(args.repoRootAbs, args.referencePath);
26549
- const base = r.ok ? path51.basename(r.abs) : path51.basename(args.referencePath);
27024
+ const base = r.ok ? path53.basename(r.abs) : path53.basename(args.referencePath);
26550
27025
  return sanitizeSlug(base);
26551
27026
  }
26552
27027
  function driftFilename(slug, runDate) {
@@ -26562,7 +27037,7 @@ function maybeDedupeSlug(slug, referenceRelPosix) {
26562
27037
  function discoverReferenceBundle(worktreeRoot, referenceAbsInWorktree) {
26563
27038
  let st;
26564
27039
  try {
26565
- st = fs54.statSync(referenceAbsInWorktree);
27040
+ st = fs55.statSync(referenceAbsInWorktree);
26566
27041
  } catch {
26567
27042
  return { ok: false, error: `Reference path not found in analysis worktree: ${referenceAbsInWorktree}` };
26568
27043
  }
@@ -26583,12 +27058,12 @@ function discoverReferenceBundle(worktreeRoot, referenceAbsInWorktree) {
26583
27058
  }
26584
27059
  let entries;
26585
27060
  try {
26586
- entries = fs54.readdirSync(dir, { withFileTypes: true });
27061
+ entries = fs55.readdirSync(dir, { withFileTypes: true });
26587
27062
  } catch {
26588
27063
  return;
26589
27064
  }
26590
27065
  for (const e of entries) {
26591
- const full = path51.join(dir, e.name);
27066
+ const full = path53.join(dir, e.name);
26592
27067
  if (e.isDirectory()) {
26593
27068
  if (e.name === "node_modules" || e.name === ".git") {
26594
27069
  continue;
@@ -26608,7 +27083,7 @@ function discoverReferenceBundle(worktreeRoot, referenceAbsInWorktree) {
26608
27083
  }
26609
27084
  function pickReferenceRootDocument(args) {
26610
27085
  if (args.indexOverrideAbs) {
26611
- if (!fs54.existsSync(args.indexOverrideAbs) || !args.indexOverrideAbs.endsWith(".md")) {
27086
+ if (!fs55.existsSync(args.indexOverrideAbs) || !args.indexOverrideAbs.endsWith(".md")) {
26612
27087
  return { ok: false, error: "--index must point to an existing .md file under the repo." };
26613
27088
  }
26614
27089
  return { ok: true, path: args.indexOverrideAbs };
@@ -26618,8 +27093,8 @@ function pickReferenceRootDocument(args) {
26618
27093
  }
26619
27094
  const dir = args.referenceAbsInWorktree;
26620
27095
  for (const name of ["index.md", "README.md"]) {
26621
- const p = path51.join(dir, name);
26622
- if (fs54.existsSync(p) && fs54.statSync(p).isFile()) {
27096
+ const p = path53.join(dir, name);
27097
+ if (fs55.existsSync(p) && fs55.statSync(p).isFile()) {
26623
27098
  return { ok: true, path: p };
26624
27099
  }
26625
27100
  }
@@ -26629,20 +27104,20 @@ function pickReferenceRootDocument(args) {
26629
27104
  };
26630
27105
  }
26631
27106
  function toWorktreeRelative(worktreeRoot, absolute) {
26632
- return path51.relative(worktreeRoot, absolute).split(path51.sep).join("/");
27107
+ return path53.relative(worktreeRoot, absolute).split(path53.sep).join("/");
26633
27108
  }
26634
27109
  function toPosixPath(p) {
26635
- return p.split(path51.sep).join("/");
27110
+ return p.split(path53.sep).join("/");
26636
27111
  }
26637
27112
 
26638
27113
  // src/factory/contextDrift/contextDriftIndex.ts
26639
- var fs55 = __toESM(require("node:fs"));
27114
+ var fs56 = __toESM(require("node:fs"));
26640
27115
  var START = "<!-- easyspecs-drift-links:start -->";
26641
27116
  var END = "<!-- easyspecs-drift-links:end -->";
26642
27117
  function patchReferenceIndexWithDriftLink(args) {
26643
27118
  let body;
26644
27119
  try {
26645
- body = fs55.readFileSync(args.referenceRootAbsolute, "utf8");
27120
+ body = fs56.readFileSync(args.referenceRootAbsolute, "utf8");
26646
27121
  } catch (e) {
26647
27122
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
26648
27123
  }
@@ -26663,7 +27138,7 @@ ${block}
26663
27138
  `;
26664
27139
  }
26665
27140
  try {
26666
- fs55.writeFileSync(args.referenceRootAbsolute, next, "utf8");
27141
+ fs56.writeFileSync(args.referenceRootAbsolute, next, "utf8");
26667
27142
  } catch (e) {
26668
27143
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
26669
27144
  }
@@ -26674,19 +27149,32 @@ function escapeRe(s) {
26674
27149
  }
26675
27150
 
26676
27151
  // src/factory/contextDrift/contextDriftPromote.ts
26677
- var fs56 = __toESM(require("node:fs"));
26678
- var path52 = __toESM(require("node:path"));
27152
+ var fs57 = __toESM(require("node:fs"));
27153
+ var path54 = __toESM(require("node:path"));
26679
27154
  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);
27155
+ const wt = path54.resolve(args.worktreeRoot);
27156
+ const ws = path54.resolve(args.workspaceRoot);
27157
+ if (wt === ws) {
27158
+ return;
27159
+ }
27160
+ const src = path54.join(args.worktreeRoot, ...args.relativePosix.split("/"));
27161
+ const dest = path54.join(args.workspaceRoot, ...args.relativePosix.split("/"));
27162
+ if (path54.resolve(src) === path54.resolve(dest)) {
27163
+ return;
27164
+ }
27165
+ fs57.mkdirSync(path54.dirname(dest), { recursive: true });
27166
+ fs57.copyFileSync(src, dest);
26684
27167
  }
26685
27168
 
26686
27169
  // src/factory/contextDrift/runContextDriftFactory.ts
26687
27170
  async function runContextDriftFactory(deps) {
26688
27171
  const runDate = utcDateString(/* @__PURE__ */ new Date());
26689
- const baseMeta = { command: "context_drift", referencePath: deps.referencePathArg };
27172
+ const inPlace = deps.inPlace === true;
27173
+ const baseMeta = {
27174
+ command: "context_drift",
27175
+ referencePath: deps.referencePathArg,
27176
+ ...inPlace ? { analysisInPlace: true } : {}
27177
+ };
26690
27178
  const resolved = resolveInsideRepo(deps.repoRootAbs, deps.referencePathArg);
26691
27179
  if (!resolved.ok) {
26692
27180
  return {
@@ -26699,7 +27187,7 @@ async function runContextDriftFactory(deps) {
26699
27187
  };
26700
27188
  }
26701
27189
  const refAbsWorkspace = resolved.abs;
26702
- if (!fs57.existsSync(refAbsWorkspace)) {
27190
+ if (!fs58.existsSync(refAbsWorkspace)) {
26703
27191
  return {
26704
27192
  exitOk: false,
26705
27193
  ok: false,
@@ -26712,7 +27200,7 @@ async function runContextDriftFactory(deps) {
26712
27200
  let indexOverrideAbsWorkspace;
26713
27201
  if (deps.indexOverrideArg?.trim()) {
26714
27202
  const ir = resolveInsideRepo(deps.repoRootAbs, deps.indexOverrideArg.trim());
26715
- if (!ir.ok || !fs57.existsSync(ir.abs)) {
27203
+ if (!ir.ok || !fs58.existsSync(ir.abs)) {
26716
27204
  return {
26717
27205
  exitOk: false,
26718
27206
  ok: false,
@@ -26730,7 +27218,7 @@ async function runContextDriftFactory(deps) {
26730
27218
  ok: true,
26731
27219
  code: "DRY_RUN",
26732
27220
  ...baseMeta,
26733
- referenceRootDocument: toPosixPath(path53.relative(deps.repoRootAbs, refAbsWorkspace)) + (fs57.statSync(refAbsWorkspace).isDirectory() ? "/" : ""),
27221
+ referenceRootDocument: toPosixPath(path55.relative(deps.repoRootAbs, refAbsWorkspace)) + (fs58.statSync(refAbsWorkspace).isDirectory() ? "/" : ""),
26734
27222
  driftReportPath: null,
26735
27223
  analysisWorktreeRoot: "",
26736
27224
  promoted: false,
@@ -26740,8 +27228,38 @@ async function runContextDriftFactory(deps) {
26740
27228
  dryRun: true
26741
27229
  };
26742
27230
  }
27231
+ const cliVersion = deps.cliVersion?.trim() || "0.0.0";
27232
+ const readinessCtx = {
27233
+ cliVersion,
27234
+ repoRootAbs: deps.repoRootAbs,
27235
+ analysisRootAbs: deps.repoRootAbs,
27236
+ apiBaseUrl: deps.merged.apiBaseUrl,
27237
+ openCodeExecutable: deps.merged.openCodeExecutable,
27238
+ openCodeSkipCredentialsCheck: deps.merged.openCodeSkipCredentialsCheck,
27239
+ providerEnvFromConfig: deps.merged.openCodeChildEnv,
27240
+ repoConfig: deps.repoConfig
27241
+ };
27242
+ const rlog = deps.readinessLog ?? deps.log;
27243
+ const pre = emitCliFactoryReadinessPreflight(rlog, "[factory] context drift readiness", readinessCtx);
27244
+ if (!pre.ok) {
27245
+ const g = pre.failure;
27246
+ return {
27247
+ exitOk: false,
27248
+ ok: false,
27249
+ code: "READINESS_FAILED",
27250
+ error: `Factory readiness failed (${g.readinessReasonCode}).`,
27251
+ readinessExitCode: g.exitCode,
27252
+ readinessReasonCode: g.readinessReasonCode,
27253
+ readinessGate: g.gate,
27254
+ openCodeConfigFiles: pre.facts.openCodeConfigFiles,
27255
+ modelConfigured: pre.facts.modelConfigured,
27256
+ driftReportPath: null,
27257
+ ...baseMeta
27258
+ };
27259
+ }
26743
27260
  const prep = await prepareSynthesisWorktree(deps.storage, deps.repoRootAbs, deps.log, {
26744
- clearPriorArtefactRun: false
27261
+ clearPriorArtefactRun: false,
27262
+ inPlace
26745
27263
  });
26746
27264
  if (!prep.ok) {
26747
27265
  prep.finalize?.();
@@ -26757,8 +27275,8 @@ async function runContextDriftFactory(deps) {
26757
27275
  const handle = prep.handle;
26758
27276
  const finalizeWt = prep.finalize;
26759
27277
  const wt = handle.path;
26760
- const refRel = path53.relative(deps.repoRootAbs, refAbsWorkspace).split(path53.sep).join("/");
26761
- const refAbsWt = path53.join(wt, ...refRel.split("/"));
27278
+ const refRel = path55.relative(deps.repoRootAbs, refAbsWorkspace).split(path55.sep).join("/");
27279
+ const refAbsWt = path55.join(wt, ...refRel.split("/"));
26762
27280
  try {
26763
27281
  materializeOpenCodeAgentsWithAce(deps.agentsDirFs, wt, {
26764
27282
  enabled: getAceAnalysisEnabledForCheckout(wt),
@@ -26797,9 +27315,9 @@ async function runContextDriftFactory(deps) {
26797
27315
  ...baseMeta
26798
27316
  };
26799
27317
  }
26800
- const indexWt = indexOverrideAbsWorkspace ? path53.join(wt, ...path53.relative(deps.repoRootAbs, indexOverrideAbsWorkspace).split(path53.sep)) : void 0;
27318
+ const indexWt = indexOverrideAbsWorkspace ? path55.join(wt, ...path55.relative(deps.repoRootAbs, indexOverrideAbsWorkspace).split(path55.sep)) : void 0;
26801
27319
  const rootPick = pickReferenceRootDocument({
26802
- referencePathIsFile: fs57.statSync(refAbsWt).isFile(),
27320
+ referencePathIsFile: fs58.statSync(refAbsWt).isFile(),
26803
27321
  referenceAbsInWorktree: refAbsWt,
26804
27322
  bundleFiles: bundle.bundleFiles,
26805
27323
  indexOverrideAbs: indexWt
@@ -26825,9 +27343,9 @@ async function runContextDriftFactory(deps) {
26825
27343
  let slug = computeSlug({ label: deps.label, referencePath: deps.referencePathArg, repoRootAbs: deps.repoRootAbs });
26826
27344
  slug = maybeDedupeSlug(slug, refRel);
26827
27345
  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);
27346
+ const driftDirWt = path55.join(wt, DRIFT_CONTEXT_SUBDIR);
27347
+ fs58.mkdirSync(driftDirWt, { recursive: true });
27348
+ const driftAbsWt = path55.join(driftDirWt, driftBase);
26831
27349
  let payload;
26832
27350
  if (deps.testOnlyFixturePayload) {
26833
27351
  payload = deps.testOnlyFixturePayload;
@@ -26863,7 +27381,7 @@ async function runContextDriftFactory(deps) {
26863
27381
  manifestTruncation: manifest.truncation
26864
27382
  });
26865
27383
  try {
26866
- fs57.writeFileSync(driftAbsWt, md, "utf8");
27384
+ fs58.writeFileSync(driftAbsWt, md, "utf8");
26867
27385
  } catch (e) {
26868
27386
  finalizeWt?.();
26869
27387
  return {
@@ -26876,7 +27394,7 @@ async function runContextDriftFactory(deps) {
26876
27394
  ...baseMeta
26877
27395
  };
26878
27396
  }
26879
- const driftRelFromRootDir = path53.relative(path53.dirname(refRootAbsWt), driftAbsWt).split(path53.sep).join("/");
27397
+ const driftRelFromRootDir = path55.relative(path55.dirname(refRootAbsWt), driftAbsWt).split(path55.sep).join("/");
26880
27398
  const linkRes = patchReferenceIndexWithDriftLink({
26881
27399
  referenceRootAbsolute: refRootAbsWt,
26882
27400
  relativeLinkFromRootToDrift: driftRelFromRootDir,
@@ -26895,10 +27413,10 @@ async function runContextDriftFactory(deps) {
26895
27413
  ...baseMeta
26896
27414
  };
26897
27415
  }
26898
- const driftRelPosix = toPosixPath(path53.relative(wt, driftAbsWt));
26899
- const rootRelPosix = toPosixPath(path53.relative(wt, refRootAbsWt));
27416
+ const driftRelPosix = toPosixPath(path55.relative(wt, driftAbsWt));
27417
+ const rootRelPosix = toPosixPath(path55.relative(wt, refRootAbsWt));
26900
27418
  const promoteEffective = deps.merged.promoteContextToWorkspace !== false;
26901
- if (promoteEffective) {
27419
+ if (promoteEffective && !inPlace) {
26902
27420
  try {
26903
27421
  copyWorktreeFileToWorkspace({
26904
27422
  worktreeRoot: wt,
@@ -26923,8 +27441,10 @@ async function runContextDriftFactory(deps) {
26923
27441
  ...baseMeta
26924
27442
  };
26925
27443
  }
27444
+ } else if (promoteEffective && inPlace) {
27445
+ deps.log("[context-drift] in-place analysis \u2014 promote skipped (artefacts already under repository root)");
26926
27446
  }
26927
- const driftReportPathFs = promoteEffective ? path53.join(deps.repoRootAbs, ...driftRelPosix.split("/")) : driftAbsWt;
27447
+ const driftReportPathFs = promoteEffective ? path55.join(deps.repoRootAbs, ...driftRelPosix.split("/")) : driftAbsWt;
26928
27448
  return {
26929
27449
  exitOk: true,
26930
27450
  ok: true,
@@ -26933,7 +27453,7 @@ async function runContextDriftFactory(deps) {
26933
27453
  referenceRootDocument: rootRelPosix,
26934
27454
  driftReportPath: driftReportPathFs,
26935
27455
  analysisWorktreeRoot: wt,
26936
- promoted: promoteEffective,
27456
+ promoted: promoteEffective && !inPlace,
26937
27457
  nameOfChangeSlug: slug,
26938
27458
  runDate,
26939
27459
  agentInvoked: !deps.testOnlyFixturePayload,
@@ -26942,8 +27462,8 @@ async function runContextDriftFactory(deps) {
26942
27462
  }
26943
27463
 
26944
27464
  // src/analysis/coordinationDuplicatesDiagnosis.ts
26945
- var fs58 = __toESM(require("fs"));
26946
- var path54 = __toESM(require("path"));
27465
+ var fs59 = __toESM(require("fs"));
27466
+ var path56 = __toESM(require("path"));
26947
27467
  var import__7 = __toESM(require__());
26948
27468
  var COORDINATION_DUPLICATES_REPORT_BASENAME = "coordination-duplicates-report.json";
26949
27469
  var COORDINATION_LIST_SCAN_ENTRIES = [
@@ -26969,7 +27489,7 @@ var RE_MD_DM_FD = /^DM-\d+_FD-\d+-.+\.md$/i;
26969
27489
  var RE_MD_DM = /^DM-\d+-.+\.md$/i;
26970
27490
  var RE_MD_TS = /^TS-\d+-.+\.md$/i;
26971
27491
  function looksLikeCoordinationDetailMarkdownBasename(basename17) {
26972
- if (!basename17 || basename17 !== path54.basename(basename17) || !/\.md$/i.test(basename17)) {
27492
+ if (!basename17 || basename17 !== path56.basename(basename17) || !/\.md$/i.test(basename17)) {
26973
27493
  return false;
26974
27494
  }
26975
27495
  if (STAPLE_CONTEXT_MARKDOWN_BASENAMES.has(basename17)) {
@@ -26978,12 +27498,12 @@ function looksLikeCoordinationDetailMarkdownBasename(basename17) {
26978
27498
  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
27499
  }
26980
27500
  function loadRawFeatureRows(contextDirAbs) {
26981
- const p = path54.join(contextDirAbs, "features-list.json");
26982
- if (!fs58.existsSync(p)) {
27501
+ const p = path56.join(contextDirAbs, "features-list.json");
27502
+ if (!fs59.existsSync(p)) {
26983
27503
  return [];
26984
27504
  }
26985
27505
  try {
26986
- const raw = stripUtf8Bom6(fs58.readFileSync(p, "utf-8"));
27506
+ const raw = stripUtf8Bom6(fs59.readFileSync(p, "utf-8"));
26987
27507
  const doc = JSON.parse(raw);
26988
27508
  return Array.isArray(doc.features) ? doc.features : [];
26989
27509
  } catch {
@@ -27018,7 +27538,7 @@ function findOrphanCoordinationMarkdown(contextDirAbs) {
27018
27538
  const featureRows = loadRawFeatureRows(contextDirAbs);
27019
27539
  let dirents;
27020
27540
  try {
27021
- dirents = fs58.readdirSync(contextDirAbs, { withFileTypes: true });
27541
+ dirents = fs59.readdirSync(contextDirAbs, { withFileTypes: true });
27022
27542
  } catch {
27023
27543
  return [];
27024
27544
  }
@@ -27271,14 +27791,14 @@ function buildCoordinationDuplicatesReport(input) {
27271
27791
  const lists = [];
27272
27792
  const duplicateGroups = [];
27273
27793
  for (const entry of COORDINATION_LIST_SCAN_ENTRIES) {
27274
- const filePath = path54.join(input.contextDirAbsolute, entry.basename);
27275
- if (!fs58.existsSync(filePath)) {
27794
+ const filePath = path56.join(input.contextDirAbsolute, entry.basename);
27795
+ if (!fs59.existsSync(filePath)) {
27276
27796
  lists.push({ basename: entry.basename, status: "missing" });
27277
27797
  continue;
27278
27798
  }
27279
27799
  let raw;
27280
27800
  try {
27281
- raw = stripUtf8Bom6(fs58.readFileSync(filePath, "utf-8"));
27801
+ raw = stripUtf8Bom6(fs59.readFileSync(filePath, "utf-8"));
27282
27802
  } catch (e) {
27283
27803
  lists.push({
27284
27804
  basename: entry.basename,
@@ -27326,8 +27846,8 @@ var validateReportCompiled;
27326
27846
  function validateReportData(data) {
27327
27847
  if (!validateReportCompiled) {
27328
27848
  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"));
27849
+ const schemaPath = path56.join(resolveContextListSchemasDir(), "coordination-duplicates-report.schema.json");
27850
+ const schemaRaw = stripUtf8Bom6(fs59.readFileSync(schemaPath, "utf-8"));
27331
27851
  validateReportCompiled = ajv2.compile(JSON.parse(schemaRaw));
27332
27852
  }
27333
27853
  if (validateReportCompiled(data)) {
@@ -27345,20 +27865,20 @@ function runCoordinationDuplicatesDiagnosis(input) {
27345
27865
  if (!v.ok) {
27346
27866
  return { ok: false, message: `Report validation failed: ${v.errors.join("; ")}` };
27347
27867
  }
27348
- const outPath = path54.join(input.contextDirAbsolute, COORDINATION_DUPLICATES_REPORT_BASENAME);
27868
+ const outPath = path56.join(input.contextDirAbsolute, COORDINATION_DUPLICATES_REPORT_BASENAME);
27349
27869
  const payload = `${JSON.stringify(report, null, 2)}
27350
27870
  `;
27351
27871
  const tmp = `${outPath}.tmp.${process.pid}`;
27352
27872
  try {
27353
- fs58.writeFileSync(tmp, payload, "utf-8");
27873
+ fs59.writeFileSync(tmp, payload, "utf-8");
27354
27874
  } catch (e) {
27355
27875
  return { ok: false, message: e instanceof Error ? e.message : String(e) };
27356
27876
  }
27357
27877
  try {
27358
- fs58.renameSync(tmp, outPath);
27878
+ fs59.renameSync(tmp, outPath);
27359
27879
  } catch (e) {
27360
27880
  try {
27361
- fs58.unlinkSync(tmp);
27881
+ fs59.unlinkSync(tmp);
27362
27882
  } catch {
27363
27883
  }
27364
27884
  return { ok: false, message: e instanceof Error ? e.message : String(e) };
@@ -27392,8 +27912,8 @@ function runCoordinationDuplicatesDiagnosis(input) {
27392
27912
  }
27393
27913
 
27394
27914
  // src/pipelines/download/downloadPipeline.ts
27395
- var fs59 = __toESM(require("node:fs"));
27396
- var path55 = __toESM(require("node:path"));
27915
+ var fs60 = __toESM(require("node:fs"));
27916
+ var path57 = __toESM(require("node:path"));
27397
27917
  var SRS_DISCOVERY_BATCH_GET_CHUNK_SIZE = 200;
27398
27918
  function isRecord7(v) {
27399
27919
  return Boolean(v) && typeof v === "object" && !Array.isArray(v);
@@ -27483,9 +28003,9 @@ function resolveSafeContextOutputPath(contextDirAbs, nameRaw) {
27483
28003
  return null;
27484
28004
  }
27485
28005
  }
27486
- const resolved = path55.resolve(contextDirAbs, ...segments);
27487
- const rel = path55.relative(contextDirAbs, resolved);
27488
- if (rel.startsWith("..") || path55.isAbsolute(rel)) {
28006
+ const resolved = path57.resolve(contextDirAbs, ...segments);
28007
+ const rel = path57.relative(contextDirAbs, resolved);
28008
+ if (rel.startsWith("..") || path57.isAbsolute(rel)) {
27489
28009
  return null;
27490
28010
  }
27491
28011
  return resolved;
@@ -27498,37 +28018,37 @@ function chunkIds(ids, size) {
27498
28018
  return out;
27499
28019
  }
27500
28020
  function clearContextDirectoryForCloudReplace(contextDirAbs) {
27501
- if (!fs59.existsSync(contextDirAbs) || !fs59.statSync(contextDirAbs).isDirectory()) {
28021
+ if (!fs60.existsSync(contextDirAbs) || !fs60.statSync(contextDirAbs).isDirectory()) {
27502
28022
  return { filesRemoved: 0 };
27503
28023
  }
27504
- const preserveAbs = path55.resolve(contextDirAbs, UPLOAD_TARGET_FILENAME);
28024
+ const preserveAbs = path57.resolve(contextDirAbs, UPLOAD_TARGET_FILENAME);
27505
28025
  const preserveSet = /* @__PURE__ */ new Set();
27506
- if (fs59.existsSync(preserveAbs) && fs59.statSync(preserveAbs).isFile()) {
28026
+ if (fs60.existsSync(preserveAbs) && fs60.statSync(preserveAbs).isFile()) {
27507
28027
  preserveSet.add(preserveAbs);
27508
28028
  }
27509
28029
  let filesRemoved = 0;
27510
28030
  const walkRm = (dir) => {
27511
28031
  let entries;
27512
28032
  try {
27513
- entries = fs59.readdirSync(dir, { withFileTypes: true });
28033
+ entries = fs60.readdirSync(dir, { withFileTypes: true });
27514
28034
  } catch {
27515
28035
  return;
27516
28036
  }
27517
28037
  for (const e of entries) {
27518
- const full = path55.join(dir, e.name);
28038
+ const full = path57.join(dir, e.name);
27519
28039
  if (e.isDirectory()) {
27520
28040
  walkRm(full);
27521
28041
  try {
27522
- fs59.rmdirSync(full);
28042
+ fs60.rmdirSync(full);
27523
28043
  } catch {
27524
28044
  }
27525
28045
  } else if (e.isFile()) {
27526
- const abs = path55.resolve(full);
28046
+ const abs = path57.resolve(full);
27527
28047
  if (preserveSet.has(abs)) {
27528
28048
  continue;
27529
28049
  }
27530
28050
  try {
27531
- fs59.unlinkSync(abs);
28051
+ fs60.unlinkSync(abs);
27532
28052
  filesRemoved += 1;
27533
28053
  } catch {
27534
28054
  }
@@ -27596,7 +28116,7 @@ async function runDownloadPipeline(opts) {
27596
28116
  failed.push({ id, message: "Missing name on srs_discovery node." });
27597
28117
  continue;
27598
28118
  }
27599
- if (name === UPLOAD_TARGET_FILENAME || path55.basename(name) === UPLOAD_TARGET_FILENAME) {
28119
+ if (name === UPLOAD_TARGET_FILENAME || path57.basename(name) === UPLOAD_TARGET_FILENAME) {
27600
28120
  skipped += 1;
27601
28121
  log?.(`[pipeline:download] skip ${name} (upload target row).`);
27602
28122
  continue;
@@ -27607,15 +28127,15 @@ async function runDownloadPipeline(opts) {
27607
28127
  failed.push({ id, name, message: "Unsafe or invalid name for local path." });
27608
28128
  continue;
27609
28129
  }
27610
- fs59.mkdirSync(path55.dirname(outAbs), { recursive: true });
27611
- const exists = fs59.existsSync(outAbs);
28130
+ fs60.mkdirSync(path57.dirname(outAbs), { recursive: true });
28131
+ const exists = fs60.existsSync(outAbs);
27612
28132
  if (exists && !opts.force && !opts.replaceFromCloud) {
27613
28133
  skipped += 1;
27614
28134
  log?.(`[pipeline:download] skip existing ${name} (use --force to overwrite).`);
27615
28135
  continue;
27616
28136
  }
27617
28137
  try {
27618
- fs59.writeFileSync(outAbs, bodyText, "utf8");
28138
+ fs60.writeFileSync(outAbs, bodyText, "utf8");
27619
28139
  downloaded += 1;
27620
28140
  succeededIds[outAbs] = id;
27621
28141
  } catch (e) {
@@ -27690,12 +28210,12 @@ function toFetchErrorMessage(e) {
27690
28210
 
27691
28211
  // src/auth/gluecharmContentNegotiation.ts
27692
28212
  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);
28213
+ function pathWithoutQuery(path62) {
28214
+ const q = path62.indexOf("?");
28215
+ return q === -1 ? path62 : path62.slice(0, q);
27696
28216
  }
27697
- function isGluecharmContentApiPath(path60) {
27698
- const p = pathWithoutQuery(path60);
28217
+ function isGluecharmContentApiPath(path62) {
28218
+ const p = pathWithoutQuery(path62);
27699
28219
  return p.startsWith("/api/content/") || p.startsWith("/api/batch/content/");
27700
28220
  }
27701
28221
  function gluecharmContentHeaders(method) {
@@ -27733,7 +28253,7 @@ async function fetchWithTimeout2(url, init, fetchImpl, timeoutMs, externalSignal
27733
28253
  }
27734
28254
  function createAuthenticatedRequestJson(deps) {
27735
28255
  const fetchImpl = deps.fetchImpl ?? fetch;
27736
- async function requestJson(path60, options = {}) {
28256
+ async function requestJson(path62, options = {}) {
27737
28257
  const base = deps.getApiBaseUrl();
27738
28258
  if (!base) {
27739
28259
  const err = { status: 0, message: "easyspecs.apiBaseUrl is not configured." };
@@ -27741,7 +28261,7 @@ function createAuthenticatedRequestJson(deps) {
27741
28261
  }
27742
28262
  const method = options.method ?? "GET";
27743
28263
  const headers = { ...options.headers };
27744
- if (isGluecharmContentApiPath(path60)) {
28264
+ if (isGluecharmContentApiPath(path62)) {
27745
28265
  Object.assign(headers, gluecharmContentHeaders(method));
27746
28266
  } else {
27747
28267
  if (!headers.Accept) {
@@ -27755,7 +28275,7 @@ function createAuthenticatedRequestJson(deps) {
27755
28275
  if (options.withAuth !== false && access) {
27756
28276
  headers.Authorization = `Bearer ${access}`;
27757
28277
  }
27758
- const url = `${base}${path60}`;
28278
+ const url = `${base}${path62}`;
27759
28279
  const timeoutMs = options.timeoutMs ?? API_TIMEOUT_MS;
27760
28280
  const response = await fetchWithTimeout2(
27761
28281
  url,
@@ -27776,7 +28296,7 @@ function createAuthenticatedRequestJson(deps) {
27776
28296
  if (shouldRetryUnauthorized) {
27777
28297
  const refreshed = await deps.refreshSession();
27778
28298
  if (refreshed) {
27779
- return requestJson(path60, { ...options, retryOnUnauthorized: false });
28299
+ return requestJson(path62, { ...options, retryOnUnauthorized: false });
27780
28300
  }
27781
28301
  }
27782
28302
  const fallback = payload == null ? `${response.statusText || "HTTP error"} (response body empty or not JSON)` : "Request failed.";
@@ -27786,15 +28306,15 @@ function createAuthenticatedRequestJson(deps) {
27786
28306
  }
27787
28307
 
27788
28308
  // 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"));
28309
+ var fs61 = __toESM(require("node:fs"));
28310
+ var os7 = __toESM(require("node:os"));
28311
+ var path58 = __toESM(require("node:path"));
27792
28312
  function defaultSessionPath() {
27793
- return path56.join(os6.homedir(), ".easyspecs", "cli-session.json");
28313
+ return path58.join(os7.homedir(), ".easyspecs", "cli-session.json");
27794
28314
  }
27795
28315
  var configSessionPath;
27796
28316
  function setCliSessionPathFromConfig(absPath) {
27797
- configSessionPath = absPath?.trim() ? path56.resolve(absPath) : void 0;
28317
+ configSessionPath = absPath?.trim() ? path58.resolve(absPath) : void 0;
27798
28318
  }
27799
28319
  function applyCliSessionPathFromRepoConfig(repoRoot, cfg) {
27800
28320
  const raw = cfg.easyspecs?.cliSessionPath?.trim();
@@ -27802,7 +28322,7 @@ function applyCliSessionPathFromRepoConfig(repoRoot, cfg) {
27802
28322
  setCliSessionPathFromConfig(void 0);
27803
28323
  return;
27804
28324
  }
27805
- const abs = path56.isAbsolute(raw) ? raw : path56.join(repoRoot, raw);
28325
+ const abs = path58.isAbsolute(raw) ? raw : path58.join(repoRoot, raw);
27806
28326
  setCliSessionPathFromConfig(abs);
27807
28327
  }
27808
28328
  function normalizeCliSessionPathForConfig(repoRoot, raw) {
@@ -27810,15 +28330,15 @@ function normalizeCliSessionPathForConfig(repoRoot, raw) {
27810
28330
  if (!t) {
27811
28331
  return "";
27812
28332
  }
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);
28333
+ const resolvedRepo = path58.resolve(repoRoot);
28334
+ const abs = path58.isAbsolute(t) ? path58.normalize(t) : path58.resolve(resolvedRepo, t);
28335
+ const rel = path58.relative(resolvedRepo, abs);
27816
28336
  if (rel === "") {
27817
28337
  return abs;
27818
28338
  }
27819
- const underRepo = !rel.startsWith("..") && !path56.isAbsolute(rel);
28339
+ const underRepo = !rel.startsWith("..") && !path58.isAbsolute(rel);
27820
28340
  if (underRepo) {
27821
- return rel.split(path56.sep).join("/");
28341
+ return rel.split(path58.sep).join("/");
27822
28342
  }
27823
28343
  return abs;
27824
28344
  }
@@ -27831,10 +28351,10 @@ function effectiveCliSessionPath() {
27831
28351
  function readCliSession() {
27832
28352
  const p = effectiveCliSessionPath();
27833
28353
  try {
27834
- if (!fs60.existsSync(p)) {
28354
+ if (!fs61.existsSync(p)) {
27835
28355
  return void 0;
27836
28356
  }
27837
- const j = JSON.parse(fs60.readFileSync(p, "utf8"));
28357
+ const j = JSON.parse(fs61.readFileSync(p, "utf8"));
27838
28358
  const apiBaseUrl = typeof j.apiBaseUrl === "string" ? j.apiBaseUrl.trim() : "";
27839
28359
  const accessToken = typeof j.accessToken === "string" ? j.accessToken : "";
27840
28360
  const refreshToken = typeof j.refreshToken === "string" ? j.refreshToken : "";
@@ -27848,33 +28368,33 @@ function readCliSession() {
27848
28368
  }
27849
28369
  function writeCliSession(s) {
27850
28370
  const p = effectiveCliSessionPath();
27851
- fs60.mkdirSync(path56.dirname(p), { recursive: true });
27852
- fs60.writeFileSync(p, `${JSON.stringify(s, null, 2)}
28371
+ fs61.mkdirSync(path58.dirname(p), { recursive: true });
28372
+ fs61.writeFileSync(p, `${JSON.stringify(s, null, 2)}
27853
28373
  `, "utf8");
27854
28374
  }
27855
28375
  function clearCliSession() {
27856
28376
  const p = effectiveCliSessionPath();
27857
28377
  try {
27858
- fs60.unlinkSync(p);
28378
+ fs61.unlinkSync(p);
27859
28379
  } catch {
27860
28380
  }
27861
28381
  }
27862
28382
 
27863
28383
  // src/analysis/acePendingTraces.ts
27864
- var fs61 = __toESM(require("fs"));
27865
- var path57 = __toESM(require("path"));
28384
+ var fs62 = __toESM(require("fs"));
28385
+ var path59 = __toESM(require("path"));
27866
28386
  function normalizeAceTraceRelativePath(rel) {
27867
28387
  return rel.split(/[/\\]/).join("/");
27868
28388
  }
27869
28389
  function readCompletedTraceRelativePaths(contextDir2) {
27870
28390
  const set = /* @__PURE__ */ new Set();
27871
28391
  const jsonlPath = aceConsolidatedSessionsJsonlPath(contextDir2);
27872
- if (!fs61.existsSync(jsonlPath)) {
28392
+ if (!fs62.existsSync(jsonlPath)) {
27873
28393
  return set;
27874
28394
  }
27875
28395
  let raw;
27876
28396
  try {
27877
- raw = fs61.readFileSync(jsonlPath, "utf8");
28397
+ raw = fs62.readFileSync(jsonlPath, "utf8");
27878
28398
  } catch {
27879
28399
  return set;
27880
28400
  }
@@ -27905,14 +28425,14 @@ function readCompletedTraceRelativePaths(contextDir2) {
27905
28425
  }
27906
28426
  function listPendingAceTraceFiles(contextDir2, worktreeRoot) {
27907
28427
  const traceSchema = opencodeAceSchemaPath(worktreeRoot, ACE_SCHEMA_TRACE);
27908
- if (!fs61.existsSync(traceSchema)) {
28428
+ if (!fs62.existsSync(traceSchema)) {
27909
28429
  return [];
27910
28430
  }
27911
28431
  const completed = readCompletedTraceRelativePaths(contextDir2);
27912
28432
  const allAbs = listAceTraceFiles(contextDir2);
27913
28433
  const pending = [];
27914
28434
  for (const abs of allAbs) {
27915
- const rel = normalizeAceTraceRelativePath(path57.relative(contextDir2, abs));
28435
+ const rel = normalizeAceTraceRelativePath(path59.relative(contextDir2, abs));
27916
28436
  const v = validateAceJsonFile(abs, traceSchema);
27917
28437
  if (!v.ok) {
27918
28438
  continue;
@@ -27927,7 +28447,7 @@ function listPendingAceTraceFiles(contextDir2, worktreeRoot) {
27927
28447
  }
27928
28448
 
27929
28449
  // src/analysis/aceAutoLearnPool.ts
27930
- var path58 = __toESM(require("path"));
28450
+ var path60 = __toESM(require("path"));
27931
28451
  function clampConcurrency2(n) {
27932
28452
  if (!Number.isFinite(n)) {
27933
28453
  return DEFAULT_MAX_CONCURRENT_AI;
@@ -27962,8 +28482,8 @@ async function runAceAutoLearnPool(p) {
27962
28482
  };
27963
28483
  const currentCap = () => Math.min(staticMaxC, adaptiveMax);
27964
28484
  let wake;
27965
- const waitTurn = () => new Promise((resolve20) => {
27966
- wake = resolve20;
28485
+ const waitTurn = () => new Promise((resolve24) => {
28486
+ wake = resolve24;
27967
28487
  });
27968
28488
  const pump = () => {
27969
28489
  wake?.();
@@ -27985,7 +28505,7 @@ async function runAceAutoLearnPool(p) {
27985
28505
  poolAbortListenerRegistered = true;
27986
28506
  }
27987
28507
  }
27988
- const traceRel = (abs) => path58.relative(contextDir2, abs).split(path58.sep).join("/");
28508
+ const traceRel = (abs) => path60.relative(contextDir2, abs).split(path60.sep).join("/");
27989
28509
  const runOne = async (traceAbs) => {
27990
28510
  if (abortSignal?.aborted) {
27991
28511
  active -= 1;
@@ -28077,8 +28597,13 @@ function parseContextDriftTail(tail) {
28077
28597
  let label;
28078
28598
  let index;
28079
28599
  let dryRun = false;
28600
+ let inPlace = false;
28080
28601
  for (let i = 0; i < tail.length; i += 1) {
28081
28602
  const a = tail[i] ?? "";
28603
+ if (a === "--no-worktree" || a === "--noworktree" || a === "--in-place") {
28604
+ inPlace = true;
28605
+ continue;
28606
+ }
28082
28607
  if (a === "--label" && tail[i + 1]) {
28083
28608
  label = tail[i + 1];
28084
28609
  i += 1;
@@ -28095,7 +28620,7 @@ function parseContextDriftTail(tail) {
28095
28620
  }
28096
28621
  rest.push(a);
28097
28622
  }
28098
- return { label, index, dryRun, rest };
28623
+ return { label, index, dryRun, inPlace, rest };
28099
28624
  }
28100
28625
  function stripRootWorktreeTokens(tokens) {
28101
28626
  const out = [...tokens];
@@ -28511,7 +29036,7 @@ function formatCliStderrLine(line, useAnsi) {
28511
29036
  }
28512
29037
 
28513
29038
  // src/cli/main.ts
28514
- var PKG_VERSION = "0.1.1";
29039
+ var PKG_VERSION = "0.3.0";
28515
29040
  function isNonEmptyFactoryFailureArray(x) {
28516
29041
  if (!Array.isArray(x) || x.length === 0) {
28517
29042
  return false;
@@ -28600,12 +29125,16 @@ function extractLegacyPositionals(argv) {
28600
29125
  }
28601
29126
  return [];
28602
29127
  }
29128
+ function rewriteArgvForCommanderParse(argv) {
29129
+ return argv.map((t) => t === "--no-worktree" ? "--in-place" : t);
29130
+ }
28603
29131
  function parseCliWithCommander(argv) {
28604
29132
  const program2 = createEasyspecsCliProgram();
28605
29133
  program2.version(PKG_VERSION, "--version", "output the version number");
28606
29134
  program2.exitOverride();
29135
+ const rawArgv = [...argv];
28607
29136
  try {
28608
- program2.parse(argv, { from: "user" });
29137
+ program2.parse(rewriteArgvForCommanderParse(rawArgv), { from: "user" });
28609
29138
  } catch (e) {
28610
29139
  const code = e?.code;
28611
29140
  if (code === "commander.helpDisplayed" || code === "commander.version") {
@@ -28628,7 +29157,7 @@ function parseCliWithCommander(argv) {
28628
29157
  help: false,
28629
29158
  version: false
28630
29159
  };
28631
- const positionals = extractLegacyPositionals(argv);
29160
+ const positionals = extractLegacyPositionals(rawArgv);
28632
29161
  return { flags, positionals };
28633
29162
  }
28634
29163
  function printHelp() {
@@ -28649,23 +29178,23 @@ function resolveAnalysisRoot(repoRoot, rootKind, worktreePath) {
28649
29178
  return repoRoot;
28650
29179
  }
28651
29180
  const wt = worktreePath?.trim();
28652
- if (wt && fs62.existsSync(path59.join(wt, ".git"))) {
28653
- return path59.resolve(wt);
29181
+ if (wt && fs63.existsSync(path61.join(wt, ".git"))) {
29182
+ return path61.resolve(wt);
28654
29183
  }
28655
29184
  throw new Error("worktree mode requires --worktree <path> to an existing analysis checkout.");
28656
29185
  }
28657
29186
  function resolveAdHocCheckoutRoot(_repoRoot, storage, worktreeFlag) {
28658
29187
  const w = worktreeFlag?.trim();
28659
29188
  if (w) {
28660
- const abs = path59.resolve(w);
28661
- if (fs62.existsSync(path59.join(abs, ".git"))) {
29189
+ const abs = path61.resolve(w);
29190
+ if (fs63.existsSync(path61.join(abs, ".git"))) {
28662
29191
  return abs;
28663
29192
  }
28664
29193
  throw new Error(`Invalid --worktree (not a git checkout): ${abs}`);
28665
29194
  }
28666
29195
  const snap = readAnalysisWorkspaceSnapshot(storage);
28667
29196
  const p = snap?.adHocWorktreePath?.trim();
28668
- if (p && fs62.existsSync(path59.join(p, ".git"))) {
29197
+ if (p && fs63.existsSync(path61.join(p, ".git"))) {
28669
29198
  return p;
28670
29199
  }
28671
29200
  throw new Error("No analysis checkout: run `easyspecs-cli run synthesis` first or pass `--worktree <path>`.");
@@ -28692,7 +29221,7 @@ async function runResumeRemediationPool(storage, repoRoot, analysisRoot, merged,
28692
29221
  requireOpenCode(merged, flags);
28693
29222
  const agentsDir = resolveOpenCodeAgentsDir(repoRoot, repoConfig);
28694
29223
  assertAgentsDirExists(agentsDir);
28695
- const ctxDir = path59.join(analysisRoot, ".gluecharm", "context");
29224
+ const ctxDir = path61.join(analysisRoot, ".gluecharm", "context");
28696
29225
  const snap = readArtefactRunSnapshot(storage);
28697
29226
  const rows = listMissingWorkstations(ctxDir, analysisRoot, snap);
28698
29227
  if (rows.length === 0) {
@@ -28710,7 +29239,7 @@ async function runResumeRemediationPool(storage, repoRoot, analysisRoot, merged,
28710
29239
  storageContext: storage,
28711
29240
  repositoryRoot: repoRoot,
28712
29241
  worktreeRoot: analysisRoot,
28713
- workspaceLabel: path59.basename(analysisRoot),
29242
+ workspaceLabel: path61.basename(analysisRoot),
28714
29243
  oc,
28715
29244
  log: (line) => logErr(flags, line),
28716
29245
  abortSignal: void 0,
@@ -28887,17 +29416,17 @@ async function main() {
28887
29416
  { easyspecs: { defaultGitRemoteUrl: url } },
28888
29417
  { warnMigration: (m) => logErr(flags, `[EasySpecs] ${m}`) }
28889
29418
  );
28890
- const path60 = easyspecsConfigPath(repoRoot);
29419
+ const path62 = easyspecsConfigPath(repoRoot);
28891
29420
  if (flags.json) {
28892
29421
  printJsonLine({
28893
29422
  command: "config set-git-remote",
28894
29423
  durationMs: Date.now() - t0,
28895
29424
  ok: true,
28896
- path: path60,
29425
+ path: path62,
28897
29426
  defaultGitRemoteUrl: cfg.easyspecs?.defaultGitRemoteUrl ?? ""
28898
29427
  });
28899
29428
  } else {
28900
- console.log(`Updated ${path60} \u2014 easyspecs.defaultGitRemoteUrl`);
29429
+ console.log(`Updated ${path62} \u2014 easyspecs.defaultGitRemoteUrl`);
28901
29430
  }
28902
29431
  process.exit(ExitCode.ok);
28903
29432
  } catch (e) {
@@ -28930,7 +29459,7 @@ async function main() {
28930
29459
  applyCliSessionPathFromRepoConfig(repoRoot, repoConfig);
28931
29460
  if (flags.sessionPath?.trim()) {
28932
29461
  const sp = flags.sessionPath.trim();
28933
- const abs = path59.isAbsolute(sp) ? path59.normalize(sp) : path59.resolve(repoRoot, sp);
29462
+ const abs = path61.isAbsolute(sp) ? path61.normalize(sp) : path61.resolve(repoRoot, sp);
28934
29463
  setCliSessionPathFromConfig(abs);
28935
29464
  }
28936
29465
  const apiResolved = initApiBaseUrlForCli(repoRoot, flags, repoConfig);
@@ -28987,20 +29516,18 @@ async function main() {
28987
29516
  logExitCodeSummary(ExitCode.usage, flags);
28988
29517
  process.exit(ExitCode.usage);
28989
29518
  }
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
- ];
29519
+ const readinessCtx = {
29520
+ cliVersion: PKG_VERSION,
29521
+ repoRootAbs: repoRoot,
29522
+ analysisRootAbs: repoRoot,
29523
+ apiBaseUrl: merged.apiBaseUrl,
29524
+ openCodeExecutable: merged.openCodeExecutable,
29525
+ openCodeSkipCredentialsCheck: merged.openCodeSkipCredentialsCheck,
29526
+ providerEnvFromConfig: merged.openCodeChildEnv,
29527
+ repoConfig
29528
+ };
29529
+ const facts = buildReadinessProbeFacts(readinessCtx);
29530
+ const lines = buildReadinessLineBlock(facts, readinessCtx);
29004
29531
  const inspectPayload = buildDoctorInspectPayload(merged, repoConfig);
29005
29532
  if (!flags.json) {
29006
29533
  const parts = [];
@@ -29016,6 +29543,12 @@ async function main() {
29016
29543
  if (modes.readiness) {
29017
29544
  envelope.lines = lines;
29018
29545
  envelope.cliVersion = PKG_VERSION;
29546
+ const jf = buildReadinessJsonFields(facts);
29547
+ envelope.modelConfigured = jf.modelConfigured;
29548
+ envelope.credentialsReady = jf.credentialsReady;
29549
+ envelope.openCodeConfigFiles = jf.openCodeConfigFiles;
29550
+ envelope.agentsDir = jf.agentsDir;
29551
+ envelope.agentsDirExists = jf.agentsDirExists;
29019
29552
  }
29020
29553
  if (modes.inspectConfig) {
29021
29554
  envelope.config = inspectPayload;
@@ -29167,7 +29700,7 @@ async function main() {
29167
29700
  const result = await runSynthesisPipeline(
29168
29701
  storage,
29169
29702
  repoRoot,
29170
- path59.basename(repoRoot),
29703
+ path61.basename(repoRoot),
29171
29704
  agentsDir,
29172
29705
  {
29173
29706
  ...merged.pipelineOpenCode
@@ -29222,7 +29755,7 @@ async function main() {
29222
29755
  if (sub === "reference-coverage") {
29223
29756
  const rootAbs = resolveAnalysisRoot(repoRoot, rootKind, worktree);
29224
29757
  requireMinimalGluecharmLayoutAt(rootAbs);
29225
- const contextDir2 = path59.join(rootAbs, ".gluecharm", "context");
29758
+ const contextDir2 = path61.join(rootAbs, ".gluecharm", "context");
29226
29759
  const res = runCoveragePipeline({
29227
29760
  repositoryRootAbs: rootAbs,
29228
29761
  contextDirAbs: contextDir2,
@@ -29245,7 +29778,7 @@ async function main() {
29245
29778
  if (sub === "coordination-duplicates") {
29246
29779
  const rootAbs = resolveAnalysisRoot(repoRoot, rootKind, worktree);
29247
29780
  requireMinimalGluecharmLayoutAt(rootAbs);
29248
- const contextDir2 = path59.join(rootAbs, ".gluecharm", "context");
29781
+ const contextDir2 = path61.join(rootAbs, ".gluecharm", "context");
29249
29782
  const res = runCoordinationDuplicatesDiagnosis({
29250
29783
  contextDirAbsolute: contextDir2,
29251
29784
  sourceRoot: rootKind === "worktree" ? "worktree" : "workspace"
@@ -29281,7 +29814,7 @@ async function main() {
29281
29814
  if (sub === "missing-artefacts") {
29282
29815
  const rootAbs = resolveAnalysisRoot(repoRoot, rootKind, worktree);
29283
29816
  requireMinimalGluecharmLayoutAt(rootAbs);
29284
- const ctxDir = path59.join(rootAbs, ".gluecharm", "context");
29817
+ const ctxDir = path61.join(rootAbs, ".gluecharm", "context");
29285
29818
  const storage = createFileBackedWorkspaceState(repoRoot);
29286
29819
  const snap = readArtefactRunSnapshot(storage);
29287
29820
  const rows = listMissingWorkstations(ctxDir, rootAbs, snap);
@@ -29331,7 +29864,7 @@ async function main() {
29331
29864
  });
29332
29865
  const bad = poolRes.cancelled || poolRes.failures > 0;
29333
29866
  if (!bad) {
29334
- const ctxDir = path59.join(analysisRoot, ".gluecharm", "context");
29867
+ const ctxDir = path61.join(analysisRoot, ".gluecharm", "context");
29335
29868
  const lg = runLinkMappingPipeline(ctxDir, { log: (line) => logErr(flags, line) });
29336
29869
  if (!lg.ok) {
29337
29870
  finish(OsExit.diagnoseZeroReferenceLinkMapping, {
@@ -29361,7 +29894,7 @@ async function main() {
29361
29894
  const worktree = wtExplicit ?? wtFromRoot;
29362
29895
  const rootAbs = resolveAnalysisRoot(repoRoot, rootKind, worktree);
29363
29896
  requireMinimalGluecharmLayoutAt(rootAbs);
29364
- const contextDir2 = path59.join(rootAbs, ".gluecharm", "context");
29897
+ const contextDir2 = path61.join(rootAbs, ".gluecharm", "context");
29365
29898
  const res = runLinkMappingPipeline(contextDir2, {
29366
29899
  log: (line) => logErr(flags, line)
29367
29900
  });
@@ -29380,10 +29913,19 @@ async function main() {
29380
29913
  if (!refPath) {
29381
29914
  finish(ExitCode.usage, {
29382
29915
  ok: false,
29383
- error: "Usage: easyspecs-cli context drift <referencePath> [--label <slug>] [--index <path>] [--dry-run]"
29916
+ error: "Usage: easyspecs-cli context drift <referencePath> [--label <slug>] [--index <path>] [--dry-run] [--in-place|--no-worktree|--noworktree]"
29384
29917
  });
29385
29918
  }
29386
29919
  const parsedTail = parseContextDriftTail(pos.slice(3));
29920
+ const { rootKind, worktree: wtFromRoot } = parseTailFlags(parsedTail.rest);
29921
+ const { worktree: wtExplicit } = parseWorktreeFlag(parsedTail.rest);
29922
+ const extWorktree = wtExplicit ?? wtFromRoot;
29923
+ if (parsedTail.inPlace && (rootKind === "worktree" || typeof extWorktree === "string" && extWorktree.trim().length > 0)) {
29924
+ finish(ExitCode.usage, {
29925
+ ok: false,
29926
+ error: "`--no-worktree` cannot be combined with `--root worktree` or `--worktree <path>`."
29927
+ });
29928
+ }
29387
29929
  const leftover = stripRootWorktreeTokens(parsedTail.rest);
29388
29930
  if (leftover.length > 0) {
29389
29931
  finish(ExitCode.usage, {
@@ -29392,11 +29934,11 @@ async function main() {
29392
29934
  });
29393
29935
  }
29394
29936
  requireMinimalGluecharmLayoutAt(repoRoot);
29395
- if (!parsedTail.dryRun) {
29396
- requireOpenCode(merged, flags);
29397
- }
29937
+ const readinessLog = (line) => {
29938
+ process.stderr.write(`${line}
29939
+ `);
29940
+ };
29398
29941
  const agentsDir = resolveOpenCodeAgentsDir(repoRoot, repoConfig);
29399
- assertAgentsDirExists(agentsDir);
29400
29942
  const storage = createFileBackedWorkspaceState(repoRoot);
29401
29943
  const ctrl = new AbortController();
29402
29944
  const dres = await runContextDriftFactory({
@@ -29409,8 +29951,11 @@ async function main() {
29409
29951
  label: parsedTail.label,
29410
29952
  indexOverrideArg: parsedTail.index,
29411
29953
  dryRun: parsedTail.dryRun,
29954
+ inPlace: parsedTail.inPlace,
29412
29955
  signal: ctrl.signal,
29413
- log: (line) => logErr(flags, line)
29956
+ log: (line) => logErr(flags, line),
29957
+ cliVersion: PKG_VERSION,
29958
+ readinessLog
29414
29959
  });
29415
29960
  if (dres.exitOk && dres.ok) {
29416
29961
  if (dres.driftReportPath && !flags.json && !dres.dryRun) {
@@ -29420,19 +29965,29 @@ async function main() {
29420
29965
  finish(ExitCode.ok, driftPayload);
29421
29966
  }
29422
29967
  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]));
29968
+ if (dres.code === "READINESS_FAILED") {
29969
+ const ec = dres.readinessExitCode ?? OsExit.readinessOpenCodeCredentials;
29970
+ const { exitOk: _ex, ...driftRest } = dres;
29971
+ finish(ec, {
29972
+ ...driftRest,
29973
+ ok: false,
29974
+ exitCode: ec
29975
+ });
29976
+ } else {
29977
+ const row2 = contextDriftFactoryFailureRow(dres.code, dres.error);
29978
+ const driftExit = contextDriftExitCodeFor(dres.code, dres.error);
29979
+ const { exitOk: _driftOkB, ...driftRest } = dres;
29980
+ const envelope = {
29981
+ ...driftRest,
29982
+ ok: false,
29983
+ factoryFailures: [row2],
29984
+ error: composeFactoryValidationError(dres.error, [row2])
29985
+ };
29986
+ if (isContextDriftSrs70ValidationExit(driftExit)) {
29987
+ Object.assign(envelope, primaryFailureAliases([row2]));
29988
+ }
29989
+ finish(driftExit, envelope);
29434
29990
  }
29435
- finish(driftExit, envelope);
29436
29991
  }
29437
29992
  finish(ExitCode.internal, { ok: false, error: "Unexpected context drift result shape." });
29438
29993
  }
@@ -29441,6 +29996,9 @@ async function main() {
29441
29996
  if (a === "--force-new-context-analysis") {
29442
29997
  continue;
29443
29998
  }
29999
+ if (a === "--no-worktree" || a === "--noworktree" || a === "--in-place") {
30000
+ continue;
30001
+ }
29444
30002
  if (a === "--upload") {
29445
30003
  finish(ExitCode.usage, {
29446
30004
  ok: false,
@@ -29455,10 +30013,11 @@ async function main() {
29455
30013
  }
29456
30014
  finish(ExitCode.usage, {
29457
30015
  ok: false,
29458
- error: `unknown analysis flag: ${a} (allowed: --force-new-context-analysis)`
30016
+ error: `unknown analysis flag: ${a} (allowed: --force-new-context-analysis, --in-place, --no-worktree, --noworktree)`
29459
30017
  });
29460
30018
  }
29461
30019
  const forceNewContextAnalysis = positionals.includes("--force-new-context-analysis");
30020
+ const analysisInPlace = positionals.includes("--no-worktree") || positionals.includes("--noworktree") || positionals.includes("--in-place");
29462
30021
  const cloudCached = readEasyspecsMergedSetting(
29463
30022
  repoConfig.easyspecs,
29464
30023
  "easyspecs.factory.cloudContextAnalyzed"
@@ -29481,11 +30040,19 @@ async function main() {
29481
30040
  });
29482
30041
  }
29483
30042
  requireMinimalGluecharmLayoutAt(repoRoot);
29484
- requireOpenCode(merged, flags);
29485
30043
  const agentsDir = resolveOpenCodeAgentsDir(repoRoot, repoConfig);
29486
- assertAgentsDirExists(agentsDir);
29487
30044
  const storage = createFileBackedWorkspaceState(repoRoot);
29488
30045
  const ctrl = new AbortController();
30046
+ const analysisReadinessCtx = {
30047
+ cliVersion: PKG_VERSION,
30048
+ repoRootAbs: repoRoot,
30049
+ analysisRootAbs: repoRoot,
30050
+ apiBaseUrl: merged.apiBaseUrl,
30051
+ openCodeExecutable: merged.openCodeExecutable,
30052
+ openCodeSkipCredentialsCheck: merged.openCodeSkipCredentialsCheck,
30053
+ providerEnvFromConfig: merged.openCodeChildEnv,
30054
+ repoConfig
30055
+ };
29489
30056
  const deps = buildFactoryDepsHeadless({
29490
30057
  storageContext: storage,
29491
30058
  repoRoot,
@@ -29496,15 +30063,22 @@ async function main() {
29496
30063
  }),
29497
30064
  log: (line) => logErr(flags, line),
29498
30065
  signal: ctrl.signal,
29499
- skipBackendSync: true
30066
+ skipBackendSync: true,
30067
+ inPlace: analysisInPlace,
30068
+ readiness: analysisReadinessCtx
29500
30069
  });
29501
30070
  const res = await runGenerateContextFactory(deps);
29502
30071
  if (res.ok && res.cancelled !== true && flags.promote !== false) {
29503
30072
  const snap = readAnalysisWorkspaceSnapshot(storage);
29504
30073
  const wt = snap?.adHocWorktreePath?.trim();
29505
30074
  if (wt) {
29506
- const sourceCtx = path59.join(wt, ".gluecharm", "context");
29507
- if (fs62.existsSync(sourceCtx)) {
30075
+ const sourceCtx = path61.join(wt, ".gluecharm", "context");
30076
+ if (path61.resolve(wt) === path61.resolve(repoRoot)) {
30077
+ logErr(
30078
+ flags,
30079
+ "[pipeline:analysis] promote skipped (in-place: analysis checkout is the repository root)"
30080
+ );
30081
+ } else if (fs63.existsSync(sourceCtx)) {
29508
30082
  const n = promoteContextDirectoryToWorkspaceFs(sourceCtx, repoRoot);
29509
30083
  logErr(flags, `[pipeline:analysis] promoted ${String(n.filesCopied)} file(s) \u2192 ${repoRoot}`);
29510
30084
  } else {
@@ -29524,19 +30098,24 @@ async function main() {
29524
30098
  ok: res.ok,
29525
30099
  cancelled: res.cancelled,
29526
30100
  totalElapsedMs: res.totalElapsedMs,
29527
- error: res.message
30101
+ error: res.message,
30102
+ ...analysisInPlace ? { analysisInPlace: true } : {}
29528
30103
  };
29529
30104
  if (!res.ok && !res.cancelled && res.factoryFailures && res.factoryFailures.length > 0) {
29530
30105
  analysisEnvelope.factoryFailures = res.factoryFailures;
29531
30106
  Object.assign(analysisEnvelope, primaryFailureAliases(res.factoryFailures));
29532
30107
  analysisEnvelope.error = composeFactoryValidationError(res.message, res.factoryFailures);
29533
30108
  }
30109
+ if (res.readinessFailure) {
30110
+ Object.assign(analysisEnvelope, res.readinessFailure);
30111
+ }
29534
30112
  finish(
29535
30113
  res.ok ? ExitCode.ok : res.cancelled ? ExitCode.cancelled : processExitFromNormalizedFactoryFailures(res.factoryFailures),
29536
30114
  analysisEnvelope
29537
30115
  );
29538
30116
  }
29539
30117
  if (pos[0] === "update" && pos[1] === "context") {
30118
+ let updateContextInPlace = false;
29540
30119
  for (const a of pos.slice(2)) {
29541
30120
  if (a === "--upload") {
29542
30121
  finish(ExitCode.usage, {
@@ -29544,14 +30123,20 @@ async function main() {
29544
30123
  error: "Removed flag: update context --upload. Run `easyspecs-cli upload context` or `upload republish` after update context completes."
29545
30124
  });
29546
30125
  }
30126
+ if (a === "--no-worktree" || a === "--noworktree" || a === "--in-place") {
30127
+ updateContextInPlace = true;
30128
+ continue;
30129
+ }
29547
30130
  finish(ExitCode.usage, { ok: false, error: `unknown update context flag: ${a}` });
29548
30131
  }
29549
30132
  requireMinimalGluecharmLayoutAt(repoRoot);
29550
- requireOpenCode(merged, flags);
29551
30133
  const agentsDir = resolveOpenCodeAgentsDir(repoRoot, repoConfig);
29552
- assertAgentsDirExists(agentsDir);
29553
30134
  const storage = createFileBackedWorkspaceState(repoRoot);
29554
30135
  const ctrl = new AbortController();
30136
+ const readinessLog = (line) => {
30137
+ process.stderr.write(`${line}
30138
+ `);
30139
+ };
29555
30140
  const ures = await runUpdateContextFactory({
29556
30141
  repoRootAbs: repoRoot,
29557
30142
  repoConfig,
@@ -29559,10 +30144,13 @@ async function main() {
29559
30144
  agentsDirFs: agentsDir,
29560
30145
  storage,
29561
30146
  signal: ctrl.signal,
29562
- log: (line) => logErr(flags, line)
30147
+ log: (line) => logErr(flags, line),
30148
+ inPlace: updateContextInPlace,
30149
+ cliVersion: PKG_VERSION,
30150
+ readinessLog
29563
30151
  });
29564
30152
  const { exitOk, ...payload } = ures;
29565
- const code = exitOk ? ExitCode.ok : ures.code === "MISSING_BASELINE" ? ExitCode.usage : OsExit.updateContextFactory;
30153
+ const code = exitOk ? ExitCode.ok : ures.code === "MISSING_BASELINE" ? ExitCode.usage : ures.code === "READINESS_FAILED" && typeof ures.readinessExitCode === "number" ? ures.readinessExitCode : OsExit.updateContextFactory;
29566
30154
  finish(code, payload);
29567
30155
  }
29568
30156
  if (pos[0] === "download" && pos[1] === "context") {
@@ -29587,10 +30175,10 @@ async function main() {
29587
30175
  finish(ExitCode.usage, { ok: false, error: `unknown download context flag: ${a}` });
29588
30176
  }
29589
30177
  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));
30178
+ const ctxDir = path61.resolve(path61.join(repoRoot, ".gluecharm", "context"));
30179
+ const gluecharmParent = path61.dirname(ctxDir);
30180
+ if (path61.basename(gluecharmParent) === ".gluecharm" && path61.basename(ctxDir) === "context") {
30181
+ requireMinimalGluecharmLayoutAt(path61.dirname(gluecharmParent));
29594
30182
  }
29595
30183
  const appIdRaw = getEasyspecsProjectIdFromRepoConfig(repoConfig)?.trim();
29596
30184
  if (!appIdRaw) {
@@ -29673,16 +30261,16 @@ async function main() {
29673
30261
  }
29674
30262
  const sess = sessRaw;
29675
30263
  requireMinimalGluecharmLayoutAt(repoRoot);
29676
- let ctxDir = path59.join(repoRoot, ".gluecharm", "context");
30264
+ let ctxDir = path61.join(repoRoot, ".gluecharm", "context");
29677
30265
  if (pos[1] === "republish") {
29678
30266
  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, ".."))) {
30267
+ const resolvedOverride = fromCfg && fromCfg.length > 0 ? path61.isAbsolute(fromCfg) ? path61.normalize(fromCfg) : path61.resolve(repoRoot, fromCfg) : "";
30268
+ if (resolvedOverride && fs63.existsSync(path61.join(resolvedOverride, ".."))) {
29681
30269
  ctxDir = resolvedOverride;
29682
30270
  } else {
29683
30271
  const storage = createFileBackedWorkspaceState(repoRoot);
29684
30272
  const snap = readAnalysisWorkspaceSnapshot(storage);
29685
- const wt = snap?.adHocWorktreePath && fs62.existsSync(path59.join(snap.adHocWorktreePath, ".gluecharm", "context")) ? path59.join(snap.adHocWorktreePath, ".gluecharm", "context") : "";
30273
+ const wt = snap?.adHocWorktreePath && fs63.existsSync(path61.join(snap.adHocWorktreePath, ".gluecharm", "context")) ? path61.join(snap.adHocWorktreePath, ".gluecharm", "context") : "";
29686
30274
  if (!wt) {
29687
30275
  finish(ExitCode.misconfiguration, {
29688
30276
  ok: false,
@@ -29692,10 +30280,10 @@ async function main() {
29692
30280
  ctxDir = wt;
29693
30281
  }
29694
30282
  }
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));
30283
+ const ctxResolved = path61.resolve(ctxDir);
30284
+ const gluecharmParent = path61.dirname(ctxResolved);
30285
+ if (path61.basename(gluecharmParent) === ".gluecharm" && path61.basename(ctxResolved) === "context") {
30286
+ requireMinimalGluecharmLayoutAt(path61.dirname(gluecharmParent));
29699
30287
  }
29700
30288
  const appIdRaw = getEasyspecsProjectIdFromRepoConfig(repoConfig)?.trim();
29701
30289
  if (!appIdRaw) {
@@ -29799,18 +30387,18 @@ async function main() {
29799
30387
  finish(failed ? ExitCode.upload : ExitCode.ok, primary);
29800
30388
  }
29801
30389
  if (pos[0] === "ace" && pos[1] === "clear") {
29802
- const learnings = path59.join(repoRoot, ".gluecharm", "context", "learnings");
29803
- if (!fs62.existsSync(learnings)) {
30390
+ const learnings = path61.join(repoRoot, ".gluecharm", "context", "learnings");
30391
+ if (!fs63.existsSync(learnings)) {
29804
30392
  finish(ExitCode.ok, { ok: true, message: "nothing to clear" });
29805
30393
  }
29806
- fs62.rmSync(learnings, { recursive: true, force: true });
30394
+ fs63.rmSync(learnings, { recursive: true, force: true });
29807
30395
  finish(ExitCode.ok, { ok: true, message: `cleared ${learnings}` });
29808
30396
  }
29809
30397
  if (pos[0] === "ace" && pos[1] === "learn") {
29810
30398
  requireOpenCode(merged, flags);
29811
30399
  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");
30400
+ const root = worktree && fs63.existsSync(path61.join(worktree, ".opencode", "schemas", "ace")) ? worktree : repoRoot;
30401
+ const contextDir2 = path61.join(root, ".gluecharm", "context");
29814
30402
  const traces = listAceTraceFiles(contextDir2);
29815
30403
  if (traces.length === 0) {
29816
30404
  finish(ExitCode.ok, { ok: true, message: "no traces", traceCount: 0 });
@@ -29834,8 +30422,8 @@ async function main() {
29834
30422
  if (pos[0] === "ace" && pos[1] === "auto-learn") {
29835
30423
  requireOpenCode(merged, flags);
29836
30424
  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");
30425
+ const root = worktree && fs63.existsSync(path61.join(worktree, ".git")) ? worktree : repoRoot;
30426
+ const contextDir2 = path61.join(root, ".gluecharm", "context");
29839
30427
  const pending = listPendingAceTraceFiles(contextDir2, root);
29840
30428
  if (pending.length === 0) {
29841
30429
  finish(ExitCode.ok, { ok: true, pending: 0 });