@gluecharm-lab/easyspecs-cli 0.0.17 → 0.0.19

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
@@ -960,7 +960,7 @@ var require_command = __commonJS({
960
960
  var EventEmitter = require("node:events").EventEmitter;
961
961
  var childProcess = require("node:child_process");
962
962
  var path60 = require("node:path");
963
- var fs61 = require("node:fs");
963
+ var fs60 = 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();
@@ -1893,10 +1893,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
1893
1893
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1894
1894
  function findFile(baseDir, baseName) {
1895
1895
  const localBin = path60.resolve(baseDir, baseName);
1896
- if (fs61.existsSync(localBin)) return localBin;
1896
+ if (fs60.existsSync(localBin)) return localBin;
1897
1897
  if (sourceExt.includes(path60.extname(baseName))) return void 0;
1898
1898
  const foundExt = sourceExt.find(
1899
- (ext) => fs61.existsSync(`${localBin}${ext}`)
1899
+ (ext) => fs60.existsSync(`${localBin}${ext}`)
1900
1900
  );
1901
1901
  if (foundExt) return `${localBin}${foundExt}`;
1902
1902
  return void 0;
@@ -1908,7 +1908,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1908
1908
  if (this._scriptPath) {
1909
1909
  let resolvedScriptPath;
1910
1910
  try {
1911
- resolvedScriptPath = fs61.realpathSync(this._scriptPath);
1911
+ resolvedScriptPath = fs60.realpathSync(this._scriptPath);
1912
1912
  } catch (err) {
1913
1913
  resolvedScriptPath = this._scriptPath;
1914
1914
  }
@@ -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, fs61, exportName) {
10625
+ function addFormats2(ajv2, list, fs60, 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, fs61[f]);
10630
+ ajv2.addFormat(f, fs60[f]);
10631
10631
  }
10632
10632
  module2.exports = exports2 = formatsPlugin;
10633
10633
  Object.defineProperty(exports2, "__esModule", { value: true });
@@ -10636,7 +10636,7 @@ var require_dist = __commonJS({
10636
10636
  });
10637
10637
 
10638
10638
  // src/cli/main.ts
10639
- var fs60 = __toESM(require("node:fs"));
10639
+ var fs59 = __toESM(require("node:fs"));
10640
10640
  var path59 = __toESM(require("node:path"));
10641
10641
 
10642
10642
  // src/cli/exitCodes.ts
@@ -10715,7 +10715,7 @@ function createEasyspecsCliProgram() {
10715
10715
  const runSynthesis = run.command("synthesis").description("Run synthesis pipeline");
10716
10716
  runSynthesis.command("resume-missing").description("Resume remediation pool for missing artefacts").option("--worktree <path>", "Path to an analysis checkout");
10717
10717
  runSynthesis.command("resume-synthesis").description("Resume synthesis pipeline").option("--worktree <path>", "Path to an analysis checkout");
10718
- program2.command("analysis").description("Run full Factory (Generate Context)").option("--synthesis-only", "Only run synthesis (skip factory phases)").option("--upload", "Upload context after generation").option("--force-new-context-analysis", "Force a new analysis even when cloud cache says analyzed");
10718
+ 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);
10719
10719
  const diagnose = program2.command("diagnose").description("Deterministic diagnostics");
10720
10720
  const addRootAndWorktree = (c) => c.option("--root <root>", "workspace|worktree").option("--worktree <path>", "Path to an analysis checkout");
10721
10721
  addRootAndWorktree(diagnose.command("reference-coverage").description("Compute reference coverage"));
@@ -10729,7 +10729,7 @@ function createEasyspecsCliProgram() {
10729
10729
  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")
10730
10730
  );
10731
10731
  const update = program2.command("update").description("Incremental context refresh");
10732
- update.command("context").description("Update context since last baseline (git delta, optional remediation, promote, upload)").option("--upload", "Upload modified context to EasySpecs after success");
10732
+ update.command("context").description("Update context since last baseline (git delta, optional remediation, promote)").allowUnknownOption(true);
10733
10733
  const download = program2.command("download").description("Download resources");
10734
10734
  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");
10735
10735
  const upload = program2.command("upload").description("Upload resources");
@@ -12507,18 +12507,18 @@ async function runParallelSinglesIntoAccum(requestJson, applicationId, paths, on
12507
12507
  const recentWaveMs = [];
12508
12508
  let idx = 0;
12509
12509
  const runOne = async (absPath) => {
12510
- const basename16 = path12.basename(absPath);
12510
+ const basename17 = path12.basename(absPath);
12511
12511
  let content;
12512
12512
  try {
12513
12513
  content = fs11.readFileSync(absPath, "utf8");
12514
12514
  } catch (e) {
12515
12515
  const msg = errorMessage(e);
12516
- logSrs13Failure(log, `read file file=${basename16}`, msg);
12516
+ logSrs13Failure(log, `read file file=${basename17}`, msg);
12517
12517
  accum.failed.push({ path: absPath, message: msg });
12518
12518
  return;
12519
12519
  }
12520
12520
  const existingId = resolveExistingId(absPath);
12521
- const payload = buildSrsDiscoverySavePayload(applicationId, basename16, content, existingId);
12521
+ const payload = buildSrsDiscoverySavePayload(applicationId, basename17, content, existingId);
12522
12522
  try {
12523
12523
  await postSingleCreate(requestJson, payload, log);
12524
12524
  accum.succeeded.push(absPath);
@@ -12532,7 +12532,7 @@ async function runParallelSinglesIntoAccum(requestJson, applicationId, paths, on
12532
12532
  throw e;
12533
12533
  }
12534
12534
  const msg = errorMessage(e);
12535
- logSrs13Failure(log, `POST /api/content/srs_discovery file=${basename16}`, msg);
12535
+ logSrs13Failure(log, `POST /api/content/srs_discovery file=${basename17}`, msg);
12536
12536
  accum.failed.push({ path: absPath, message: msg });
12537
12537
  }
12538
12538
  };
@@ -12614,18 +12614,18 @@ async function executeContextSrsDiscoveryUploadPhase(filePaths, phaseOpts, accum
12614
12614
  const items = [];
12615
12615
  const chunkPaths = [];
12616
12616
  for (const absPath of chunk) {
12617
- const basename16 = path12.basename(absPath);
12617
+ const basename17 = path12.basename(absPath);
12618
12618
  let content;
12619
12619
  try {
12620
12620
  content = fs11.readFileSync(absPath, "utf8");
12621
12621
  } catch (e) {
12622
12622
  const msg = errorMessage(e);
12623
- logSrs13Failure(log, `read file file=${basename16}`, msg);
12623
+ logSrs13Failure(log, `read file file=${basename17}`, msg);
12624
12624
  accum.failed.push({ path: absPath, message: msg });
12625
12625
  continue;
12626
12626
  }
12627
12627
  const existingId = resolveExistingId(absPath);
12628
- items.push(buildSrsDiscoverySavePayloadForBatch(applicationId, basename16, content, existingId));
12628
+ items.push(buildSrsDiscoverySavePayloadForBatch(applicationId, basename17, content, existingId));
12629
12629
  chunkPaths.push(absPath);
12630
12630
  }
12631
12631
  if (items.length === 0) {
@@ -12811,7 +12811,7 @@ async function fetchUploadCloudContextStatusWithR8Policy(args) {
12811
12811
  }
12812
12812
  }
12813
12813
  function shouldSkipAnalysisForCachedCloudContext(args) {
12814
- if (args.synthesisOnly || args.forceNewContextAnalysis) {
12814
+ if (args.forceNewContextAnalysis) {
12815
12815
  return false;
12816
12816
  }
12817
12817
  return args.cloudContextAnalyzed === true;
@@ -13101,9 +13101,9 @@ var ANALYSIS_STATIC_CONTEXT_OUTPUTS = [
13101
13101
  "tech-stack-list.json"
13102
13102
  ];
13103
13103
  function discoverDynamicAnalysisTestSteps(contextDir2) {
13104
- const staticOutputs = ANALYSIS_STATIC_CONTEXT_OUTPUTS.map((basename16) => ({
13105
- basename: basename16,
13106
- exists: nonEmptyContextFile(path14.join(contextDir2, basename16))
13104
+ const staticOutputs = ANALYSIS_STATIC_CONTEXT_OUTPUTS.map((basename17) => ({
13105
+ basename: basename17,
13106
+ exists: nonEmptyContextFile(path14.join(contextDir2, basename17))
13107
13107
  }));
13108
13108
  const featuresPath = path14.join(contextDir2, "features-list.json");
13109
13109
  const featuresData = readJson(featuresPath);
@@ -13274,8 +13274,8 @@ function aceCurationPath(contextDir2, agentStem, runId) {
13274
13274
  function aceConsolidatedSessionsJsonlPath(contextDir2) {
13275
13275
  return path15.join(aceLearningsRoot(contextDir2), ACE_CONSOLIDATED_SESSIONS_JSONL);
13276
13276
  }
13277
- function opencodeAceSchemaPath(worktreeRoot, basename16) {
13278
- return path15.join(worktreeRoot, ".opencode", "schemas", "ace", basename16);
13277
+ function opencodeAceSchemaPath(worktreeRoot, basename17) {
13278
+ return path15.join(worktreeRoot, ".opencode", "schemas", "ace", basename17);
13279
13279
  }
13280
13280
 
13281
13281
  // src/analysis/aceJsonValidate.ts
@@ -17149,16 +17149,16 @@ function outputPaths(step, worktreeRoot, listTarget) {
17149
17149
  if (!fe) {
17150
17150
  throw new Error("listUseCases requires listTarget.featureCode");
17151
17151
  }
17152
- const basename16 = `${fe}-use-cases-list.json`;
17153
- return { absolute: path26.join(ctx, basename16), basename: basename16 };
17152
+ const basename17 = `${fe}-use-cases-list.json`;
17153
+ return { absolute: path26.join(ctx, basename17), basename: basename17 };
17154
17154
  }
17155
17155
  case "reviewUseCasesList": {
17156
17156
  const fe = listTarget?.featureCode;
17157
17157
  if (!fe) {
17158
17158
  throw new Error("reviewUseCasesList requires listTarget.featureCode");
17159
17159
  }
17160
- const basename16 = `${fe}-use-cases-list.json`;
17161
- return { absolute: path26.join(ctx, basename16), basename: basename16 };
17160
+ const basename17 = `${fe}-use-cases-list.json`;
17161
+ return { absolute: path26.join(ctx, basename17), basename: basename17 };
17162
17162
  }
17163
17163
  case "listScenarios": {
17164
17164
  const fe = listTarget?.featureCode;
@@ -17166,8 +17166,8 @@ function outputPaths(step, worktreeRoot, listTarget) {
17166
17166
  if (!fe || !uc) {
17167
17167
  throw new Error("listScenarios requires listTarget.featureCode and useCaseCode");
17168
17168
  }
17169
- const basename16 = `${fe}_${uc}-scenarios-list.json`;
17170
- return { absolute: path26.join(ctx, basename16), basename: basename16 };
17169
+ const basename17 = `${fe}_${uc}-scenarios-list.json`;
17170
+ return { absolute: path26.join(ctx, basename17), basename: basename17 };
17171
17171
  }
17172
17172
  case "reviewScenariosList": {
17173
17173
  const fe = listTarget?.featureCode;
@@ -17175,24 +17175,24 @@ function outputPaths(step, worktreeRoot, listTarget) {
17175
17175
  if (!fe || !uc) {
17176
17176
  throw new Error("reviewScenariosList requires listTarget.featureCode and useCaseCode");
17177
17177
  }
17178
- const basename16 = `${fe}_${uc}-scenarios-list.json`;
17179
- return { absolute: path26.join(ctx, basename16), basename: basename16 };
17178
+ const basename17 = `${fe}_${uc}-scenarios-list.json`;
17179
+ return { absolute: path26.join(ctx, basename17), basename: basename17 };
17180
17180
  }
17181
17181
  case "listEntityFields": {
17182
17182
  const dm = listTarget?.entityCode;
17183
17183
  if (!dm) {
17184
17184
  throw new Error("listEntityFields requires listTarget.entityCode");
17185
17185
  }
17186
- const basename16 = `${dm}-fields-list.json`;
17187
- return { absolute: path26.join(ctx, basename16), basename: basename16 };
17186
+ const basename17 = `${dm}-fields-list.json`;
17187
+ return { absolute: path26.join(ctx, basename17), basename: basename17 };
17188
17188
  }
17189
17189
  case "reviewEntityFieldsList": {
17190
17190
  const dm = listTarget?.entityCode;
17191
17191
  if (!dm) {
17192
17192
  throw new Error("reviewEntityFieldsList requires listTarget.entityCode");
17193
17193
  }
17194
- const basename16 = `${dm}-fields-list.json`;
17195
- return { absolute: path26.join(ctx, basename16), basename: basename16 };
17194
+ const basename17 = `${dm}-fields-list.json`;
17195
+ return { absolute: path26.join(ctx, basename17), basename: basename17 };
17196
17196
  }
17197
17197
  default: {
17198
17198
  const _u = step;
@@ -18519,10 +18519,33 @@ Expected output: ${outputFileAbsolute}`;
18519
18519
  }
18520
18520
 
18521
18521
  // src/analysis/worktreeManager.ts
18522
- var import_child_process2 = require("child_process");
18522
+ var import_child_process3 = require("child_process");
18523
18523
  var fs29 = __toESM(require("fs"));
18524
18524
  var os2 = __toESM(require("os"));
18525
18525
  var path27 = __toESM(require("path"));
18526
+
18527
+ // src/analysis/gitWorktreeStaleRecovery.ts
18528
+ var import_child_process2 = require("child_process");
18529
+ function isMissingRegisteredWorktreeError(combinedStderrStdout) {
18530
+ return /missing but already registered worktree/i.test(combinedStderrStdout);
18531
+ }
18532
+ function gitWorktreePruneSync(repoRoot) {
18533
+ const r = (0, import_child_process2.spawnSync)("git", ["worktree", "prune"], {
18534
+ cwd: repoRoot,
18535
+ encoding: "utf-8",
18536
+ timeout: 6e4
18537
+ });
18538
+ if (r.status !== 0) {
18539
+ const msg = [r.stderr, r.stdout].filter(Boolean).join("\n").trim();
18540
+ return {
18541
+ ok: false,
18542
+ message: msg || `git worktree prune failed (exit ${String(r.status ?? "unknown")}).`
18543
+ };
18544
+ }
18545
+ return { ok: true };
18546
+ }
18547
+
18548
+ // src/analysis/worktreeManager.ts
18526
18549
  var EASYSPECS_WT_DIR_RE = /^easyspecs-(\d+)$/;
18527
18550
  function maxEasyspecsWorktreeIndex(parentDir) {
18528
18551
  let max = 0;
@@ -18563,7 +18586,7 @@ function allocateEasyspecsWorktreePath(parentDir) {
18563
18586
  return null;
18564
18587
  }
18565
18588
  function readHeadBranchShort(repoRoot) {
18566
- const r = (0, import_child_process2.spawnSync)("git", ["symbolic-ref", "--short", "-q", "HEAD"], {
18589
+ const r = (0, import_child_process3.spawnSync)("git", ["symbolic-ref", "--short", "-q", "HEAD"], {
18567
18590
  cwd: repoRoot,
18568
18591
  encoding: "utf-8",
18569
18592
  timeout: 3e4
@@ -18581,7 +18604,7 @@ function attachWorktreeHandle(worktreePath, repositoryRoot) {
18581
18604
  path: wt,
18582
18605
  repoRoot: repo,
18583
18606
  remove() {
18584
- (0, import_child_process2.spawnSync)("git", ["worktree", "remove", "--force", wt], {
18607
+ (0, import_child_process3.spawnSync)("git", ["worktree", "remove", "--force", wt], {
18585
18608
  cwd: repo,
18586
18609
  encoding: "utf-8",
18587
18610
  timeout: 6e4
@@ -18593,7 +18616,7 @@ function attachWorktreeHandle(worktreePath, repositoryRoot) {
18593
18616
  }
18594
18617
  };
18595
18618
  }
18596
- function createAnalysisWorktree(repoRoot) {
18619
+ function createAnalysisWorktree(repoRoot, options) {
18597
18620
  const parent = path27.join(os2.tmpdir(), "easyspecs-analysis");
18598
18621
  const wt = allocateEasyspecsWorktreePath(parent);
18599
18622
  if (!wt) {
@@ -18603,27 +18626,41 @@ function createAnalysisWorktree(repoRoot) {
18603
18626
  };
18604
18627
  }
18605
18628
  const sourceBranchAtCreation = readHeadBranchShort(repoRoot);
18606
- const r = (0, import_child_process2.spawnSync)("git", ["worktree", "add", "--detach", wt, "HEAD"], {
18607
- cwd: repoRoot,
18608
- encoding: "utf-8",
18609
- timeout: 12e4
18610
- });
18611
- if (r.status !== 0) {
18629
+ for (let attempt = 0; attempt < 2; attempt++) {
18630
+ const r = (0, import_child_process3.spawnSync)("git", ["worktree", "add", "--detach", wt, "HEAD"], {
18631
+ cwd: repoRoot,
18632
+ encoding: "utf-8",
18633
+ timeout: 12e4
18634
+ });
18635
+ if (r.status === 0) {
18636
+ try {
18637
+ writeAnalysisWorktreeMarker(wt, repoRoot);
18638
+ } catch {
18639
+ }
18640
+ return {
18641
+ ok: true,
18642
+ handle: attachWorktreeHandle(wt, repoRoot),
18643
+ ...sourceBranchAtCreation ? { sourceBranchAtCreation } : {}
18644
+ };
18645
+ }
18612
18646
  const msg = [r.stderr, r.stdout].filter(Boolean).join("\n").trim();
18613
- return {
18614
- ok: false,
18615
- error: msg || `git worktree add failed (exit ${r.status ?? "unknown"}). Is this folder a Git repository?`
18616
- };
18617
- }
18618
- try {
18619
- writeAnalysisWorktreeMarker(wt, repoRoot);
18620
- } catch {
18647
+ const fullMsg = msg || `git worktree add failed (exit ${r.status ?? "unknown"}). Is this folder a Git repository?`;
18648
+ if (attempt === 0 && isMissingRegisteredWorktreeError(fullMsg)) {
18649
+ const pr = gitWorktreePruneSync(repoRoot);
18650
+ if (pr.ok) {
18651
+ const wtName = path27.basename(wt);
18652
+ options?.log?.(`[worktree] git worktree prune \u2014 cleared stale registration for ${wtName} (${wt})`);
18653
+ continue;
18654
+ }
18655
+ return {
18656
+ ok: false,
18657
+ error: `${fullMsg}
18658
+ (git worktree prune failed: ${pr.message ?? "unknown"})`
18659
+ };
18660
+ }
18661
+ return { ok: false, error: fullMsg };
18621
18662
  }
18622
- return {
18623
- ok: true,
18624
- handle: attachWorktreeHandle(wt, repoRoot),
18625
- ...sourceBranchAtCreation ? { sourceBranchAtCreation } : {}
18626
- };
18663
+ throw new Error("createAnalysisWorktree: retry loop exited without result.");
18627
18664
  }
18628
18665
 
18629
18666
  // src/stores/workstationRunStore.ts
@@ -19593,8 +19630,8 @@ function renderProjectMdSections(contextDir2) {
19593
19630
  chunks.push("### Data model", "", dmLines.length ? dmLines.join("\n") : NONE_LINE, "");
19594
19631
  return chunks;
19595
19632
  }
19596
- function patchOneFile(contextDir2, basename16, innerChildren, innerParents, opts) {
19597
- const abs = path29.join(contextDir2, basename16);
19633
+ function patchOneFile(contextDir2, basename17, innerChildren, innerParents, opts) {
19634
+ const abs = path29.join(contextDir2, basename17);
19598
19635
  if (!fs31.existsSync(abs)) {
19599
19636
  return;
19600
19637
  }
@@ -19602,7 +19639,7 @@ function patchOneFile(contextDir2, basename16, innerChildren, innerParents, opts
19602
19639
  try {
19603
19640
  body = fs31.readFileSync(abs, "utf8");
19604
19641
  } catch (e) {
19605
- opts.log?.(`[pipeline:link-mapping] skip read ${basename16}: ${e instanceof Error ? e.message : String(e)}`);
19642
+ opts.log?.(`[pipeline:link-mapping] skip read ${basename17}: ${e instanceof Error ? e.message : String(e)}`);
19606
19643
  return;
19607
19644
  }
19608
19645
  let next = replaceOrAppendRegion(body, NAV_CHILDREN_START, NAV_CHILDREN_END, innerChildren);
@@ -19634,16 +19671,16 @@ function runLinkMappingPipeline(contextDirAbs, opts = {}) {
19634
19671
  };
19635
19672
  visitEdgeBasenames(edges.children);
19636
19673
  visitEdgeBasenames(edges.parents);
19637
- for (const basename16 of managedBasenames) {
19638
- if (basename16 === "project.md" || basename16 === "architecture.md") {
19674
+ for (const basename17 of managedBasenames) {
19675
+ if (basename17 === "project.md" || basename17 === "architecture.md") {
19639
19676
  continue;
19640
19677
  }
19641
- const abs = path29.join(contextDir2, basename16);
19678
+ const abs = path29.join(contextDir2, basename17);
19642
19679
  if (!fs31.existsSync(abs)) {
19643
19680
  continue;
19644
19681
  }
19645
- const childRows = edges.children.get(basename16) ?? [];
19646
- const parentRows = edges.parents.get(basename16) ?? [];
19682
+ const childRows = edges.children.get(basename17) ?? [];
19683
+ const parentRows = edges.parents.get(basename17) ?? [];
19647
19684
  const childLines = childRows.length === 0 ? NONE_LINE : childRows.map(
19648
19685
  (c) => bulletLink(c.title, markdownRelativeHref(abs, path29.join(contextDir2, c.basename)))
19649
19686
  ).join("\n");
@@ -19655,7 +19692,7 @@ function runLinkMappingPipeline(contextDirAbs, opts = {}) {
19655
19692
  ${childLines}
19656
19693
  `;
19657
19694
  const innerParents = buildInnerParents(parentLines.split("\n").filter(Boolean));
19658
- patchOneFile(contextDir2, basename16, innerChildren, innerParents, opts);
19695
+ patchOneFile(contextDir2, basename17, innerChildren, innerParents, opts);
19659
19696
  }
19660
19697
  const validation = validateEasyspecsNavLinksInContext(contextDir2);
19661
19698
  if (!validation.ok) {
@@ -19964,91 +20001,91 @@ function mdItem(id, parentIds, t) {
19964
20001
  };
19965
20002
  }
19966
20003
  function featureDetailTarget(contextDir2, code, name, slug) {
19967
- const basename16 = `${code}-${slug}.md`;
20004
+ const basename17 = `${code}-${slug}.md`;
19968
20005
  return {
19969
20006
  openCodeAgentStem: "agent-md-feature-detail",
19970
20007
  agentId: "ctx-md-feature-detail",
19971
20008
  displayName: "Feature detail",
19972
- outputBasename: basename16,
20009
+ outputBasename: basename17,
19973
20010
  taskDescription: `Document feature **${code}** (**${name}**, slug **${slug}**) per \`.gluecharm/context/features-list.json\`: scope, behaviour, main dependencies, entry points, and links to code under the worktree. Write exactly one markdown file at the output path; cite substantive claims with file and line (or range).`,
19974
- exists: fs34.existsSync(path32.join(contextDir2, basename16)) && fs34.statSync(path32.join(contextDir2, basename16)).size > 0
20011
+ exists: fs34.existsSync(path32.join(contextDir2, basename17)) && fs34.statSync(path32.join(contextDir2, basename17)).size > 0
19975
20012
  };
19976
20013
  }
19977
20014
  function viewDetailTarget(row2, contextDir2) {
19978
- const basename16 = `${row2.code}-${row2.slug}.md`;
20015
+ const basename17 = `${row2.code}-${row2.slug}.md`;
19979
20016
  return {
19980
20017
  openCodeAgentStem: "agent-md-view-detail",
19981
20018
  agentId: "ctx-md-view-detail",
19982
20019
  displayName: "View detail",
19983
- outputBasename: basename16,
20020
+ outputBasename: basename17,
19984
20021
  taskDescription: `Describe view **${row2.code}** (**${row2.name}**, slug **${row2.slug}**) per \`.gluecharm/context/experiences-list.json\`: purpose, layout, controls, navigation, data shown; ground in components and routes.`,
19985
- exists: fs34.existsSync(path32.join(contextDir2, basename16)) && fs34.statSync(path32.join(contextDir2, basename16)).size > 0
20022
+ exists: fs34.existsSync(path32.join(contextDir2, basename17)) && fs34.statSync(path32.join(contextDir2, basename17)).size > 0
19986
20023
  };
19987
20024
  }
19988
20025
  function interactionDetailTarget(viewCode, ix, contextDir2) {
19989
- const basename16 = `${viewCode}_${ix.code}-${ix.slug}.md`;
20026
+ const basename17 = `${viewCode}_${ix.code}-${ix.slug}.md`;
19990
20027
  return {
19991
20028
  openCodeAgentStem: "agent-md-interaction-detail",
19992
20029
  agentId: "ctx-md-interaction-detail",
19993
20030
  displayName: "Interaction detail",
19994
- outputBasename: basename16,
20031
+ outputBasename: basename17,
19995
20032
  taskDescription: `Document interaction **${ix.code}** (**${ix.name}**) on view **${viewCode}** per \`.gluecharm/context/experiences-list.json\`.`,
19996
- exists: fs34.existsSync(path32.join(contextDir2, basename16)) && fs34.statSync(path32.join(contextDir2, basename16)).size > 0
20033
+ exists: fs34.existsSync(path32.join(contextDir2, basename17)) && fs34.statSync(path32.join(contextDir2, basename17)).size > 0
19997
20034
  };
19998
20035
  }
19999
20036
  function serviceDetailTarget(row2, contextDir2) {
20000
- const basename16 = `${row2.code}-${row2.slug}.md`;
20037
+ const basename17 = `${row2.code}-${row2.slug}.md`;
20001
20038
  return {
20002
20039
  openCodeAgentStem: "agent-md-service-detail",
20003
20040
  agentId: "ctx-md-service-detail",
20004
20041
  displayName: "Service detail",
20005
- outputBasename: basename16,
20042
+ outputBasename: basename17,
20006
20043
  taskDescription: `Describe service **${row2.code}** (**${row2.name}**, slug **${row2.slug}**) per \`.gluecharm/context/services-list.json\`: responsibilities, consumers, errors, integration points.`,
20007
- exists: fs34.existsSync(path32.join(contextDir2, basename16)) && fs34.statSync(path32.join(contextDir2, basename16)).size > 0
20044
+ exists: fs34.existsSync(path32.join(contextDir2, basename17)) && fs34.statSync(path32.join(contextDir2, basename17)).size > 0
20008
20045
  };
20009
20046
  }
20010
20047
  function methodDetailTarget(svc, m, contextDir2) {
20011
- const basename16 = `${svc.code}_${m.code}-${m.slug}.md`;
20048
+ const basename17 = `${svc.code}_${m.code}-${m.slug}.md`;
20012
20049
  return {
20013
20050
  openCodeAgentStem: "agent-md-method-detail",
20014
20051
  agentId: "ctx-md-method-detail",
20015
20052
  displayName: "Method detail",
20016
- outputBasename: basename16,
20053
+ outputBasename: basename17,
20017
20054
  taskDescription: `Document method **${m.code}** (**${m.name}**) on service **${svc.code}** per \`.gluecharm/context/services-list.json\`.`,
20018
- exists: fs34.existsSync(path32.join(contextDir2, basename16)) && fs34.statSync(path32.join(contextDir2, basename16)).size > 0
20055
+ exists: fs34.existsSync(path32.join(contextDir2, basename17)) && fs34.statSync(path32.join(contextDir2, basename17)).size > 0
20019
20056
  };
20020
20057
  }
20021
20058
  function entityDetailTarget(dmCode, ename, slug, contextDir2) {
20022
- const basename16 = `${dmCode}-${slug}.md`;
20059
+ const basename17 = `${dmCode}-${slug}.md`;
20023
20060
  return {
20024
20061
  openCodeAgentStem: "agent-md-entity-detail",
20025
20062
  agentId: "ctx-md-entity-detail",
20026
20063
  displayName: "Entity detail",
20027
- outputBasename: basename16,
20064
+ outputBasename: basename17,
20028
20065
  taskDescription: `Describe entity **${dmCode}** (**${ename}**, slug **${slug}**) per \`.gluecharm/context/data-model-list.json\`: lifecycle, invariants, storage, ORM/schema mapping.`,
20029
- exists: fs34.existsSync(path32.join(contextDir2, basename16)) && fs34.statSync(path32.join(contextDir2, basename16)).size > 0
20066
+ exists: fs34.existsSync(path32.join(contextDir2, basename17)) && fs34.statSync(path32.join(contextDir2, basename17)).size > 0
20030
20067
  };
20031
20068
  }
20032
20069
  function fieldDetailTarget(dmCode, fdCode, fname, fSlug, contextDir2) {
20033
- const basename16 = `${dmCode}_${fdCode}-${fSlug}.md`;
20070
+ const basename17 = `${dmCode}_${fdCode}-${fSlug}.md`;
20034
20071
  return {
20035
20072
  openCodeAgentStem: "agent-md-field-detail",
20036
20073
  agentId: "ctx-md-field-detail",
20037
20074
  displayName: "Field detail",
20038
- outputBasename: basename16,
20075
+ outputBasename: basename17,
20039
20076
  taskDescription: `Document field **${fdCode}** (**${fname}**) on entity **${dmCode}** per \`.gluecharm/context/${dmCode}-fields-list.json\`. Cite types and constraints with file and line.`,
20040
- exists: fs34.existsSync(path32.join(contextDir2, basename16)) && fs34.statSync(path32.join(contextDir2, basename16)).size > 0
20077
+ exists: fs34.existsSync(path32.join(contextDir2, basename17)) && fs34.statSync(path32.join(contextDir2, basename17)).size > 0
20041
20078
  };
20042
20079
  }
20043
20080
  function toolDetailTarget(row2, contextDir2) {
20044
- const basename16 = `${row2.code}-${row2.slug}.md`;
20081
+ const basename17 = `${row2.code}-${row2.slug}.md`;
20045
20082
  return {
20046
20083
  openCodeAgentStem: "agent-md-tool-detail",
20047
20084
  agentId: "ctx-md-tool-detail",
20048
20085
  displayName: "Tool detail",
20049
- outputBasename: basename16,
20086
+ outputBasename: basename17,
20050
20087
  taskDescription: `Describe tool **${row2.code}** (**${row2.name}**, slug **${row2.slug}**) per \`.gluecharm/context/tech-stack-list.json\`: role, version hints, configuration, boundaries.`,
20051
- exists: fs34.existsSync(path32.join(contextDir2, basename16)) && fs34.statSync(path32.join(contextDir2, basename16)).size > 0
20088
+ exists: fs34.existsSync(path32.join(contextDir2, basename17)) && fs34.statSync(path32.join(contextDir2, basename17)).size > 0
20052
20089
  };
20053
20090
  }
20054
20091
  function useCaseDetailTarget(feCode, ucCode, ucName, ucSlug, contextDir2) {
@@ -20065,14 +20102,14 @@ Follow bundled agent **agent-md-use-case-detail**: include **## Data inputs and
20065
20102
  };
20066
20103
  }
20067
20104
  function scenarioDetailTarget(feCode, ucCode, scCode, scName, contextDir2) {
20068
- const basename16 = `${feCode}_${ucCode}_${scCode}.md`;
20105
+ const basename17 = `${feCode}_${ucCode}_${scCode}.md`;
20069
20106
  return {
20070
20107
  openCodeAgentStem: "agent-md-scenario-detail",
20071
20108
  agentId: "ctx-md-scenario-detail",
20072
20109
  displayName: "Scenario detail",
20073
- outputBasename: basename16,
20110
+ outputBasename: basename17,
20074
20111
  taskDescription: `Document scenario **${scCode}** (**${scName}**) for **${feCode}** / **${ucCode}** per \`.gluecharm/context/${feCode}_${ucCode}-scenarios-list.json\`. Cite steps with file and line where possible.`,
20075
- exists: fs34.existsSync(path32.join(contextDir2, basename16)) && fs34.statSync(path32.join(contextDir2, basename16)).size > 0
20112
+ exists: fs34.existsSync(path32.join(contextDir2, basename17)) && fs34.statSync(path32.join(contextDir2, basename17)).size > 0
20076
20113
  };
20077
20114
  }
20078
20115
  function parentsDone(item, byId) {
@@ -20298,15 +20335,15 @@ function expandAfterSuccess(completed, contextDir2, byId, fifo) {
20298
20335
  return;
20299
20336
  }
20300
20337
  if (completed.kind === "markdown") {
20301
- const basename16 = completed.payload.outputBasename;
20338
+ const basename17 = completed.payload.outputBasename;
20302
20339
  const mdId = completed.id;
20303
- const feFromFeatureMd = basename16.match(/^(FE-\d+)-[^/]+\.md$/);
20340
+ const feFromFeatureMd = basename17.match(/^(FE-\d+)-[^/]+\.md$/);
20304
20341
  if (feFromFeatureMd) {
20305
20342
  const fe = feFromFeatureMd[1];
20306
20343
  add(coordItem(`coord:uc:${fe}`, [mdId], "listUseCases", { featureCode: fe }));
20307
20344
  return;
20308
20345
  }
20309
- const xpFromView = basename16.match(/^(XP-\d+)-[^/]+\.md$/);
20346
+ const xpFromView = basename17.match(/^(XP-\d+)-[^/]+\.md$/);
20310
20347
  if (xpFromView) {
20311
20348
  const xp = xpFromView[1];
20312
20349
  const row2 = discoverExperienceTreeRows(contextDir2).find((r) => r.code === xp);
@@ -20318,7 +20355,7 @@ function expandAfterSuccess(completed, contextDir2, byId, fifo) {
20318
20355
  }
20319
20356
  return;
20320
20357
  }
20321
- const svFromSvc = basename16.match(/^(SV-\d+)-[^/]+\.md$/);
20358
+ const svFromSvc = basename17.match(/^(SV-\d+)-[^/]+\.md$/);
20322
20359
  if (svFromSvc) {
20323
20360
  const sv = svFromSvc[1];
20324
20361
  const srow = discoverServiceTreeRows(contextDir2).find((r) => r.code === sv);
@@ -20330,7 +20367,7 @@ function expandAfterSuccess(completed, contextDir2, byId, fifo) {
20330
20367
  }
20331
20368
  return;
20332
20369
  }
20333
- const dmFromEnt = basename16.match(/^(DM-\d+)-[^/]+\.md$/);
20370
+ const dmFromEnt = basename17.match(/^(DM-\d+)-[^/]+\.md$/);
20334
20371
  if (dmFromEnt) {
20335
20372
  const dm = dmFromEnt[1];
20336
20373
  add(coordItem(`coord:ef:${dm}`, [mdId], "listEntityFields", { entityCode: dm }));
@@ -20634,7 +20671,7 @@ async function prepareSynthesisWorktree(storageContext, repoRoot, log, options)
20634
20671
  if (options?.clearPriorArtefactRun !== false) {
20635
20672
  await clearArtefactRun(storageContext);
20636
20673
  }
20637
- const wt = createAnalysisWorktree(repoRoot);
20674
+ const wt = createAnalysisWorktree(repoRoot, { log });
20638
20675
  if (!wt.ok) {
20639
20676
  return { ok: false, error: wt.error };
20640
20677
  }
@@ -21596,8 +21633,8 @@ function expectedFeatureDetailBasenameFromRow(row2) {
21596
21633
  }
21597
21634
  return `${code}-${slug}.md`;
21598
21635
  }
21599
- function ctxPath(contextDir2, basename16) {
21600
- return path34.join(contextDir2, basename16);
21636
+ function ctxPath(contextDir2, basename17) {
21637
+ return path34.join(contextDir2, basename17);
21601
21638
  }
21602
21639
  function pushTarget(targets, stem, outputBasename, taskDescription, contextDir2) {
21603
21640
  const meta = STEM_TO_AGENT[stem];
@@ -21626,11 +21663,11 @@ function discoverDetailMarkdownGroups(contextDir2) {
21626
21663
  continue;
21627
21664
  }
21628
21665
  const name = safeStr4(row2.name) || code;
21629
- const basename16 = `${code}-${slug}.md`;
21666
+ const basename17 = `${code}-${slug}.md`;
21630
21667
  pushTarget(
21631
21668
  featureTargets,
21632
21669
  "agent-md-feature-detail",
21633
- basename16,
21670
+ basename17,
21634
21671
  `Document feature **${code}** (**${name}**, slug **${slug}**) per \`.gluecharm/context/features-list.json\`: scope, behaviour, main dependencies, entry points, and links to code under the worktree. Write exactly one markdown file at the output path; cite substantive claims with file and line (or range).`,
21635
21672
  contextDir2
21636
21673
  );
@@ -22278,7 +22315,7 @@ async function runRemediationPipelineMissingPass(p) {
22278
22315
  }
22279
22316
 
22280
22317
  // src/pipelines/coverage/coveragePipeline.ts
22281
- var import_child_process3 = require("child_process");
22318
+ var import_child_process4 = require("child_process");
22282
22319
  var fs39 = __toESM(require("fs"));
22283
22320
  var path38 = __toESM(require("path"));
22284
22321
 
@@ -22382,8 +22419,8 @@ function tryLoadGitNonIgnoredPathSet(repositoryRootAbs) {
22382
22419
  env
22383
22420
  };
22384
22421
  try {
22385
- const tracked = (0, import_child_process3.execFileSync)("git", ["-c", "core.quotepath=false", "ls-files", "-z"], opts);
22386
- const others = (0, import_child_process3.execFileSync)(
22422
+ const tracked = (0, import_child_process4.execFileSync)("git", ["-c", "core.quotepath=false", "ls-files", "-z"], opts);
22423
+ const others = (0, import_child_process4.execFileSync)(
22387
22424
  "git",
22388
22425
  ["-c", "core.quotepath=false", "ls-files", "-z", "--others", "--exclude-standard"],
22389
22426
  opts
@@ -22822,8 +22859,8 @@ function formatAjvErrors6(errors) {
22822
22859
  });
22823
22860
  }
22824
22861
  var ajv = new import__6.default({ allErrors: true, strict: false });
22825
- function compileSchema(basename16) {
22826
- const schemaPath = path39.join(schemasDir(), basename16);
22862
+ function compileSchema(basename17) {
22863
+ const schemaPath = path39.join(schemasDir(), basename17);
22827
22864
  const schemaRaw = stripUtf8Bom5(fs40.readFileSync(schemaPath, "utf-8"));
22828
22865
  const schema = JSON.parse(schemaRaw);
22829
22866
  return ajv.compile(schema);
@@ -24700,7 +24737,6 @@ function stderrLinesForFactoryFailures(failures, exitCode) {
24700
24737
  }
24701
24738
 
24702
24739
  // src/factory/updateContext/runUpdateContextFactory.ts
24703
- var fs49 = __toESM(require("node:fs"));
24704
24740
  var path48 = __toESM(require("node:path"));
24705
24741
 
24706
24742
  // src/factory/updateContext/updateContextBaseline.ts
@@ -24886,7 +24922,7 @@ function renderChangesSinceDateMarkdown(p) {
24886
24922
  `- **Paths touched (union):** ${String(p.touchedPathsPosix.length)}`,
24887
24923
  `- **Remediation:** ${p.remediationSkipped ? `skipped (${p.remediationSkipReason ?? "n/a"})` : "ran"}`,
24888
24924
  `- **Promote:** ${p.promoteEffective ? "yes" : "no"}`,
24889
- `- **Upload requested:** ${p.uploadRequested ? "yes" : "no"}`,
24925
+ `- **Upload:** run \`easyspecs-cli upload context\` (or \`upload republish\`) after this command if you need cloud sync`,
24890
24926
  `- **Analysis worktree:** \`${p.worktreeRootAbs}\``,
24891
24927
  "",
24892
24928
  "## Commits (oldest \u2192 newest)",
@@ -24974,41 +25010,10 @@ var REMEDIATION_CHUNK_MAX = 40;
24974
25010
  function contextDirUnderRoot(wtRoot) {
24975
25011
  return path48.join(wtRoot, ".gluecharm", "context");
24976
25012
  }
24977
- function listContextPathsWithMtimeSince(contextDirAbs, sinceMs) {
24978
- const out = [];
24979
- const walk = (dir) => {
24980
- let entries;
24981
- try {
24982
- entries = fs49.readdirSync(dir, { withFileTypes: true });
24983
- } catch {
24984
- return;
24985
- }
24986
- for (const e of entries) {
24987
- const full = path48.join(dir, e.name);
24988
- if (e.isDirectory()) {
24989
- if (e.name === ".git") {
24990
- continue;
24991
- }
24992
- walk(full);
24993
- } else if (e.isFile()) {
24994
- try {
24995
- if (fs49.statSync(full).mtimeMs >= sinceMs) {
24996
- out.push(full);
24997
- }
24998
- } catch {
24999
- }
25000
- }
25001
- }
25002
- };
25003
- walk(contextDirAbs);
25004
- out.sort((a, b) => a.localeCompare(b));
25005
- return out;
25006
- }
25007
25013
  async function runUpdateContextFactory(deps) {
25008
- const runStartMs = Date.now();
25009
25014
  const baseMeta = {
25010
25015
  command: "update_context",
25011
- uploadRequested: deps.wantsUpload
25016
+ uploadRequested: false
25012
25017
  };
25013
25018
  const baseline = resolveUpdateContextBaseline(deps.repoRootAbs, deps.repoConfig);
25014
25019
  if (!baseline) {
@@ -25123,7 +25128,6 @@ async function runUpdateContextFactory(deps) {
25123
25128
  commitsInOrder: gitWin.commitsInOrder,
25124
25129
  touchedPathsPosix: gitWin.touchedPathsPosix,
25125
25130
  promoteEffective,
25126
- uploadRequested: deps.wantsUpload,
25127
25131
  remediationSkipped,
25128
25132
  remediationSkipReason,
25129
25133
  worktreeRootAbs: handle.path
@@ -25261,52 +25265,8 @@ async function runUpdateContextFactory(deps) {
25261
25265
  };
25262
25266
  }
25263
25267
  }
25264
- let filesUploaded = 0;
25265
- let uploadSkipped = !deps.wantsUpload;
25266
- if (deps.wantsUpload) {
25267
- if (!deps.runUploadFn) {
25268
- finalizeWt?.();
25269
- return {
25270
- exitOk: false,
25271
- ok: false,
25272
- code: "UPLOAD_FAILED",
25273
- error: "Upload requested but no upload implementation was wired.",
25274
- ...baseMeta
25275
- };
25276
- }
25277
- const cand = listContextPathsWithMtimeSince(ctxDirAbs, runStartMs);
25278
- if (cand.length === 0) {
25279
- deps.log("[update-context] upload \u2014 no context files modified at or after run start (skip).");
25280
- uploadSkipped = true;
25281
- } else {
25282
- uploadSkipped = false;
25283
- const ur = await deps.runUploadFn({ wtContextDir: ctxDirAbs, filePaths: cand });
25284
- if (!ur.ok) {
25285
- finalizeWt?.();
25286
- return {
25287
- exitOk: false,
25288
- ok: false,
25289
- code: "UPLOAD_FAILED",
25290
- error: ur.message ?? "Upload failed.",
25291
- baselineDate: baseline.baselineIsoUtc,
25292
- baselineSource: baseline.source,
25293
- headCommit: gitWin.headCommit,
25294
- rangeStartCommit: gitWin.rangeStartCommit,
25295
- commitsReviewed: gitWin.commitsInOrder.length,
25296
- filesDetected: inventory.length,
25297
- filesRemediated,
25298
- analysisWorktreeRoot: handle.path,
25299
- promoted,
25300
- remediationSkipped,
25301
- ...remediationSkipReason ? { skipReason: remediationSkipReason } : {},
25302
- changesReportRelativePath: ".gluecharm/context/changes-since-date.md",
25303
- uploadSkipped: false,
25304
- ...baseMeta
25305
- };
25306
- }
25307
- filesUploaded = ur.uploadedCount ?? cand.length;
25308
- }
25309
- }
25268
+ const uploadSkipped = true;
25269
+ const filesUploaded = 0;
25310
25270
  let persisted = false;
25311
25271
  try {
25312
25272
  persistUpdateContextLastRunAt(deps.repoRootAbs, (/* @__PURE__ */ new Date()).toISOString());
@@ -25338,11 +25298,11 @@ async function runUpdateContextFactory(deps) {
25338
25298
  }
25339
25299
 
25340
25300
  // src/factory/contextDrift/runContextDriftFactory.ts
25341
- var fs55 = __toESM(require("node:fs"));
25301
+ var fs54 = __toESM(require("node:fs"));
25342
25302
  var path53 = __toESM(require("node:path"));
25343
25303
 
25344
25304
  // src/factory/contextDrift/contextDriftManifest.ts
25345
- var fs50 = __toESM(require("node:fs"));
25305
+ var fs49 = __toESM(require("node:fs"));
25346
25306
  var path49 = __toESM(require("node:path"));
25347
25307
  var MAX_REFERENCE_BYTES = 256 * 1024;
25348
25308
  var MAX_EVIDENCE_FILES = 300;
@@ -25351,7 +25311,7 @@ var MAX_EXCERPT = 4e3;
25351
25311
  function readFileLimited(abs, maxBytes) {
25352
25312
  let buf;
25353
25313
  try {
25354
- buf = fs50.readFileSync(abs);
25314
+ buf = fs49.readFileSync(abs);
25355
25315
  } catch {
25356
25316
  return { text: "", truncated: false };
25357
25317
  }
@@ -25364,14 +25324,14 @@ function collectEvidencePaths(repoRoot) {
25364
25324
  const roots = ["src", "test", "tests", "packages", ".gluecharm", "scripts"];
25365
25325
  for (const rel of roots) {
25366
25326
  const abs = path49.join(repoRoot, rel);
25367
- if (!fs50.existsSync(abs)) {
25327
+ if (!fs49.existsSync(abs)) {
25368
25328
  continue;
25369
25329
  }
25370
25330
  walkFiles(abs, repoRoot, out, 0);
25371
25331
  }
25372
25332
  for (const leaf of ["package.json", "tsconfig.json"]) {
25373
25333
  const abs = path49.join(repoRoot, leaf);
25374
- if (fs50.existsSync(abs) && fs50.statSync(abs).isFile()) {
25334
+ if (fs49.existsSync(abs) && fs49.statSync(abs).isFile()) {
25375
25335
  const r = path49.relative(repoRoot, abs).split(path49.sep).join("/");
25376
25336
  out.push(r);
25377
25337
  }
@@ -25389,7 +25349,7 @@ function walkFiles(dir, repoRoot, out, depth) {
25389
25349
  }
25390
25350
  let entries;
25391
25351
  try {
25392
- entries = fs50.readdirSync(dir, { withFileTypes: true });
25352
+ entries = fs49.readdirSync(dir, { withFileTypes: true });
25393
25353
  } catch {
25394
25354
  return;
25395
25355
  }
@@ -25426,7 +25386,7 @@ function buildComparisonManifest(args) {
25426
25386
  const evidenceFiles = [];
25427
25387
  for (const rel of evidencePathsTrimmed) {
25428
25388
  const abs = path49.join(args.worktreeRoot, ...rel.split("/"));
25429
- const st = fs50.existsSync(abs) ? fs50.statSync(abs) : null;
25389
+ const st = fs49.existsSync(abs) ? fs49.statSync(abs) : null;
25430
25390
  const size = st && st.isFile() ? st.size : 0;
25431
25391
  const { text, truncated } = readFileLimited(abs, MAX_EVIDENCE_READ);
25432
25392
  const excerpt = truncated ? `${text.slice(0, MAX_EXCERPT)}
@@ -25448,7 +25408,7 @@ function buildComparisonManifest(args) {
25448
25408
  }
25449
25409
 
25450
25410
  // src/factory/contextDrift/contextDriftAgent.ts
25451
- var fs51 = __toESM(require("node:fs"));
25411
+ var fs50 = __toESM(require("node:fs"));
25452
25412
  var path50 = __toESM(require("node:path"));
25453
25413
 
25454
25414
  // src/factory/contextDrift/contextDriftPayload.ts
@@ -25595,16 +25555,16 @@ function buildDriftPrompt(args) {
25595
25555
  }
25596
25556
  async function runDriftComparisonOpenCode(args) {
25597
25557
  const runDir = path50.join(args.worktreeRoot, ".opencode", "_run");
25598
- fs51.mkdirSync(runDir, { recursive: true });
25558
+ fs50.mkdirSync(runDir, { recursive: true });
25599
25559
  const manifestPath = path50.join(runDir, "context-drift-manifest.json");
25600
25560
  const outputPath = path50.join(runDir, "context-drift-payload.json");
25601
- fs51.writeFileSync(manifestPath, `${JSON.stringify(args.manifestObject, null, 2)}
25561
+ fs50.writeFileSync(manifestPath, `${JSON.stringify(args.manifestObject, null, 2)}
25602
25562
  `, "utf8");
25603
- if (fs51.existsSync(outputPath)) {
25604
- fs51.unlinkSync(outputPath);
25563
+ if (fs50.existsSync(outputPath)) {
25564
+ fs50.unlinkSync(outputPath);
25605
25565
  }
25606
25566
  const promptPath = path50.join(runDir, `context-drift-${Date.now()}.prompt.txt`);
25607
- fs51.writeFileSync(
25567
+ fs50.writeFileSync(
25608
25568
  promptPath,
25609
25569
  buildDriftPrompt({
25610
25570
  worktreeRoot: args.worktreeRoot,
@@ -25646,7 +25606,7 @@ async function runDriftComparisonOpenCode(args) {
25646
25606
  }
25647
25607
  let raw;
25648
25608
  try {
25649
- const txt = fs51.readFileSync(outputPath, "utf8");
25609
+ const txt = fs50.readFileSync(outputPath, "utf8");
25650
25610
  raw = JSON.parse(txt);
25651
25611
  } catch (e) {
25652
25612
  return {
@@ -25663,7 +25623,7 @@ async function runDriftComparisonOpenCode(args) {
25663
25623
 
25664
25624
  // src/factory/contextDrift/contextDriftPaths.ts
25665
25625
  var crypto2 = __toESM(require("node:crypto"));
25666
- var fs52 = __toESM(require("node:fs"));
25626
+ var fs51 = __toESM(require("node:fs"));
25667
25627
  var path51 = __toESM(require("node:path"));
25668
25628
  var DRIFT_CONTEXT_SUBDIR = path51.join(".gluecharm", "context", "drift");
25669
25629
  function sanitizeSlug(raw) {
@@ -25702,7 +25662,7 @@ function maybeDedupeSlug(slug, referenceRelPosix) {
25702
25662
  function discoverReferenceBundle(worktreeRoot, referenceAbsInWorktree) {
25703
25663
  let st;
25704
25664
  try {
25705
- st = fs52.statSync(referenceAbsInWorktree);
25665
+ st = fs51.statSync(referenceAbsInWorktree);
25706
25666
  } catch {
25707
25667
  return { ok: false, error: `Reference path not found in analysis worktree: ${referenceAbsInWorktree}` };
25708
25668
  }
@@ -25723,7 +25683,7 @@ function discoverReferenceBundle(worktreeRoot, referenceAbsInWorktree) {
25723
25683
  }
25724
25684
  let entries;
25725
25685
  try {
25726
- entries = fs52.readdirSync(dir, { withFileTypes: true });
25686
+ entries = fs51.readdirSync(dir, { withFileTypes: true });
25727
25687
  } catch {
25728
25688
  return;
25729
25689
  }
@@ -25748,7 +25708,7 @@ function discoverReferenceBundle(worktreeRoot, referenceAbsInWorktree) {
25748
25708
  }
25749
25709
  function pickReferenceRootDocument(args) {
25750
25710
  if (args.indexOverrideAbs) {
25751
- if (!fs52.existsSync(args.indexOverrideAbs) || !args.indexOverrideAbs.endsWith(".md")) {
25711
+ if (!fs51.existsSync(args.indexOverrideAbs) || !args.indexOverrideAbs.endsWith(".md")) {
25752
25712
  return { ok: false, error: "--index must point to an existing .md file under the repo." };
25753
25713
  }
25754
25714
  return { ok: true, path: args.indexOverrideAbs };
@@ -25759,7 +25719,7 @@ function pickReferenceRootDocument(args) {
25759
25719
  const dir = args.referenceAbsInWorktree;
25760
25720
  for (const name of ["index.md", "README.md"]) {
25761
25721
  const p = path51.join(dir, name);
25762
- if (fs52.existsSync(p) && fs52.statSync(p).isFile()) {
25722
+ if (fs51.existsSync(p) && fs51.statSync(p).isFile()) {
25763
25723
  return { ok: true, path: p };
25764
25724
  }
25765
25725
  }
@@ -25776,13 +25736,13 @@ function toPosixPath(p) {
25776
25736
  }
25777
25737
 
25778
25738
  // src/factory/contextDrift/contextDriftIndex.ts
25779
- var fs53 = __toESM(require("node:fs"));
25739
+ var fs52 = __toESM(require("node:fs"));
25780
25740
  var START = "<!-- easyspecs-drift-links:start -->";
25781
25741
  var END = "<!-- easyspecs-drift-links:end -->";
25782
25742
  function patchReferenceIndexWithDriftLink(args) {
25783
25743
  let body;
25784
25744
  try {
25785
- body = fs53.readFileSync(args.referenceRootAbsolute, "utf8");
25745
+ body = fs52.readFileSync(args.referenceRootAbsolute, "utf8");
25786
25746
  } catch (e) {
25787
25747
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
25788
25748
  }
@@ -25803,7 +25763,7 @@ ${block}
25803
25763
  `;
25804
25764
  }
25805
25765
  try {
25806
- fs53.writeFileSync(args.referenceRootAbsolute, next, "utf8");
25766
+ fs52.writeFileSync(args.referenceRootAbsolute, next, "utf8");
25807
25767
  } catch (e) {
25808
25768
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
25809
25769
  }
@@ -25814,13 +25774,13 @@ function escapeRe(s) {
25814
25774
  }
25815
25775
 
25816
25776
  // src/factory/contextDrift/contextDriftPromote.ts
25817
- var fs54 = __toESM(require("node:fs"));
25777
+ var fs53 = __toESM(require("node:fs"));
25818
25778
  var path52 = __toESM(require("node:path"));
25819
25779
  function copyWorktreeFileToWorkspace(args) {
25820
25780
  const src = path52.join(args.worktreeRoot, ...args.relativePosix.split("/"));
25821
25781
  const dest = path52.join(args.workspaceRoot, ...args.relativePosix.split("/"));
25822
- fs54.mkdirSync(path52.dirname(dest), { recursive: true });
25823
- fs54.copyFileSync(src, dest);
25782
+ fs53.mkdirSync(path52.dirname(dest), { recursive: true });
25783
+ fs53.copyFileSync(src, dest);
25824
25784
  }
25825
25785
 
25826
25786
  // src/factory/contextDrift/runContextDriftFactory.ts
@@ -25839,7 +25799,7 @@ async function runContextDriftFactory(deps) {
25839
25799
  };
25840
25800
  }
25841
25801
  const refAbsWorkspace = resolved.abs;
25842
- if (!fs55.existsSync(refAbsWorkspace)) {
25802
+ if (!fs54.existsSync(refAbsWorkspace)) {
25843
25803
  return {
25844
25804
  exitOk: false,
25845
25805
  ok: false,
@@ -25852,7 +25812,7 @@ async function runContextDriftFactory(deps) {
25852
25812
  let indexOverrideAbsWorkspace;
25853
25813
  if (deps.indexOverrideArg?.trim()) {
25854
25814
  const ir = resolveInsideRepo(deps.repoRootAbs, deps.indexOverrideArg.trim());
25855
- if (!ir.ok || !fs55.existsSync(ir.abs)) {
25815
+ if (!ir.ok || !fs54.existsSync(ir.abs)) {
25856
25816
  return {
25857
25817
  exitOk: false,
25858
25818
  ok: false,
@@ -25870,7 +25830,7 @@ async function runContextDriftFactory(deps) {
25870
25830
  ok: true,
25871
25831
  code: "DRY_RUN",
25872
25832
  ...baseMeta,
25873
- referenceRootDocument: toPosixPath(path53.relative(deps.repoRootAbs, refAbsWorkspace)) + (fs55.statSync(refAbsWorkspace).isDirectory() ? "/" : ""),
25833
+ referenceRootDocument: toPosixPath(path53.relative(deps.repoRootAbs, refAbsWorkspace)) + (fs54.statSync(refAbsWorkspace).isDirectory() ? "/" : ""),
25874
25834
  driftReportPath: null,
25875
25835
  analysisWorktreeRoot: "",
25876
25836
  promoted: false,
@@ -25939,7 +25899,7 @@ async function runContextDriftFactory(deps) {
25939
25899
  }
25940
25900
  const indexWt = indexOverrideAbsWorkspace ? path53.join(wt, ...path53.relative(deps.repoRootAbs, indexOverrideAbsWorkspace).split(path53.sep)) : void 0;
25941
25901
  const rootPick = pickReferenceRootDocument({
25942
- referencePathIsFile: fs55.statSync(refAbsWt).isFile(),
25902
+ referencePathIsFile: fs54.statSync(refAbsWt).isFile(),
25943
25903
  referenceAbsInWorktree: refAbsWt,
25944
25904
  bundleFiles: bundle.bundleFiles,
25945
25905
  indexOverrideAbs: indexWt
@@ -25966,7 +25926,7 @@ async function runContextDriftFactory(deps) {
25966
25926
  slug = maybeDedupeSlug(slug, refRel);
25967
25927
  const driftBase = driftFilename(slug, runDate);
25968
25928
  const driftDirWt = path53.join(wt, DRIFT_CONTEXT_SUBDIR);
25969
- fs55.mkdirSync(driftDirWt, { recursive: true });
25929
+ fs54.mkdirSync(driftDirWt, { recursive: true });
25970
25930
  const driftAbsWt = path53.join(driftDirWt, driftBase);
25971
25931
  let payload;
25972
25932
  if (deps.testOnlyFixturePayload) {
@@ -26003,7 +25963,7 @@ async function runContextDriftFactory(deps) {
26003
25963
  manifestTruncation: manifest.truncation
26004
25964
  });
26005
25965
  try {
26006
- fs55.writeFileSync(driftAbsWt, md, "utf8");
25966
+ fs54.writeFileSync(driftAbsWt, md, "utf8");
26007
25967
  } catch (e) {
26008
25968
  finalizeWt?.();
26009
25969
  return {
@@ -26082,7 +26042,7 @@ async function runContextDriftFactory(deps) {
26082
26042
  }
26083
26043
 
26084
26044
  // src/analysis/coordinationDuplicatesDiagnosis.ts
26085
- var fs56 = __toESM(require("fs"));
26045
+ var fs55 = __toESM(require("fs"));
26086
26046
  var path54 = __toESM(require("path"));
26087
26047
  var import__7 = __toESM(require__());
26088
26048
  var COORDINATION_DUPLICATES_REPORT_BASENAME = "coordination-duplicates-report.json";
@@ -26108,30 +26068,30 @@ var RE_MD_SV = /^SV-\d+-.+\.md$/i;
26108
26068
  var RE_MD_DM_FD = /^DM-\d+_FD-\d+-.+\.md$/i;
26109
26069
  var RE_MD_DM = /^DM-\d+-.+\.md$/i;
26110
26070
  var RE_MD_TS = /^TS-\d+-.+\.md$/i;
26111
- function looksLikeCoordinationDetailMarkdownBasename(basename16) {
26112
- if (!basename16 || basename16 !== path54.basename(basename16) || !/\.md$/i.test(basename16)) {
26071
+ function looksLikeCoordinationDetailMarkdownBasename(basename17) {
26072
+ if (!basename17 || basename17 !== path54.basename(basename17) || !/\.md$/i.test(basename17)) {
26113
26073
  return false;
26114
26074
  }
26115
- if (STAPLE_CONTEXT_MARKDOWN_BASENAMES.has(basename16)) {
26075
+ if (STAPLE_CONTEXT_MARKDOWN_BASENAMES.has(basename17)) {
26116
26076
  return false;
26117
26077
  }
26118
- return RE_MD_FE_UC_SC.test(basename16) || RE_MD_FE_UC_SLUG.test(basename16) || RE_MD_FE_UC_PLAIN.test(basename16) || RE_MD_FE_FEATURE.test(basename16) || RE_MD_XP_BH.test(basename16) || RE_MD_XP_VIEW.test(basename16) || RE_MD_SV_ME.test(basename16) || RE_MD_SV.test(basename16) || RE_MD_DM_FD.test(basename16) || RE_MD_DM.test(basename16) || RE_MD_TS.test(basename16);
26078
+ 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);
26119
26079
  }
26120
26080
  function loadRawFeatureRows(contextDirAbs) {
26121
26081
  const p = path54.join(contextDirAbs, "features-list.json");
26122
- if (!fs56.existsSync(p)) {
26082
+ if (!fs55.existsSync(p)) {
26123
26083
  return [];
26124
26084
  }
26125
26085
  try {
26126
- const raw = stripUtf8Bom6(fs56.readFileSync(p, "utf-8"));
26086
+ const raw = stripUtf8Bom6(fs55.readFileSync(p, "utf-8"));
26127
26087
  const doc = JSON.parse(raw);
26128
26088
  return Array.isArray(doc.features) ? doc.features : [];
26129
26089
  } catch {
26130
26090
  return [];
26131
26091
  }
26132
26092
  }
26133
- function hintForOrphanFeatureMarkdown(basename16, featureRows) {
26134
- const m = /^FE-(\d+)-(.+)\.md$/i.exec(basename16);
26093
+ function hintForOrphanFeatureMarkdown(basename17, featureRows) {
26094
+ const m = /^FE-(\d+)-(.+)\.md$/i.exec(basename17);
26135
26095
  if (!m) {
26136
26096
  return void 0;
26137
26097
  }
@@ -26143,8 +26103,8 @@ function hintForOrphanFeatureMarkdown(basename16, featureRows) {
26143
26103
  continue;
26144
26104
  }
26145
26105
  const expected = expectedFeatureDetailBasenameFromRow(row2);
26146
- if (expected && expected !== basename16) {
26147
- return `features-list row ${code} currently implies detail file ${expected} (slug/name changed \u2014 ${basename16} may be stale).`;
26106
+ if (expected && expected !== basename17) {
26107
+ return `features-list row ${code} currently implies detail file ${expected} (slug/name changed \u2014 ${basename17} may be stale).`;
26148
26108
  }
26149
26109
  if (!expected) {
26150
26110
  return `features-list row ${code} has no resolvable slug for a detail markdown basename.`;
@@ -26158,7 +26118,7 @@ function findOrphanCoordinationMarkdown(contextDirAbs) {
26158
26118
  const featureRows = loadRawFeatureRows(contextDirAbs);
26159
26119
  let dirents;
26160
26120
  try {
26161
- dirents = fs56.readdirSync(contextDirAbs, { withFileTypes: true });
26121
+ dirents = fs55.readdirSync(contextDirAbs, { withFileTypes: true });
26162
26122
  } catch {
26163
26123
  return [];
26164
26124
  }
@@ -26412,13 +26372,13 @@ function buildCoordinationDuplicatesReport(input) {
26412
26372
  const duplicateGroups = [];
26413
26373
  for (const entry of COORDINATION_LIST_SCAN_ENTRIES) {
26414
26374
  const filePath = path54.join(input.contextDirAbsolute, entry.basename);
26415
- if (!fs56.existsSync(filePath)) {
26375
+ if (!fs55.existsSync(filePath)) {
26416
26376
  lists.push({ basename: entry.basename, status: "missing" });
26417
26377
  continue;
26418
26378
  }
26419
26379
  let raw;
26420
26380
  try {
26421
- raw = stripUtf8Bom6(fs56.readFileSync(filePath, "utf-8"));
26381
+ raw = stripUtf8Bom6(fs55.readFileSync(filePath, "utf-8"));
26422
26382
  } catch (e) {
26423
26383
  lists.push({
26424
26384
  basename: entry.basename,
@@ -26467,7 +26427,7 @@ function validateReportData(data) {
26467
26427
  if (!validateReportCompiled) {
26468
26428
  const ajv2 = new import__7.default({ allErrors: true, strict: false });
26469
26429
  const schemaPath = path54.join(resolveContextListSchemasDir(), "coordination-duplicates-report.schema.json");
26470
- const schemaRaw = stripUtf8Bom6(fs56.readFileSync(schemaPath, "utf-8"));
26430
+ const schemaRaw = stripUtf8Bom6(fs55.readFileSync(schemaPath, "utf-8"));
26471
26431
  validateReportCompiled = ajv2.compile(JSON.parse(schemaRaw));
26472
26432
  }
26473
26433
  if (validateReportCompiled(data)) {
@@ -26490,15 +26450,15 @@ function runCoordinationDuplicatesDiagnosis(input) {
26490
26450
  `;
26491
26451
  const tmp = `${outPath}.tmp.${process.pid}`;
26492
26452
  try {
26493
- fs56.writeFileSync(tmp, payload, "utf-8");
26453
+ fs55.writeFileSync(tmp, payload, "utf-8");
26494
26454
  } catch (e) {
26495
26455
  return { ok: false, message: e instanceof Error ? e.message : String(e) };
26496
26456
  }
26497
26457
  try {
26498
- fs56.renameSync(tmp, outPath);
26458
+ fs55.renameSync(tmp, outPath);
26499
26459
  } catch (e) {
26500
26460
  try {
26501
- fs56.unlinkSync(tmp);
26461
+ fs55.unlinkSync(tmp);
26502
26462
  } catch {
26503
26463
  }
26504
26464
  return { ok: false, message: e instanceof Error ? e.message : String(e) };
@@ -26532,7 +26492,7 @@ function runCoordinationDuplicatesDiagnosis(input) {
26532
26492
  }
26533
26493
 
26534
26494
  // src/pipelines/download/downloadPipeline.ts
26535
- var fs57 = __toESM(require("node:fs"));
26495
+ var fs56 = __toESM(require("node:fs"));
26536
26496
  var path55 = __toESM(require("node:path"));
26537
26497
  var SRS_DISCOVERY_BATCH_GET_CHUNK_SIZE = 200;
26538
26498
  function isRecord7(v) {
@@ -26638,19 +26598,19 @@ function chunkIds(ids, size) {
26638
26598
  return out;
26639
26599
  }
26640
26600
  function clearContextDirectoryForCloudReplace(contextDirAbs) {
26641
- if (!fs57.existsSync(contextDirAbs) || !fs57.statSync(contextDirAbs).isDirectory()) {
26601
+ if (!fs56.existsSync(contextDirAbs) || !fs56.statSync(contextDirAbs).isDirectory()) {
26642
26602
  return { filesRemoved: 0 };
26643
26603
  }
26644
26604
  const preserveAbs = path55.resolve(contextDirAbs, UPLOAD_TARGET_FILENAME);
26645
26605
  const preserveSet = /* @__PURE__ */ new Set();
26646
- if (fs57.existsSync(preserveAbs) && fs57.statSync(preserveAbs).isFile()) {
26606
+ if (fs56.existsSync(preserveAbs) && fs56.statSync(preserveAbs).isFile()) {
26647
26607
  preserveSet.add(preserveAbs);
26648
26608
  }
26649
26609
  let filesRemoved = 0;
26650
26610
  const walkRm = (dir) => {
26651
26611
  let entries;
26652
26612
  try {
26653
- entries = fs57.readdirSync(dir, { withFileTypes: true });
26613
+ entries = fs56.readdirSync(dir, { withFileTypes: true });
26654
26614
  } catch {
26655
26615
  return;
26656
26616
  }
@@ -26659,7 +26619,7 @@ function clearContextDirectoryForCloudReplace(contextDirAbs) {
26659
26619
  if (e.isDirectory()) {
26660
26620
  walkRm(full);
26661
26621
  try {
26662
- fs57.rmdirSync(full);
26622
+ fs56.rmdirSync(full);
26663
26623
  } catch {
26664
26624
  }
26665
26625
  } else if (e.isFile()) {
@@ -26668,7 +26628,7 @@ function clearContextDirectoryForCloudReplace(contextDirAbs) {
26668
26628
  continue;
26669
26629
  }
26670
26630
  try {
26671
- fs57.unlinkSync(abs);
26631
+ fs56.unlinkSync(abs);
26672
26632
  filesRemoved += 1;
26673
26633
  } catch {
26674
26634
  }
@@ -26747,15 +26707,15 @@ async function runDownloadPipeline(opts) {
26747
26707
  failed.push({ id, name, message: "Unsafe or invalid name for local path." });
26748
26708
  continue;
26749
26709
  }
26750
- fs57.mkdirSync(path55.dirname(outAbs), { recursive: true });
26751
- const exists = fs57.existsSync(outAbs);
26710
+ fs56.mkdirSync(path55.dirname(outAbs), { recursive: true });
26711
+ const exists = fs56.existsSync(outAbs);
26752
26712
  if (exists && !opts.force && !opts.replaceFromCloud) {
26753
26713
  skipped += 1;
26754
26714
  log?.(`[pipeline:download] skip existing ${name} (use --force to overwrite).`);
26755
26715
  continue;
26756
26716
  }
26757
26717
  try {
26758
- fs57.writeFileSync(outAbs, bodyText, "utf8");
26718
+ fs56.writeFileSync(outAbs, bodyText, "utf8");
26759
26719
  downloaded += 1;
26760
26720
  succeededIds[outAbs] = id;
26761
26721
  } catch (e) {
@@ -26926,7 +26886,7 @@ function createAuthenticatedRequestJson(deps) {
26926
26886
  }
26927
26887
 
26928
26888
  // src/cli/cliSession.ts
26929
- var fs58 = __toESM(require("node:fs"));
26889
+ var fs57 = __toESM(require("node:fs"));
26930
26890
  var os3 = __toESM(require("node:os"));
26931
26891
  var path56 = __toESM(require("node:path"));
26932
26892
  function defaultSessionPath() {
@@ -26971,10 +26931,10 @@ function effectiveCliSessionPath() {
26971
26931
  function readCliSession() {
26972
26932
  const p = effectiveCliSessionPath();
26973
26933
  try {
26974
- if (!fs58.existsSync(p)) {
26934
+ if (!fs57.existsSync(p)) {
26975
26935
  return void 0;
26976
26936
  }
26977
- const j = JSON.parse(fs58.readFileSync(p, "utf8"));
26937
+ const j = JSON.parse(fs57.readFileSync(p, "utf8"));
26978
26938
  const apiBaseUrl = typeof j.apiBaseUrl === "string" ? j.apiBaseUrl.trim() : "";
26979
26939
  const accessToken = typeof j.accessToken === "string" ? j.accessToken : "";
26980
26940
  const refreshToken = typeof j.refreshToken === "string" ? j.refreshToken : "";
@@ -26988,20 +26948,20 @@ function readCliSession() {
26988
26948
  }
26989
26949
  function writeCliSession(s) {
26990
26950
  const p = effectiveCliSessionPath();
26991
- fs58.mkdirSync(path56.dirname(p), { recursive: true });
26992
- fs58.writeFileSync(p, `${JSON.stringify(s, null, 2)}
26951
+ fs57.mkdirSync(path56.dirname(p), { recursive: true });
26952
+ fs57.writeFileSync(p, `${JSON.stringify(s, null, 2)}
26993
26953
  `, "utf8");
26994
26954
  }
26995
26955
  function clearCliSession() {
26996
26956
  const p = effectiveCliSessionPath();
26997
26957
  try {
26998
- fs58.unlinkSync(p);
26958
+ fs57.unlinkSync(p);
26999
26959
  } catch {
27000
26960
  }
27001
26961
  }
27002
26962
 
27003
26963
  // src/analysis/acePendingTraces.ts
27004
- var fs59 = __toESM(require("fs"));
26964
+ var fs58 = __toESM(require("fs"));
27005
26965
  var path57 = __toESM(require("path"));
27006
26966
  function normalizeAceTraceRelativePath(rel) {
27007
26967
  return rel.split(/[/\\]/).join("/");
@@ -27009,12 +26969,12 @@ function normalizeAceTraceRelativePath(rel) {
27009
26969
  function readCompletedTraceRelativePaths(contextDir2) {
27010
26970
  const set = /* @__PURE__ */ new Set();
27011
26971
  const jsonlPath = aceConsolidatedSessionsJsonlPath(contextDir2);
27012
- if (!fs59.existsSync(jsonlPath)) {
26972
+ if (!fs58.existsSync(jsonlPath)) {
27013
26973
  return set;
27014
26974
  }
27015
26975
  let raw;
27016
26976
  try {
27017
- raw = fs59.readFileSync(jsonlPath, "utf8");
26977
+ raw = fs58.readFileSync(jsonlPath, "utf8");
27018
26978
  } catch {
27019
26979
  return set;
27020
26980
  }
@@ -27045,7 +27005,7 @@ function readCompletedTraceRelativePaths(contextDir2) {
27045
27005
  }
27046
27006
  function listPendingAceTraceFiles(contextDir2, worktreeRoot) {
27047
27007
  const traceSchema = opencodeAceSchemaPath(worktreeRoot, ACE_SCHEMA_TRACE);
27048
- if (!fs59.existsSync(traceSchema)) {
27008
+ if (!fs58.existsSync(traceSchema)) {
27049
27009
  return [];
27050
27010
  }
27051
27011
  const completed = readCompletedTraceRelativePaths(contextDir2);
@@ -27611,7 +27571,7 @@ function formatCliStderrLine(line, useAnsi) {
27611
27571
  }
27612
27572
 
27613
27573
  // src/cli/main.ts
27614
- var PKG_VERSION = "0.0.17";
27574
+ var PKG_VERSION = "0.0.19";
27615
27575
  function isNonEmptyFactoryFailureArray(x) {
27616
27576
  if (!Array.isArray(x) || x.length === 0) {
27617
27577
  return false;
@@ -27743,7 +27703,7 @@ function resolveAnalysisRoot(repoRoot, rootKind, worktreePath) {
27743
27703
  return repoRoot;
27744
27704
  }
27745
27705
  const wt = worktreePath?.trim();
27746
- if (wt && fs60.existsSync(path59.join(wt, ".git"))) {
27706
+ if (wt && fs59.existsSync(path59.join(wt, ".git"))) {
27747
27707
  return path59.resolve(wt);
27748
27708
  }
27749
27709
  throw new Error("worktree mode requires --worktree <path> to an existing analysis checkout.");
@@ -27752,14 +27712,14 @@ function resolveAdHocCheckoutRoot(_repoRoot, storage, worktreeFlag) {
27752
27712
  const w = worktreeFlag?.trim();
27753
27713
  if (w) {
27754
27714
  const abs = path59.resolve(w);
27755
- if (fs60.existsSync(path59.join(abs, ".git"))) {
27715
+ if (fs59.existsSync(path59.join(abs, ".git"))) {
27756
27716
  return abs;
27757
27717
  }
27758
27718
  throw new Error(`Invalid --worktree (not a git checkout): ${abs}`);
27759
27719
  }
27760
27720
  const snap = readAnalysisWorkspaceSnapshot(storage);
27761
27721
  const p = snap?.adHocWorktreePath?.trim();
27762
- if (p && fs60.existsSync(path59.join(p, ".git"))) {
27722
+ if (p && fs59.existsSync(path59.join(p, ".git"))) {
27763
27723
  return p;
27764
27724
  }
27765
27725
  throw new Error("No analysis checkout: run `easyspecs-cli run synthesis` first or pass `--worktree <path>`.");
@@ -28030,7 +27990,7 @@ async function main() {
28030
27990
  process.exit(ExitCode.usage);
28031
27991
  }
28032
27992
  const agentsDir = resolveOpenCodeAgentsDir(repoRoot, repoConfig);
28033
- const agentsOk = fs60.existsSync(agentsDir);
27993
+ const agentsOk = fs59.existsSync(agentsDir);
28034
27994
  const oc = getOpenCodeReadiness({
28035
27995
  executable: merged.openCodeExecutable,
28036
27996
  skipCredentialsCheck: merged.openCodeSkipCredentialsCheck,
@@ -28477,7 +28437,27 @@ async function main() {
28477
28437
  finish(ExitCode.internal, { ok: false, error: "Unexpected context drift result shape." });
28478
28438
  }
28479
28439
  if (pos[0] === "analysis") {
28480
- const synthesisOnly = positionals.includes("--synthesis-only");
28440
+ for (const a of pos.slice(1)) {
28441
+ if (a === "--force-new-context-analysis") {
28442
+ continue;
28443
+ }
28444
+ if (a === "--upload") {
28445
+ finish(ExitCode.usage, {
28446
+ ok: false,
28447
+ error: "Removed flag: analysis --upload. Run `easyspecs-cli upload context` or `easyspecs-cli upload republish` after analysis (after `auth login` and easyspecs.easyspecsProjectId)."
28448
+ });
28449
+ }
28450
+ if (a === "--synthesis-only") {
28451
+ console.error(
28452
+ "[deprecated] Ignoring deprecated flag --synthesis-only (it has no effect). Use `easyspecs-cli run synthesis` for a single synthesis pass, or the VS Code Factory \u201CSynthesis only\u201D control for factory-style convergence."
28453
+ );
28454
+ continue;
28455
+ }
28456
+ finish(ExitCode.usage, {
28457
+ ok: false,
28458
+ error: `unknown analysis flag: ${a} (allowed: --force-new-context-analysis)`
28459
+ });
28460
+ }
28481
28461
  const forceNewContextAnalysis = positionals.includes("--force-new-context-analysis");
28482
28462
  const cloudCached = readEasyspecsMergedSetting(
28483
28463
  repoConfig.easyspecs,
@@ -28486,12 +28466,11 @@ async function main() {
28486
28466
  const cloudCachedAt = readEasyspecsMergedSetting(repoConfig.easyspecs, "easyspecs.factory.cloudContextAnalyzedAt") ?? null;
28487
28467
  if (shouldSkipAnalysisForCachedCloudContext({
28488
28468
  cloudContextAnalyzed: cloudCached,
28489
- synthesisOnly,
28490
28469
  forceNewContextAnalysis
28491
28470
  })) {
28492
28471
  if (!flags.json) {
28493
28472
  console.error(
28494
- `Skipping analysis: easyspecs.factory.cloudContextAnalyzed is true (cached at ${cloudCachedAt ?? "null"}). Re-run with --force-new-context-analysis to run the factory, or use upload context / upload republish without the analysis command.`
28473
+ `Skipping analysis: easyspecs.factory.cloudContextAnalyzed is true (cached at ${cloudCachedAt ?? "null"}). Re-run with --force-new-context-analysis to run the factory, or use upload context / upload republish without running analysis.`
28495
28474
  );
28496
28475
  }
28497
28476
  finish(ExitCode.ok, {
@@ -28503,65 +28482,9 @@ async function main() {
28503
28482
  }
28504
28483
  requireMinimalGluecharmLayoutAt(repoRoot);
28505
28484
  requireOpenCode(merged, flags);
28506
- const wantsUpload = positionals.includes("--upload");
28507
- const uploadSession = wantsUpload ? readCliSession() : void 0;
28508
- if (wantsUpload && !uploadSession) {
28509
- finish(ExitCode.auth, {
28510
- ok: false,
28511
- error: "analysis --upload requires `easyspecs-cli auth login --email \u2026 --password \u2026` or `--ci` with easyspecs.auth.ciLogin in .easyspecs/config.json."
28512
- });
28513
- }
28514
- const skipBackendSync = !wantsUpload;
28515
28485
  const agentsDir = resolveOpenCodeAgentsDir(repoRoot, repoConfig);
28516
28486
  assertAgentsDirExists(agentsDir);
28517
28487
  const storage = createFileBackedWorkspaceState(repoRoot);
28518
- const runBackendSyncImpl = wantsUpload && uploadSession ? async () => {
28519
- const s = uploadSession;
28520
- const snap = readAnalysisWorkspaceSnapshot(storage);
28521
- const wsContextDir = path59.join(repoRoot, ".gluecharm", "context");
28522
- const wtContextDir = snap?.adHocWorktreePath && fs60.existsSync(path59.join(snap.adHocWorktreePath, ".gluecharm", "context")) ? path59.join(snap.adHocWorktreePath, ".gluecharm", "context") : "";
28523
- if (!wtContextDir) {
28524
- return { ok: false, message: "No worktree context to upload." };
28525
- }
28526
- const appId = getEasyspecsProjectIdFromRepoConfig(repoConfig)?.trim();
28527
- if (!appId) {
28528
- return {
28529
- ok: false,
28530
- message: "Missing easyspecs.easyspecsProjectId in .easyspecs/config.json."
28531
- };
28532
- }
28533
- let access = s.accessToken;
28534
- const refresh = s.refreshToken;
28535
- const requestJson = createAuthenticatedRequestJson({
28536
- getApiBaseUrl: () => s.apiBaseUrl,
28537
- getAccessToken: () => access,
28538
- getRefreshToken: () => refresh,
28539
- refreshSession: async () => {
28540
- try {
28541
- const r = await refreshTokenWithApi(s.apiBaseUrl, fetch, refresh);
28542
- access = r.accessToken;
28543
- writeCliSession({ ...s, accessToken: r.accessToken, refreshToken: r.refreshToken });
28544
- return true;
28545
- } catch {
28546
- return false;
28547
- }
28548
- }
28549
- });
28550
- await validateApplicationExists(requestJson, appId);
28551
- const paths = listContextFilesForUpload(wtContextDir);
28552
- const up = await runUploadPipeline({
28553
- requestJson,
28554
- applicationId: appId,
28555
- useBatch: true,
28556
- contextDir: wtContextDir,
28557
- filePaths: paths,
28558
- log: (line) => logErr(flags, line)
28559
- });
28560
- if (up.failed.length > 0) {
28561
- return { ok: false, message: `${String(up.failed.length)} file(s) failed to upload.` };
28562
- }
28563
- return { ok: true, message: `Uploaded ${String(up.succeeded.length)} file(s).` };
28564
- } : void 0;
28565
28488
  const ctrl = new AbortController();
28566
28489
  const deps = buildFactoryDepsHeadless({
28567
28490
  storageContext: storage,
@@ -28573,9 +28496,7 @@ async function main() {
28573
28496
  }),
28574
28497
  log: (line) => logErr(flags, line),
28575
28498
  signal: ctrl.signal,
28576
- synthesisOnly,
28577
- skipBackendSync,
28578
- runBackendSyncImpl
28499
+ skipBackendSync: true
28579
28500
  });
28580
28501
  const res = await runGenerateContextFactory(deps);
28581
28502
  const analysisEnvelope = {
@@ -28594,87 +28515,30 @@ async function main() {
28594
28515
  if (pos[0] === "update" && pos[1] === "context") {
28595
28516
  for (const a of pos.slice(2)) {
28596
28517
  if (a === "--upload") {
28597
- continue;
28518
+ finish(ExitCode.usage, {
28519
+ ok: false,
28520
+ error: "Removed flag: update context --upload. Run `easyspecs-cli upload context` or `upload republish` after update context completes."
28521
+ });
28598
28522
  }
28599
28523
  finish(ExitCode.usage, { ok: false, error: `unknown update context flag: ${a}` });
28600
28524
  }
28601
28525
  requireMinimalGluecharmLayoutAt(repoRoot);
28602
28526
  requireOpenCode(merged, flags);
28603
- const wantsUpload = positionals.includes("--upload");
28604
- const uploadSession = wantsUpload ? readCliSession() : void 0;
28605
- if (wantsUpload && !uploadSession) {
28606
- finish(ExitCode.auth, {
28607
- ok: false,
28608
- error: "update context --upload requires `easyspecs-cli auth login --email \u2026 --password \u2026` or `--ci` with easyspecs.auth.ciLogin in .easyspecs/config.json."
28609
- });
28610
- }
28611
28527
  const agentsDir = resolveOpenCodeAgentsDir(repoRoot, repoConfig);
28612
28528
  assertAgentsDirExists(agentsDir);
28613
28529
  const storage = createFileBackedWorkspaceState(repoRoot);
28614
28530
  const ctrl = new AbortController();
28615
- const uploadBatch = readEasyspecsMergedSetting(repoConfig.easyspecs, "easyspecs.pipelines.upload.useBatch") !== false;
28616
- const runUploadFn = wantsUpload && uploadSession ? async (args) => {
28617
- const s = uploadSession;
28618
- const appId = getEasyspecsProjectIdFromRepoConfig(repoConfig)?.trim();
28619
- if (!appId) {
28620
- return { ok: false, message: "Missing easyspecs.easyspecsProjectId in .easyspecs/config.json." };
28621
- }
28622
- let access = s.accessToken;
28623
- const refresh = s.refreshToken;
28624
- const requestJson = createAuthenticatedRequestJson({
28625
- getApiBaseUrl: () => s.apiBaseUrl,
28626
- getAccessToken: () => access,
28627
- getRefreshToken: () => refresh,
28628
- refreshSession: async () => {
28629
- try {
28630
- const r = await refreshTokenWithApi(s.apiBaseUrl, fetch, refresh);
28631
- access = r.accessToken;
28632
- writeCliSession({ ...s, accessToken: r.accessToken, refreshToken: r.refreshToken });
28633
- return true;
28634
- } catch {
28635
- return false;
28636
- }
28637
- }
28638
- });
28639
- try {
28640
- await validateApplicationExists(requestJson, appId);
28641
- } catch (e) {
28642
- return { ok: false, message: toFetchErrorMessage(e).message };
28643
- }
28644
- const up = await runUploadPipeline({
28645
- requestJson,
28646
- applicationId: appId,
28647
- useBatch: uploadBatch,
28648
- contextDir: args.wtContextDir,
28649
- filePaths: args.filePaths,
28650
- log: (line) => logErr(flags, line)
28651
- });
28652
- if (up.failed.length > 0) {
28653
- return {
28654
- ok: false,
28655
- message: `${String(up.failed.length)} file(s) failed to upload.`,
28656
- uploadedCount: up.succeeded.length
28657
- };
28658
- }
28659
- return {
28660
- ok: true,
28661
- uploadedCount: up.succeeded.length,
28662
- message: `Uploaded ${String(up.succeeded.length)} file(s).`
28663
- };
28664
- } : void 0;
28665
28531
  const ures = await runUpdateContextFactory({
28666
28532
  repoRootAbs: repoRoot,
28667
28533
  repoConfig,
28668
28534
  merged,
28669
28535
  agentsDirFs: agentsDir,
28670
28536
  storage,
28671
- wantsUpload,
28672
28537
  signal: ctrl.signal,
28673
- log: (line) => logErr(flags, line),
28674
- runUploadFn
28538
+ log: (line) => logErr(flags, line)
28675
28539
  });
28676
28540
  const { exitOk, ...payload } = ures;
28677
- const code = exitOk ? ExitCode.ok : ures.code === "MISSING_BASELINE" ? ExitCode.usage : ures.code === "UPLOAD_FAILED" ? ExitCode.upload : ExitCode.validation;
28541
+ const code = exitOk ? ExitCode.ok : ures.code === "MISSING_BASELINE" ? ExitCode.usage : ExitCode.validation;
28678
28542
  finish(code, payload);
28679
28543
  }
28680
28544
  if (pos[0] === "download" && pos[1] === "context") {
@@ -28789,12 +28653,12 @@ async function main() {
28789
28653
  if (pos[1] === "republish") {
28790
28654
  const fromCfg = repoConfig.easyspecs?.upload?.contextDirectory?.trim();
28791
28655
  const resolvedOverride = fromCfg && fromCfg.length > 0 ? path59.isAbsolute(fromCfg) ? path59.normalize(fromCfg) : path59.resolve(repoRoot, fromCfg) : "";
28792
- if (resolvedOverride && fs60.existsSync(path59.join(resolvedOverride, ".."))) {
28656
+ if (resolvedOverride && fs59.existsSync(path59.join(resolvedOverride, ".."))) {
28793
28657
  ctxDir = resolvedOverride;
28794
28658
  } else {
28795
28659
  const storage = createFileBackedWorkspaceState(repoRoot);
28796
28660
  const snap = readAnalysisWorkspaceSnapshot(storage);
28797
- const wt = snap?.adHocWorktreePath && fs60.existsSync(path59.join(snap.adHocWorktreePath, ".gluecharm", "context")) ? path59.join(snap.adHocWorktreePath, ".gluecharm", "context") : "";
28661
+ const wt = snap?.adHocWorktreePath && fs59.existsSync(path59.join(snap.adHocWorktreePath, ".gluecharm", "context")) ? path59.join(snap.adHocWorktreePath, ".gluecharm", "context") : "";
28798
28662
  if (!wt) {
28799
28663
  finish(ExitCode.misconfiguration, {
28800
28664
  ok: false,
@@ -28912,16 +28776,16 @@ async function main() {
28912
28776
  }
28913
28777
  if (pos[0] === "ace" && pos[1] === "clear") {
28914
28778
  const learnings = path59.join(repoRoot, ".gluecharm", "context", "learnings");
28915
- if (!fs60.existsSync(learnings)) {
28779
+ if (!fs59.existsSync(learnings)) {
28916
28780
  finish(ExitCode.ok, { ok: true, message: "nothing to clear" });
28917
28781
  }
28918
- fs60.rmSync(learnings, { recursive: true, force: true });
28782
+ fs59.rmSync(learnings, { recursive: true, force: true });
28919
28783
  finish(ExitCode.ok, { ok: true, message: `cleared ${learnings}` });
28920
28784
  }
28921
28785
  if (pos[0] === "ace" && pos[1] === "learn") {
28922
28786
  requireOpenCode(merged, flags);
28923
28787
  const { worktree } = parseWorktreeFlag(pos.slice(2));
28924
- const root = worktree && fs60.existsSync(path59.join(worktree, ".opencode", "schemas", "ace")) ? worktree : repoRoot;
28788
+ const root = worktree && fs59.existsSync(path59.join(worktree, ".opencode", "schemas", "ace")) ? worktree : repoRoot;
28925
28789
  const contextDir2 = path59.join(root, ".gluecharm", "context");
28926
28790
  const traces = listAceTraceFiles(contextDir2);
28927
28791
  if (traces.length === 0) {
@@ -28946,7 +28810,7 @@ async function main() {
28946
28810
  if (pos[0] === "ace" && pos[1] === "auto-learn") {
28947
28811
  requireOpenCode(merged, flags);
28948
28812
  const { worktree } = parseWorktreeFlag(pos.slice(2));
28949
- const root = worktree && fs60.existsSync(path59.join(worktree, ".git")) ? worktree : repoRoot;
28813
+ const root = worktree && fs59.existsSync(path59.join(worktree, ".git")) ? worktree : repoRoot;
28950
28814
  const contextDir2 = path59.join(root, ".gluecharm", "context");
28951
28815
  const pending = listPendingAceTraceFiles(contextDir2, root);
28952
28816
  if (pending.length === 0) {