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