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