@gluecharm-lab/easyspecs-cli 0.0.3 → 0.0.7
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/LICENSE +95 -0
- package/README.md +86 -0
- package/commands.md +122 -0
- package/dist/main.cjs +1444 -753
- package/dist/main.cjs.map +4 -4
- package/package.json +6 -3
package/dist/main.cjs
CHANGED
|
@@ -2251,8 +2251,8 @@ var require_resolve = __commonJS({
|
|
|
2251
2251
|
}
|
|
2252
2252
|
return count;
|
|
2253
2253
|
}
|
|
2254
|
-
function getFullPath(resolver, id = "",
|
|
2255
|
-
if (
|
|
2254
|
+
function getFullPath(resolver, id = "", normalize4) {
|
|
2255
|
+
if (normalize4 !== false)
|
|
2256
2256
|
id = normalizeId(id);
|
|
2257
2257
|
const p = resolver.parse(id);
|
|
2258
2258
|
return _getFullPath(resolver, p);
|
|
@@ -3000,7 +3000,7 @@ var require_compile = __commonJS({
|
|
|
3000
3000
|
const schOrFunc = root.refs[ref];
|
|
3001
3001
|
if (schOrFunc)
|
|
3002
3002
|
return schOrFunc;
|
|
3003
|
-
let _sch =
|
|
3003
|
+
let _sch = resolve15.call(this, root, ref);
|
|
3004
3004
|
if (_sch === void 0) {
|
|
3005
3005
|
const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
|
|
3006
3006
|
const { schemaId } = this.opts;
|
|
@@ -3027,7 +3027,7 @@ var require_compile = __commonJS({
|
|
|
3027
3027
|
function sameSchemaEnv(s1, s2) {
|
|
3028
3028
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
3029
3029
|
}
|
|
3030
|
-
function
|
|
3030
|
+
function resolve15(root, ref) {
|
|
3031
3031
|
let sch;
|
|
3032
3032
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
3033
3033
|
ref = sch;
|
|
@@ -3592,7 +3592,7 @@ var require_fast_uri = __commonJS({
|
|
|
3592
3592
|
"use strict";
|
|
3593
3593
|
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizeComponentEncoding, isIPv4, nonSimpleDomain } = require_utils();
|
|
3594
3594
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
3595
|
-
function
|
|
3595
|
+
function normalize4(uri, options) {
|
|
3596
3596
|
if (typeof uri === "string") {
|
|
3597
3597
|
uri = /** @type {T} */
|
|
3598
3598
|
serialize(parse(uri, options), options);
|
|
@@ -3602,55 +3602,55 @@ var require_fast_uri = __commonJS({
|
|
|
3602
3602
|
}
|
|
3603
3603
|
return uri;
|
|
3604
3604
|
}
|
|
3605
|
-
function
|
|
3605
|
+
function resolve15(baseURI, relativeURI, options) {
|
|
3606
3606
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3607
3607
|
const resolved = resolveComponent(parse(baseURI, schemelessOptions), parse(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
3608
3608
|
schemelessOptions.skipEscape = true;
|
|
3609
3609
|
return serialize(resolved, schemelessOptions);
|
|
3610
3610
|
}
|
|
3611
|
-
function resolveComponent(base,
|
|
3611
|
+
function resolveComponent(base, relative12, options, skipNormalization) {
|
|
3612
3612
|
const target = {};
|
|
3613
3613
|
if (!skipNormalization) {
|
|
3614
3614
|
base = parse(serialize(base, options), options);
|
|
3615
|
-
|
|
3615
|
+
relative12 = parse(serialize(relative12, options), options);
|
|
3616
3616
|
}
|
|
3617
3617
|
options = options || {};
|
|
3618
|
-
if (!options.tolerant &&
|
|
3619
|
-
target.scheme =
|
|
3620
|
-
target.userinfo =
|
|
3621
|
-
target.host =
|
|
3622
|
-
target.port =
|
|
3623
|
-
target.path = removeDotSegments(
|
|
3624
|
-
target.query =
|
|
3618
|
+
if (!options.tolerant && relative12.scheme) {
|
|
3619
|
+
target.scheme = relative12.scheme;
|
|
3620
|
+
target.userinfo = relative12.userinfo;
|
|
3621
|
+
target.host = relative12.host;
|
|
3622
|
+
target.port = relative12.port;
|
|
3623
|
+
target.path = removeDotSegments(relative12.path || "");
|
|
3624
|
+
target.query = relative12.query;
|
|
3625
3625
|
} else {
|
|
3626
|
-
if (
|
|
3627
|
-
target.userinfo =
|
|
3628
|
-
target.host =
|
|
3629
|
-
target.port =
|
|
3630
|
-
target.path = removeDotSegments(
|
|
3631
|
-
target.query =
|
|
3626
|
+
if (relative12.userinfo !== void 0 || relative12.host !== void 0 || relative12.port !== void 0) {
|
|
3627
|
+
target.userinfo = relative12.userinfo;
|
|
3628
|
+
target.host = relative12.host;
|
|
3629
|
+
target.port = relative12.port;
|
|
3630
|
+
target.path = removeDotSegments(relative12.path || "");
|
|
3631
|
+
target.query = relative12.query;
|
|
3632
3632
|
} else {
|
|
3633
|
-
if (!
|
|
3633
|
+
if (!relative12.path) {
|
|
3634
3634
|
target.path = base.path;
|
|
3635
|
-
if (
|
|
3636
|
-
target.query =
|
|
3635
|
+
if (relative12.query !== void 0) {
|
|
3636
|
+
target.query = relative12.query;
|
|
3637
3637
|
} else {
|
|
3638
3638
|
target.query = base.query;
|
|
3639
3639
|
}
|
|
3640
3640
|
} else {
|
|
3641
|
-
if (
|
|
3642
|
-
target.path = removeDotSegments(
|
|
3641
|
+
if (relative12.path[0] === "/") {
|
|
3642
|
+
target.path = removeDotSegments(relative12.path);
|
|
3643
3643
|
} else {
|
|
3644
3644
|
if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
|
|
3645
|
-
target.path = "/" +
|
|
3645
|
+
target.path = "/" + relative12.path;
|
|
3646
3646
|
} else if (!base.path) {
|
|
3647
|
-
target.path =
|
|
3647
|
+
target.path = relative12.path;
|
|
3648
3648
|
} else {
|
|
3649
|
-
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) +
|
|
3649
|
+
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative12.path;
|
|
3650
3650
|
}
|
|
3651
3651
|
target.path = removeDotSegments(target.path);
|
|
3652
3652
|
}
|
|
3653
|
-
target.query =
|
|
3653
|
+
target.query = relative12.query;
|
|
3654
3654
|
}
|
|
3655
3655
|
target.userinfo = base.userinfo;
|
|
3656
3656
|
target.host = base.host;
|
|
@@ -3658,7 +3658,7 @@ var require_fast_uri = __commonJS({
|
|
|
3658
3658
|
}
|
|
3659
3659
|
target.scheme = base.scheme;
|
|
3660
3660
|
}
|
|
3661
|
-
target.fragment =
|
|
3661
|
+
target.fragment = relative12.fragment;
|
|
3662
3662
|
return target;
|
|
3663
3663
|
}
|
|
3664
3664
|
function equal(uriA, uriB, options) {
|
|
@@ -3828,8 +3828,8 @@ var require_fast_uri = __commonJS({
|
|
|
3828
3828
|
}
|
|
3829
3829
|
var fastUri = {
|
|
3830
3830
|
SCHEMES,
|
|
3831
|
-
normalize,
|
|
3832
|
-
resolve:
|
|
3831
|
+
normalize: normalize4,
|
|
3832
|
+
resolve: resolve15,
|
|
3833
3833
|
resolveComponent,
|
|
3834
3834
|
equal,
|
|
3835
3835
|
serialize,
|
|
@@ -7082,7 +7082,14 @@ var path43 = __toESM(require("node:path"));
|
|
|
7082
7082
|
|
|
7083
7083
|
// src/cli/argv.ts
|
|
7084
7084
|
function isGlobalFlag(s) {
|
|
7085
|
-
return s === "--cwd" || s === "--ci" || s === "--json" || s === "--verbose" || s === "--config" || s === "--api-base-url" || s === "--promote" || s === "--no-promote" || s === "--help" || s === "-h" || s === "--version" || s === "-V";
|
|
7085
|
+
return s === "--cwd" || s === "--ci" || s === "--json" || s === "--verbose" || s === "--config" || s === "--api-base-url" || s === "--session-path" || s === "--environment" || s === "--env" || s === "--promote" || s === "--no-promote" || s === "--help" || s === "-h" || s === "--version" || s === "-V";
|
|
7086
|
+
}
|
|
7087
|
+
function parseEnvironmentToken(raw) {
|
|
7088
|
+
const t = raw?.trim().toLowerCase();
|
|
7089
|
+
if (t === "production" || t === "staging") {
|
|
7090
|
+
return t;
|
|
7091
|
+
}
|
|
7092
|
+
throw new Error(`Invalid --environment: ${raw ?? "(missing)"} (expected production or staging)`);
|
|
7086
7093
|
}
|
|
7087
7094
|
function parseArgv(argv) {
|
|
7088
7095
|
const flags = {
|
|
@@ -7115,6 +7122,16 @@ function parseArgv(argv) {
|
|
|
7115
7122
|
i += 1;
|
|
7116
7123
|
continue;
|
|
7117
7124
|
}
|
|
7125
|
+
if (a === "--session-path" && argv[i + 1]) {
|
|
7126
|
+
flags.sessionPath = argv[i + 1];
|
|
7127
|
+
i += 1;
|
|
7128
|
+
continue;
|
|
7129
|
+
}
|
|
7130
|
+
if ((a === "--environment" || a === "--env") && argv[i + 1]) {
|
|
7131
|
+
flags.environment = parseEnvironmentToken(argv[i + 1]);
|
|
7132
|
+
i += 1;
|
|
7133
|
+
continue;
|
|
7134
|
+
}
|
|
7118
7135
|
if (a === "--ci") {
|
|
7119
7136
|
flags.ci = true;
|
|
7120
7137
|
continue;
|
|
@@ -7147,9 +7164,6 @@ function parseArgv(argv) {
|
|
|
7147
7164
|
throw new Error(`Unknown flag: ${a}`);
|
|
7148
7165
|
}
|
|
7149
7166
|
}
|
|
7150
|
-
if (process.env.EASYSPECS_CI === "1" || process.env.EASYSPECS_CI === "true") {
|
|
7151
|
-
flags.ci = true;
|
|
7152
|
-
}
|
|
7153
7167
|
return { flags, positionals };
|
|
7154
7168
|
}
|
|
7155
7169
|
|
|
@@ -7173,8 +7187,8 @@ function printJsonLine(envelope) {
|
|
|
7173
7187
|
}
|
|
7174
7188
|
|
|
7175
7189
|
// src/cli/cliContext.ts
|
|
7176
|
-
var
|
|
7177
|
-
var
|
|
7190
|
+
var fs2 = __toESM(require("node:fs"));
|
|
7191
|
+
var path2 = __toESM(require("path"));
|
|
7178
7192
|
|
|
7179
7193
|
// src/repositoryProvenance.ts
|
|
7180
7194
|
var import_node_child_process = require("node:child_process");
|
|
@@ -7343,98 +7357,115 @@ function attachRepositoryProvenance(doc, contextDir2, opts) {
|
|
|
7343
7357
|
}
|
|
7344
7358
|
|
|
7345
7359
|
// src/apiBaseUrlResolve.ts
|
|
7346
|
-
var fs2 = __toESM(require("fs"));
|
|
7347
|
-
var path2 = __toESM(require("path"));
|
|
7348
7360
|
var vscode = __toESM(require_vscode_stub());
|
|
7349
|
-
|
|
7350
|
-
// src/envDotEnvParse.ts
|
|
7351
|
-
function parseDotEnvContent(content) {
|
|
7352
|
-
const out = {};
|
|
7353
|
-
for (const line of content.split(/\r?\n/)) {
|
|
7354
|
-
const t = line.trim();
|
|
7355
|
-
if (t.length === 0 || t.startsWith("#")) {
|
|
7356
|
-
continue;
|
|
7357
|
-
}
|
|
7358
|
-
const eq = t.indexOf("=");
|
|
7359
|
-
if (eq <= 0) {
|
|
7360
|
-
continue;
|
|
7361
|
-
}
|
|
7362
|
-
const key = t.slice(0, eq).trim();
|
|
7363
|
-
let val = t.slice(eq + 1).trim();
|
|
7364
|
-
if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'")) {
|
|
7365
|
-
val = val.slice(1, -1);
|
|
7366
|
-
}
|
|
7367
|
-
out[key] = val;
|
|
7368
|
-
}
|
|
7369
|
-
return out;
|
|
7370
|
-
}
|
|
7371
|
-
|
|
7372
|
-
// src/apiBaseUrlResolve.ts
|
|
7373
|
-
var ENV_KEYS = ["VITE_SYSTEM_MANAGER_API_URL", "VITE_API_BASE_URL"];
|
|
7374
7361
|
var extensionRoot;
|
|
7375
7362
|
var cachedExtensionDotEnv = null;
|
|
7376
7363
|
function setApiBaseUrlExtensionRoot(extensionFsPath) {
|
|
7377
7364
|
extensionRoot = extensionFsPath;
|
|
7378
7365
|
cachedExtensionDotEnv = null;
|
|
7379
7366
|
}
|
|
7367
|
+
|
|
7368
|
+
// src/easyspecsBuiltInApiUrls.ts
|
|
7369
|
+
var PRODUCTION_SYSTEM_MANAGER_URL = "https://api.easyspecs.ai";
|
|
7370
|
+
var STAGING_SYSTEM_MANAGER_URL = "https://system-manager-api.staging.gluecharm.info:8092";
|
|
7371
|
+
|
|
7372
|
+
// src/easyspecsApiBaseUrlCli.ts
|
|
7380
7373
|
function stripTrailingSlash(url) {
|
|
7381
7374
|
return url.replace(/\/$/, "");
|
|
7382
7375
|
}
|
|
7383
|
-
function
|
|
7384
|
-
|
|
7385
|
-
|
|
7376
|
+
function resolveEasyspecsApiBaseUrlForCli(input) {
|
|
7377
|
+
const fromFlag = input.flagApiBaseUrl?.trim();
|
|
7378
|
+
if (fromFlag) {
|
|
7379
|
+
return stripTrailingSlash(fromFlag);
|
|
7386
7380
|
}
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
return stripTrailingSlash(v);
|
|
7391
|
-
}
|
|
7381
|
+
const fromFile = input.config.easyspecs?.apiBaseUrl?.trim();
|
|
7382
|
+
if (fromFile) {
|
|
7383
|
+
return stripTrailingSlash(fromFile);
|
|
7392
7384
|
}
|
|
7393
|
-
|
|
7385
|
+
const eff = input.flagEnvironment ?? input.config.easyspecs?.deploymentEnvironment ?? "production";
|
|
7386
|
+
return eff === "staging" ? STAGING_SYSTEM_MANAGER_URL : PRODUCTION_SYSTEM_MANAGER_URL;
|
|
7394
7387
|
}
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
|
|
7399
|
-
|
|
7400
|
-
|
|
7401
|
-
|
|
7402
|
-
|
|
7403
|
-
|
|
7388
|
+
|
|
7389
|
+
// src/cli/cliContext.ts
|
|
7390
|
+
function thisDir() {
|
|
7391
|
+
return __dirname;
|
|
7392
|
+
}
|
|
7393
|
+
function resolveRepoRoot(flags) {
|
|
7394
|
+
const abs = path2.resolve(flags.cwd);
|
|
7395
|
+
const git = findGitRepoRoot(abs);
|
|
7396
|
+
return git ?? abs;
|
|
7397
|
+
}
|
|
7398
|
+
function resolveExtensionRoot() {
|
|
7399
|
+
const env = process.env.EASYSPECS_EXTENSION_ROOT?.trim();
|
|
7400
|
+
if (env) {
|
|
7401
|
+
return path2.resolve(env);
|
|
7404
7402
|
}
|
|
7403
|
+
const here = thisDir();
|
|
7404
|
+
if (here.includes(`${path2.sep}packages${path2.sep}cli${path2.sep}dist`)) {
|
|
7405
|
+
return path2.resolve(here, "..", "..", "..");
|
|
7406
|
+
}
|
|
7407
|
+
return path2.resolve(here, "..", "..");
|
|
7405
7408
|
}
|
|
7406
|
-
function
|
|
7407
|
-
const
|
|
7408
|
-
if (
|
|
7409
|
-
return
|
|
7409
|
+
function resolveOpenCodeAgentsDir() {
|
|
7410
|
+
const resEnv = process.env.EASYSPECS_CLI_RESOURCES?.trim();
|
|
7411
|
+
if (resEnv) {
|
|
7412
|
+
return path2.join(path2.resolve(resEnv), "opencode-agents");
|
|
7410
7413
|
}
|
|
7411
|
-
const
|
|
7412
|
-
if (
|
|
7413
|
-
return
|
|
7414
|
+
const here = thisDir();
|
|
7415
|
+
if (here.includes(`${path2.sep}packages${path2.sep}cli${path2.sep}dist`)) {
|
|
7416
|
+
return path2.join(here, "..", "resources", "opencode-agents");
|
|
7414
7417
|
}
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
|
|
7418
|
+
return path2.join(resolveExtensionRoot(), "resources", "opencode-agents");
|
|
7419
|
+
}
|
|
7420
|
+
function initApiBaseUrlForCli(repoRoot, flags, config) {
|
|
7421
|
+
const extensionRoot2 = resolveExtensionRoot();
|
|
7422
|
+
setApiBaseUrlExtensionRoot(extensionRoot2);
|
|
7423
|
+
return resolveEasyspecsApiBaseUrlForCli({
|
|
7424
|
+
flagApiBaseUrl: flags.apiBaseUrl,
|
|
7425
|
+
flagEnvironment: flags.environment,
|
|
7426
|
+
config
|
|
7427
|
+
});
|
|
7428
|
+
}
|
|
7429
|
+
function assertAgentsDirExists(agentsDir) {
|
|
7430
|
+
if (!fs2.existsSync(agentsDir)) {
|
|
7431
|
+
throw new Error(
|
|
7432
|
+
`OpenCode agents directory missing: ${agentsDir}. Set EASYSPECS_EXTENSION_ROOT or EASYSPECS_CLI_RESOURCES, or run \`npm run build:cli\` to copy resources.`
|
|
7433
|
+
);
|
|
7420
7434
|
}
|
|
7421
|
-
|
|
7422
|
-
|
|
7423
|
-
|
|
7424
|
-
|
|
7435
|
+
}
|
|
7436
|
+
|
|
7437
|
+
// src/config/openCodeProviderEnv.ts
|
|
7438
|
+
var path3 = __toESM(require("node:path"));
|
|
7439
|
+
var PROVIDER_TO_ENV = {
|
|
7440
|
+
anthropic: "ANTHROPIC_API_KEY",
|
|
7441
|
+
openai: "OPENAI_API_KEY",
|
|
7442
|
+
openrouter: "OPENROUTER_API_KEY",
|
|
7443
|
+
google: "GOOGLE_API_KEY",
|
|
7444
|
+
opencode: "OPENCODE_API_KEY"
|
|
7445
|
+
};
|
|
7446
|
+
function buildOpenCodeProviderEnvFromConfig(cfg, repoRoot) {
|
|
7447
|
+
const out = {};
|
|
7448
|
+
const prov = cfg.easyspecs?.openCodeRuntime?.providers;
|
|
7449
|
+
if (prov) {
|
|
7450
|
+
for (const id of Object.keys(PROVIDER_TO_ENV)) {
|
|
7451
|
+
const envName = PROVIDER_TO_ENV[id];
|
|
7452
|
+
const key = prov[id]?.apiKey?.trim();
|
|
7453
|
+
if (key) {
|
|
7454
|
+
out[envName] = key;
|
|
7455
|
+
}
|
|
7456
|
+
}
|
|
7425
7457
|
}
|
|
7426
|
-
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7458
|
+
const raw = cfg.easyspecs?.openCodeRuntime?.credentialsPath;
|
|
7459
|
+
if (repoRoot && typeof raw === "string") {
|
|
7460
|
+
const t = raw.trim();
|
|
7461
|
+
if (t.length > 0) {
|
|
7462
|
+
out.OPENCODE_AUTH_PATH = path3.isAbsolute(t) ? path3.normalize(t) : path3.resolve(repoRoot, t);
|
|
7430
7463
|
}
|
|
7431
7464
|
}
|
|
7432
|
-
return
|
|
7465
|
+
return out;
|
|
7433
7466
|
}
|
|
7434
7467
|
|
|
7435
7468
|
// src/cli/cliSettings.ts
|
|
7436
|
-
var fs3 = __toESM(require("node:fs"));
|
|
7437
|
-
var path3 = __toESM(require("node:path"));
|
|
7438
7469
|
var DEFAULT_OPEN_CODE_TEST_ARGV = [
|
|
7439
7470
|
"run",
|
|
7440
7471
|
"--agent",
|
|
@@ -7444,72 +7475,23 @@ var DEFAULT_OPEN_CODE_TEST_ARGV = [
|
|
|
7444
7475
|
"{promptFile}"
|
|
7445
7476
|
];
|
|
7446
7477
|
var CI_DEFAULT_MAX_OUTER = 3;
|
|
7447
|
-
function
|
|
7448
|
-
const
|
|
7449
|
-
try {
|
|
7450
|
-
if (!fs3.existsSync(f)) {
|
|
7451
|
-
return void 0;
|
|
7452
|
-
}
|
|
7453
|
-
const raw = fs3.readFileSync(f, "utf8");
|
|
7454
|
-
return JSON.parse(raw);
|
|
7455
|
-
} catch {
|
|
7456
|
-
return void 0;
|
|
7457
|
-
}
|
|
7458
|
-
}
|
|
7459
|
-
function numEnv(name, fallback) {
|
|
7460
|
-
const v = process.env[name]?.trim();
|
|
7461
|
-
if (!v) {
|
|
7462
|
-
return fallback;
|
|
7463
|
-
}
|
|
7464
|
-
const n = Number(v);
|
|
7465
|
-
return Number.isFinite(n) ? n : fallback;
|
|
7466
|
-
}
|
|
7467
|
-
function boolEnv(name, fallback) {
|
|
7468
|
-
const v = process.env[name]?.trim().toLowerCase();
|
|
7469
|
-
if (v === "1" || v === "true" || v === "yes") {
|
|
7470
|
-
return true;
|
|
7471
|
-
}
|
|
7472
|
-
if (v === "0" || v === "false" || v === "no") {
|
|
7473
|
-
return false;
|
|
7474
|
-
}
|
|
7475
|
-
return fallback;
|
|
7476
|
-
}
|
|
7477
|
-
function mergeCliSettings(repoRoot, overrides = {}) {
|
|
7478
|
-
const file = readCliJson(repoRoot);
|
|
7479
|
-
const es = file?.easyspecs ?? {};
|
|
7478
|
+
function mergeEasyspecsCliSettings(cfg, overrides = {}) {
|
|
7479
|
+
const es = cfg.easyspecs ?? {};
|
|
7480
7480
|
const analysis = es.analysis ?? {};
|
|
7481
7481
|
const orch = es.orchestration ?? {};
|
|
7482
|
-
const
|
|
7483
|
-
const
|
|
7484
|
-
const
|
|
7485
|
-
const
|
|
7486
|
-
|
|
7487
|
-
|
|
7488
|
-
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
}
|
|
7494
|
-
} catch {
|
|
7495
|
-
}
|
|
7496
|
-
}
|
|
7497
|
-
const timeoutMs = overrides.timeoutMs ?? numEnv("EASYSPECS_ANALYSIS_TIMEOUT_MS", analysis.openCodeTestTimeoutMs ?? 6e5);
|
|
7498
|
-
const listJsonSchemaRepairAttempts = numEnv(
|
|
7499
|
-
"EASYSPECS_LIST_JSON_SCHEMA_REPAIR_ATTEMPTS",
|
|
7500
|
-
analysis.listJsonSchemaRepairAttempts ?? 1
|
|
7501
|
-
);
|
|
7502
|
-
const markdownEvidenceRepairAttempts = numEnv(
|
|
7503
|
-
"EASYSPECS_MARKDOWN_EVIDENCE_REPAIR_ATTEMPTS",
|
|
7504
|
-
analysis.markdownEvidenceRepairAttempts ?? 2
|
|
7505
|
-
);
|
|
7506
|
-
const markdownOpenQuestionIterations = numEnv(
|
|
7507
|
-
"EASYSPECS_MARKDOWN_OPEN_QUESTION_ITERATIONS",
|
|
7508
|
-
analysis.markdownOpenQuestionIterations ?? 5
|
|
7509
|
-
);
|
|
7510
|
-
const maxConcurrentOpenCodeAgents = overrides.maxConcurrentOpenCodeAgents ?? numEnv("EASYSPECS_MAX_CONCURRENT_AGENTS", analysis.maxConcurrentOpenCodeAgents ?? 30);
|
|
7482
|
+
const rt = es.openCodeRuntime;
|
|
7483
|
+
const ci = overrides.ci === true;
|
|
7484
|
+
const apiBaseUrl = overrides.apiBaseUrl?.trim() || (typeof es.apiBaseUrl === "string" ? es.apiBaseUrl.trim() : "") || "";
|
|
7485
|
+
const openCodeExecutable = overrides.openCodeExecutable?.trim() || es.openCode?.executable?.trim() || rt?.executable?.trim() || "opencode";
|
|
7486
|
+
const openCodeSkipCredentialsCheck = es.openCode?.skipCredentialsCheck === true || rt?.skipCredentialsCheck === true;
|
|
7487
|
+
let argvTemplate = overrides.argvTemplate ?? (rt?.run?.argvTemplate && rt.run.argvTemplate.length > 0 && rt.run.argvTemplate.every((x) => typeof x === "string") ? [...rt.run.argvTemplate] : void 0) ?? (Array.isArray(analysis.openCodeTestArgv) && analysis.openCodeTestArgv.length > 0 && analysis.openCodeTestArgv.every((x) => typeof x === "string") ? analysis.openCodeTestArgv : [...DEFAULT_OPEN_CODE_TEST_ARGV]);
|
|
7488
|
+
const timeoutMs = overrides.timeoutMs ?? rt?.run?.timeoutMs ?? analysis.openCodeTestTimeoutMs ?? 6e5;
|
|
7489
|
+
const listJsonSchemaRepairAttempts = rt?.coordinationRepairs?.listJsonSchemaRepairAttempts ?? analysis.listJsonSchemaRepairAttempts ?? 1;
|
|
7490
|
+
const markdownEvidenceRepairAttempts = rt?.coordinationRepairs?.markdownEvidenceRepairAttempts ?? analysis.markdownEvidenceRepairAttempts ?? 2;
|
|
7491
|
+
const markdownOpenQuestionIterations = rt?.coordinationRepairs?.markdownOpenQuestionIterations ?? analysis.markdownOpenQuestionIterations ?? 5;
|
|
7492
|
+
const maxConcurrentOpenCodeAgents = overrides.maxConcurrentOpenCodeAgents ?? rt?.pool?.maxConcurrentAgents ?? analysis.maxConcurrentOpenCodeAgents ?? 30;
|
|
7511
7493
|
const promoteContextToWorkspace = overrides.promote === false ? false : overrides.promote === true ? true : analysis.promoteContextToWorkspace !== false;
|
|
7512
|
-
let maxOuter = overrides.maxOuterIterationsPerPhase ?? orch.maxOuterIterationsPerPhase ??
|
|
7494
|
+
let maxOuter = overrides.maxOuterIterationsPerPhase ?? orch.maxOuterIterationsPerPhase ?? 0;
|
|
7513
7495
|
if (ci && maxOuter === 0) {
|
|
7514
7496
|
maxOuter = CI_DEFAULT_MAX_OUTER;
|
|
7515
7497
|
}
|
|
@@ -7521,12 +7503,15 @@ function mergeCliSettings(repoRoot, overrides = {}) {
|
|
|
7521
7503
|
maxMacroPingPongCycles: orch.maxMacroPingPongCycles ?? 5,
|
|
7522
7504
|
synthesisRemediationShareBackoff: orch.synthesisRemediationShareBackoff !== false
|
|
7523
7505
|
};
|
|
7506
|
+
const openCodeChildEnv = buildOpenCodeProviderEnvFromConfig(cfg, overrides.repoRoot);
|
|
7507
|
+
const projectConfigOverlay = cfg.easyspecs?.openCodeRuntime?.projectConfigOverlay;
|
|
7524
7508
|
return {
|
|
7525
7509
|
apiBaseUrl,
|
|
7526
7510
|
openCodeExecutable,
|
|
7527
7511
|
openCodeSkipCredentialsCheck,
|
|
7528
7512
|
promoteContextToWorkspace,
|
|
7529
7513
|
ci,
|
|
7514
|
+
openCodeChildEnv,
|
|
7530
7515
|
pipelineOpenCode: {
|
|
7531
7516
|
executable: openCodeExecutable,
|
|
7532
7517
|
argvTemplate,
|
|
@@ -7534,85 +7519,420 @@ function mergeCliSettings(repoRoot, overrides = {}) {
|
|
|
7534
7519
|
listJsonSchemaRepairAttempts,
|
|
7535
7520
|
markdownEvidenceRepairAttempts,
|
|
7536
7521
|
markdownOpenQuestionIterations,
|
|
7537
|
-
maxConcurrentOpenCodeAgents
|
|
7522
|
+
maxConcurrentOpenCodeAgents,
|
|
7523
|
+
openCodeChildEnv,
|
|
7524
|
+
projectConfigOverlay
|
|
7538
7525
|
},
|
|
7539
7526
|
macroOrchestration
|
|
7540
7527
|
};
|
|
7541
7528
|
}
|
|
7542
7529
|
|
|
7543
|
-
// src/cli/
|
|
7544
|
-
function
|
|
7545
|
-
|
|
7530
|
+
// src/cli/cliSettingsDump.ts
|
|
7531
|
+
function redactMergedCliSettingsForDump(merged) {
|
|
7532
|
+
const child = merged.openCodeChildEnv;
|
|
7533
|
+
const childRedacted = child && Object.keys(child).length > 0 ? Object.fromEntries(Object.keys(child).map((k) => [k, "(redacted)"])) : {};
|
|
7534
|
+
return {
|
|
7535
|
+
...merged,
|
|
7536
|
+
apiBaseUrl: merged.apiBaseUrl ? "(set)" : "",
|
|
7537
|
+
openCodeChildEnv: childRedacted,
|
|
7538
|
+
pipelineOpenCode: {
|
|
7539
|
+
...merged.pipelineOpenCode,
|
|
7540
|
+
openCodeChildEnv: childRedacted
|
|
7541
|
+
}
|
|
7542
|
+
};
|
|
7546
7543
|
}
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
|
|
7544
|
+
|
|
7545
|
+
// src/config/easyspecsConfigFile.ts
|
|
7546
|
+
var fs5 = __toESM(require("node:fs"));
|
|
7547
|
+
var path6 = __toESM(require("node:path"));
|
|
7548
|
+
|
|
7549
|
+
// src/easySpecsWorkspaceSettingsCore.ts
|
|
7550
|
+
var fs4 = __toESM(require("node:fs"));
|
|
7551
|
+
var path5 = __toESM(require("node:path"));
|
|
7552
|
+
|
|
7553
|
+
// src/analysis/easySpecsWorktreeMarker.ts
|
|
7554
|
+
var fs3 = __toESM(require("fs"));
|
|
7555
|
+
var path4 = __toESM(require("path"));
|
|
7556
|
+
var EASYSPECS_LOCAL_DIR = ".easyspecs";
|
|
7557
|
+
var EASYSPECS_WORKTREE_MARKER_REL = path4.join(EASYSPECS_LOCAL_DIR, "analysis-worktree.json");
|
|
7558
|
+
var MARKER_KIND = "easyspecs-analysis-worktree";
|
|
7559
|
+
function writeAnalysisWorktreeMarker(worktreeRoot, repositoryRoot) {
|
|
7560
|
+
const dir = path4.join(worktreeRoot, EASYSPECS_LOCAL_DIR);
|
|
7561
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
7562
|
+
const payload = {
|
|
7563
|
+
kind: MARKER_KIND,
|
|
7564
|
+
repositoryRoot: path4.resolve(repositoryRoot)
|
|
7565
|
+
};
|
|
7566
|
+
fs3.writeFileSync(path4.join(dir, "analysis-worktree.json"), `${JSON.stringify(payload)}
|
|
7567
|
+
`, "utf-8");
|
|
7551
7568
|
}
|
|
7552
|
-
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
|
|
7569
|
+
|
|
7570
|
+
// src/easySpecsWorkspaceSettingsCore.ts
|
|
7571
|
+
var EASYSPECS_WORKSPACE_DIR = EASYSPECS_LOCAL_DIR;
|
|
7572
|
+
var EASYSPECS_SETTINGS_JSON = "settings.json";
|
|
7573
|
+
var EASYSPECS_SETTINGS_ACE_KEY = "easyspecs.analysis.ace.enabled";
|
|
7574
|
+
var EASYSPECS_SETTINGS_ACE_OFFLINE_AFTER_TRACE_KEY = "easyspecs.analysis.ace.offlineLearnAfterSameSessionTrace";
|
|
7575
|
+
function isRecord(v) {
|
|
7576
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
7577
|
+
}
|
|
7578
|
+
function readAceEnabledFromEasySpecsSettingsFile(workspaceRootFsPath) {
|
|
7579
|
+
const filePath = path5.join(workspaceRootFsPath, EASYSPECS_WORKSPACE_DIR, EASYSPECS_SETTINGS_JSON);
|
|
7580
|
+
let raw;
|
|
7581
|
+
try {
|
|
7582
|
+
raw = fs4.readFileSync(filePath, "utf8");
|
|
7583
|
+
} catch {
|
|
7584
|
+
return void 0;
|
|
7556
7585
|
}
|
|
7557
|
-
|
|
7558
|
-
|
|
7559
|
-
|
|
7586
|
+
let parsed;
|
|
7587
|
+
try {
|
|
7588
|
+
parsed = JSON.parse(raw);
|
|
7589
|
+
} catch {
|
|
7590
|
+
return void 0;
|
|
7560
7591
|
}
|
|
7561
|
-
|
|
7592
|
+
if (!isRecord(parsed) || !Object.prototype.hasOwnProperty.call(parsed, EASYSPECS_SETTINGS_ACE_KEY)) {
|
|
7593
|
+
return void 0;
|
|
7594
|
+
}
|
|
7595
|
+
const v = parsed[EASYSPECS_SETTINGS_ACE_KEY];
|
|
7596
|
+
return typeof v === "boolean" ? v : void 0;
|
|
7562
7597
|
}
|
|
7563
|
-
function
|
|
7564
|
-
const
|
|
7565
|
-
|
|
7566
|
-
|
|
7598
|
+
function readAceOfflineLearnAfterSameSessionTraceFromEasySpecsSettingsFile(workspaceRootFsPath) {
|
|
7599
|
+
const filePath = path5.join(workspaceRootFsPath, EASYSPECS_WORKSPACE_DIR, EASYSPECS_SETTINGS_JSON);
|
|
7600
|
+
let raw;
|
|
7601
|
+
try {
|
|
7602
|
+
raw = fs4.readFileSync(filePath, "utf8");
|
|
7603
|
+
} catch {
|
|
7604
|
+
return void 0;
|
|
7567
7605
|
}
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7606
|
+
let parsed;
|
|
7607
|
+
try {
|
|
7608
|
+
parsed = JSON.parse(raw);
|
|
7609
|
+
} catch {
|
|
7610
|
+
return void 0;
|
|
7571
7611
|
}
|
|
7572
|
-
|
|
7612
|
+
if (!isRecord(parsed) || !Object.prototype.hasOwnProperty.call(parsed, EASYSPECS_SETTINGS_ACE_OFFLINE_AFTER_TRACE_KEY)) {
|
|
7613
|
+
return void 0;
|
|
7614
|
+
}
|
|
7615
|
+
const v = parsed[EASYSPECS_SETTINGS_ACE_OFFLINE_AFTER_TRACE_KEY];
|
|
7616
|
+
return typeof v === "boolean" ? v : void 0;
|
|
7573
7617
|
}
|
|
7574
|
-
|
|
7575
|
-
|
|
7576
|
-
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
|
|
7585
|
-
|
|
7586
|
-
|
|
7618
|
+
|
|
7619
|
+
// src/config/easyspecsConfigJson.ts
|
|
7620
|
+
function mergeEasyspecsConfigDefaults(defaults, partial) {
|
|
7621
|
+
if (!partial) {
|
|
7622
|
+
return defaults;
|
|
7623
|
+
}
|
|
7624
|
+
const esInRaw = partial.easyspecs ?? {};
|
|
7625
|
+
const legacyProjectId = esInRaw.applicationId;
|
|
7626
|
+
const { applicationId: _omitLegacyApplicationIdKey, ...esIn } = esInRaw;
|
|
7627
|
+
void _omitLegacyApplicationIdKey;
|
|
7628
|
+
const defEs = defaults.easyspecs;
|
|
7629
|
+
const mergedEs = {
|
|
7630
|
+
...defEs,
|
|
7631
|
+
...esIn,
|
|
7632
|
+
deploymentEnvironment: esIn.deploymentEnvironment ?? defEs.deploymentEnvironment,
|
|
7633
|
+
apiBaseUrl: esIn.apiBaseUrl ?? defEs.apiBaseUrl,
|
|
7634
|
+
easyspecsProjectId: esIn.easyspecsProjectId !== void 0 ? esIn.easyspecsProjectId : legacyProjectId !== void 0 ? legacyProjectId : defEs.easyspecsProjectId,
|
|
7635
|
+
defaultGitRemoteUrl: esIn.defaultGitRemoteUrl !== void 0 ? esIn.defaultGitRemoteUrl : defEs.defaultGitRemoteUrl,
|
|
7636
|
+
cliSessionPath: esIn.cliSessionPath !== void 0 ? esIn.cliSessionPath : defEs.cliSessionPath,
|
|
7637
|
+
openCode: { ...defEs.openCode, ...esIn.openCode },
|
|
7638
|
+
analysis: mergeAnalysisBlock(
|
|
7639
|
+
defEs.analysis ?? { promoteContextToWorkspace: true },
|
|
7640
|
+
esIn.analysis
|
|
7641
|
+
),
|
|
7642
|
+
orchestration: { ...defEs.orchestration, ...esIn.orchestration },
|
|
7643
|
+
openCodeRuntime: mergeOpenCodeRuntime(defEs.openCodeRuntime, esIn.openCodeRuntime)
|
|
7644
|
+
};
|
|
7645
|
+
return {
|
|
7646
|
+
schemaVersion: partial.schemaVersion ?? defaults.schemaVersion,
|
|
7647
|
+
easyspecs: mergedEs
|
|
7648
|
+
};
|
|
7587
7649
|
}
|
|
7588
|
-
function
|
|
7589
|
-
if (!
|
|
7590
|
-
|
|
7591
|
-
|
|
7592
|
-
|
|
7650
|
+
function mergeAnalysisBlock(base, over) {
|
|
7651
|
+
if (!over || Object.keys(over).length === 0) {
|
|
7652
|
+
return { ...base };
|
|
7653
|
+
}
|
|
7654
|
+
const merged = {
|
|
7655
|
+
...base,
|
|
7656
|
+
...over
|
|
7657
|
+
};
|
|
7658
|
+
if (base.ace || over.ace) {
|
|
7659
|
+
merged.ace = { ...base.ace, ...over.ace };
|
|
7660
|
+
}
|
|
7661
|
+
return merged;
|
|
7662
|
+
}
|
|
7663
|
+
function mergeOpenCodeRuntime(base, over) {
|
|
7664
|
+
if (!over && !base) {
|
|
7665
|
+
return void 0;
|
|
7666
|
+
}
|
|
7667
|
+
const b = base ?? {};
|
|
7668
|
+
const o = over ?? {};
|
|
7669
|
+
return {
|
|
7670
|
+
...b,
|
|
7671
|
+
...o,
|
|
7672
|
+
executable: o.executable ?? b.executable,
|
|
7673
|
+
skipCredentialsCheck: o.skipCredentialsCheck ?? b.skipCredentialsCheck,
|
|
7674
|
+
credentialsPath: o.credentialsPath !== void 0 ? o.credentialsPath : b.credentialsPath,
|
|
7675
|
+
providers: { ...b.providers, ...o.providers },
|
|
7676
|
+
run: { ...b.run, ...o.run },
|
|
7677
|
+
coordinationRepairs: { ...b.coordinationRepairs, ...o.coordinationRepairs },
|
|
7678
|
+
pool: { ...b.pool, ...o.pool },
|
|
7679
|
+
projectConfigOverlay: b.projectConfigOverlay || o.projectConfigOverlay ? { ...b.projectConfigOverlay ?? {}, ...o.projectConfigOverlay ?? {} } : void 0
|
|
7680
|
+
};
|
|
7681
|
+
}
|
|
7682
|
+
function getDefaultEasyspecsConfig() {
|
|
7683
|
+
const openCodeRuntime = {
|
|
7684
|
+
executable: "opencode",
|
|
7685
|
+
skipCredentialsCheck: false,
|
|
7686
|
+
credentialsPath: ".opencode/auth.json",
|
|
7687
|
+
providers: {},
|
|
7688
|
+
run: {
|
|
7689
|
+
argvTemplate: [
|
|
7690
|
+
"run",
|
|
7691
|
+
"--agent",
|
|
7692
|
+
"{agentId}",
|
|
7693
|
+
"Execute the task described in the attached EasySpecs prompt file.",
|
|
7694
|
+
"-f",
|
|
7695
|
+
"{promptFile}"
|
|
7696
|
+
],
|
|
7697
|
+
timeoutMs: 6e5
|
|
7698
|
+
},
|
|
7699
|
+
coordinationRepairs: {
|
|
7700
|
+
listJsonSchemaRepairAttempts: 1,
|
|
7701
|
+
markdownEvidenceRepairAttempts: 2,
|
|
7702
|
+
markdownOpenQuestionIterations: 5
|
|
7703
|
+
},
|
|
7704
|
+
pool: {
|
|
7705
|
+
maxConcurrentAgents: 30
|
|
7706
|
+
},
|
|
7707
|
+
projectConfigOverlay: {}
|
|
7708
|
+
};
|
|
7709
|
+
return {
|
|
7710
|
+
schemaVersion: 1,
|
|
7711
|
+
easyspecs: {
|
|
7712
|
+
deploymentEnvironment: "production",
|
|
7713
|
+
apiBaseUrl: PRODUCTION_SYSTEM_MANAGER_URL,
|
|
7714
|
+
easyspecsProjectId: "",
|
|
7715
|
+
defaultGitRemoteUrl: "",
|
|
7716
|
+
cliSessionPath: "",
|
|
7717
|
+
openCode: {
|
|
7718
|
+
executable: "opencode",
|
|
7719
|
+
skipCredentialsCheck: false
|
|
7720
|
+
},
|
|
7721
|
+
analysis: {
|
|
7722
|
+
promoteContextToWorkspace: true
|
|
7723
|
+
},
|
|
7724
|
+
orchestration: {},
|
|
7725
|
+
openCodeRuntime
|
|
7726
|
+
}
|
|
7727
|
+
};
|
|
7728
|
+
}
|
|
7729
|
+
|
|
7730
|
+
// src/config/easyspecsConfigFile.ts
|
|
7731
|
+
var DIRNAME = ".easyspecs";
|
|
7732
|
+
var CONFIG_BASENAME = "config.json";
|
|
7733
|
+
var LEGACY_CLI_JSON = "cli.json";
|
|
7734
|
+
var LEGACY_SETTINGS_JSON = "settings.json";
|
|
7735
|
+
function easyspecsConfigPath(repoRoot) {
|
|
7736
|
+
return path6.join(repoRoot, DIRNAME, CONFIG_BASENAME);
|
|
7737
|
+
}
|
|
7738
|
+
function easyspecsLegacyCliJsonPath(repoRoot) {
|
|
7739
|
+
return path6.join(repoRoot, DIRNAME, LEGACY_CLI_JSON);
|
|
7740
|
+
}
|
|
7741
|
+
function easyspecsLegacySettingsJsonPath(repoRoot) {
|
|
7742
|
+
return path6.join(repoRoot, DIRNAME, LEGACY_SETTINGS_JSON);
|
|
7743
|
+
}
|
|
7744
|
+
var EasyspecsConfigInvalidJsonError = class extends Error {
|
|
7745
|
+
constructor(filePath, cause) {
|
|
7746
|
+
super(`Invalid JSON in ${filePath}${cause instanceof Error ? `: ${cause.message}` : ""}`);
|
|
7747
|
+
this.filePath = filePath;
|
|
7748
|
+
this.cause = cause;
|
|
7749
|
+
this.name = "EasyspecsConfigInvalidJsonError";
|
|
7750
|
+
}
|
|
7751
|
+
};
|
|
7752
|
+
function parseEasyspecsConfigJson(raw, filePath) {
|
|
7753
|
+
try {
|
|
7754
|
+
const parsed = JSON.parse(raw);
|
|
7755
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
7756
|
+
throw new EasyspecsConfigInvalidJsonError(filePath);
|
|
7757
|
+
}
|
|
7758
|
+
return mergeEasyspecsConfigDefaults(getDefaultEasyspecsConfig(), parsed);
|
|
7759
|
+
} catch (e) {
|
|
7760
|
+
if (e instanceof EasyspecsConfigInvalidJsonError) {
|
|
7761
|
+
throw e;
|
|
7762
|
+
}
|
|
7763
|
+
throw new EasyspecsConfigInvalidJsonError(filePath, e);
|
|
7764
|
+
}
|
|
7765
|
+
}
|
|
7766
|
+
function readEasyspecsConfig(repoRoot) {
|
|
7767
|
+
const p = easyspecsConfigPath(repoRoot);
|
|
7768
|
+
const raw = fs5.readFileSync(p, "utf8");
|
|
7769
|
+
return parseEasyspecsConfigJson(raw, p);
|
|
7770
|
+
}
|
|
7771
|
+
function cliJsonFileToConfigPartial(legacy) {
|
|
7772
|
+
const es = legacy.easyspecs ?? {};
|
|
7773
|
+
const analysis = es.analysis ?? {};
|
|
7774
|
+
const orch = es.orchestration ?? {};
|
|
7775
|
+
const partial = {
|
|
7776
|
+
easyspecs: {
|
|
7777
|
+
apiBaseUrl: legacy.apiBaseUrl ?? es.apiBaseUrl ?? "",
|
|
7778
|
+
openCode: es.openCode,
|
|
7779
|
+
analysis: {
|
|
7780
|
+
openCodeTestArgv: analysis.openCodeTestArgv,
|
|
7781
|
+
openCodeTestTimeoutMs: analysis.openCodeTestTimeoutMs,
|
|
7782
|
+
listJsonSchemaRepairAttempts: analysis.listJsonSchemaRepairAttempts,
|
|
7783
|
+
markdownEvidenceRepairAttempts: analysis.markdownEvidenceRepairAttempts,
|
|
7784
|
+
markdownOpenQuestionIterations: analysis.markdownOpenQuestionIterations,
|
|
7785
|
+
maxConcurrentOpenCodeAgents: analysis.maxConcurrentOpenCodeAgents,
|
|
7786
|
+
promoteContextToWorkspace: analysis.promoteContextToWorkspace
|
|
7787
|
+
},
|
|
7788
|
+
orchestration: {
|
|
7789
|
+
initialDelayMs: orch.initialDelayMs,
|
|
7790
|
+
backoffMultiplier: orch.backoffMultiplier,
|
|
7791
|
+
maxDelayMs: orch.maxDelayMs,
|
|
7792
|
+
maxOuterIterationsPerPhase: orch.maxOuterIterationsPerPhase,
|
|
7793
|
+
maxMacroPingPongCycles: orch.maxMacroPingPongCycles,
|
|
7794
|
+
synthesisRemediationShareBackoff: orch.synthesisRemediationShareBackoff
|
|
7795
|
+
}
|
|
7796
|
+
}
|
|
7797
|
+
};
|
|
7798
|
+
return partial;
|
|
7799
|
+
}
|
|
7800
|
+
function atomicWriteFile(targetPath, contents) {
|
|
7801
|
+
const dir = path6.dirname(targetPath);
|
|
7802
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
7803
|
+
const tmp = path6.join(dir, `.${path6.basename(targetPath)}.${process.pid}.${Date.now()}.tmp`);
|
|
7804
|
+
fs5.writeFileSync(tmp, contents, "utf8");
|
|
7805
|
+
fs5.renameSync(tmp, targetPath);
|
|
7806
|
+
}
|
|
7807
|
+
function buildFreshEasyspecsConfigFromLegacy(repoRoot, warnMigration) {
|
|
7808
|
+
let base = getDefaultEasyspecsConfig();
|
|
7809
|
+
const legacyPath = easyspecsLegacyCliJsonPath(repoRoot);
|
|
7810
|
+
if (fs5.existsSync(legacyPath)) {
|
|
7811
|
+
try {
|
|
7812
|
+
const rawLegacy = fs5.readFileSync(legacyPath, "utf8");
|
|
7813
|
+
const legacyParsed = JSON.parse(rawLegacy);
|
|
7814
|
+
base = mergeEasyspecsConfigDefaults(base, cliJsonFileToConfigPartial(legacyParsed));
|
|
7815
|
+
warnMigration?.(`Imported settings from ${LEGACY_CLI_JSON} into ${CONFIG_BASENAME} (SRS-43 migration).`);
|
|
7816
|
+
} catch (e) {
|
|
7817
|
+
warnMigration?.(`Could not import ${LEGACY_CLI_JSON}: ${e instanceof Error ? e.message : String(e)}`);
|
|
7818
|
+
}
|
|
7819
|
+
}
|
|
7820
|
+
const settingsLegacyPath = easyspecsLegacySettingsJsonPath(repoRoot);
|
|
7821
|
+
if (fs5.existsSync(settingsLegacyPath)) {
|
|
7822
|
+
try {
|
|
7823
|
+
const rawS = fs5.readFileSync(settingsLegacyPath, "utf8");
|
|
7824
|
+
const leg = JSON.parse(rawS);
|
|
7825
|
+
const ace = {};
|
|
7826
|
+
if (Object.prototype.hasOwnProperty.call(leg, EASYSPECS_SETTINGS_ACE_KEY)) {
|
|
7827
|
+
const v = leg[EASYSPECS_SETTINGS_ACE_KEY];
|
|
7828
|
+
if (typeof v === "boolean") {
|
|
7829
|
+
ace.enabled = v;
|
|
7830
|
+
}
|
|
7831
|
+
}
|
|
7832
|
+
if (Object.prototype.hasOwnProperty.call(leg, EASYSPECS_SETTINGS_ACE_OFFLINE_AFTER_TRACE_KEY)) {
|
|
7833
|
+
const v = leg[EASYSPECS_SETTINGS_ACE_OFFLINE_AFTER_TRACE_KEY];
|
|
7834
|
+
if (typeof v === "boolean") {
|
|
7835
|
+
ace.offlineLearnAfterSameSessionTrace = v;
|
|
7836
|
+
}
|
|
7837
|
+
}
|
|
7838
|
+
if (Object.keys(ace).length > 0) {
|
|
7839
|
+
base = mergeEasyspecsConfigDefaults(base, { easyspecs: { analysis: { ace } } });
|
|
7840
|
+
warnMigration?.(`Imported ACE toggles from ${LEGACY_SETTINGS_JSON} into ${CONFIG_BASENAME}.`);
|
|
7841
|
+
}
|
|
7842
|
+
} catch (e) {
|
|
7843
|
+
warnMigration?.(
|
|
7844
|
+
`Could not import ${LEGACY_SETTINGS_JSON}: ${e instanceof Error ? e.message : String(e)}`
|
|
7845
|
+
);
|
|
7846
|
+
}
|
|
7593
7847
|
}
|
|
7848
|
+
return base;
|
|
7849
|
+
}
|
|
7850
|
+
function initEasyspecsConfigFile(repoRoot, opts) {
|
|
7851
|
+
const configPath = easyspecsConfigPath(repoRoot);
|
|
7852
|
+
const existed = fs5.existsSync(configPath);
|
|
7853
|
+
if (existed && !opts.overwrite) {
|
|
7854
|
+
return { outcome: "unchanged", path: configPath, config: readEasyspecsConfig(repoRoot) };
|
|
7855
|
+
}
|
|
7856
|
+
const base = buildFreshEasyspecsConfigFromLegacy(repoRoot, opts.warnMigration);
|
|
7857
|
+
atomicWriteFile(configPath, `${JSON.stringify(base, null, 2)}
|
|
7858
|
+
`);
|
|
7859
|
+
return {
|
|
7860
|
+
outcome: existed ? "overwritten" : "created",
|
|
7861
|
+
path: configPath,
|
|
7862
|
+
config: readEasyspecsConfig(repoRoot)
|
|
7863
|
+
};
|
|
7864
|
+
}
|
|
7865
|
+
function ensureEasyspecsConfig(repoRoot, opts) {
|
|
7866
|
+
const configPath = easyspecsConfigPath(repoRoot);
|
|
7867
|
+
const legacyPath = easyspecsLegacyCliJsonPath(repoRoot);
|
|
7868
|
+
if (fs5.existsSync(configPath)) {
|
|
7869
|
+
if (fs5.existsSync(legacyPath)) {
|
|
7870
|
+
opts.warnMigration?.(
|
|
7871
|
+
`${legacyPath} is deprecated alongside ${configPath}; prefer editing ${CONFIG_BASENAME} only.`
|
|
7872
|
+
);
|
|
7873
|
+
}
|
|
7874
|
+
const settingsLegacy = easyspecsLegacySettingsJsonPath(repoRoot);
|
|
7875
|
+
if (fs5.existsSync(settingsLegacy)) {
|
|
7876
|
+
opts.warnMigration?.(
|
|
7877
|
+
`${settingsLegacy} is deprecated; use easyspecs.analysis.ace in ${CONFIG_BASENAME} (see USER-MANUAL-SRS-35).`
|
|
7878
|
+
);
|
|
7879
|
+
}
|
|
7880
|
+
return readEasyspecsConfig(repoRoot);
|
|
7881
|
+
}
|
|
7882
|
+
const base = buildFreshEasyspecsConfigFromLegacy(repoRoot, opts.warnMigration);
|
|
7883
|
+
if (!opts.allowCreate) {
|
|
7884
|
+
return base;
|
|
7885
|
+
}
|
|
7886
|
+
const body = `${JSON.stringify(base, null, 2)}
|
|
7887
|
+
`;
|
|
7888
|
+
atomicWriteFile(configPath, body);
|
|
7889
|
+
return readEasyspecsConfig(repoRoot);
|
|
7890
|
+
}
|
|
7891
|
+
function updateEasyspecsConfig(repoRoot, patch, opts) {
|
|
7892
|
+
const configPath = easyspecsConfigPath(repoRoot);
|
|
7893
|
+
const base = fs5.existsSync(configPath) ? readEasyspecsConfig(repoRoot) : buildFreshEasyspecsConfigFromLegacy(repoRoot, opts?.warnMigration);
|
|
7894
|
+
const merged = mergeEasyspecsConfigDefaults(base, patch);
|
|
7895
|
+
atomicWriteFile(configPath, `${JSON.stringify(merged, null, 2)}
|
|
7896
|
+
`);
|
|
7897
|
+
return merged;
|
|
7898
|
+
}
|
|
7899
|
+
|
|
7900
|
+
// src/config/easyspecsConfigRedact.ts
|
|
7901
|
+
function redactEasyspecsConfigRootForDump(cfg) {
|
|
7902
|
+
const o = JSON.parse(JSON.stringify(cfg));
|
|
7903
|
+
const es = o.easyspecs;
|
|
7904
|
+
const rt = es?.openCodeRuntime;
|
|
7905
|
+
const prov = rt?.providers;
|
|
7906
|
+
if (prov && typeof prov === "object") {
|
|
7907
|
+
for (const p of Object.values(prov)) {
|
|
7908
|
+
if (p && typeof p === "object" && "apiKey" in p) {
|
|
7909
|
+
p.apiKey = "(redacted)";
|
|
7910
|
+
}
|
|
7911
|
+
}
|
|
7912
|
+
}
|
|
7913
|
+
return o;
|
|
7594
7914
|
}
|
|
7595
7915
|
|
|
7596
7916
|
// src/cli/cliFileWorkspaceState.ts
|
|
7597
|
-
var
|
|
7598
|
-
var
|
|
7917
|
+
var fs6 = __toESM(require("node:fs"));
|
|
7918
|
+
var path7 = __toESM(require("node:path"));
|
|
7599
7919
|
function createFileBackedWorkspaceState(repoRoot) {
|
|
7600
|
-
const dir =
|
|
7601
|
-
const file =
|
|
7602
|
-
|
|
7920
|
+
const dir = path7.join(repoRoot, ".gluecharm", "logs");
|
|
7921
|
+
const file = path7.join(dir, "easyspecs-cli-workspace-state.json");
|
|
7922
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
7603
7923
|
const load = () => {
|
|
7604
7924
|
try {
|
|
7605
|
-
if (!
|
|
7925
|
+
if (!fs6.existsSync(file)) {
|
|
7606
7926
|
return {};
|
|
7607
7927
|
}
|
|
7608
|
-
const j = JSON.parse(
|
|
7928
|
+
const j = JSON.parse(fs6.readFileSync(file, "utf8"));
|
|
7609
7929
|
return typeof j === "object" && j !== null && !Array.isArray(j) ? j : {};
|
|
7610
7930
|
} catch {
|
|
7611
7931
|
return {};
|
|
7612
7932
|
}
|
|
7613
7933
|
};
|
|
7614
7934
|
const save = (m) => {
|
|
7615
|
-
|
|
7935
|
+
fs6.writeFileSync(file, `${JSON.stringify(m, null, 2)}
|
|
7616
7936
|
`, "utf8");
|
|
7617
7937
|
};
|
|
7618
7938
|
const workspaceState = {
|
|
@@ -7638,8 +7958,8 @@ var fs27 = __toESM(require("fs"));
|
|
|
7638
7958
|
var path25 = __toESM(require("path"));
|
|
7639
7959
|
|
|
7640
7960
|
// src/analysis/analysisDynamicTestSteps.ts
|
|
7641
|
-
var
|
|
7642
|
-
var
|
|
7961
|
+
var fs7 = __toESM(require("fs"));
|
|
7962
|
+
var path8 = __toESM(require("path"));
|
|
7643
7963
|
var FE_CODE = /^FE-\d+$/;
|
|
7644
7964
|
var UC_CODE = /^UC-\d+$/;
|
|
7645
7965
|
var DM_CODE = /^DM-\d+$/;
|
|
@@ -7648,7 +7968,7 @@ function stripUtf8Bom(s) {
|
|
|
7648
7968
|
}
|
|
7649
7969
|
function readJson(filePath) {
|
|
7650
7970
|
try {
|
|
7651
|
-
const raw = stripUtf8Bom(
|
|
7971
|
+
const raw = stripUtf8Bom(fs7.readFileSync(filePath, "utf-8"));
|
|
7652
7972
|
return JSON.parse(raw);
|
|
7653
7973
|
} catch {
|
|
7654
7974
|
return null;
|
|
@@ -7681,7 +8001,7 @@ function slugOrFallbackCoord(row2) {
|
|
|
7681
8001
|
return null;
|
|
7682
8002
|
}
|
|
7683
8003
|
function discoverExperienceTreeRows(contextDir2) {
|
|
7684
|
-
const expPath =
|
|
8004
|
+
const expPath = path8.join(contextDir2, "experiences-list.json");
|
|
7685
8005
|
const exp = readJson(expPath);
|
|
7686
8006
|
const views = Array.isArray(exp?.views) ? exp.views : [];
|
|
7687
8007
|
const out = [];
|
|
@@ -7714,7 +8034,7 @@ function discoverExperienceTreeRows(contextDir2) {
|
|
|
7714
8034
|
return out;
|
|
7715
8035
|
}
|
|
7716
8036
|
function discoverServiceTreeRows(contextDir2) {
|
|
7717
|
-
const svcPath =
|
|
8037
|
+
const svcPath = path8.join(contextDir2, "services-list.json");
|
|
7718
8038
|
const svcFile = readJson(svcPath);
|
|
7719
8039
|
const svcs = Array.isArray(svcFile?.services) ? svcFile.services : [];
|
|
7720
8040
|
const out = [];
|
|
@@ -7747,7 +8067,7 @@ function discoverServiceTreeRows(contextDir2) {
|
|
|
7747
8067
|
return out;
|
|
7748
8068
|
}
|
|
7749
8069
|
function discoverTechStackToolRows(contextDir2) {
|
|
7750
|
-
const tsPath =
|
|
8070
|
+
const tsPath = path8.join(contextDir2, "tech-stack-list.json");
|
|
7751
8071
|
const tsFile = readJson(tsPath);
|
|
7752
8072
|
const tools = Array.isArray(tsFile?.tools) ? tsFile.tools : [];
|
|
7753
8073
|
const out = [];
|
|
@@ -7770,7 +8090,7 @@ function safeFeatureName(v) {
|
|
|
7770
8090
|
}
|
|
7771
8091
|
function nonEmptyContextFile(absolutePath) {
|
|
7772
8092
|
try {
|
|
7773
|
-
const st =
|
|
8093
|
+
const st = fs7.statSync(absolutePath);
|
|
7774
8094
|
return st.isFile() && st.size > 0;
|
|
7775
8095
|
} catch {
|
|
7776
8096
|
return false;
|
|
@@ -7787,17 +8107,17 @@ var ANALYSIS_STATIC_CONTEXT_OUTPUTS = [
|
|
|
7787
8107
|
"tech-stack-list.json"
|
|
7788
8108
|
];
|
|
7789
8109
|
function discoverDynamicAnalysisTestSteps(contextDir2) {
|
|
7790
|
-
const staticOutputs = ANALYSIS_STATIC_CONTEXT_OUTPUTS.map((
|
|
7791
|
-
basename:
|
|
7792
|
-
exists: nonEmptyContextFile(
|
|
8110
|
+
const staticOutputs = ANALYSIS_STATIC_CONTEXT_OUTPUTS.map((basename12) => ({
|
|
8111
|
+
basename: basename12,
|
|
8112
|
+
exists: nonEmptyContextFile(path8.join(contextDir2, basename12))
|
|
7793
8113
|
}));
|
|
7794
|
-
const featuresPath =
|
|
8114
|
+
const featuresPath = path8.join(contextDir2, "features-list.json");
|
|
7795
8115
|
const featuresData = readJson(featuresPath);
|
|
7796
8116
|
const rawFeatures = Array.isArray(featuresData?.features) ? featuresData.features : [];
|
|
7797
8117
|
const entityFieldsRuns = [];
|
|
7798
8118
|
const useCaseRuns = [];
|
|
7799
8119
|
const scenarioRuns = [];
|
|
7800
|
-
const dmPath =
|
|
8120
|
+
const dmPath = path8.join(contextDir2, "data-model-list.json");
|
|
7801
8121
|
const dmData = readJson(dmPath);
|
|
7802
8122
|
const rawEntities = Array.isArray(dmData?.entities) ? dmData.entities : [];
|
|
7803
8123
|
for (const erow of rawEntities) {
|
|
@@ -7806,7 +8126,7 @@ function discoverDynamicAnalysisTestSteps(contextDir2) {
|
|
|
7806
8126
|
continue;
|
|
7807
8127
|
}
|
|
7808
8128
|
const ename = safeFeatureName(erow.name);
|
|
7809
|
-
const fieldsListPath =
|
|
8129
|
+
const fieldsListPath = path8.join(contextDir2, `${dm}-fields-list.json`);
|
|
7810
8130
|
entityFieldsRuns.push({
|
|
7811
8131
|
entityCode: dm,
|
|
7812
8132
|
entityName: ename,
|
|
@@ -7819,7 +8139,7 @@ function discoverDynamicAnalysisTestSteps(contextDir2) {
|
|
|
7819
8139
|
continue;
|
|
7820
8140
|
}
|
|
7821
8141
|
const name = safeFeatureName(row2.name);
|
|
7822
|
-
const useCasesListPath =
|
|
8142
|
+
const useCasesListPath = path8.join(contextDir2, `${code}-use-cases-list.json`);
|
|
7823
8143
|
useCaseRuns.push({
|
|
7824
8144
|
featureCode: code,
|
|
7825
8145
|
featureName: name,
|
|
@@ -7839,54 +8159,54 @@ function discoverDynamicAnalysisTestSteps(contextDir2) {
|
|
|
7839
8159
|
useCaseCode: ucc,
|
|
7840
8160
|
useCaseName: ucName,
|
|
7841
8161
|
featureName: name,
|
|
7842
|
-
scenariosListExists: nonEmptyContextFile(
|
|
8162
|
+
scenariosListExists: nonEmptyContextFile(path8.join(contextDir2, scenariosBasename))
|
|
7843
8163
|
});
|
|
7844
8164
|
}
|
|
7845
8165
|
}
|
|
7846
|
-
const entityFieldsEmptyHint = !
|
|
7847
|
-
const expPath =
|
|
8166
|
+
const entityFieldsEmptyHint = !fs7.existsSync(dmPath) || dmData === null ? "No data-model-list.json yet \u2014 run the data model list step after Materialize agents." : entityFieldsRuns.length === 0 ? "data-model-list.json has no valid DM-nn rows \u2014 run the data model step or edit that file." : "";
|
|
8167
|
+
const expPath = path8.join(contextDir2, "experiences-list.json");
|
|
7848
8168
|
const expFileData = readJson(expPath);
|
|
7849
8169
|
const expTreeRows = discoverExperienceTreeRows(contextDir2);
|
|
7850
8170
|
const experienceViewRuns = expTreeRows.map((row2) => ({
|
|
7851
8171
|
code: row2.code,
|
|
7852
8172
|
name: row2.name,
|
|
7853
8173
|
slug: row2.slug,
|
|
7854
|
-
viewDetailExists: nonEmptyContextFile(
|
|
8174
|
+
viewDetailExists: nonEmptyContextFile(path8.join(contextDir2, `${row2.code}-${row2.slug}.md`)),
|
|
7855
8175
|
interactions: row2.interactions.map((ix) => ({
|
|
7856
8176
|
code: ix.code,
|
|
7857
8177
|
name: ix.name,
|
|
7858
8178
|
slug: ix.slug,
|
|
7859
|
-
detailExists: nonEmptyContextFile(
|
|
8179
|
+
detailExists: nonEmptyContextFile(path8.join(contextDir2, `${row2.code}_${ix.code}-${ix.slug}.md`))
|
|
7860
8180
|
}))
|
|
7861
8181
|
}));
|
|
7862
|
-
const experienceEmptyHint = !
|
|
7863
|
-
const svcPath =
|
|
8182
|
+
const experienceEmptyHint = !fs7.existsSync(expPath) || expFileData === null ? "No experiences-list.json yet \u2014 run the experiences list step after Materialize agents." : experienceViewRuns.length === 0 ? "experiences-list.json has no valid XP-* views with resolvable URL-safe slugs (check code/slug fields and JSON syntax, including UTF-8 BOM)." : "";
|
|
8183
|
+
const svcPath = path8.join(contextDir2, "services-list.json");
|
|
7864
8184
|
const svcFileData = readJson(svcPath);
|
|
7865
8185
|
const svcTreeRows = discoverServiceTreeRows(contextDir2);
|
|
7866
8186
|
const serviceRuns = svcTreeRows.map((row2) => ({
|
|
7867
8187
|
code: row2.code,
|
|
7868
8188
|
name: row2.name,
|
|
7869
8189
|
slug: row2.slug,
|
|
7870
|
-
serviceDetailExists: nonEmptyContextFile(
|
|
8190
|
+
serviceDetailExists: nonEmptyContextFile(path8.join(contextDir2, `${row2.code}-${row2.slug}.md`)),
|
|
7871
8191
|
methods: row2.methods.map((m) => ({
|
|
7872
8192
|
code: m.code,
|
|
7873
8193
|
name: m.name,
|
|
7874
8194
|
slug: m.slug,
|
|
7875
|
-
detailExists: nonEmptyContextFile(
|
|
8195
|
+
detailExists: nonEmptyContextFile(path8.join(contextDir2, `${row2.code}_${m.code}-${m.slug}.md`))
|
|
7876
8196
|
}))
|
|
7877
8197
|
}));
|
|
7878
|
-
const servicesEmptyHint = !
|
|
7879
|
-
const tsListPath =
|
|
8198
|
+
const servicesEmptyHint = !fs7.existsSync(svcPath) || svcFileData === null ? "No services-list.json yet \u2014 run the services list step after Materialize agents." : serviceRuns.length === 0 ? "services-list.json has no valid SV-* services with resolvable URL-safe slugs (check code/slug fields and JSON syntax, including UTF-8 BOM)." : "";
|
|
8199
|
+
const tsListPath = path8.join(contextDir2, "tech-stack-list.json");
|
|
7880
8200
|
const tsListFileData = readJson(tsListPath);
|
|
7881
8201
|
const toolTreeRows = discoverTechStackToolRows(contextDir2);
|
|
7882
8202
|
const techStackToolRuns = toolTreeRows.map((row2) => ({
|
|
7883
8203
|
code: row2.code,
|
|
7884
8204
|
name: row2.name,
|
|
7885
8205
|
slug: row2.slug,
|
|
7886
|
-
toolDetailExists: nonEmptyContextFile(
|
|
8206
|
+
toolDetailExists: nonEmptyContextFile(path8.join(contextDir2, `${row2.code}-${row2.slug}.md`))
|
|
7887
8207
|
}));
|
|
7888
|
-
const techStackEmptyHint = !
|
|
7889
|
-
const useCaseEmptyHint = !
|
|
8208
|
+
const techStackEmptyHint = !fs7.existsSync(tsListPath) || tsListFileData === null ? "No tech-stack-list.json yet \u2014 run the tech stack list step after Materialize agents." : techStackToolRuns.length === 0 ? "tech-stack-list.json has no valid TS-* tools with resolvable URL-safe slugs (check code/slug fields and JSON syntax, including UTF-8 BOM)." : "";
|
|
8209
|
+
const useCaseEmptyHint = !fs7.existsSync(featuresPath) || featuresData === null ? "No features-list.json yet \u2014 run step 3 (features list) after Materialize agents." : useCaseRuns.length === 0 ? "features-list.json has no valid FE-nn rows \u2014 run step 3 or edit that file." : "";
|
|
7890
8210
|
const scenarioEmptyHint = scenarioRuns.length === 0 ? useCaseRuns.length === 0 ? "Scenario runs appear after features exist and per-feature use-case lists define UC rows." : "Run a per-feature use case list (above) or add UC rows to each FE-nn-use-cases-list.json." : "";
|
|
7891
8211
|
return {
|
|
7892
8212
|
staticOutputs,
|
|
@@ -7906,15 +8226,15 @@ function discoverDynamicAnalysisTestSteps(contextDir2) {
|
|
|
7906
8226
|
}
|
|
7907
8227
|
|
|
7908
8228
|
// src/analysis/materializeOpenCodeAgents.ts
|
|
7909
|
-
var
|
|
7910
|
-
var
|
|
8229
|
+
var fs10 = __toESM(require("fs"));
|
|
8230
|
+
var path11 = __toESM(require("path"));
|
|
7911
8231
|
|
|
7912
8232
|
// src/analysis/applyAceMaterializedAgents.ts
|
|
7913
|
-
var
|
|
7914
|
-
var
|
|
8233
|
+
var fs9 = __toESM(require("fs"));
|
|
8234
|
+
var path10 = __toESM(require("path"));
|
|
7915
8235
|
|
|
7916
8236
|
// src/analysis/acePaths.ts
|
|
7917
|
-
var
|
|
8237
|
+
var path9 = __toESM(require("path"));
|
|
7918
8238
|
var ACE_LEARNINGS_DIR = "learnings";
|
|
7919
8239
|
var ACE_OVERLAYS_SUBDIR = "overlays";
|
|
7920
8240
|
var ACE_TRACES_SUBDIR = "traces";
|
|
@@ -7927,10 +8247,10 @@ var ACE_SCHEMA_TRACE = "ace-generator-trace.schema.json";
|
|
|
7927
8247
|
var ACE_SCHEMA_REFLECTOR = "ace-reflector-lessons.schema.json";
|
|
7928
8248
|
var ACE_SCHEMA_CURATOR = "ace-curator-delta.schema.json";
|
|
7929
8249
|
function gluecharmContextDir(worktreeRoot) {
|
|
7930
|
-
return
|
|
8250
|
+
return path9.join(worktreeRoot, ".gluecharm", "context");
|
|
7931
8251
|
}
|
|
7932
8252
|
function aceLearningsRoot(contextDir2) {
|
|
7933
|
-
return
|
|
8253
|
+
return path9.join(contextDir2, ACE_LEARNINGS_DIR);
|
|
7934
8254
|
}
|
|
7935
8255
|
function sanitizeAcePathSegment(s) {
|
|
7936
8256
|
return s.replace(/[^a-zA-Z0-9_.-]+/g, "_").slice(0, 200) || "id";
|
|
@@ -7943,29 +8263,29 @@ function aceTraceFileRunStem(artefactRunId, openCodeSessionId) {
|
|
|
7943
8263
|
return joined.length <= 240 ? joined : joined.slice(0, 240);
|
|
7944
8264
|
}
|
|
7945
8265
|
function acePlaybookPath(contextDir2, agentStem) {
|
|
7946
|
-
return
|
|
8266
|
+
return path9.join(aceLearningsRoot(contextDir2), `${agentStem}.json`);
|
|
7947
8267
|
}
|
|
7948
8268
|
function aceOverlayPath(contextDir2, agentStem) {
|
|
7949
|
-
return
|
|
8269
|
+
return path9.join(aceLearningsRoot(contextDir2), ACE_OVERLAYS_SUBDIR, `${agentStem}.json`);
|
|
7950
8270
|
}
|
|
7951
8271
|
function aceTracePath(contextDir2, agentStem, runId) {
|
|
7952
|
-
return
|
|
8272
|
+
return path9.join(aceLearningsRoot(contextDir2), ACE_TRACES_SUBDIR, agentStem, `${runId}-trace.json`);
|
|
7953
8273
|
}
|
|
7954
8274
|
function aceReflectionPath(contextDir2, agentStem, runId) {
|
|
7955
|
-
return
|
|
8275
|
+
return path9.join(aceLearningsRoot(contextDir2), ACE_REFLECTIONS_SUBDIR, agentStem, `${runId}-lessons.json`);
|
|
7956
8276
|
}
|
|
7957
8277
|
function aceCurationPath(contextDir2, agentStem, runId) {
|
|
7958
|
-
return
|
|
8278
|
+
return path9.join(aceLearningsRoot(contextDir2), ACE_CURATIONS_SUBDIR, agentStem, `${runId}-delta.json`);
|
|
7959
8279
|
}
|
|
7960
8280
|
function aceConsolidatedSessionsJsonlPath(contextDir2) {
|
|
7961
|
-
return
|
|
8281
|
+
return path9.join(aceLearningsRoot(contextDir2), ACE_CONSOLIDATED_SESSIONS_JSONL);
|
|
7962
8282
|
}
|
|
7963
|
-
function opencodeAceSchemaPath(worktreeRoot,
|
|
7964
|
-
return
|
|
8283
|
+
function opencodeAceSchemaPath(worktreeRoot, basename12) {
|
|
8284
|
+
return path9.join(worktreeRoot, ".opencode", "schemas", "ace", basename12);
|
|
7965
8285
|
}
|
|
7966
8286
|
|
|
7967
8287
|
// src/analysis/aceJsonValidate.ts
|
|
7968
|
-
var
|
|
8288
|
+
var fs8 = __toESM(require("fs"));
|
|
7969
8289
|
var import__ = __toESM(require__());
|
|
7970
8290
|
function stripUtf8Bom2(s) {
|
|
7971
8291
|
return s.length > 0 && s.charCodeAt(0) === 65279 ? s.slice(1) : s;
|
|
@@ -7983,7 +8303,7 @@ function formatAjvErrors(errors) {
|
|
|
7983
8303
|
function validateAceJsonFile(jsonAbsolutePath, schemaAbsolutePath) {
|
|
7984
8304
|
let raw;
|
|
7985
8305
|
try {
|
|
7986
|
-
raw = stripUtf8Bom2(
|
|
8306
|
+
raw = stripUtf8Bom2(fs8.readFileSync(jsonAbsolutePath, "utf-8"));
|
|
7987
8307
|
} catch (e) {
|
|
7988
8308
|
return { ok: false, kind: "read", message: e instanceof Error ? e.message : String(e) };
|
|
7989
8309
|
}
|
|
@@ -8071,7 +8391,7 @@ function balancedJsonObjectFrom(s, start) {
|
|
|
8071
8391
|
function validateAceJsonValue(data, schemaAbsolutePath) {
|
|
8072
8392
|
let schemaRaw;
|
|
8073
8393
|
try {
|
|
8074
|
-
schemaRaw = stripUtf8Bom2(
|
|
8394
|
+
schemaRaw = stripUtf8Bom2(fs8.readFileSync(schemaAbsolutePath, "utf-8"));
|
|
8075
8395
|
} catch (e) {
|
|
8076
8396
|
return { ok: false, kind: "read", message: `Schema read failed: ${e instanceof Error ? e.message : String(e)}` };
|
|
8077
8397
|
}
|
|
@@ -8165,26 +8485,26 @@ function applyAceToMaterializedAgents(worktreeRoot, options) {
|
|
|
8165
8485
|
if (!options.enabled) {
|
|
8166
8486
|
return;
|
|
8167
8487
|
}
|
|
8168
|
-
const agentsDir =
|
|
8169
|
-
if (!
|
|
8488
|
+
const agentsDir = path10.join(worktreeRoot, ".opencode", "agents");
|
|
8489
|
+
if (!fs9.existsSync(agentsDir) || !fs9.statSync(agentsDir).isDirectory()) {
|
|
8170
8490
|
log(`[ace] skip apply \u2014 missing agents dir: ${agentsDir}`);
|
|
8171
8491
|
return;
|
|
8172
8492
|
}
|
|
8173
8493
|
const contextDir2 = gluecharmContextDir(worktreeRoot);
|
|
8174
8494
|
const learningsRoot = aceLearningsRoot(contextDir2);
|
|
8175
|
-
|
|
8495
|
+
fs9.mkdirSync(learningsRoot, { recursive: true });
|
|
8176
8496
|
const playbookSchema = opencodeAceSchemaPath(worktreeRoot, ACE_SCHEMA_PLAYBOOK);
|
|
8177
8497
|
const overlaySchema = opencodeAceSchemaPath(worktreeRoot, ACE_SCHEMA_OVERLAY);
|
|
8178
|
-
const entries =
|
|
8498
|
+
const entries = fs9.readdirSync(agentsDir, { withFileTypes: true });
|
|
8179
8499
|
for (const e of entries) {
|
|
8180
8500
|
if (!e.isFile() || !e.name.endsWith(".md") || e.name === "README.md") {
|
|
8181
8501
|
continue;
|
|
8182
8502
|
}
|
|
8183
8503
|
const stem = e.name.replace(/\.md$/i, "");
|
|
8184
|
-
const agentPath =
|
|
8504
|
+
const agentPath = path10.join(agentsDir, e.name);
|
|
8185
8505
|
let raw;
|
|
8186
8506
|
try {
|
|
8187
|
-
raw =
|
|
8507
|
+
raw = fs9.readFileSync(agentPath, "utf-8");
|
|
8188
8508
|
} catch (err) {
|
|
8189
8509
|
log(`[ace] skip ${stem} \u2014 read failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
8190
8510
|
continue;
|
|
@@ -8197,7 +8517,7 @@ function applyAceToMaterializedAgents(worktreeRoot, options) {
|
|
|
8197
8517
|
const pbPath = acePlaybookPath(contextDir2, stem);
|
|
8198
8518
|
const ovPath = aceOverlayPath(contextDir2, stem);
|
|
8199
8519
|
let playbookDoc;
|
|
8200
|
-
if (
|
|
8520
|
+
if (fs9.existsSync(pbPath)) {
|
|
8201
8521
|
const v = validateAceJsonFile(pbPath, playbookSchema);
|
|
8202
8522
|
if (v.ok) {
|
|
8203
8523
|
const d = v.data;
|
|
@@ -8212,7 +8532,7 @@ ${v.errorsText.slice(0, 500)}` : ""}`
|
|
|
8212
8532
|
}
|
|
8213
8533
|
}
|
|
8214
8534
|
let overlayDoc;
|
|
8215
|
-
if (
|
|
8535
|
+
if (fs9.existsSync(ovPath)) {
|
|
8216
8536
|
const v = validateAceJsonFile(ovPath, overlaySchema);
|
|
8217
8537
|
if (v.ok) {
|
|
8218
8538
|
overlayDoc = v.data;
|
|
@@ -8243,14 +8563,14 @@ ${extra}
|
|
|
8243
8563
|
|
|
8244
8564
|
${extra}
|
|
8245
8565
|
`;
|
|
8246
|
-
|
|
8566
|
+
fs9.writeFileSync(agentPath, out, "utf-8");
|
|
8247
8567
|
log(`[ace] merged playbook/overlay into materialized agent: ${e.name}`);
|
|
8248
8568
|
}
|
|
8249
8569
|
}
|
|
8250
8570
|
|
|
8251
8571
|
// src/analysis/materializeOpenCodeAgents.ts
|
|
8252
8572
|
function posixFsPath(absPath) {
|
|
8253
|
-
return
|
|
8573
|
+
return path11.resolve(absPath).split(path11.sep).join("/");
|
|
8254
8574
|
}
|
|
8255
8575
|
function mergeStringKeyedObject(permission, key, additions) {
|
|
8256
8576
|
const cur = permission[key];
|
|
@@ -8270,10 +8590,22 @@ function ensurePathToolAllows(permission, tool, rules) {
|
|
|
8270
8590
|
}
|
|
8271
8591
|
mergeStringKeyedObject(permission, tool, rules);
|
|
8272
8592
|
}
|
|
8273
|
-
function
|
|
8274
|
-
const
|
|
8593
|
+
function mergeDeepUnknown(base, over) {
|
|
8594
|
+
const out = { ...base };
|
|
8595
|
+
for (const [k, v] of Object.entries(over)) {
|
|
8596
|
+
const cur = out[k];
|
|
8597
|
+
if (v && typeof v === "object" && !Array.isArray(v) && cur && typeof cur === "object" && !Array.isArray(cur)) {
|
|
8598
|
+
out[k] = mergeDeepUnknown(cur, v);
|
|
8599
|
+
} else {
|
|
8600
|
+
out[k] = v;
|
|
8601
|
+
}
|
|
8602
|
+
}
|
|
8603
|
+
return out;
|
|
8604
|
+
}
|
|
8605
|
+
function ensureAnalysisOpenCodePermissionsConfig(analysisCheckoutRoot, projectConfigOverlay) {
|
|
8606
|
+
const root = path11.resolve(analysisCheckoutRoot);
|
|
8275
8607
|
const r = posixFsPath(root);
|
|
8276
|
-
const contextDir2 = posixFsPath(
|
|
8608
|
+
const contextDir2 = posixFsPath(path11.join(root, ".gluecharm", "context"));
|
|
8277
8609
|
const externalAllows = {
|
|
8278
8610
|
[`${r}/**`]: "allow",
|
|
8279
8611
|
[`${r}/.gluecharm/**`]: "allow",
|
|
@@ -8291,11 +8623,11 @@ function ensureAnalysisOpenCodePermissionsConfig(analysisCheckoutRoot) {
|
|
|
8291
8623
|
[`${r}/**`]: "allow",
|
|
8292
8624
|
[`${r}/*`]: "allow"
|
|
8293
8625
|
};
|
|
8294
|
-
const configPath =
|
|
8626
|
+
const configPath = path11.join(root, "opencode.json");
|
|
8295
8627
|
let cfg = {};
|
|
8296
|
-
if (
|
|
8628
|
+
if (fs10.existsSync(configPath)) {
|
|
8297
8629
|
try {
|
|
8298
|
-
const raw =
|
|
8630
|
+
const raw = fs10.readFileSync(configPath, "utf-8");
|
|
8299
8631
|
const parsed = JSON.parse(raw);
|
|
8300
8632
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
8301
8633
|
cfg = { ...parsed };
|
|
@@ -8315,55 +8647,58 @@ function ensureAnalysisOpenCodePermissionsConfig(analysisCheckoutRoot) {
|
|
|
8315
8647
|
if (cfg.$schema === void 0) {
|
|
8316
8648
|
cfg.$schema = "https://opencode.ai/config.json";
|
|
8317
8649
|
}
|
|
8318
|
-
|
|
8650
|
+
if (projectConfigOverlay && Object.keys(projectConfigOverlay).length > 0) {
|
|
8651
|
+
cfg = mergeDeepUnknown(cfg, projectConfigOverlay);
|
|
8652
|
+
}
|
|
8653
|
+
fs10.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
|
|
8319
8654
|
`, "utf-8");
|
|
8320
8655
|
}
|
|
8321
8656
|
function copyRecursive(src, dest) {
|
|
8322
|
-
|
|
8323
|
-
const entries =
|
|
8657
|
+
fs10.mkdirSync(dest, { recursive: true });
|
|
8658
|
+
const entries = fs10.readdirSync(src, { withFileTypes: true });
|
|
8324
8659
|
for (const e of entries) {
|
|
8325
|
-
const s =
|
|
8326
|
-
const d =
|
|
8660
|
+
const s = path11.join(src, e.name);
|
|
8661
|
+
const d = path11.join(dest, e.name);
|
|
8327
8662
|
if (e.isDirectory()) {
|
|
8328
8663
|
copyRecursive(s, d);
|
|
8329
8664
|
} else {
|
|
8330
|
-
|
|
8665
|
+
fs10.copyFileSync(s, d);
|
|
8331
8666
|
}
|
|
8332
8667
|
}
|
|
8333
8668
|
}
|
|
8334
|
-
function materializeOpenCodeAgents(extensionResourcesAgents, analysisCheckoutRoot) {
|
|
8335
|
-
const dest =
|
|
8336
|
-
if (!
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8669
|
+
function materializeOpenCodeAgents(extensionResourcesAgents, analysisCheckoutRoot, projectConfigOverlay) {
|
|
8670
|
+
const dest = path11.join(analysisCheckoutRoot, ".opencode", "agents");
|
|
8671
|
+
if (!fs10.existsSync(extensionResourcesAgents)) {
|
|
8672
|
+
fs10.mkdirSync(dest, { recursive: true });
|
|
8673
|
+
fs10.writeFileSync(
|
|
8674
|
+
path11.join(dest, "README.md"),
|
|
8340
8675
|
"# OpenCode agents\n\nPlaceholder: add agent configs here. Bundled folder was missing at materialize time.\n",
|
|
8341
8676
|
"utf-8"
|
|
8342
8677
|
);
|
|
8343
|
-
ensureAnalysisOpenCodePermissionsConfig(analysisCheckoutRoot);
|
|
8678
|
+
ensureAnalysisOpenCodePermissionsConfig(analysisCheckoutRoot, projectConfigOverlay);
|
|
8344
8679
|
return;
|
|
8345
8680
|
}
|
|
8346
8681
|
copyRecursive(extensionResourcesAgents, dest);
|
|
8347
|
-
const schemasSrc =
|
|
8348
|
-
if (
|
|
8349
|
-
const schemasDest =
|
|
8682
|
+
const schemasSrc = path11.join(path11.dirname(extensionResourcesAgents), "schemas", "context-lists");
|
|
8683
|
+
if (fs10.existsSync(schemasSrc)) {
|
|
8684
|
+
const schemasDest = path11.join(analysisCheckoutRoot, ".opencode", "schemas", "context-lists");
|
|
8350
8685
|
copyRecursive(schemasSrc, schemasDest);
|
|
8351
8686
|
}
|
|
8352
|
-
const aceSchemasSrc =
|
|
8353
|
-
if (
|
|
8354
|
-
const aceSchemasDest =
|
|
8687
|
+
const aceSchemasSrc = path11.join(path11.dirname(extensionResourcesAgents), "schemas", "ace");
|
|
8688
|
+
if (fs10.existsSync(aceSchemasSrc)) {
|
|
8689
|
+
const aceSchemasDest = path11.join(analysisCheckoutRoot, ".opencode", "schemas", "ace");
|
|
8355
8690
|
copyRecursive(aceSchemasSrc, aceSchemasDest);
|
|
8356
8691
|
}
|
|
8357
|
-
ensureAnalysisOpenCodePermissionsConfig(analysisCheckoutRoot);
|
|
8692
|
+
ensureAnalysisOpenCodePermissionsConfig(analysisCheckoutRoot, projectConfigOverlay);
|
|
8358
8693
|
}
|
|
8359
8694
|
function materializeOpenCodeAgentsWithAce(extensionResourcesAgents, analysisCheckoutRoot, ace) {
|
|
8360
|
-
materializeOpenCodeAgents(extensionResourcesAgents, analysisCheckoutRoot);
|
|
8695
|
+
materializeOpenCodeAgents(extensionResourcesAgents, analysisCheckoutRoot, ace.projectConfigOverlay);
|
|
8361
8696
|
applyAceToMaterializedAgents(analysisCheckoutRoot, ace);
|
|
8362
8697
|
}
|
|
8363
8698
|
|
|
8364
8699
|
// src/analysis/openCodeTestAgent.ts
|
|
8365
|
-
var
|
|
8366
|
-
var
|
|
8700
|
+
var fs20 = __toESM(require("fs"));
|
|
8701
|
+
var path18 = __toESM(require("path"));
|
|
8367
8702
|
|
|
8368
8703
|
// src/analysis/promptTemplates.ts
|
|
8369
8704
|
function fillMarkdownPrompt(p) {
|
|
@@ -8514,8 +8849,8 @@ function synthesisStepLabel(step, ctx) {
|
|
|
8514
8849
|
}
|
|
8515
8850
|
|
|
8516
8851
|
// src/analysis/aceTracePhase.ts
|
|
8517
|
-
var
|
|
8518
|
-
var
|
|
8852
|
+
var fs15 = __toESM(require("fs"));
|
|
8853
|
+
var path15 = __toESM(require("path"));
|
|
8519
8854
|
|
|
8520
8855
|
// src/opencodeCli.ts
|
|
8521
8856
|
var import_child_process = require("child_process");
|
|
@@ -8648,19 +8983,21 @@ function resolveExecutable(executable) {
|
|
|
8648
8983
|
const t = executable?.trim();
|
|
8649
8984
|
return t && t.length > 0 ? t : "opencode";
|
|
8650
8985
|
}
|
|
8651
|
-
function spawnCliSync(executable, args, cwd, timeoutMs) {
|
|
8986
|
+
function spawnCliSync(executable, args, cwd, timeoutMs, env) {
|
|
8987
|
+
const mergedEnv = env ? { ...process.env, ...env } : process.env;
|
|
8652
8988
|
return (0, import_child_process.spawnSync)(executable, args, {
|
|
8653
8989
|
encoding: "utf-8",
|
|
8654
8990
|
cwd,
|
|
8655
8991
|
shell: USE_SHELL,
|
|
8656
8992
|
timeout: timeoutMs,
|
|
8657
|
-
env:
|
|
8993
|
+
env: mergedEnv
|
|
8658
8994
|
});
|
|
8659
8995
|
}
|
|
8660
|
-
function isOpenCodeOnPath(executable = "opencode") {
|
|
8996
|
+
function isOpenCodeOnPath(executable = "opencode", probeEnv) {
|
|
8661
8997
|
const cmd = resolveExecutable(executable);
|
|
8998
|
+
const extra = probeEnv ? { ...probeEnv } : void 0;
|
|
8662
8999
|
for (const args of [["--version"], ["-h"], ["help"]]) {
|
|
8663
|
-
const r = spawnCliSync(cmd, args, void 0, 12e3);
|
|
9000
|
+
const r = spawnCliSync(cmd, args, void 0, 12e3, extra);
|
|
8664
9001
|
if (r.status === 0) {
|
|
8665
9002
|
return true;
|
|
8666
9003
|
}
|
|
@@ -8684,10 +9021,11 @@ function hasProviderEnvConfigured() {
|
|
|
8684
9021
|
return false;
|
|
8685
9022
|
}
|
|
8686
9023
|
var CREDENTIAL_PROBE_ARG_SETS = [["auth", "status"], ["whoami"], ["auth", "whoami"]];
|
|
8687
|
-
function isOpenCodeCredentialsReady(executable = "opencode") {
|
|
9024
|
+
function isOpenCodeCredentialsReady(executable = "opencode", options) {
|
|
8688
9025
|
const cmd = resolveExecutable(executable);
|
|
9026
|
+
const mergedEnv = options?.mergedEnv ? { ...process.env, ...options.mergedEnv } : void 0;
|
|
8689
9027
|
for (const args of CREDENTIAL_PROBE_ARG_SETS) {
|
|
8690
|
-
const r = spawnCliSync(cmd, args, void 0, 15e3);
|
|
9028
|
+
const r = spawnCliSync(cmd, args, void 0, 15e3, mergedEnv);
|
|
8691
9029
|
if (r.status === 0) {
|
|
8692
9030
|
return true;
|
|
8693
9031
|
}
|
|
@@ -8700,18 +9038,31 @@ ${r.stderr ?? ""}`.toLowerCase();
|
|
|
8700
9038
|
if (hasProviderEnvConfigured()) {
|
|
8701
9039
|
return true;
|
|
8702
9040
|
}
|
|
9041
|
+
if (mergedEnv) {
|
|
9042
|
+
for (const k of PROVIDER_ENV_KEYS) {
|
|
9043
|
+
const v = mergedEnv[k];
|
|
9044
|
+
if (typeof v === "string" && v.trim().length > 0) {
|
|
9045
|
+
return true;
|
|
9046
|
+
}
|
|
9047
|
+
}
|
|
9048
|
+
}
|
|
8703
9049
|
return false;
|
|
8704
9050
|
}
|
|
8705
9051
|
function getOpenCodeReadiness(options) {
|
|
8706
9052
|
const exe = resolveExecutable(options?.executable);
|
|
8707
|
-
const
|
|
9053
|
+
const probeEnv = options?.providerEnvFromConfig;
|
|
9054
|
+
const mergedProbe = probeEnv && Object.keys(probeEnv).length > 0 ? { ...probeEnv } : void 0;
|
|
9055
|
+
const installed = isOpenCodeOnPath(exe, probeEnv);
|
|
8708
9056
|
if (!installed) {
|
|
8709
9057
|
return { installed: false, credentialsReady: false };
|
|
8710
9058
|
}
|
|
8711
9059
|
if (options?.skipCredentialsCheck) {
|
|
8712
9060
|
return { installed: true, credentialsReady: true };
|
|
8713
9061
|
}
|
|
8714
|
-
return {
|
|
9062
|
+
return {
|
|
9063
|
+
installed: true,
|
|
9064
|
+
credentialsReady: isOpenCodeCredentialsReady(exe, { mergedEnv: mergedProbe })
|
|
9065
|
+
};
|
|
8715
9066
|
}
|
|
8716
9067
|
var DIAG_STDERR_MAX = 16384;
|
|
8717
9068
|
var DIAG_STDOUT_MAX = 12288;
|
|
@@ -8744,15 +9095,16 @@ function runOpenCodeAgent(cwd, args, options) {
|
|
|
8744
9095
|
log?.(`[OpenCode] command: ${formatCliCommandForLog(cmd, args)}`);
|
|
8745
9096
|
log?.(`[OpenCode] cwd: ${JSON.stringify(cwd)}`);
|
|
8746
9097
|
log?.(`[OpenCode] argv: ${JSON.stringify(args)}`);
|
|
8747
|
-
return new Promise((
|
|
9098
|
+
return new Promise((resolve15) => {
|
|
8748
9099
|
if (sig?.aborted) {
|
|
8749
|
-
|
|
9100
|
+
resolve15({ ok: false, message: "Stopped by user.", cancelled: true });
|
|
8750
9101
|
return;
|
|
8751
9102
|
}
|
|
9103
|
+
const spawnEnv = options?.childEnv && Object.keys(options.childEnv).length > 0 ? { ...process.env, ...options.childEnv } : process.env;
|
|
8752
9104
|
const child = (0, import_child_process.spawn)(cmd, args, {
|
|
8753
9105
|
cwd,
|
|
8754
9106
|
shell: USE_SHELL,
|
|
8755
|
-
env:
|
|
9107
|
+
env: spawnEnv,
|
|
8756
9108
|
stdio: ["ignore", "pipe", "pipe"]
|
|
8757
9109
|
});
|
|
8758
9110
|
options?.onAgentLaunched?.();
|
|
@@ -8815,7 +9167,7 @@ ${truncateForDiag(outBody, DIAG_STDOUT_MAX)}`);
|
|
|
8815
9167
|
if (diag) {
|
|
8816
9168
|
finishDiag(diag.label, diag.code, diag.dumpStreams);
|
|
8817
9169
|
}
|
|
8818
|
-
|
|
9170
|
+
resolve15(result);
|
|
8819
9171
|
};
|
|
8820
9172
|
let onAbort;
|
|
8821
9173
|
const clearAbortHandler = () => {
|
|
@@ -8890,7 +9242,7 @@ ${truncateForDiag(outBody, DIAG_STDOUT_MAX)}`);
|
|
|
8890
9242
|
}
|
|
8891
9243
|
|
|
8892
9244
|
// src/analysis/aceTraceNormalize.ts
|
|
8893
|
-
var
|
|
9245
|
+
var fs11 = __toESM(require("fs"));
|
|
8894
9246
|
var ACE_VERSION = "1.0.0-draft";
|
|
8895
9247
|
var REASONING_PHASES = /* @__PURE__ */ new Set([
|
|
8896
9248
|
"explore",
|
|
@@ -8900,7 +9252,7 @@ var REASONING_PHASES = /* @__PURE__ */ new Set([
|
|
|
8900
9252
|
"repair",
|
|
8901
9253
|
"finalize"
|
|
8902
9254
|
]);
|
|
8903
|
-
function
|
|
9255
|
+
function isRecord2(v) {
|
|
8904
9256
|
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
8905
9257
|
}
|
|
8906
9258
|
function sanitizeReasoningSteps(input, legacyTopLevelDecisions) {
|
|
@@ -8908,7 +9260,7 @@ function sanitizeReasoningSteps(input, legacyTopLevelDecisions) {
|
|
|
8908
9260
|
input = [];
|
|
8909
9261
|
}
|
|
8910
9262
|
const steps = input.map((item, idx) => {
|
|
8911
|
-
if (!
|
|
9263
|
+
if (!isRecord2(item)) {
|
|
8912
9264
|
return { stepId: `auto-${idx}`, phase: "explore", summary: "(invalid reasoningSteps entry)" };
|
|
8913
9265
|
}
|
|
8914
9266
|
const stepId = typeof item.stepId === "string" && item.stepId.trim() ? item.stepId : typeof item.step === "string" ? `legacy-${idx}` : `s${idx}`;
|
|
@@ -8955,7 +9307,7 @@ function sanitizeDecisions(input) {
|
|
|
8955
9307
|
return [];
|
|
8956
9308
|
}
|
|
8957
9309
|
return input.map((item, idx) => {
|
|
8958
|
-
if (!
|
|
9310
|
+
if (!isRecord2(item)) {
|
|
8959
9311
|
return {
|
|
8960
9312
|
decisionId: `d${idx}`,
|
|
8961
9313
|
topic: "",
|
|
@@ -8979,7 +9331,7 @@ function sanitizeFailures(input) {
|
|
|
8979
9331
|
return [];
|
|
8980
9332
|
}
|
|
8981
9333
|
return input.map((item, idx) => {
|
|
8982
|
-
if (!
|
|
9334
|
+
if (!isRecord2(item)) {
|
|
8983
9335
|
return { failureId: `f${idx}`, description: "(invalid failuresAndRetries entry)" };
|
|
8984
9336
|
}
|
|
8985
9337
|
const failureId = typeof item.failureId === "string" && item.failureId.trim() ? item.failureId : `f${idx}`;
|
|
@@ -8997,7 +9349,7 @@ function sanitizeEvidenceIndex(input) {
|
|
|
8997
9349
|
}
|
|
8998
9350
|
const out = [];
|
|
8999
9351
|
for (const item of input) {
|
|
9000
|
-
if (!
|
|
9352
|
+
if (!isRecord2(item)) {
|
|
9001
9353
|
continue;
|
|
9002
9354
|
}
|
|
9003
9355
|
const pathStr = typeof item.path === "string" ? item.path : typeof item.filePath === "string" ? item.filePath : "";
|
|
@@ -9020,7 +9372,7 @@ function sanitizePlaybookHooks(input) {
|
|
|
9020
9372
|
const effects = /* @__PURE__ */ new Set(["applied", "violated", "absent"]);
|
|
9021
9373
|
const out = [];
|
|
9022
9374
|
for (const item of input) {
|
|
9023
|
-
if (!
|
|
9375
|
+
if (!isRecord2(item)) {
|
|
9024
9376
|
continue;
|
|
9025
9377
|
}
|
|
9026
9378
|
const ruleRef = typeof item.ruleRef === "string" ? item.ruleRef : "";
|
|
@@ -9035,7 +9387,7 @@ function sanitizePlaybookHooks(input) {
|
|
|
9035
9387
|
function rewriteAceTraceFileWithCanonicalEnvelope(traceAbsolutePath, canonical, diagnosticLog) {
|
|
9036
9388
|
let raw;
|
|
9037
9389
|
try {
|
|
9038
|
-
raw =
|
|
9390
|
+
raw = fs11.readFileSync(traceAbsolutePath, "utf-8");
|
|
9039
9391
|
} catch (e) {
|
|
9040
9392
|
diagnosticLog?.(`[ace] trace normalize read failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
9041
9393
|
return false;
|
|
@@ -9047,7 +9399,7 @@ function rewriteAceTraceFileWithCanonicalEnvelope(traceAbsolutePath, canonical,
|
|
|
9047
9399
|
diagnosticLog?.(`[ace] trace normalize JSON.parse failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
9048
9400
|
return false;
|
|
9049
9401
|
}
|
|
9050
|
-
const prev =
|
|
9402
|
+
const prev = isRecord2(parsed) ? parsed : {};
|
|
9051
9403
|
const sessionMeta = {
|
|
9052
9404
|
openCodeSessionId: canonical.openCodeSessionId,
|
|
9053
9405
|
runId: canonical.runId,
|
|
@@ -9055,7 +9407,7 @@ function rewriteAceTraceFileWithCanonicalEnvelope(traceAbsolutePath, canonical,
|
|
|
9055
9407
|
startedAt: canonical.startedAt
|
|
9056
9408
|
};
|
|
9057
9409
|
const prevSm = prev.sessionMeta;
|
|
9058
|
-
if (
|
|
9410
|
+
if (isRecord2(prevSm)) {
|
|
9059
9411
|
if (typeof prevSm.sessionTitle === "string") {
|
|
9060
9412
|
sessionMeta.sessionTitle = prevSm.sessionTitle;
|
|
9061
9413
|
}
|
|
@@ -9080,7 +9432,7 @@ function rewriteAceTraceFileWithCanonicalEnvelope(traceAbsolutePath, canonical,
|
|
|
9080
9432
|
doc.playbookHooks = hooks;
|
|
9081
9433
|
}
|
|
9082
9434
|
try {
|
|
9083
|
-
|
|
9435
|
+
fs11.writeFileSync(traceAbsolutePath, `${JSON.stringify(doc, null, 2)}
|
|
9084
9436
|
`, "utf-8");
|
|
9085
9437
|
} catch (e) {
|
|
9086
9438
|
diagnosticLog?.(`[ace] trace normalize write failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
@@ -9091,15 +9443,15 @@ function rewriteAceTraceFileWithCanonicalEnvelope(traceAbsolutePath, canonical,
|
|
|
9091
9443
|
}
|
|
9092
9444
|
|
|
9093
9445
|
// src/analysis/aceOfflineLearn.ts
|
|
9094
|
-
var
|
|
9095
|
-
var
|
|
9446
|
+
var fs14 = __toESM(require("fs"));
|
|
9447
|
+
var path14 = __toESM(require("path"));
|
|
9096
9448
|
|
|
9097
9449
|
// src/analysis/aceCuratorApplier.ts
|
|
9098
|
-
var
|
|
9099
|
-
var
|
|
9450
|
+
var fs12 = __toESM(require("fs"));
|
|
9451
|
+
var path12 = __toESM(require("path"));
|
|
9100
9452
|
function writeJson(pathAbs, obj) {
|
|
9101
|
-
|
|
9102
|
-
|
|
9453
|
+
fs12.mkdirSync(path12.dirname(pathAbs), { recursive: true });
|
|
9454
|
+
fs12.writeFileSync(pathAbs, `${JSON.stringify(obj, null, 2)}
|
|
9103
9455
|
`, "utf-8");
|
|
9104
9456
|
}
|
|
9105
9457
|
function emptyPlaybook(agentStem) {
|
|
@@ -9125,7 +9477,7 @@ function applyAceCuratorDeltaFile(worktreeRoot, deltaAbsolutePath, log) {
|
|
|
9125
9477
|
const pbPath = acePlaybookPath(contextDir2, agentStem);
|
|
9126
9478
|
const ovPath = aceOverlayPath(contextDir2, agentStem);
|
|
9127
9479
|
let playbook;
|
|
9128
|
-
if (
|
|
9480
|
+
if (fs12.existsSync(pbPath)) {
|
|
9129
9481
|
const pv = validateAceJsonFile(pbPath, playbookSchema);
|
|
9130
9482
|
if (!pv.ok) {
|
|
9131
9483
|
return { ok: false, message: `Existing playbook invalid: ${pv.message}` };
|
|
@@ -9135,7 +9487,7 @@ function applyAceCuratorDeltaFile(worktreeRoot, deltaAbsolutePath, log) {
|
|
|
9135
9487
|
playbook = emptyPlaybook(agentStem);
|
|
9136
9488
|
}
|
|
9137
9489
|
let overlay;
|
|
9138
|
-
if (
|
|
9490
|
+
if (fs12.existsSync(ovPath)) {
|
|
9139
9491
|
const ov = validateAceJsonFile(ovPath, overlaySchema);
|
|
9140
9492
|
if (!ov.ok) {
|
|
9141
9493
|
return { ok: false, message: `Existing overlay invalid: ${ov.message}` };
|
|
@@ -9208,13 +9560,13 @@ function applyAceCuratorDeltaFile(worktreeRoot, deltaAbsolutePath, log) {
|
|
|
9208
9560
|
}
|
|
9209
9561
|
writeJson(pbPath, playbook);
|
|
9210
9562
|
writeJson(ovPath, overlay);
|
|
9211
|
-
log?.(`[ace] curator applier wrote ${
|
|
9563
|
+
log?.(`[ace] curator applier wrote ${path12.relative(contextDir2, pbPath)} and overlay`);
|
|
9212
9564
|
return { ok: true, message: "Applied curator delta" };
|
|
9213
9565
|
}
|
|
9214
9566
|
|
|
9215
9567
|
// src/analysis/aceOfflineLearnFallbacks.ts
|
|
9216
|
-
var
|
|
9217
|
-
var
|
|
9568
|
+
var fs13 = __toESM(require("fs"));
|
|
9569
|
+
var path13 = __toESM(require("path"));
|
|
9218
9570
|
var ACE_VERSION2 = "1.0.0-draft";
|
|
9219
9571
|
function buildEmptyReflectorLessons(traceRelativePath, sessionRunId) {
|
|
9220
9572
|
return {
|
|
@@ -9237,9 +9589,9 @@ function buildEmptyCuratorDelta(agentStem, lessonsRelativePath) {
|
|
|
9237
9589
|
}
|
|
9238
9590
|
function appendAceConsolidatedSessionRecord(contextDir2, record, diagnosticLog) {
|
|
9239
9591
|
const abs = aceConsolidatedSessionsJsonlPath(contextDir2);
|
|
9240
|
-
const rel =
|
|
9241
|
-
|
|
9242
|
-
|
|
9592
|
+
const rel = path13.relative(contextDir2, abs).split(path13.sep).join("/");
|
|
9593
|
+
fs13.mkdirSync(aceLearningsRoot(contextDir2), { recursive: true });
|
|
9594
|
+
fs13.appendFileSync(abs, `${JSON.stringify(record)}
|
|
9243
9595
|
`, "utf-8");
|
|
9244
9596
|
diagnosticLog?.(`[ace] consolidated session record appended \u2014 ${rel}`);
|
|
9245
9597
|
}
|
|
@@ -9261,7 +9613,7 @@ function safeRunIdSegment(runId) {
|
|
|
9261
9613
|
}
|
|
9262
9614
|
function readHead(p, max) {
|
|
9263
9615
|
try {
|
|
9264
|
-
const raw =
|
|
9616
|
+
const raw = fs14.readFileSync(p, "utf-8");
|
|
9265
9617
|
return raw.length <= max ? raw : `${raw.slice(0, max)}
|
|
9266
9618
|
\u2026 (truncated)`;
|
|
9267
9619
|
} catch {
|
|
@@ -9269,14 +9621,14 @@ function readHead(p, max) {
|
|
|
9269
9621
|
}
|
|
9270
9622
|
}
|
|
9271
9623
|
function listAceTraceFiles(contextDir2) {
|
|
9272
|
-
const root =
|
|
9273
|
-
if (!
|
|
9624
|
+
const root = path14.join(aceLearningsRoot(contextDir2), "traces");
|
|
9625
|
+
if (!fs14.existsSync(root)) {
|
|
9274
9626
|
return [];
|
|
9275
9627
|
}
|
|
9276
9628
|
const out = [];
|
|
9277
9629
|
const walk = (dir) => {
|
|
9278
|
-
for (const e of
|
|
9279
|
-
const full =
|
|
9630
|
+
for (const e of fs14.readdirSync(dir, { withFileTypes: true })) {
|
|
9631
|
+
const full = path14.join(dir, e.name);
|
|
9280
9632
|
if (e.isDirectory()) {
|
|
9281
9633
|
walk(full);
|
|
9282
9634
|
} else if (e.isFile() && e.name.endsWith(".json")) {
|
|
@@ -9297,20 +9649,20 @@ async function runAceOfflineLearnFromTrace(traceAbsolutePath, opts) {
|
|
|
9297
9649
|
return { ok: false, message: `Trace invalid: ${tv.message}` };
|
|
9298
9650
|
}
|
|
9299
9651
|
const traceData = tv.data;
|
|
9300
|
-
const runId = opts.artefactRunId ?? (typeof traceData.sessionMeta?.runId === "string" ? traceData.sessionMeta.runId : void 0) ??
|
|
9301
|
-
const agentStem = opts.agentStemOverride ?? (typeof traceData.sessionMeta?.agentStem === "string" ? traceData.sessionMeta.agentStem :
|
|
9652
|
+
const runId = opts.artefactRunId ?? (typeof traceData.sessionMeta?.runId === "string" ? traceData.sessionMeta.runId : void 0) ?? path14.basename(traceAbsolutePath).replace(/-trace\.json$/i, "") ?? "unknown";
|
|
9653
|
+
const agentStem = opts.agentStemOverride ?? (typeof traceData.sessionMeta?.agentStem === "string" ? traceData.sessionMeta.agentStem : path14.basename(path14.dirname(traceAbsolutePath)));
|
|
9302
9654
|
const safeId = safeRunIdSegment(runId);
|
|
9303
|
-
const traceRel =
|
|
9655
|
+
const traceRel = path14.relative(contextDir2, traceAbsolutePath).split(path14.sep).join("/");
|
|
9304
9656
|
const lessonsAbs = aceReflectionPath(contextDir2, agentStem, safeId);
|
|
9305
9657
|
const deltaAbs = aceCurationPath(contextDir2, agentStem, safeId);
|
|
9306
|
-
|
|
9307
|
-
|
|
9308
|
-
const pbPath =
|
|
9309
|
-
const ovPath =
|
|
9310
|
-
const pbExcerpt =
|
|
9311
|
-
const ovExcerpt =
|
|
9312
|
-
const runDir =
|
|
9313
|
-
|
|
9658
|
+
fs14.mkdirSync(path14.dirname(lessonsAbs), { recursive: true });
|
|
9659
|
+
fs14.mkdirSync(path14.dirname(deltaAbs), { recursive: true });
|
|
9660
|
+
const pbPath = path14.join(aceLearningsRoot(contextDir2), `${agentStem}.json`);
|
|
9661
|
+
const ovPath = path14.join(aceLearningsRoot(contextDir2), "overlays", `${agentStem}.json`);
|
|
9662
|
+
const pbExcerpt = fs14.existsSync(pbPath) ? readHead(pbPath, 6e3) : "(no playbook yet)";
|
|
9663
|
+
const ovExcerpt = fs14.existsSync(ovPath) ? readHead(ovPath, 4e3) : "(no overlay yet)";
|
|
9664
|
+
const runDir = path14.join(opts.worktreeRoot, ".opencode", "_run");
|
|
9665
|
+
fs14.mkdirSync(runDir, { recursive: true });
|
|
9314
9666
|
let reflectorUsedEmptyFallback = false;
|
|
9315
9667
|
let curatorUsedEmptyFallback = false;
|
|
9316
9668
|
const reflectPrompt = [
|
|
@@ -9328,8 +9680,8 @@ async function runAceOfflineLearnFromTrace(traceAbsolutePath, opts) {
|
|
|
9328
9680
|
"",
|
|
9329
9681
|
"Schema: `aceSchemaVersion` **1.0.0-draft**, `sourceTrace`, `lessons` (see ace-reflector-lessons schema)."
|
|
9330
9682
|
].join("\n");
|
|
9331
|
-
const reflectPromptPath =
|
|
9332
|
-
|
|
9683
|
+
const reflectPromptPath = path14.join(runDir, `ace-reflect-${safeId}-${Date.now()}.prompt.txt`);
|
|
9684
|
+
fs14.writeFileSync(reflectPromptPath, reflectPrompt, "utf-8");
|
|
9333
9685
|
const reflectVars = {
|
|
9334
9686
|
promptFile: reflectPromptPath,
|
|
9335
9687
|
agentId: ACE_REFLECTOR_AGENT_STEM,
|
|
@@ -9351,7 +9703,8 @@ async function runAceOfflineLearnFromTrace(traceAbsolutePath, opts) {
|
|
|
9351
9703
|
onAgentLaunched: opts.onAgentLaunched,
|
|
9352
9704
|
signal: opts.abortSignal,
|
|
9353
9705
|
/** Keep raw stdout in `message` so we can recover lessons JSON if the model prints it instead of writing the file. */
|
|
9354
|
-
parseOpenCodeSessionFromJsonStdout: false
|
|
9706
|
+
parseOpenCodeSessionFromJsonStdout: false,
|
|
9707
|
+
...opts.openCodeChildEnv ? { childEnv: opts.openCodeChildEnv } : {}
|
|
9355
9708
|
});
|
|
9356
9709
|
if (rCli.cancelled || opts.abortSignal?.aborted) {
|
|
9357
9710
|
return { ok: false, message: "[ace] reflector cancelled" };
|
|
@@ -9359,11 +9712,11 @@ async function runAceOfflineLearnFromTrace(traceAbsolutePath, opts) {
|
|
|
9359
9712
|
if (!rCli.ok) {
|
|
9360
9713
|
return { ok: false, message: `[ace] reflector OpenCode failed: ${rCli.message}` };
|
|
9361
9714
|
}
|
|
9362
|
-
if (!
|
|
9715
|
+
if (!fs14.existsSync(lessonsAbs)) {
|
|
9363
9716
|
const recovered = extractJsonObjectWithTopLevelKeys(rCli.message, ["aceSchemaVersion", "sourceTrace", "lessons"]);
|
|
9364
9717
|
if (recovered) {
|
|
9365
9718
|
try {
|
|
9366
|
-
|
|
9719
|
+
fs14.writeFileSync(lessonsAbs, `${recovered}
|
|
9367
9720
|
`, "utf-8");
|
|
9368
9721
|
opts.diagnosticLog?.(`[ace] reflector recovered from OpenCode stdout/stderr \u2192 ${lessonsAbs}`);
|
|
9369
9722
|
} catch (e) {
|
|
@@ -9373,7 +9726,7 @@ async function runAceOfflineLearnFromTrace(traceAbsolutePath, opts) {
|
|
|
9373
9726
|
}
|
|
9374
9727
|
}
|
|
9375
9728
|
}
|
|
9376
|
-
if (!
|
|
9729
|
+
if (!fs14.existsSync(lessonsAbs)) {
|
|
9377
9730
|
return { ok: false, message: `[ace] reflector output missing: ${lessonsAbs}` };
|
|
9378
9731
|
}
|
|
9379
9732
|
let lv = validateAceJsonFile(lessonsAbs, reflectorSchema);
|
|
@@ -9385,7 +9738,7 @@ async function runAceOfflineLearnFromTrace(traceAbsolutePath, opts) {
|
|
|
9385
9738
|
]);
|
|
9386
9739
|
if (recoveredAgain) {
|
|
9387
9740
|
try {
|
|
9388
|
-
|
|
9741
|
+
fs14.writeFileSync(lessonsAbs, `${recoveredAgain}
|
|
9389
9742
|
`, "utf-8");
|
|
9390
9743
|
opts.diagnosticLog?.(`[ace] reflector re-recovered from CLI output after schema failure \u2192 ${lessonsAbs}`);
|
|
9391
9744
|
lv = validateAceJsonFile(lessonsAbs, reflectorSchema);
|
|
@@ -9399,7 +9752,7 @@ async function runAceOfflineLearnFromTrace(traceAbsolutePath, opts) {
|
|
|
9399
9752
|
if (!lv.ok) {
|
|
9400
9753
|
const hint = lv.message.length > 220 ? `${lv.message.slice(0, 220)}\u2026` : lv.message;
|
|
9401
9754
|
opts.diagnosticLog?.(`[ace] reflector lessons failed schema \u2014 writing valid empty lessons \u2014 ${hint}`);
|
|
9402
|
-
|
|
9755
|
+
fs14.writeFileSync(
|
|
9403
9756
|
lessonsAbs,
|
|
9404
9757
|
`${JSON.stringify(buildEmptyReflectorLessons(traceRel, runId), null, 2)}
|
|
9405
9758
|
`,
|
|
@@ -9411,7 +9764,7 @@ async function runAceOfflineLearnFromTrace(traceAbsolutePath, opts) {
|
|
|
9411
9764
|
if (!lv.ok) {
|
|
9412
9765
|
return { ok: false, message: `[ace] lessons invalid after empty fallback: ${lv.message}` };
|
|
9413
9766
|
}
|
|
9414
|
-
const lessonsRel =
|
|
9767
|
+
const lessonsRel = path14.relative(contextDir2, lessonsAbs).split(path14.sep).join("/");
|
|
9415
9768
|
const curPrompt = [
|
|
9416
9769
|
"# ACE Curator (offline)",
|
|
9417
9770
|
"",
|
|
@@ -9445,8 +9798,8 @@ async function runAceOfflineLearnFromTrace(traceAbsolutePath, opts) {
|
|
|
9445
9798
|
"",
|
|
9446
9799
|
"Schema: `aceSchemaVersion` **1.0.0-draft**, `agentStem`, `sourceLessons`, `operations` (see ace-curator-delta schema)."
|
|
9447
9800
|
].join("\n");
|
|
9448
|
-
const curPromptPath =
|
|
9449
|
-
|
|
9801
|
+
const curPromptPath = path14.join(runDir, `ace-curate-${safeId}-${Date.now()}.prompt.txt`);
|
|
9802
|
+
fs14.writeFileSync(curPromptPath, curPrompt, "utf-8");
|
|
9450
9803
|
const curVars = {
|
|
9451
9804
|
promptFile: curPromptPath,
|
|
9452
9805
|
agentId: ACE_CURATOR_AGENT_STEM,
|
|
@@ -9467,7 +9820,8 @@ async function runAceOfflineLearnFromTrace(traceAbsolutePath, opts) {
|
|
|
9467
9820
|
diagnosticLog: opts.diagnosticLog,
|
|
9468
9821
|
onAgentLaunched: opts.onAgentLaunched,
|
|
9469
9822
|
signal: opts.abortSignal,
|
|
9470
|
-
parseOpenCodeSessionFromJsonStdout: false
|
|
9823
|
+
parseOpenCodeSessionFromJsonStdout: false,
|
|
9824
|
+
...opts.openCodeChildEnv ? { childEnv: opts.openCodeChildEnv } : {}
|
|
9471
9825
|
});
|
|
9472
9826
|
if (cCli.cancelled || opts.abortSignal?.aborted) {
|
|
9473
9827
|
return { ok: false, message: "[ace] curator cancelled" };
|
|
@@ -9475,7 +9829,7 @@ async function runAceOfflineLearnFromTrace(traceAbsolutePath, opts) {
|
|
|
9475
9829
|
if (!cCli.ok) {
|
|
9476
9830
|
return { ok: false, message: `[ace] curator OpenCode failed: ${cCli.message}` };
|
|
9477
9831
|
}
|
|
9478
|
-
if (!
|
|
9832
|
+
if (!fs14.existsSync(deltaAbs)) {
|
|
9479
9833
|
const recovered = extractJsonObjectWithTopLevelKeys(cCli.message, [
|
|
9480
9834
|
"aceSchemaVersion",
|
|
9481
9835
|
"agentStem",
|
|
@@ -9484,7 +9838,7 @@ async function runAceOfflineLearnFromTrace(traceAbsolutePath, opts) {
|
|
|
9484
9838
|
]);
|
|
9485
9839
|
if (recovered) {
|
|
9486
9840
|
try {
|
|
9487
|
-
|
|
9841
|
+
fs14.writeFileSync(deltaAbs, `${recovered}
|
|
9488
9842
|
`, "utf-8");
|
|
9489
9843
|
opts.diagnosticLog?.(`[ace] curator recovered from OpenCode stdout/stderr \u2192 ${deltaAbs}`);
|
|
9490
9844
|
} catch (e) {
|
|
@@ -9494,7 +9848,7 @@ async function runAceOfflineLearnFromTrace(traceAbsolutePath, opts) {
|
|
|
9494
9848
|
}
|
|
9495
9849
|
}
|
|
9496
9850
|
}
|
|
9497
|
-
if (!
|
|
9851
|
+
if (!fs14.existsSync(deltaAbs)) {
|
|
9498
9852
|
return { ok: false, message: `[ace] curator output missing: ${deltaAbs}` };
|
|
9499
9853
|
}
|
|
9500
9854
|
let dv = validateAceJsonFile(deltaAbs, curatorSchema);
|
|
@@ -9507,7 +9861,7 @@ async function runAceOfflineLearnFromTrace(traceAbsolutePath, opts) {
|
|
|
9507
9861
|
]);
|
|
9508
9862
|
if (recoveredCur) {
|
|
9509
9863
|
try {
|
|
9510
|
-
|
|
9864
|
+
fs14.writeFileSync(deltaAbs, `${recoveredCur}
|
|
9511
9865
|
`, "utf-8");
|
|
9512
9866
|
opts.diagnosticLog?.(`[ace] curator re-recovered from CLI output after schema failure \u2192 ${deltaAbs}`);
|
|
9513
9867
|
dv = validateAceJsonFile(deltaAbs, curatorSchema);
|
|
@@ -9521,7 +9875,7 @@ async function runAceOfflineLearnFromTrace(traceAbsolutePath, opts) {
|
|
|
9521
9875
|
if (!dv.ok) {
|
|
9522
9876
|
const hint = dv.message.length > 220 ? `${dv.message.slice(0, 220)}\u2026` : dv.message;
|
|
9523
9877
|
opts.diagnosticLog?.(`[ace] curator delta failed schema \u2014 writing valid empty operations \u2014 ${hint}`);
|
|
9524
|
-
|
|
9878
|
+
fs14.writeFileSync(
|
|
9525
9879
|
deltaAbs,
|
|
9526
9880
|
`${JSON.stringify(buildEmptyCuratorDelta(agentStem, lessonsRel), null, 2)}
|
|
9527
9881
|
`,
|
|
@@ -9540,13 +9894,13 @@ async function runAceOfflineLearnFromTrace(traceAbsolutePath, opts) {
|
|
|
9540
9894
|
let lessonCount = 0;
|
|
9541
9895
|
let curatorOperationCount = 0;
|
|
9542
9896
|
try {
|
|
9543
|
-
const lessonsDoc = JSON.parse(
|
|
9897
|
+
const lessonsDoc = JSON.parse(fs14.readFileSync(lessonsAbs, "utf-8"));
|
|
9544
9898
|
lessonCount = Array.isArray(lessonsDoc.lessons) ? lessonsDoc.lessons.length : 0;
|
|
9545
|
-
const deltaDoc = JSON.parse(
|
|
9899
|
+
const deltaDoc = JSON.parse(fs14.readFileSync(deltaAbs, "utf-8"));
|
|
9546
9900
|
curatorOperationCount = Array.isArray(deltaDoc.operations) ? deltaDoc.operations.length : 0;
|
|
9547
9901
|
} catch {
|
|
9548
9902
|
}
|
|
9549
|
-
const deltaRel =
|
|
9903
|
+
const deltaRel = path14.relative(contextDir2, deltaAbs).split(path14.sep).join("/");
|
|
9550
9904
|
appendAceConsolidatedSessionRecord(
|
|
9551
9905
|
contextDir2,
|
|
9552
9906
|
{
|
|
@@ -9601,15 +9955,15 @@ async function runAceTracePhase(params) {
|
|
|
9601
9955
|
const contextDir2 = gluecharmContextDir(params.worktreeRoot);
|
|
9602
9956
|
const traceStem = aceTraceFileRunStem(params.artefactRunId, params.followUpSessionId);
|
|
9603
9957
|
const traceAbs = aceTracePath(contextDir2, params.producerAgentStem, traceStem);
|
|
9604
|
-
|
|
9958
|
+
fs15.mkdirSync(path15.dirname(traceAbs), { recursive: true });
|
|
9605
9959
|
const schemaAbs = opencodeAceSchemaPath(params.worktreeRoot, ACE_SCHEMA_TRACE);
|
|
9606
|
-
if (!
|
|
9960
|
+
if (!fs15.existsSync(schemaAbs)) {
|
|
9607
9961
|
const msg = `[ace] trace skipped \u2014 schema missing: ${schemaAbs}`;
|
|
9608
9962
|
params.diagnosticLog?.(msg);
|
|
9609
9963
|
return { ok: false, message: msg };
|
|
9610
9964
|
}
|
|
9611
9965
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9612
|
-
const primaryAbs =
|
|
9966
|
+
const primaryAbs = path15.join(contextDir2, params.primaryRelativePathUnderContext.split("/").join(path15.sep));
|
|
9613
9967
|
const promptBody = [
|
|
9614
9968
|
`# ACE trace (same session)`,
|
|
9615
9969
|
``,
|
|
@@ -9651,10 +10005,10 @@ async function runAceTracePhase(params) {
|
|
|
9651
10005
|
`sessionMeta must include \`openCodeSessionId\` = the session id above, \`runId\` = **exactly** \`${traceStem}\`, \`agentStem\` = producer stem, \`startedAt\` = \`${startedAt}\`.`,
|
|
9652
10006
|
`Use only evidence from this session's transcript and tool history.`
|
|
9653
10007
|
].join("\n");
|
|
9654
|
-
const runDir =
|
|
9655
|
-
|
|
9656
|
-
const promptPath =
|
|
9657
|
-
|
|
10008
|
+
const runDir = path15.join(params.worktreeRoot, ".opencode", "_run");
|
|
10009
|
+
fs15.mkdirSync(runDir, { recursive: true });
|
|
10010
|
+
const promptPath = path15.join(runDir, `ace-trace-${traceStem}-${Date.now()}.prompt.txt`);
|
|
10011
|
+
fs15.writeFileSync(promptPath, promptBody, "utf-8");
|
|
9658
10012
|
const vars = {
|
|
9659
10013
|
promptFile: promptPath,
|
|
9660
10014
|
agentId: ACE_TRACE_RECORDER_AGENT_STEM,
|
|
@@ -9677,7 +10031,7 @@ async function runAceTracePhase(params) {
|
|
|
9677
10031
|
if (!cli.ok) {
|
|
9678
10032
|
return { ok: false, message: `[ace] trace OpenCode failed: ${cli.message}` };
|
|
9679
10033
|
}
|
|
9680
|
-
if (!
|
|
10034
|
+
if (!fs15.existsSync(traceAbs)) {
|
|
9681
10035
|
const recovered = extractJsonObjectWithTopLevelKeys(cli.message, [
|
|
9682
10036
|
"aceSchemaVersion",
|
|
9683
10037
|
"sessionMeta",
|
|
@@ -9685,7 +10039,7 @@ async function runAceTracePhase(params) {
|
|
|
9685
10039
|
]);
|
|
9686
10040
|
if (recovered) {
|
|
9687
10041
|
try {
|
|
9688
|
-
|
|
10042
|
+
fs15.writeFileSync(traceAbs, `${recovered}
|
|
9689
10043
|
`, "utf-8");
|
|
9690
10044
|
params.diagnosticLog?.(`[ace] trace recovered from OpenCode stdout/stderr \u2192 ${traceAbs}`);
|
|
9691
10045
|
} catch (e) {
|
|
@@ -9695,7 +10049,7 @@ async function runAceTracePhase(params) {
|
|
|
9695
10049
|
}
|
|
9696
10050
|
}
|
|
9697
10051
|
}
|
|
9698
|
-
if (!
|
|
10052
|
+
if (!fs15.existsSync(traceAbs)) {
|
|
9699
10053
|
const msg = `[ace] trace file missing after run: ${traceAbs}`;
|
|
9700
10054
|
params.diagnosticLog?.(msg);
|
|
9701
10055
|
return { ok: false, message: msg };
|
|
@@ -9727,7 +10081,7 @@ async function runAceTracePhase(params) {
|
|
|
9727
10081
|
return { ok: false, message: msg };
|
|
9728
10082
|
}
|
|
9729
10083
|
try {
|
|
9730
|
-
const rawAlign =
|
|
10084
|
+
const rawAlign = fs15.readFileSync(traceAbs, "utf-8");
|
|
9731
10085
|
const docAlign = JSON.parse(rawAlign);
|
|
9732
10086
|
const smRun = docAlign.sessionMeta?.runId;
|
|
9733
10087
|
if (typeof smRun !== "string" || smRun !== traceStem) {
|
|
@@ -9776,14 +10130,14 @@ async function runAceTracePhase(params) {
|
|
|
9776
10130
|
}
|
|
9777
10131
|
} else {
|
|
9778
10132
|
params.diagnosticLog?.(
|
|
9779
|
-
'[ace] Reflector/Curator not run automatically. Set easyspecs.analysis.ace.offlineLearnAfterSameSessionTrace
|
|
10133
|
+
'[ace] Reflector/Curator not run automatically. Set easyspecs.analysis.ace.offlineLearnAfterSameSessionTrace in .easyspecs/config.json (or legacy .easyspecs/settings.json), or Command Palette: "EasySpecs: ACE \u2014 Learn from traces".'
|
|
9780
10134
|
);
|
|
9781
10135
|
}
|
|
9782
10136
|
return { ok: true, message: "ACE trace OK", traceAbsolutePath: traceAbs };
|
|
9783
10137
|
}
|
|
9784
10138
|
|
|
9785
10139
|
// src/analysis/coordinationListJsonValidate.ts
|
|
9786
|
-
var
|
|
10140
|
+
var fs16 = __toESM(require("fs"));
|
|
9787
10141
|
var import__2 = __toESM(require__());
|
|
9788
10142
|
function stripUtf8Bom3(s) {
|
|
9789
10143
|
return s.length > 0 && s.charCodeAt(0) === 65279 ? s.slice(1) : s;
|
|
@@ -9847,7 +10201,7 @@ function formatAjvErrors2(errors) {
|
|
|
9847
10201
|
function validateCoordinationListJson(jsonAbsolutePath, schemaAbsolutePath) {
|
|
9848
10202
|
let raw;
|
|
9849
10203
|
try {
|
|
9850
|
-
raw = stripUtf8Bom3(
|
|
10204
|
+
raw = stripUtf8Bom3(fs16.readFileSync(jsonAbsolutePath, "utf-8"));
|
|
9851
10205
|
} catch (e) {
|
|
9852
10206
|
return {
|
|
9853
10207
|
ok: false,
|
|
@@ -9863,7 +10217,7 @@ function validateCoordinationListJson(jsonAbsolutePath, schemaAbsolutePath) {
|
|
|
9863
10217
|
}
|
|
9864
10218
|
let schemaRaw;
|
|
9865
10219
|
try {
|
|
9866
|
-
schemaRaw = stripUtf8Bom3(
|
|
10220
|
+
schemaRaw = stripUtf8Bom3(fs16.readFileSync(schemaAbsolutePath, "utf-8"));
|
|
9867
10221
|
} catch (e) {
|
|
9868
10222
|
return {
|
|
9869
10223
|
ok: false,
|
|
@@ -9924,7 +10278,7 @@ function validateCoordinationListJson(jsonAbsolutePath, schemaAbsolutePath) {
|
|
|
9924
10278
|
var FILE_PREVIEW_MAX = 4e3;
|
|
9925
10279
|
function readCoordinationJsonPreview(jsonAbsolutePath) {
|
|
9926
10280
|
try {
|
|
9927
|
-
const raw = stripUtf8Bom3(
|
|
10281
|
+
const raw = stripUtf8Bom3(fs16.readFileSync(jsonAbsolutePath, "utf-8"));
|
|
9928
10282
|
return raw.length <= FILE_PREVIEW_MAX ? raw : `${raw.slice(0, FILE_PREVIEW_MAX)}
|
|
9929
10283
|
|
|
9930
10284
|
\u2026 (truncated)`;
|
|
@@ -10000,7 +10354,7 @@ function formatCoordinationJsonRepairAppendix(outputBasename, failure, rawFilePr
|
|
|
10000
10354
|
}
|
|
10001
10355
|
|
|
10002
10356
|
// src/analysis/markdownEvidenceIndexValidate.ts
|
|
10003
|
-
var
|
|
10357
|
+
var fs17 = __toESM(require("fs"));
|
|
10004
10358
|
var EVIDENCE_HEADING = "## Evidence index";
|
|
10005
10359
|
function evidenceIndexMentionsReadmeMd(body) {
|
|
10006
10360
|
const re = /README\.md/gi;
|
|
@@ -10128,7 +10482,7 @@ function markdownEvidenceValidationPasses(content) {
|
|
|
10128
10482
|
function validateMarkdownEvidenceIndexFile(absolutePath) {
|
|
10129
10483
|
let text;
|
|
10130
10484
|
try {
|
|
10131
|
-
const buf =
|
|
10485
|
+
const buf = fs17.readFileSync(absolutePath);
|
|
10132
10486
|
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
10133
10487
|
text = decoder.decode(buf);
|
|
10134
10488
|
} catch (e) {
|
|
@@ -10169,11 +10523,11 @@ function formatMarkdownEvidenceRepairAppendix(outputFileAbsolute, kind = "empty"
|
|
|
10169
10523
|
}
|
|
10170
10524
|
|
|
10171
10525
|
// src/analysis/openQuestionResolution.ts
|
|
10172
|
-
var
|
|
10173
|
-
var
|
|
10526
|
+
var fs18 = __toESM(require("fs"));
|
|
10527
|
+
var path16 = __toESM(require("path"));
|
|
10174
10528
|
var OPEN_QUESTION_RESOLUTION_JSON_BASENAME = "open-question-resolution.json";
|
|
10175
10529
|
function openQuestionResolutionJsonAbsolute(worktreeRoot) {
|
|
10176
|
-
return
|
|
10530
|
+
return path16.join(worktreeRoot, ".opencode", "_run", OPEN_QUESTION_RESOLUTION_JSON_BASENAME);
|
|
10177
10531
|
}
|
|
10178
10532
|
function asTrimmedString(v) {
|
|
10179
10533
|
if (typeof v !== "string") {
|
|
@@ -10208,10 +10562,10 @@ function parseOpenQuestionResolutionJsonText(raw) {
|
|
|
10208
10562
|
function readOpenQuestionResolutionFile(worktreeRoot) {
|
|
10209
10563
|
const p = openQuestionResolutionJsonAbsolute(worktreeRoot);
|
|
10210
10564
|
try {
|
|
10211
|
-
if (!
|
|
10565
|
+
if (!fs18.existsSync(p)) {
|
|
10212
10566
|
return { ok: false, error: `Missing resolution file: ${p}` };
|
|
10213
10567
|
}
|
|
10214
|
-
const raw =
|
|
10568
|
+
const raw = fs18.readFileSync(p, "utf-8");
|
|
10215
10569
|
return parseOpenQuestionResolutionJsonText(raw);
|
|
10216
10570
|
} catch (e) {
|
|
10217
10571
|
const m = e instanceof Error ? e.message : String(e);
|
|
@@ -10221,16 +10575,16 @@ function readOpenQuestionResolutionFile(worktreeRoot) {
|
|
|
10221
10575
|
function deleteOpenQuestionResolutionFile(worktreeRoot) {
|
|
10222
10576
|
try {
|
|
10223
10577
|
const p = openQuestionResolutionJsonAbsolute(worktreeRoot);
|
|
10224
|
-
if (
|
|
10225
|
-
|
|
10578
|
+
if (fs18.existsSync(p)) {
|
|
10579
|
+
fs18.unlinkSync(p);
|
|
10226
10580
|
}
|
|
10227
10581
|
} catch {
|
|
10228
10582
|
}
|
|
10229
10583
|
}
|
|
10230
10584
|
|
|
10231
10585
|
// src/analysis/openQuestionsSectionValidate.ts
|
|
10232
|
-
var
|
|
10233
|
-
var
|
|
10586
|
+
var fs19 = __toESM(require("fs"));
|
|
10587
|
+
var path17 = __toESM(require("path"));
|
|
10234
10588
|
var CANONICAL_NORMALIZED = "open questions";
|
|
10235
10589
|
function normalizeOpenQuestionsHeadingTitle(raw) {
|
|
10236
10590
|
const t = raw.trim().replace(/\s+/gu, " ");
|
|
@@ -10347,9 +10701,9 @@ function parseOpenQuestionsSection(content) {
|
|
|
10347
10701
|
return { kind: "hasResidualQuestions", questions, startLine1Based };
|
|
10348
10702
|
}
|
|
10349
10703
|
function isContextMarkdownPathForOpenQuestions(worktreeRoot, absolutePath) {
|
|
10350
|
-
const ctx =
|
|
10351
|
-
const abs =
|
|
10352
|
-
const ctxNorm = ctx +
|
|
10704
|
+
const ctx = path17.join(path17.resolve(worktreeRoot), ".gluecharm", "context");
|
|
10705
|
+
const abs = path17.resolve(absolutePath);
|
|
10706
|
+
const ctxNorm = ctx + path17.sep;
|
|
10353
10707
|
return abs === ctx || abs.startsWith(ctxNorm);
|
|
10354
10708
|
}
|
|
10355
10709
|
function validateOpenQuestionsSectionFile(absolutePath, scope) {
|
|
@@ -10362,7 +10716,7 @@ function validateOpenQuestionsSectionFile(absolutePath, scope) {
|
|
|
10362
10716
|
}
|
|
10363
10717
|
let text;
|
|
10364
10718
|
try {
|
|
10365
|
-
const buf =
|
|
10719
|
+
const buf = fs19.readFileSync(absolutePath);
|
|
10366
10720
|
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
10367
10721
|
text = decoder.decode(buf);
|
|
10368
10722
|
} catch (e) {
|
|
@@ -10398,10 +10752,10 @@ function formatOpenQuestionsProducerRepairAppendix(outputFileAbsolute, stepLabel
|
|
|
10398
10752
|
// src/analysis/openCodeTestAgent.ts
|
|
10399
10753
|
var CITATION_EXAMPLE = "`src/example.ts:42` or `src/example.ts:10-25`";
|
|
10400
10754
|
function contextDir(worktreeRoot) {
|
|
10401
|
-
return
|
|
10755
|
+
return path18.join(worktreeRoot, ".gluecharm", "context");
|
|
10402
10756
|
}
|
|
10403
10757
|
function schemaRef(worktreeRoot, schemaBasename) {
|
|
10404
|
-
return
|
|
10758
|
+
return path18.join(worktreeRoot, ".opencode", "schemas", "context-lists", schemaBasename);
|
|
10405
10759
|
}
|
|
10406
10760
|
function expandArgvTemplate3(template, vars) {
|
|
10407
10761
|
return template.map((part) => {
|
|
@@ -10829,7 +11183,7 @@ function clampMarkdownOpenQuestionIterations(raw) {
|
|
|
10829
11183
|
}
|
|
10830
11184
|
function getExpectedOutputArtefactStatus(absolutePath) {
|
|
10831
11185
|
try {
|
|
10832
|
-
const st =
|
|
11186
|
+
const st = fs20.statSync(absolutePath);
|
|
10833
11187
|
if (!st.isFile()) {
|
|
10834
11188
|
return { generated: false, reason: "not_a_file" };
|
|
10835
11189
|
}
|
|
@@ -10845,46 +11199,46 @@ function outputPaths(step, worktreeRoot, listTarget) {
|
|
|
10845
11199
|
const ctx = contextDir(worktreeRoot);
|
|
10846
11200
|
switch (step) {
|
|
10847
11201
|
case "docsProject":
|
|
10848
|
-
return { absolute:
|
|
11202
|
+
return { absolute: path18.join(contextDir(worktreeRoot), "project.md"), basename: "project.md" };
|
|
10849
11203
|
case "architecture":
|
|
10850
|
-
return { absolute:
|
|
11204
|
+
return { absolute: path18.join(ctx, "architecture.md"), basename: "architecture.md" };
|
|
10851
11205
|
case "listFeatures":
|
|
10852
|
-
return { absolute:
|
|
11206
|
+
return { absolute: path18.join(ctx, "features-list.json"), basename: "features-list.json" };
|
|
10853
11207
|
case "reviewFeaturesList":
|
|
10854
|
-
return { absolute:
|
|
11208
|
+
return { absolute: path18.join(ctx, "features-list.json"), basename: "features-list.json" };
|
|
10855
11209
|
case "listRepoSurface":
|
|
10856
|
-
return { absolute:
|
|
11210
|
+
return { absolute: path18.join(ctx, "repo-surface-scan.json"), basename: "repo-surface-scan.json" };
|
|
10857
11211
|
case "listExperiences":
|
|
10858
|
-
return { absolute:
|
|
11212
|
+
return { absolute: path18.join(ctx, "experiences-list.json"), basename: "experiences-list.json" };
|
|
10859
11213
|
case "reviewExperiencesList":
|
|
10860
|
-
return { absolute:
|
|
11214
|
+
return { absolute: path18.join(ctx, "experiences-list.json"), basename: "experiences-list.json" };
|
|
10861
11215
|
case "listServices":
|
|
10862
|
-
return { absolute:
|
|
11216
|
+
return { absolute: path18.join(ctx, "services-list.json"), basename: "services-list.json" };
|
|
10863
11217
|
case "reviewServicesList":
|
|
10864
|
-
return { absolute:
|
|
11218
|
+
return { absolute: path18.join(ctx, "services-list.json"), basename: "services-list.json" };
|
|
10865
11219
|
case "listDataModel":
|
|
10866
|
-
return { absolute:
|
|
11220
|
+
return { absolute: path18.join(ctx, "data-model-list.json"), basename: "data-model-list.json" };
|
|
10867
11221
|
case "reviewDataModelList":
|
|
10868
|
-
return { absolute:
|
|
11222
|
+
return { absolute: path18.join(ctx, "data-model-list.json"), basename: "data-model-list.json" };
|
|
10869
11223
|
case "listTechStack":
|
|
10870
|
-
return { absolute:
|
|
11224
|
+
return { absolute: path18.join(ctx, "tech-stack-list.json"), basename: "tech-stack-list.json" };
|
|
10871
11225
|
case "reviewTechStackList":
|
|
10872
|
-
return { absolute:
|
|
11226
|
+
return { absolute: path18.join(ctx, "tech-stack-list.json"), basename: "tech-stack-list.json" };
|
|
10873
11227
|
case "listUseCases": {
|
|
10874
11228
|
const fe = listTarget?.featureCode;
|
|
10875
11229
|
if (!fe) {
|
|
10876
11230
|
throw new Error("listUseCases requires listTarget.featureCode");
|
|
10877
11231
|
}
|
|
10878
|
-
const
|
|
10879
|
-
return { absolute:
|
|
11232
|
+
const basename12 = `${fe}-use-cases-list.json`;
|
|
11233
|
+
return { absolute: path18.join(ctx, basename12), basename: basename12 };
|
|
10880
11234
|
}
|
|
10881
11235
|
case "reviewUseCasesList": {
|
|
10882
11236
|
const fe = listTarget?.featureCode;
|
|
10883
11237
|
if (!fe) {
|
|
10884
11238
|
throw new Error("reviewUseCasesList requires listTarget.featureCode");
|
|
10885
11239
|
}
|
|
10886
|
-
const
|
|
10887
|
-
return { absolute:
|
|
11240
|
+
const basename12 = `${fe}-use-cases-list.json`;
|
|
11241
|
+
return { absolute: path18.join(ctx, basename12), basename: basename12 };
|
|
10888
11242
|
}
|
|
10889
11243
|
case "listScenarios": {
|
|
10890
11244
|
const fe = listTarget?.featureCode;
|
|
@@ -10892,8 +11246,8 @@ function outputPaths(step, worktreeRoot, listTarget) {
|
|
|
10892
11246
|
if (!fe || !uc) {
|
|
10893
11247
|
throw new Error("listScenarios requires listTarget.featureCode and useCaseCode");
|
|
10894
11248
|
}
|
|
10895
|
-
const
|
|
10896
|
-
return { absolute:
|
|
11249
|
+
const basename12 = `${fe}_${uc}-scenarios-list.json`;
|
|
11250
|
+
return { absolute: path18.join(ctx, basename12), basename: basename12 };
|
|
10897
11251
|
}
|
|
10898
11252
|
case "reviewScenariosList": {
|
|
10899
11253
|
const fe = listTarget?.featureCode;
|
|
@@ -10901,24 +11255,24 @@ function outputPaths(step, worktreeRoot, listTarget) {
|
|
|
10901
11255
|
if (!fe || !uc) {
|
|
10902
11256
|
throw new Error("reviewScenariosList requires listTarget.featureCode and useCaseCode");
|
|
10903
11257
|
}
|
|
10904
|
-
const
|
|
10905
|
-
return { absolute:
|
|
11258
|
+
const basename12 = `${fe}_${uc}-scenarios-list.json`;
|
|
11259
|
+
return { absolute: path18.join(ctx, basename12), basename: basename12 };
|
|
10906
11260
|
}
|
|
10907
11261
|
case "listEntityFields": {
|
|
10908
11262
|
const dm = listTarget?.entityCode;
|
|
10909
11263
|
if (!dm) {
|
|
10910
11264
|
throw new Error("listEntityFields requires listTarget.entityCode");
|
|
10911
11265
|
}
|
|
10912
|
-
const
|
|
10913
|
-
return { absolute:
|
|
11266
|
+
const basename12 = `${dm}-fields-list.json`;
|
|
11267
|
+
return { absolute: path18.join(ctx, basename12), basename: basename12 };
|
|
10914
11268
|
}
|
|
10915
11269
|
case "reviewEntityFieldsList": {
|
|
10916
11270
|
const dm = listTarget?.entityCode;
|
|
10917
11271
|
if (!dm) {
|
|
10918
11272
|
throw new Error("reviewEntityFieldsList requires listTarget.entityCode");
|
|
10919
11273
|
}
|
|
10920
|
-
const
|
|
10921
|
-
return { absolute:
|
|
11274
|
+
const basename12 = `${dm}-fields-list.json`;
|
|
11275
|
+
return { absolute: path18.join(ctx, basename12), basename: basename12 };
|
|
10922
11276
|
}
|
|
10923
11277
|
default: {
|
|
10924
11278
|
const _u = step;
|
|
@@ -10927,8 +11281,8 @@ function outputPaths(step, worktreeRoot, listTarget) {
|
|
|
10927
11281
|
}
|
|
10928
11282
|
}
|
|
10929
11283
|
async function runOpenCodeResolveOpenQuestionStep(opts) {
|
|
10930
|
-
const runDir =
|
|
10931
|
-
|
|
11284
|
+
const runDir = path18.join(opts.worktreeRoot, ".opencode", "_run");
|
|
11285
|
+
fs20.mkdirSync(runDir, { recursive: true });
|
|
10932
11286
|
const resolutionJsonAbsolute = openQuestionResolutionJsonAbsolute(opts.worktreeRoot);
|
|
10933
11287
|
const body = fillResolveOpenQuestionPrompt({
|
|
10934
11288
|
worktreeRoot: opts.worktreeRoot,
|
|
@@ -10937,8 +11291,8 @@ async function runOpenCodeResolveOpenQuestionStep(opts) {
|
|
|
10937
11291
|
questionText: opts.questionText,
|
|
10938
11292
|
resolutionJsonAbsolute
|
|
10939
11293
|
});
|
|
10940
|
-
const promptPath =
|
|
10941
|
-
|
|
11294
|
+
const promptPath = path18.join(runDir, `resolve-open-question-${Date.now()}.prompt.txt`);
|
|
11295
|
+
fs20.writeFileSync(promptPath, body, "utf-8");
|
|
10942
11296
|
const vars = {
|
|
10943
11297
|
promptFile: promptPath,
|
|
10944
11298
|
agentId: RESOLVE_OPEN_QUESTION_AGENT_STEM,
|
|
@@ -10965,7 +11319,8 @@ async function runOpenCodeResolveOpenQuestionStep(opts) {
|
|
|
10965
11319
|
diagnosticLog: opts.diagnosticLog,
|
|
10966
11320
|
onAgentLaunched: opts.onAgentLaunched,
|
|
10967
11321
|
signal: opts.abortSignal,
|
|
10968
|
-
parseOpenCodeSessionFromJsonStdout: opts.followUpOpenCodeSessionId === void 0
|
|
11322
|
+
parseOpenCodeSessionFromJsonStdout: opts.followUpOpenCodeSessionId === void 0,
|
|
11323
|
+
childEnv: opts.openCodeChildEnv
|
|
10969
11324
|
});
|
|
10970
11325
|
opts.onRemediationPhase?.("validating");
|
|
10971
11326
|
if (cli.cancelled || opts.abortSignal?.aborted) {
|
|
@@ -11000,8 +11355,8 @@ ${cli.message}`,
|
|
|
11000
11355
|
}
|
|
11001
11356
|
async function runSynthesisMarkdownRemediationChain(common, step, workspaceLabel, initialMarkdownAppendix) {
|
|
11002
11357
|
const totalMarkdownRuns = 1 + common.maxMarkdownEvidenceRepairs;
|
|
11003
|
-
const runDir =
|
|
11004
|
-
|
|
11358
|
+
const runDir = path18.join(common.worktreeRoot, ".opencode", "_run");
|
|
11359
|
+
fs20.mkdirSync(runDir, { recursive: true });
|
|
11005
11360
|
let markdownEvidenceRepairAppendix = initialMarkdownAppendix;
|
|
11006
11361
|
let lastPromptPath = "";
|
|
11007
11362
|
let lastCliMessage = "";
|
|
@@ -11019,9 +11374,9 @@ async function runSynthesisMarkdownRemediationChain(common, step, workspaceLabel
|
|
|
11019
11374
|
void 0,
|
|
11020
11375
|
markdownEvidenceRepairAppendix
|
|
11021
11376
|
);
|
|
11022
|
-
const promptPath =
|
|
11377
|
+
const promptPath = path18.join(runDir, `${step}-oqrem-a${attempt}-${Date.now()}.prompt.txt`);
|
|
11023
11378
|
lastPromptPath = promptPath;
|
|
11024
|
-
|
|
11379
|
+
fs20.writeFileSync(promptPath, body, "utf-8");
|
|
11025
11380
|
const vars = {
|
|
11026
11381
|
promptFile: promptPath,
|
|
11027
11382
|
agentId: STEP_OPEN_CODE_AGENT_IDS[step],
|
|
@@ -11043,7 +11398,8 @@ async function runSynthesisMarkdownRemediationChain(common, step, workspaceLabel
|
|
|
11043
11398
|
diagnosticLog: common.diagnosticLog,
|
|
11044
11399
|
onAgentLaunched: common.onAgentLaunched,
|
|
11045
11400
|
signal: common.abortSignal,
|
|
11046
|
-
parseOpenCodeSessionFromJsonStdout: common.producerOpenCodeSessionId === void 0
|
|
11401
|
+
parseOpenCodeSessionFromJsonStdout: common.producerOpenCodeSessionId === void 0,
|
|
11402
|
+
childEnv: common.openCodeChildEnv
|
|
11047
11403
|
});
|
|
11048
11404
|
common.onRemediationPhase?.("validating");
|
|
11049
11405
|
lastCliMessage = cli.message;
|
|
@@ -11119,8 +11475,8 @@ ${common.outputFileAbsolute}`,
|
|
|
11119
11475
|
}
|
|
11120
11476
|
async function runDetailMarkdownRemediationChain(common, target, initialMarkdownAppendix) {
|
|
11121
11477
|
const totalMarkdownRuns = 1 + common.maxMarkdownEvidenceRepairs;
|
|
11122
|
-
const runDir =
|
|
11123
|
-
|
|
11478
|
+
const runDir = path18.join(common.worktreeRoot, ".opencode", "_run");
|
|
11479
|
+
fs20.mkdirSync(runDir, { recursive: true });
|
|
11124
11480
|
const safeStem = target.outputBasename.replace(/[^A-Za-z0-9_.-]+/g, "_").slice(0, 120);
|
|
11125
11481
|
let markdownEvidenceRepairAppendix = initialMarkdownAppendix;
|
|
11126
11482
|
let lastPromptPath = "";
|
|
@@ -11139,12 +11495,12 @@ async function runDetailMarkdownRemediationChain(common, target, initialMarkdown
|
|
|
11139
11495
|
citationFormatExample: CITATION_EXAMPLE,
|
|
11140
11496
|
repairAppendix: markdownEvidenceRepairAppendix
|
|
11141
11497
|
});
|
|
11142
|
-
const promptPath =
|
|
11498
|
+
const promptPath = path18.join(
|
|
11143
11499
|
runDir,
|
|
11144
11500
|
`markdownDetail-${target.openCodeAgentStem}-${safeStem}-oqrem-a${attempt}-${Date.now()}.prompt.txt`
|
|
11145
11501
|
);
|
|
11146
11502
|
lastPromptPath = promptPath;
|
|
11147
|
-
|
|
11503
|
+
fs20.writeFileSync(promptPath, body, "utf-8");
|
|
11148
11504
|
const vars = {
|
|
11149
11505
|
promptFile: promptPath,
|
|
11150
11506
|
agentId: target.openCodeAgentStem,
|
|
@@ -11166,7 +11522,8 @@ async function runDetailMarkdownRemediationChain(common, target, initialMarkdown
|
|
|
11166
11522
|
diagnosticLog: common.diagnosticLog,
|
|
11167
11523
|
onAgentLaunched: common.onAgentLaunched,
|
|
11168
11524
|
signal: common.abortSignal,
|
|
11169
|
-
parseOpenCodeSessionFromJsonStdout: common.producerOpenCodeSessionId === void 0
|
|
11525
|
+
parseOpenCodeSessionFromJsonStdout: common.producerOpenCodeSessionId === void 0,
|
|
11526
|
+
childEnv: common.openCodeChildEnv
|
|
11170
11527
|
});
|
|
11171
11528
|
common.onRemediationPhase?.("validating");
|
|
11172
11529
|
lastCliMessage = cli.message;
|
|
@@ -11240,7 +11597,7 @@ ${common.outputFileAbsolute}`,
|
|
|
11240
11597
|
promptPath: lastPromptPath
|
|
11241
11598
|
};
|
|
11242
11599
|
}
|
|
11243
|
-
async function remediateOpenQuestionsForContextMarkdown(mode, producerStepLabel, outputFileAbsolute, outputBasename, worktreeRoot, markdownOpenQuestionIterations, markdownEvidenceRepairAttempts, executable, argvTemplate, timeoutMs, diagnosticLog, abortSignal, onRemediationPhase, onAgentLaunched, stewardship) {
|
|
11600
|
+
async function remediateOpenQuestionsForContextMarkdown(mode, producerStepLabel, outputFileAbsolute, outputBasename, worktreeRoot, markdownOpenQuestionIterations, markdownEvidenceRepairAttempts, executable, argvTemplate, timeoutMs, diagnosticLog, abortSignal, onRemediationPhase, onAgentLaunched, stewardship, openCodeChildEnv) {
|
|
11244
11601
|
const maxOq = clampMarkdownOpenQuestionIterations(markdownOpenQuestionIterations);
|
|
11245
11602
|
let maxMdEv = markdownEvidenceRepairAttempts === void 0 ? 2 : Math.floor(Number(markdownEvidenceRepairAttempts));
|
|
11246
11603
|
if (!Number.isFinite(maxMdEv)) {
|
|
@@ -11264,7 +11621,8 @@ async function remediateOpenQuestionsForContextMarkdown(mode, producerStepLabel,
|
|
|
11264
11621
|
artefactRunId: runId,
|
|
11265
11622
|
artefactWorkItemId: workItemId,
|
|
11266
11623
|
stewardshipStepLabel: `${producerStepLabel}|open-questions-chain`,
|
|
11267
|
-
producerOpenCodeSessionId: stewardship?.producerOpenCodeSessionId
|
|
11624
|
+
producerOpenCodeSessionId: stewardship?.producerOpenCodeSessionId,
|
|
11625
|
+
openCodeChildEnv
|
|
11268
11626
|
};
|
|
11269
11627
|
const first = validateOpenQuestionsSectionFile(outputFileAbsolute, { worktreeRoot });
|
|
11270
11628
|
if (!first.ok) {
|
|
@@ -11320,7 +11678,8 @@ async function remediateOpenQuestionsForContextMarkdown(mode, producerStepLabel,
|
|
|
11320
11678
|
followUpOpenCodeSessionId: stewardship?.producerOpenCodeSessionId,
|
|
11321
11679
|
artefactRunId: runId,
|
|
11322
11680
|
artefactWorkItemId: workItemId,
|
|
11323
|
-
stewardshipStepLabel: `${producerStepLabel}|resolve-oq
|
|
11681
|
+
stewardshipStepLabel: `${producerStepLabel}|resolve-oq`,
|
|
11682
|
+
openCodeChildEnv
|
|
11324
11683
|
});
|
|
11325
11684
|
if (resolveRes.cancelled || abortSignal?.aborted) {
|
|
11326
11685
|
return { ok: false, cancelled: true, message: resolveRes.message };
|
|
@@ -11463,7 +11822,7 @@ async function runOpenCodeTestAgentStep(opts) {
|
|
|
11463
11822
|
let schemaAbsoluteForList;
|
|
11464
11823
|
if (effectiveListSchemaFile) {
|
|
11465
11824
|
schemaAbsoluteForList = schemaRef(opts.worktreeRoot, effectiveListSchemaFile);
|
|
11466
|
-
if (!
|
|
11825
|
+
if (!fs20.existsSync(schemaAbsoluteForList)) {
|
|
11467
11826
|
return {
|
|
11468
11827
|
ok: false,
|
|
11469
11828
|
message: `JSON Schema not found: ${schemaAbsoluteForList}
|
|
@@ -11476,11 +11835,11 @@ Run **Materialize agents** first (copies list schemas into this folder\u2019s \`
|
|
|
11476
11835
|
}
|
|
11477
11836
|
if (opts.step === "reviewExperiencesList" && effectiveListSchemaFile) {
|
|
11478
11837
|
const schemaAbs = schemaRef(opts.worktreeRoot, effectiveListSchemaFile);
|
|
11479
|
-
if (
|
|
11838
|
+
if (fs20.existsSync(outputFileAbsolute)) {
|
|
11480
11839
|
const v = validateCoordinationListJson(outputFileAbsolute, schemaAbs);
|
|
11481
11840
|
if (v.ok) {
|
|
11482
11841
|
try {
|
|
11483
|
-
const raw =
|
|
11842
|
+
const raw = fs20.readFileSync(outputFileAbsolute, "utf-8");
|
|
11484
11843
|
const data = JSON.parse(raw);
|
|
11485
11844
|
if (Array.isArray(data.views) && data.views.length === 0) {
|
|
11486
11845
|
return {
|
|
@@ -11496,9 +11855,9 @@ Run **Materialize agents** first (copies list schemas into this folder\u2019s \`
|
|
|
11496
11855
|
}
|
|
11497
11856
|
}
|
|
11498
11857
|
}
|
|
11499
|
-
|
|
11500
|
-
const runDir =
|
|
11501
|
-
|
|
11858
|
+
fs20.mkdirSync(path18.dirname(outputFileAbsolute), { recursive: true });
|
|
11859
|
+
const runDir = path18.join(opts.worktreeRoot, ".opencode", "_run");
|
|
11860
|
+
fs20.mkdirSync(runDir, { recursive: true });
|
|
11502
11861
|
const scopeSuffix = (opts.step === "listUseCases" || opts.step === "reviewUseCasesList") && opts.listTarget?.featureCode ? `-${opts.listTarget.featureCode}` : (opts.step === "listScenarios" || opts.step === "reviewScenariosList") && opts.listTarget?.featureCode && opts.listTarget?.useCaseCode ? `-${opts.listTarget.featureCode}_${opts.listTarget.useCaseCode}` : (opts.step === "listEntityFields" || opts.step === "reviewEntityFieldsList") && opts.listTarget?.entityCode ? `-${opts.listTarget.entityCode}` : "";
|
|
11503
11862
|
const rawRepair = opts.listJsonSchemaRepairAttempts;
|
|
11504
11863
|
let maxRepairAttempts = rawRepair === void 0 ? 1 : Math.floor(Number(rawRepair));
|
|
@@ -11549,9 +11908,9 @@ Run **Materialize agents** first (copies list schemas into this folder\u2019s \`
|
|
|
11549
11908
|
effectiveListSchemaFile ? repairAppendix : void 0,
|
|
11550
11909
|
effectiveListSchemaFile ? void 0 : markdownEvidenceRepairAppendix
|
|
11551
11910
|
);
|
|
11552
|
-
const promptPath =
|
|
11911
|
+
const promptPath = path18.join(runDir, `${opts.step}${scopeSuffix}-a${attempt}-${Date.now()}.prompt.txt`);
|
|
11553
11912
|
lastPromptPath = promptPath;
|
|
11554
|
-
|
|
11913
|
+
fs20.writeFileSync(promptPath, body, "utf-8");
|
|
11555
11914
|
const vars = {
|
|
11556
11915
|
promptFile: promptPath,
|
|
11557
11916
|
agentId: STEP_OPEN_CODE_AGENT_IDS[opts.step],
|
|
@@ -11576,7 +11935,8 @@ Run **Materialize agents** first (copies list schemas into this folder\u2019s \`
|
|
|
11576
11935
|
diagnosticLog: opts.diagnosticLog,
|
|
11577
11936
|
onAgentLaunched: opts.onAgentLaunched,
|
|
11578
11937
|
signal: opts.abortSignal,
|
|
11579
|
-
parseOpenCodeSessionFromJsonStdout: !isFollowUpSpawn
|
|
11938
|
+
parseOpenCodeSessionFromJsonStdout: !isFollowUpSpawn,
|
|
11939
|
+
childEnv: opts.openCodeChildEnv
|
|
11580
11940
|
});
|
|
11581
11941
|
if (cli.cancelled || opts.abortSignal?.aborted) {
|
|
11582
11942
|
return {
|
|
@@ -11660,7 +12020,8 @@ Run **Materialize agents** first (copies list schemas into this folder\u2019s \`
|
|
|
11660
12020
|
artefactRunId: stewardshipRunId,
|
|
11661
12021
|
artefactWorkItemId: stewardshipWorkItemId,
|
|
11662
12022
|
producerOpenCodeSessionId: capturedOpenCodeSessionId
|
|
11663
|
-
}
|
|
12023
|
+
},
|
|
12024
|
+
opts.openCodeChildEnv
|
|
11664
12025
|
);
|
|
11665
12026
|
if (oqRes.cancelled) {
|
|
11666
12027
|
return {
|
|
@@ -11789,7 +12150,7 @@ Expected output: ${outputFileAbsolute}`;
|
|
|
11789
12150
|
const orderSet = new Set(CONTEXT_SYNTHESIS_TEST_STEP_ORDER);
|
|
11790
12151
|
if (orderSet.has(opts.step)) {
|
|
11791
12152
|
const ctx = contextDir(opts.worktreeRoot);
|
|
11792
|
-
const rel =
|
|
12153
|
+
const rel = path18.relative(ctx, outputFileAbsolute).split(path18.sep).join("/");
|
|
11793
12154
|
opts.onRemediationPhase?.("aceTracing");
|
|
11794
12155
|
try {
|
|
11795
12156
|
await runAceTracePhase({
|
|
@@ -11836,7 +12197,7 @@ Expected output: ${outputFileAbsolute}`;
|
|
|
11836
12197
|
var MARKDOWN_DETAIL_RUN_STEP = "markdownDetail";
|
|
11837
12198
|
async function runOpenCodeMarkdownDetailStep(opts) {
|
|
11838
12199
|
const ctx = contextDir(opts.worktreeRoot);
|
|
11839
|
-
const outputFileAbsolute =
|
|
12200
|
+
const outputFileAbsolute = path18.join(ctx, opts.target.outputBasename);
|
|
11840
12201
|
const outputBasename = opts.target.outputBasename;
|
|
11841
12202
|
const rawMdEv = opts.markdownEvidenceRepairAttempts;
|
|
11842
12203
|
let maxMarkdownEvidenceRepairs = rawMdEv === void 0 ? 2 : Math.floor(Number(rawMdEv));
|
|
@@ -11845,9 +12206,9 @@ async function runOpenCodeMarkdownDetailStep(opts) {
|
|
|
11845
12206
|
}
|
|
11846
12207
|
maxMarkdownEvidenceRepairs = Math.min(5, Math.max(0, maxMarkdownEvidenceRepairs));
|
|
11847
12208
|
const totalMarkdownRuns = 1 + maxMarkdownEvidenceRepairs;
|
|
11848
|
-
|
|
11849
|
-
const runDir =
|
|
11850
|
-
|
|
12209
|
+
fs20.mkdirSync(path18.dirname(outputFileAbsolute), { recursive: true });
|
|
12210
|
+
const runDir = path18.join(opts.worktreeRoot, ".opencode", "_run");
|
|
12211
|
+
fs20.mkdirSync(runDir, { recursive: true });
|
|
11851
12212
|
const safeStem = opts.target.outputBasename.replace(/[^A-Za-z0-9_.-]+/g, "_").slice(0, 120);
|
|
11852
12213
|
let markdownEvidenceRepairAppendix;
|
|
11853
12214
|
let lastPromptPath = "";
|
|
@@ -11882,12 +12243,12 @@ async function runOpenCodeMarkdownDetailStep(opts) {
|
|
|
11882
12243
|
citationFormatExample: CITATION_EXAMPLE,
|
|
11883
12244
|
repairAppendix: markdownEvidenceRepairAppendix
|
|
11884
12245
|
});
|
|
11885
|
-
const promptPath =
|
|
12246
|
+
const promptPath = path18.join(
|
|
11886
12247
|
runDir,
|
|
11887
12248
|
`markdownDetail-${opts.target.openCodeAgentStem}-${safeStem}-a${attempt}-${Date.now()}.prompt.txt`
|
|
11888
12249
|
);
|
|
11889
12250
|
lastPromptPath = promptPath;
|
|
11890
|
-
|
|
12251
|
+
fs20.writeFileSync(promptPath, body, "utf-8");
|
|
11891
12252
|
const vars = {
|
|
11892
12253
|
promptFile: promptPath,
|
|
11893
12254
|
agentId: opts.target.openCodeAgentStem,
|
|
@@ -11912,7 +12273,8 @@ async function runOpenCodeMarkdownDetailStep(opts) {
|
|
|
11912
12273
|
diagnosticLog: opts.diagnosticLog,
|
|
11913
12274
|
onAgentLaunched: opts.onAgentLaunched,
|
|
11914
12275
|
signal: opts.abortSignal,
|
|
11915
|
-
parseOpenCodeSessionFromJsonStdout: !isFollowUpSpawn
|
|
12276
|
+
parseOpenCodeSessionFromJsonStdout: !isFollowUpSpawn,
|
|
12277
|
+
childEnv: opts.openCodeChildEnv
|
|
11916
12278
|
});
|
|
11917
12279
|
if (cli.cancelled || opts.abortSignal?.aborted) {
|
|
11918
12280
|
return {
|
|
@@ -11979,7 +12341,8 @@ async function runOpenCodeMarkdownDetailStep(opts) {
|
|
|
11979
12341
|
artefactRunId: mdRunId,
|
|
11980
12342
|
artefactWorkItemId: mdWorkItemId,
|
|
11981
12343
|
producerOpenCodeSessionId: capturedOpenCodeSessionId
|
|
11982
|
-
}
|
|
12344
|
+
},
|
|
12345
|
+
opts.openCodeChildEnv
|
|
11983
12346
|
);
|
|
11984
12347
|
if (oqRes.cancelled) {
|
|
11985
12348
|
return {
|
|
@@ -12071,7 +12434,7 @@ Expected output: ${outputFileAbsolute}`;
|
|
|
12071
12434
|
}
|
|
12072
12435
|
const ok = cliProcessOk && artefactOk && validationOk;
|
|
12073
12436
|
if (ok && opts.aceEnabled && sessionIdForAceTrace) {
|
|
12074
|
-
const rel =
|
|
12437
|
+
const rel = path18.relative(ctx, outputFileAbsolute).split(path18.sep).join("/");
|
|
12075
12438
|
opts.onRemediationPhase?.("aceTracing");
|
|
12076
12439
|
try {
|
|
12077
12440
|
await runAceTracePhase({
|
|
@@ -12119,26 +12482,7 @@ Expected output: ${outputFileAbsolute}`;
|
|
|
12119
12482
|
var import_child_process2 = require("child_process");
|
|
12120
12483
|
var fs21 = __toESM(require("fs"));
|
|
12121
12484
|
var os = __toESM(require("os"));
|
|
12122
|
-
var
|
|
12123
|
-
|
|
12124
|
-
// src/analysis/easySpecsWorktreeMarker.ts
|
|
12125
|
-
var fs20 = __toESM(require("fs"));
|
|
12126
|
-
var path17 = __toESM(require("path"));
|
|
12127
|
-
var EASYSPECS_LOCAL_DIR = ".easyspecs";
|
|
12128
|
-
var EASYSPECS_WORKTREE_MARKER_REL = path17.join(EASYSPECS_LOCAL_DIR, "analysis-worktree.json");
|
|
12129
|
-
var MARKER_KIND = "easyspecs-analysis-worktree";
|
|
12130
|
-
function writeAnalysisWorktreeMarker(worktreeRoot, repositoryRoot) {
|
|
12131
|
-
const dir = path17.join(worktreeRoot, EASYSPECS_LOCAL_DIR);
|
|
12132
|
-
fs20.mkdirSync(dir, { recursive: true });
|
|
12133
|
-
const payload = {
|
|
12134
|
-
kind: MARKER_KIND,
|
|
12135
|
-
repositoryRoot: path17.resolve(repositoryRoot)
|
|
12136
|
-
};
|
|
12137
|
-
fs20.writeFileSync(path17.join(dir, "analysis-worktree.json"), `${JSON.stringify(payload)}
|
|
12138
|
-
`, "utf-8");
|
|
12139
|
-
}
|
|
12140
|
-
|
|
12141
|
-
// src/analysis/worktreeManager.ts
|
|
12485
|
+
var path19 = __toESM(require("path"));
|
|
12142
12486
|
var EASYSPECS_WT_DIR_RE = /^easyspecs-(\d+)$/;
|
|
12143
12487
|
function maxEasyspecsWorktreeIndex(parentDir) {
|
|
12144
12488
|
let max = 0;
|
|
@@ -12171,7 +12515,7 @@ function allocateEasyspecsWorktreePath(parentDir) {
|
|
|
12171
12515
|
const start = maxEasyspecsWorktreeIndex(parentDir);
|
|
12172
12516
|
for (let i = start + 1; i < start + 1e4; i++) {
|
|
12173
12517
|
const name = formatEasyspecsWorktreeFolderName(i);
|
|
12174
|
-
const wt =
|
|
12518
|
+
const wt = path19.join(parentDir, name);
|
|
12175
12519
|
if (!fs21.existsSync(wt)) {
|
|
12176
12520
|
return wt;
|
|
12177
12521
|
}
|
|
@@ -12191,8 +12535,8 @@ function readHeadBranchShort(repoRoot) {
|
|
|
12191
12535
|
return b.length > 0 ? b : void 0;
|
|
12192
12536
|
}
|
|
12193
12537
|
function attachWorktreeHandle(worktreePath, repositoryRoot) {
|
|
12194
|
-
const wt =
|
|
12195
|
-
const repo =
|
|
12538
|
+
const wt = path19.resolve(worktreePath);
|
|
12539
|
+
const repo = path19.resolve(repositoryRoot);
|
|
12196
12540
|
return {
|
|
12197
12541
|
path: wt,
|
|
12198
12542
|
repoRoot: repo,
|
|
@@ -12210,7 +12554,7 @@ function attachWorktreeHandle(worktreePath, repositoryRoot) {
|
|
|
12210
12554
|
};
|
|
12211
12555
|
}
|
|
12212
12556
|
function createAnalysisWorktree(repoRoot) {
|
|
12213
|
-
const parent =
|
|
12557
|
+
const parent = path19.join(os.tmpdir(), "easyspecs-analysis");
|
|
12214
12558
|
const wt = allocateEasyspecsWorktreePath(parent);
|
|
12215
12559
|
if (!wt) {
|
|
12216
12560
|
return {
|
|
@@ -12247,12 +12591,12 @@ var STORAGE_KEY = "easyspecs.analysis.artefactRun.v1";
|
|
|
12247
12591
|
function randomRunId() {
|
|
12248
12592
|
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
12249
12593
|
}
|
|
12250
|
-
function
|
|
12594
|
+
function isRecord3(v) {
|
|
12251
12595
|
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
12252
12596
|
}
|
|
12253
12597
|
function readArtefactRunSnapshot(context) {
|
|
12254
12598
|
const raw = context.workspaceState.get(STORAGE_KEY);
|
|
12255
|
-
if (!raw || !
|
|
12599
|
+
if (!raw || !isRecord3(raw)) {
|
|
12256
12600
|
return void 0;
|
|
12257
12601
|
}
|
|
12258
12602
|
const runId = raw.runId;
|
|
@@ -12261,7 +12605,7 @@ function readArtefactRunSnapshot(context) {
|
|
|
12261
12605
|
const startedAtIso = raw.startedAtIso;
|
|
12262
12606
|
const overallStatus = raw.overallStatus;
|
|
12263
12607
|
const items = raw.items;
|
|
12264
|
-
if (typeof runId !== "string" || typeof repositoryRoot !== "string" || typeof analysisRoot !== "string" || typeof startedAtIso !== "string" || overallStatus !== "idle" && overallStatus !== "running" && overallStatus !== "complete" && overallStatus !== "failed" || !
|
|
12608
|
+
if (typeof runId !== "string" || typeof repositoryRoot !== "string" || typeof analysisRoot !== "string" || typeof startedAtIso !== "string" || overallStatus !== "idle" && overallStatus !== "running" && overallStatus !== "complete" && overallStatus !== "failed" || !isRecord3(items)) {
|
|
12265
12609
|
return void 0;
|
|
12266
12610
|
}
|
|
12267
12611
|
const fin = raw.finishedAtIso;
|
|
@@ -12325,7 +12669,7 @@ function noteOpenCodeAgentLaunched() {
|
|
|
12325
12669
|
|
|
12326
12670
|
// src/contextIndexAssembler.ts
|
|
12327
12671
|
var fs24 = __toESM(require("fs"));
|
|
12328
|
-
var
|
|
12672
|
+
var path22 = __toESM(require("path"));
|
|
12329
12673
|
|
|
12330
12674
|
// src/srsModel.ts
|
|
12331
12675
|
var APPLICATION_CONTEXT_KIND = "easyspecs.application-context";
|
|
@@ -12333,26 +12677,26 @@ var APPLICATION_CONTEXT_KIND = "easyspecs.application-context";
|
|
|
12333
12677
|
// src/indexApplicationContextValidate.ts
|
|
12334
12678
|
var import__3 = __toESM(require__());
|
|
12335
12679
|
var fs23 = __toESM(require("fs"));
|
|
12336
|
-
var
|
|
12680
|
+
var path21 = __toESM(require("path"));
|
|
12337
12681
|
|
|
12338
12682
|
// src/shared/repoResourcesRoot.ts
|
|
12339
12683
|
var fs22 = __toESM(require("node:fs"));
|
|
12340
|
-
var
|
|
12341
|
-
var CONTEXT_LIST_MARKER =
|
|
12684
|
+
var path20 = __toESM(require("node:path"));
|
|
12685
|
+
var CONTEXT_LIST_MARKER = path20.join("schemas", "context-lists", "zero-reference-classifier-record.schema.json");
|
|
12342
12686
|
function hasMarker(resourcesRoot) {
|
|
12343
|
-
return fs22.existsSync(
|
|
12687
|
+
return fs22.existsSync(path20.join(resourcesRoot, CONTEXT_LIST_MARKER));
|
|
12344
12688
|
}
|
|
12345
12689
|
function resolveRepoResourcesRoot() {
|
|
12346
12690
|
const env = process.env.EASYSPECS_EXTENSION_ROOT?.trim();
|
|
12347
12691
|
if (env) {
|
|
12348
|
-
const r =
|
|
12692
|
+
const r = path20.join(path20.resolve(env), "resources");
|
|
12349
12693
|
if (hasMarker(r)) {
|
|
12350
12694
|
return r;
|
|
12351
12695
|
}
|
|
12352
12696
|
}
|
|
12353
|
-
const candidates = [
|
|
12697
|
+
const candidates = [path20.join(__dirname, "..", "resources"), path20.join(__dirname, "..", "..", "resources")];
|
|
12354
12698
|
for (const c of candidates) {
|
|
12355
|
-
const abs =
|
|
12699
|
+
const abs = path20.resolve(c);
|
|
12356
12700
|
if (hasMarker(abs)) {
|
|
12357
12701
|
return abs;
|
|
12358
12702
|
}
|
|
@@ -12362,10 +12706,10 @@ function resolveRepoResourcesRoot() {
|
|
|
12362
12706
|
);
|
|
12363
12707
|
}
|
|
12364
12708
|
function resolveContextListSchemasDir() {
|
|
12365
|
-
return
|
|
12709
|
+
return path20.join(resolveRepoResourcesRoot(), "schemas", "context-lists");
|
|
12366
12710
|
}
|
|
12367
12711
|
function resolveIndexApplicationContextSchemaPath() {
|
|
12368
|
-
return
|
|
12712
|
+
return path20.join(resolveRepoResourcesRoot(), "schemas", "index-application-context.schema.json");
|
|
12369
12713
|
}
|
|
12370
12714
|
|
|
12371
12715
|
// src/indexApplicationContextValidate.ts
|
|
@@ -12374,7 +12718,7 @@ function getDefaultIndexSchemaPath() {
|
|
|
12374
12718
|
return resolveIndexApplicationContextSchemaPath();
|
|
12375
12719
|
}
|
|
12376
12720
|
function getValidator(schemaPath) {
|
|
12377
|
-
const abs =
|
|
12721
|
+
const abs = path21.resolve(schemaPath);
|
|
12378
12722
|
let v = validators.get(abs);
|
|
12379
12723
|
if (!v) {
|
|
12380
12724
|
const raw = fs23.readFileSync(abs, "utf-8");
|
|
@@ -12430,7 +12774,7 @@ function tryAttachMarkdown(node, contextDir2, relativePath) {
|
|
|
12430
12774
|
if (!norm || norm.includes("..")) {
|
|
12431
12775
|
return false;
|
|
12432
12776
|
}
|
|
12433
|
-
const full =
|
|
12777
|
+
const full = path22.join(contextDir2, norm);
|
|
12434
12778
|
try {
|
|
12435
12779
|
if (!fs24.existsSync(full) || !fs24.statSync(full).isFile()) {
|
|
12436
12780
|
return false;
|
|
@@ -12488,7 +12832,7 @@ function mergePersistedIndexUploadMetadata(previous, next) {
|
|
|
12488
12832
|
walkScopes3(next, apply);
|
|
12489
12833
|
}
|
|
12490
12834
|
function tryReadExistingIndexForMerge(contextDir2) {
|
|
12491
|
-
const p =
|
|
12835
|
+
const p = path22.join(contextDir2, "index-application-context.json");
|
|
12492
12836
|
try {
|
|
12493
12837
|
if (!fs24.existsSync(p)) {
|
|
12494
12838
|
return null;
|
|
@@ -12547,7 +12891,7 @@ function applyDetailMarkdownToDocument(doc, contextDir2) {
|
|
|
12547
12891
|
}
|
|
12548
12892
|
}
|
|
12549
12893
|
}
|
|
12550
|
-
const exp = readJson2(
|
|
12894
|
+
const exp = readJson2(path22.join(contextDir2, "experiences-list.json"));
|
|
12551
12895
|
if (doc.scopes.Experience?.nodes && exp?.views) {
|
|
12552
12896
|
for (const vNode of doc.scopes.Experience.nodes) {
|
|
12553
12897
|
if (vNode.type !== "View" || !vNode.code) {
|
|
@@ -12573,7 +12917,7 @@ function applyDetailMarkdownToDocument(doc, contextDir2) {
|
|
|
12573
12917
|
}
|
|
12574
12918
|
}
|
|
12575
12919
|
}
|
|
12576
|
-
const svcData = readJson2(
|
|
12920
|
+
const svcData = readJson2(path22.join(contextDir2, "services-list.json"));
|
|
12577
12921
|
if (doc.scopes.Service?.nodes && svcData?.services) {
|
|
12578
12922
|
for (const sNode of doc.scopes.Service.nodes) {
|
|
12579
12923
|
if (sNode.type !== "Service" || !sNode.code) {
|
|
@@ -12599,7 +12943,7 @@ function applyDetailMarkdownToDocument(doc, contextDir2) {
|
|
|
12599
12943
|
}
|
|
12600
12944
|
}
|
|
12601
12945
|
}
|
|
12602
|
-
const dmData = readJson2(
|
|
12946
|
+
const dmData = readJson2(path22.join(contextDir2, "data-model-list.json"));
|
|
12603
12947
|
if (doc.scopes.DataModel?.nodes && dmData?.entities) {
|
|
12604
12948
|
for (const eNode of doc.scopes.DataModel.nodes) {
|
|
12605
12949
|
if (eNode.type !== "Entity" || !eNode.code) {
|
|
@@ -12631,7 +12975,7 @@ function applyDetailMarkdownToDocument(doc, contextDir2) {
|
|
|
12631
12975
|
}
|
|
12632
12976
|
}
|
|
12633
12977
|
}
|
|
12634
|
-
const tsData = readJson2(
|
|
12978
|
+
const tsData = readJson2(path22.join(contextDir2, "tech-stack-list.json"));
|
|
12635
12979
|
if (doc.scopes.TechStack?.nodes && tsData?.tools) {
|
|
12636
12980
|
for (const tNode of doc.scopes.TechStack.nodes) {
|
|
12637
12981
|
if (tNode.type !== "Tool" || !tNode.code) {
|
|
@@ -12655,7 +12999,7 @@ function readJson2(filePath) {
|
|
|
12655
12999
|
}
|
|
12656
13000
|
}
|
|
12657
13001
|
function safeReadFeaturesList(contextDir2) {
|
|
12658
|
-
const p =
|
|
13002
|
+
const p = path22.join(contextDir2, "features-list.json");
|
|
12659
13003
|
const data = readJson2(p);
|
|
12660
13004
|
if (!data?.features?.length) {
|
|
12661
13005
|
return null;
|
|
@@ -12663,7 +13007,7 @@ function safeReadFeaturesList(contextDir2) {
|
|
|
12663
13007
|
return data;
|
|
12664
13008
|
}
|
|
12665
13009
|
function safeReadUseCasesList(contextDir2, feCode) {
|
|
12666
|
-
const p =
|
|
13010
|
+
const p = path22.join(contextDir2, `${feCode}-use-cases-list.json`);
|
|
12667
13011
|
const data = readJson2(p);
|
|
12668
13012
|
if (!data?.useCases?.length) {
|
|
12669
13013
|
return null;
|
|
@@ -12671,7 +13015,7 @@ function safeReadUseCasesList(contextDir2, feCode) {
|
|
|
12671
13015
|
return data;
|
|
12672
13016
|
}
|
|
12673
13017
|
function scenariosListPath(contextDir2, feCode, ucCode) {
|
|
12674
|
-
return
|
|
13018
|
+
return path22.join(contextDir2, `${feCode}_${ucCode}-scenarios-list.json`);
|
|
12675
13019
|
}
|
|
12676
13020
|
function buildFeatureScope(contextDir2) {
|
|
12677
13021
|
const fl = safeReadFeaturesList(contextDir2);
|
|
@@ -12708,7 +13052,7 @@ function buildFeatureScope(contextDir2) {
|
|
|
12708
13052
|
return nodes;
|
|
12709
13053
|
}
|
|
12710
13054
|
function buildExperienceScope(contextDir2) {
|
|
12711
|
-
const data = readJson2(
|
|
13055
|
+
const data = readJson2(path22.join(contextDir2, "experiences-list.json"));
|
|
12712
13056
|
if (!data?.views?.length) {
|
|
12713
13057
|
return [];
|
|
12714
13058
|
}
|
|
@@ -12720,7 +13064,7 @@ function buildExperienceScope(contextDir2) {
|
|
|
12720
13064
|
}));
|
|
12721
13065
|
}
|
|
12722
13066
|
function buildServiceScope(contextDir2) {
|
|
12723
|
-
const data = readJson2(
|
|
13067
|
+
const data = readJson2(path22.join(contextDir2, "services-list.json"));
|
|
12724
13068
|
if (!data?.services?.length) {
|
|
12725
13069
|
return [];
|
|
12726
13070
|
}
|
|
@@ -12732,13 +13076,13 @@ function buildServiceScope(contextDir2) {
|
|
|
12732
13076
|
}));
|
|
12733
13077
|
}
|
|
12734
13078
|
function readEntityFieldsList(contextDir2, dmCode) {
|
|
12735
|
-
const p =
|
|
13079
|
+
const p = path22.join(contextDir2, `${dmCode}-fields-list.json`);
|
|
12736
13080
|
const file = readJson2(p);
|
|
12737
13081
|
const rows = Array.isArray(file?.fields) ? file.fields : [];
|
|
12738
13082
|
return rows.filter((f) => Boolean(f?.code && f?.name));
|
|
12739
13083
|
}
|
|
12740
13084
|
function buildDataModelScope(contextDir2) {
|
|
12741
|
-
const data = readJson2(
|
|
13085
|
+
const data = readJson2(path22.join(contextDir2, "data-model-list.json"));
|
|
12742
13086
|
if (!data?.entities?.length) {
|
|
12743
13087
|
return [];
|
|
12744
13088
|
}
|
|
@@ -12756,7 +13100,7 @@ function buildDataModelScope(contextDir2) {
|
|
|
12756
13100
|
});
|
|
12757
13101
|
}
|
|
12758
13102
|
function buildTechStackScope(contextDir2) {
|
|
12759
|
-
const data = readJson2(
|
|
13103
|
+
const data = readJson2(path22.join(contextDir2, "tech-stack-list.json"));
|
|
12760
13104
|
if (!data?.tools?.length) {
|
|
12761
13105
|
return [];
|
|
12762
13106
|
}
|
|
@@ -12825,7 +13169,7 @@ function writeIndexApplicationContext(contextDir2, title, options) {
|
|
|
12825
13169
|
if (!validation.ok) {
|
|
12826
13170
|
throw new Error(`index-application-context.json schema validation failed: ${validation.errors.join("; ")}`);
|
|
12827
13171
|
}
|
|
12828
|
-
const target =
|
|
13172
|
+
const target = path22.join(contextDir2, "index-application-context.json");
|
|
12829
13173
|
const tmp = `${target}.${process.pid}.tmp`;
|
|
12830
13174
|
try {
|
|
12831
13175
|
fs24.writeFileSync(tmp, JSON.stringify(doc, null, 2), "utf-8");
|
|
@@ -12837,61 +13181,74 @@ function writeIndexApplicationContext(contextDir2, title, options) {
|
|
|
12837
13181
|
}
|
|
12838
13182
|
throw e;
|
|
12839
13183
|
}
|
|
12840
|
-
return doc;
|
|
12841
|
-
}
|
|
12842
|
-
|
|
12843
|
-
// src/analysis/aceAnalysisConfig.ts
|
|
12844
|
-
var path23 = __toESM(require("node:path"));
|
|
12845
|
-
var vscode2 = __toESM(require_vscode_stub());
|
|
12846
|
-
|
|
12847
|
-
// src/easySpecsWorkspaceSettingsCore.ts
|
|
12848
|
-
var fs25 = __toESM(require("node:fs"));
|
|
12849
|
-
var path22 = __toESM(require("node:path"));
|
|
12850
|
-
var EASYSPECS_WORKSPACE_DIR = EASYSPECS_LOCAL_DIR;
|
|
12851
|
-
var EASYSPECS_SETTINGS_JSON = "settings.json";
|
|
12852
|
-
var EASYSPECS_SETTINGS_ACE_KEY = "easyspecs.analysis.ace.enabled";
|
|
12853
|
-
var EASYSPECS_SETTINGS_ACE_OFFLINE_AFTER_TRACE_KEY = "easyspecs.analysis.ace.offlineLearnAfterSameSessionTrace";
|
|
12854
|
-
function isRecord3(v) {
|
|
12855
|
-
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
13184
|
+
return doc;
|
|
12856
13185
|
}
|
|
12857
|
-
|
|
12858
|
-
|
|
13186
|
+
|
|
13187
|
+
// src/analysis/aceAnalysisConfig.ts
|
|
13188
|
+
var path23 = __toESM(require("node:path"));
|
|
13189
|
+
var vscode2 = __toESM(require_vscode_stub());
|
|
13190
|
+
|
|
13191
|
+
// src/config/easyspecsAceConfigRead.ts
|
|
13192
|
+
var fs25 = __toESM(require("node:fs"));
|
|
13193
|
+
function readRawConfigJson(repoRoot) {
|
|
13194
|
+
const p = easyspecsConfigPath(repoRoot);
|
|
13195
|
+
if (!fs25.existsSync(p)) {
|
|
13196
|
+
return void 0;
|
|
13197
|
+
}
|
|
12859
13198
|
let raw;
|
|
12860
13199
|
try {
|
|
12861
|
-
raw = fs25.readFileSync(
|
|
13200
|
+
raw = fs25.readFileSync(p, "utf8");
|
|
12862
13201
|
} catch {
|
|
12863
13202
|
return void 0;
|
|
12864
13203
|
}
|
|
12865
|
-
let parsed;
|
|
12866
13204
|
try {
|
|
12867
|
-
parsed = JSON.parse(raw);
|
|
13205
|
+
const parsed = JSON.parse(raw);
|
|
13206
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
13207
|
+
return void 0;
|
|
13208
|
+
}
|
|
13209
|
+
return parsed;
|
|
12868
13210
|
} catch {
|
|
12869
13211
|
return void 0;
|
|
12870
13212
|
}
|
|
12871
|
-
|
|
13213
|
+
}
|
|
13214
|
+
function readAceEnabledFromEasyspecsConfigFile(repoRoot) {
|
|
13215
|
+
const parsed = readRawConfigJson(repoRoot);
|
|
13216
|
+
const es = parsed?.easyspecs;
|
|
13217
|
+
if (!es || typeof es !== "object" || Array.isArray(es)) {
|
|
13218
|
+
return void 0;
|
|
13219
|
+
}
|
|
13220
|
+
const analysis = es.analysis;
|
|
13221
|
+
if (!analysis || typeof analysis !== "object" || Array.isArray(analysis)) {
|
|
12872
13222
|
return void 0;
|
|
12873
13223
|
}
|
|
12874
|
-
const
|
|
13224
|
+
const ace = analysis.ace;
|
|
13225
|
+
if (!ace || typeof ace !== "object" || Array.isArray(ace)) {
|
|
13226
|
+
return void 0;
|
|
13227
|
+
}
|
|
13228
|
+
if (!Object.prototype.hasOwnProperty.call(ace, "enabled")) {
|
|
13229
|
+
return void 0;
|
|
13230
|
+
}
|
|
13231
|
+
const v = ace.enabled;
|
|
12875
13232
|
return typeof v === "boolean" ? v : void 0;
|
|
12876
13233
|
}
|
|
12877
|
-
function
|
|
12878
|
-
const
|
|
12879
|
-
|
|
12880
|
-
|
|
12881
|
-
raw = fs25.readFileSync(filePath, "utf8");
|
|
12882
|
-
} catch {
|
|
13234
|
+
function readAceOfflineLearnAfterSameSessionTraceFromEasyspecsConfigFile(repoRoot) {
|
|
13235
|
+
const parsed = readRawConfigJson(repoRoot);
|
|
13236
|
+
const es = parsed?.easyspecs;
|
|
13237
|
+
if (!es || typeof es !== "object" || Array.isArray(es)) {
|
|
12883
13238
|
return void 0;
|
|
12884
13239
|
}
|
|
12885
|
-
|
|
12886
|
-
|
|
12887
|
-
parsed = JSON.parse(raw);
|
|
12888
|
-
} catch {
|
|
13240
|
+
const analysis = es.analysis;
|
|
13241
|
+
if (!analysis || typeof analysis !== "object" || Array.isArray(analysis)) {
|
|
12889
13242
|
return void 0;
|
|
12890
13243
|
}
|
|
12891
|
-
|
|
13244
|
+
const ace = analysis.ace;
|
|
13245
|
+
if (!ace || typeof ace !== "object" || Array.isArray(ace)) {
|
|
12892
13246
|
return void 0;
|
|
12893
13247
|
}
|
|
12894
|
-
|
|
13248
|
+
if (!Object.prototype.hasOwnProperty.call(ace, "offlineLearnAfterSameSessionTrace")) {
|
|
13249
|
+
return void 0;
|
|
13250
|
+
}
|
|
13251
|
+
const v = ace.offlineLearnAfterSameSessionTrace;
|
|
12895
13252
|
return typeof v === "boolean" ? v : void 0;
|
|
12896
13253
|
}
|
|
12897
13254
|
|
|
@@ -12927,9 +13284,13 @@ function getAceAnalysisEnabledForCheckout(analysisCheckoutRoot) {
|
|
|
12927
13284
|
push(cliWorkspaceRootOverride);
|
|
12928
13285
|
push(vscode2.workspace.workspaceFolders?.[0]?.uri.fsPath);
|
|
12929
13286
|
for (const root of roots) {
|
|
12930
|
-
const
|
|
12931
|
-
if (
|
|
12932
|
-
return
|
|
13287
|
+
const fromConfig = readAceEnabledFromEasyspecsConfigFile(root);
|
|
13288
|
+
if (fromConfig !== void 0) {
|
|
13289
|
+
return fromConfig;
|
|
13290
|
+
}
|
|
13291
|
+
const fromLegacy = readAceEnabledFromEasySpecsSettingsFile(root);
|
|
13292
|
+
if (fromLegacy !== void 0) {
|
|
13293
|
+
return fromLegacy;
|
|
12933
13294
|
}
|
|
12934
13295
|
}
|
|
12935
13296
|
if (cliHeadlessMode) {
|
|
@@ -12956,9 +13317,13 @@ function getAceOfflineLearnAfterSameSessionTrace(analysisCheckoutRoot) {
|
|
|
12956
13317
|
push(cliWorkspaceRootOverride);
|
|
12957
13318
|
push(vscode2.workspace.workspaceFolders?.[0]?.uri.fsPath);
|
|
12958
13319
|
for (const root of roots) {
|
|
12959
|
-
const
|
|
12960
|
-
if (
|
|
12961
|
-
return
|
|
13320
|
+
const fromConfig = readAceOfflineLearnAfterSameSessionTraceFromEasyspecsConfigFile(root);
|
|
13321
|
+
if (fromConfig !== void 0) {
|
|
13322
|
+
return fromConfig;
|
|
13323
|
+
}
|
|
13324
|
+
const fromLegacy = readAceOfflineLearnAfterSameSessionTraceFromEasySpecsSettingsFile(root);
|
|
13325
|
+
if (fromLegacy !== void 0) {
|
|
13326
|
+
return fromLegacy;
|
|
12962
13327
|
}
|
|
12963
13328
|
}
|
|
12964
13329
|
if (cliHeadlessMode) {
|
|
@@ -13115,91 +13480,91 @@ function mdItem(id, parentIds, t) {
|
|
|
13115
13480
|
};
|
|
13116
13481
|
}
|
|
13117
13482
|
function featureDetailTarget(contextDir2, code, name, slug) {
|
|
13118
|
-
const
|
|
13483
|
+
const basename12 = `${code}-${slug}.md`;
|
|
13119
13484
|
return {
|
|
13120
13485
|
openCodeAgentStem: "agent-md-feature-detail",
|
|
13121
13486
|
agentId: "ctx-md-feature-detail",
|
|
13122
13487
|
displayName: "Feature detail",
|
|
13123
|
-
outputBasename:
|
|
13488
|
+
outputBasename: basename12,
|
|
13124
13489
|
taskDescription: `Document feature **${code}** (**${name}**, slug **${slug}**) per \`.gluecharm/context/features-list.json\`: scope, behaviour, main dependencies, entry points, and links to code under the worktree. Write exactly one markdown file at the output path; cite substantive claims with file and line (or range).`,
|
|
13125
|
-
exists: fs27.existsSync(path25.join(contextDir2,
|
|
13490
|
+
exists: fs27.existsSync(path25.join(contextDir2, basename12)) && fs27.statSync(path25.join(contextDir2, basename12)).size > 0
|
|
13126
13491
|
};
|
|
13127
13492
|
}
|
|
13128
13493
|
function viewDetailTarget(row2, contextDir2) {
|
|
13129
|
-
const
|
|
13494
|
+
const basename12 = `${row2.code}-${row2.slug}.md`;
|
|
13130
13495
|
return {
|
|
13131
13496
|
openCodeAgentStem: "agent-md-view-detail",
|
|
13132
13497
|
agentId: "ctx-md-view-detail",
|
|
13133
13498
|
displayName: "View detail",
|
|
13134
|
-
outputBasename:
|
|
13499
|
+
outputBasename: basename12,
|
|
13135
13500
|
taskDescription: `Describe view **${row2.code}** (**${row2.name}**, slug **${row2.slug}**) per \`.gluecharm/context/experiences-list.json\`: purpose, layout, controls, navigation, data shown; ground in components and routes.`,
|
|
13136
|
-
exists: fs27.existsSync(path25.join(contextDir2,
|
|
13501
|
+
exists: fs27.existsSync(path25.join(contextDir2, basename12)) && fs27.statSync(path25.join(contextDir2, basename12)).size > 0
|
|
13137
13502
|
};
|
|
13138
13503
|
}
|
|
13139
13504
|
function interactionDetailTarget(viewCode, ix, contextDir2) {
|
|
13140
|
-
const
|
|
13505
|
+
const basename12 = `${viewCode}_${ix.code}-${ix.slug}.md`;
|
|
13141
13506
|
return {
|
|
13142
13507
|
openCodeAgentStem: "agent-md-interaction-detail",
|
|
13143
13508
|
agentId: "ctx-md-interaction-detail",
|
|
13144
13509
|
displayName: "Interaction detail",
|
|
13145
|
-
outputBasename:
|
|
13510
|
+
outputBasename: basename12,
|
|
13146
13511
|
taskDescription: `Document interaction **${ix.code}** (**${ix.name}**) on view **${viewCode}** per \`.gluecharm/context/experiences-list.json\`.`,
|
|
13147
|
-
exists: fs27.existsSync(path25.join(contextDir2,
|
|
13512
|
+
exists: fs27.existsSync(path25.join(contextDir2, basename12)) && fs27.statSync(path25.join(contextDir2, basename12)).size > 0
|
|
13148
13513
|
};
|
|
13149
13514
|
}
|
|
13150
13515
|
function serviceDetailTarget(row2, contextDir2) {
|
|
13151
|
-
const
|
|
13516
|
+
const basename12 = `${row2.code}-${row2.slug}.md`;
|
|
13152
13517
|
return {
|
|
13153
13518
|
openCodeAgentStem: "agent-md-service-detail",
|
|
13154
13519
|
agentId: "ctx-md-service-detail",
|
|
13155
13520
|
displayName: "Service detail",
|
|
13156
|
-
outputBasename:
|
|
13521
|
+
outputBasename: basename12,
|
|
13157
13522
|
taskDescription: `Describe service **${row2.code}** (**${row2.name}**, slug **${row2.slug}**) per \`.gluecharm/context/services-list.json\`: responsibilities, consumers, errors, integration points.`,
|
|
13158
|
-
exists: fs27.existsSync(path25.join(contextDir2,
|
|
13523
|
+
exists: fs27.existsSync(path25.join(contextDir2, basename12)) && fs27.statSync(path25.join(contextDir2, basename12)).size > 0
|
|
13159
13524
|
};
|
|
13160
13525
|
}
|
|
13161
13526
|
function methodDetailTarget(svc, m, contextDir2) {
|
|
13162
|
-
const
|
|
13527
|
+
const basename12 = `${svc.code}_${m.code}-${m.slug}.md`;
|
|
13163
13528
|
return {
|
|
13164
13529
|
openCodeAgentStem: "agent-md-method-detail",
|
|
13165
13530
|
agentId: "ctx-md-method-detail",
|
|
13166
13531
|
displayName: "Method detail",
|
|
13167
|
-
outputBasename:
|
|
13532
|
+
outputBasename: basename12,
|
|
13168
13533
|
taskDescription: `Document method **${m.code}** (**${m.name}**) on service **${svc.code}** per \`.gluecharm/context/services-list.json\`.`,
|
|
13169
|
-
exists: fs27.existsSync(path25.join(contextDir2,
|
|
13534
|
+
exists: fs27.existsSync(path25.join(contextDir2, basename12)) && fs27.statSync(path25.join(contextDir2, basename12)).size > 0
|
|
13170
13535
|
};
|
|
13171
13536
|
}
|
|
13172
13537
|
function entityDetailTarget(dmCode, ename, slug, contextDir2) {
|
|
13173
|
-
const
|
|
13538
|
+
const basename12 = `${dmCode}-${slug}.md`;
|
|
13174
13539
|
return {
|
|
13175
13540
|
openCodeAgentStem: "agent-md-entity-detail",
|
|
13176
13541
|
agentId: "ctx-md-entity-detail",
|
|
13177
13542
|
displayName: "Entity detail",
|
|
13178
|
-
outputBasename:
|
|
13543
|
+
outputBasename: basename12,
|
|
13179
13544
|
taskDescription: `Describe entity **${dmCode}** (**${ename}**, slug **${slug}**) per \`.gluecharm/context/data-model-list.json\`: lifecycle, invariants, storage, ORM/schema mapping.`,
|
|
13180
|
-
exists: fs27.existsSync(path25.join(contextDir2,
|
|
13545
|
+
exists: fs27.existsSync(path25.join(contextDir2, basename12)) && fs27.statSync(path25.join(contextDir2, basename12)).size > 0
|
|
13181
13546
|
};
|
|
13182
13547
|
}
|
|
13183
13548
|
function fieldDetailTarget(dmCode, fdCode, fname, fSlug, contextDir2) {
|
|
13184
|
-
const
|
|
13549
|
+
const basename12 = `${dmCode}_${fdCode}-${fSlug}.md`;
|
|
13185
13550
|
return {
|
|
13186
13551
|
openCodeAgentStem: "agent-md-field-detail",
|
|
13187
13552
|
agentId: "ctx-md-field-detail",
|
|
13188
13553
|
displayName: "Field detail",
|
|
13189
|
-
outputBasename:
|
|
13554
|
+
outputBasename: basename12,
|
|
13190
13555
|
taskDescription: `Document field **${fdCode}** (**${fname}**) on entity **${dmCode}** per \`.gluecharm/context/${dmCode}-fields-list.json\`. Cite types and constraints with file and line.`,
|
|
13191
|
-
exists: fs27.existsSync(path25.join(contextDir2,
|
|
13556
|
+
exists: fs27.existsSync(path25.join(contextDir2, basename12)) && fs27.statSync(path25.join(contextDir2, basename12)).size > 0
|
|
13192
13557
|
};
|
|
13193
13558
|
}
|
|
13194
13559
|
function toolDetailTarget(row2, contextDir2) {
|
|
13195
|
-
const
|
|
13560
|
+
const basename12 = `${row2.code}-${row2.slug}.md`;
|
|
13196
13561
|
return {
|
|
13197
13562
|
openCodeAgentStem: "agent-md-tool-detail",
|
|
13198
13563
|
agentId: "ctx-md-tool-detail",
|
|
13199
13564
|
displayName: "Tool detail",
|
|
13200
|
-
outputBasename:
|
|
13565
|
+
outputBasename: basename12,
|
|
13201
13566
|
taskDescription: `Describe tool **${row2.code}** (**${row2.name}**, slug **${row2.slug}**) per \`.gluecharm/context/tech-stack-list.json\`: role, version hints, configuration, boundaries.`,
|
|
13202
|
-
exists: fs27.existsSync(path25.join(contextDir2,
|
|
13567
|
+
exists: fs27.existsSync(path25.join(contextDir2, basename12)) && fs27.statSync(path25.join(contextDir2, basename12)).size > 0
|
|
13203
13568
|
};
|
|
13204
13569
|
}
|
|
13205
13570
|
function useCaseDetailTarget(feCode, ucCode, ucName, ucSlug, contextDir2) {
|
|
@@ -13216,14 +13581,14 @@ Follow bundled agent **agent-md-use-case-detail**: include **## Data inputs and
|
|
|
13216
13581
|
};
|
|
13217
13582
|
}
|
|
13218
13583
|
function scenarioDetailTarget(feCode, ucCode, scCode, scName, contextDir2) {
|
|
13219
|
-
const
|
|
13584
|
+
const basename12 = `${feCode}_${ucCode}_${scCode}.md`;
|
|
13220
13585
|
return {
|
|
13221
13586
|
openCodeAgentStem: "agent-md-scenario-detail",
|
|
13222
13587
|
agentId: "ctx-md-scenario-detail",
|
|
13223
13588
|
displayName: "Scenario detail",
|
|
13224
|
-
outputBasename:
|
|
13589
|
+
outputBasename: basename12,
|
|
13225
13590
|
taskDescription: `Document scenario **${scCode}** (**${scName}**) for **${feCode}** / **${ucCode}** per \`.gluecharm/context/${feCode}_${ucCode}-scenarios-list.json\`. Cite steps with file and line where possible.`,
|
|
13226
|
-
exists: fs27.existsSync(path25.join(contextDir2,
|
|
13591
|
+
exists: fs27.existsSync(path25.join(contextDir2, basename12)) && fs27.statSync(path25.join(contextDir2, basename12)).size > 0
|
|
13227
13592
|
};
|
|
13228
13593
|
}
|
|
13229
13594
|
function parentsDone(item, byId) {
|
|
@@ -13449,15 +13814,15 @@ function expandAfterSuccess(completed, contextDir2, byId, fifo) {
|
|
|
13449
13814
|
return;
|
|
13450
13815
|
}
|
|
13451
13816
|
if (completed.kind === "markdown") {
|
|
13452
|
-
const
|
|
13817
|
+
const basename12 = completed.payload.outputBasename;
|
|
13453
13818
|
const mdId = completed.id;
|
|
13454
|
-
const feFromFeatureMd =
|
|
13819
|
+
const feFromFeatureMd = basename12.match(/^(FE-\d+)-[^/]+\.md$/);
|
|
13455
13820
|
if (feFromFeatureMd) {
|
|
13456
13821
|
const fe = feFromFeatureMd[1];
|
|
13457
13822
|
add(coordItem(`coord:uc:${fe}`, [mdId], "listUseCases", { featureCode: fe }));
|
|
13458
13823
|
return;
|
|
13459
13824
|
}
|
|
13460
|
-
const xpFromView =
|
|
13825
|
+
const xpFromView = basename12.match(/^(XP-\d+)-[^/]+\.md$/);
|
|
13461
13826
|
if (xpFromView) {
|
|
13462
13827
|
const xp = xpFromView[1];
|
|
13463
13828
|
const row2 = discoverExperienceTreeRows(contextDir2).find((r) => r.code === xp);
|
|
@@ -13469,7 +13834,7 @@ function expandAfterSuccess(completed, contextDir2, byId, fifo) {
|
|
|
13469
13834
|
}
|
|
13470
13835
|
return;
|
|
13471
13836
|
}
|
|
13472
|
-
const svFromSvc =
|
|
13837
|
+
const svFromSvc = basename12.match(/^(SV-\d+)-[^/]+\.md$/);
|
|
13473
13838
|
if (svFromSvc) {
|
|
13474
13839
|
const sv = svFromSvc[1];
|
|
13475
13840
|
const srow = discoverServiceTreeRows(contextDir2).find((r) => r.code === sv);
|
|
@@ -13481,7 +13846,7 @@ function expandAfterSuccess(completed, contextDir2, byId, fifo) {
|
|
|
13481
13846
|
}
|
|
13482
13847
|
return;
|
|
13483
13848
|
}
|
|
13484
|
-
const dmFromEnt =
|
|
13849
|
+
const dmFromEnt = basename12.match(/^(DM-\d+)-[^/]+\.md$/);
|
|
13485
13850
|
if (dmFromEnt) {
|
|
13486
13851
|
const dm = dmFromEnt[1];
|
|
13487
13852
|
add(coordItem(`coord:ef:${dm}`, [mdId], "listEntityFields", { entityCode: dm }));
|
|
@@ -13520,7 +13885,8 @@ async function runArtefactWorkItemOpenCode(item, worktreeRoot, workspaceLabel, o
|
|
|
13520
13885
|
artefactRunId,
|
|
13521
13886
|
artefactWorkItemId: item.id,
|
|
13522
13887
|
aceEnabled: oc.aceEnabled === true,
|
|
13523
|
-
offlineLearnAfterSameSessionTrace: oc.offlineLearnAfterSameSessionTrace === true
|
|
13888
|
+
offlineLearnAfterSameSessionTrace: oc.offlineLearnAfterSameSessionTrace === true,
|
|
13889
|
+
openCodeChildEnv: oc.openCodeChildEnv
|
|
13524
13890
|
};
|
|
13525
13891
|
if (item.kind === "coord") {
|
|
13526
13892
|
const { step, listTarget } = item.payload;
|
|
@@ -13577,6 +13943,7 @@ async function runArtefactWorkItemOpenCode(item, worktreeRoot, workspaceLabel, o
|
|
|
13577
13943
|
artefactWorkItemId: item.id,
|
|
13578
13944
|
aceEnabled: oc.aceEnabled === true,
|
|
13579
13945
|
offlineLearnAfterSameSessionTrace: oc.offlineLearnAfterSameSessionTrace === true,
|
|
13946
|
+
openCodeChildEnv: oc.openCodeChildEnv,
|
|
13580
13947
|
target: {
|
|
13581
13948
|
openCodeAgentStem: p.openCodeAgentStem,
|
|
13582
13949
|
agentId: p.agentId,
|
|
@@ -13645,8 +14012,8 @@ async function drainArtefactWorkPool(p) {
|
|
|
13645
14012
|
const artefactRunId = readArtefactRunSnapshot(storageContext)?.runId ?? "unknown-run";
|
|
13646
14013
|
let active = 0;
|
|
13647
14014
|
let wake;
|
|
13648
|
-
const waitTurn = () => new Promise((
|
|
13649
|
-
wake =
|
|
14015
|
+
const waitTurn = () => new Promise((resolve15) => {
|
|
14016
|
+
wake = resolve15;
|
|
13650
14017
|
});
|
|
13651
14018
|
const persist = async () => {
|
|
13652
14019
|
const items = {};
|
|
@@ -13886,7 +14253,8 @@ async function runContextArtefactPipelineAsync(storageContext, repoRoot, workspa
|
|
|
13886
14253
|
try {
|
|
13887
14254
|
materializeOpenCodeAgentsWithAce(extensionAgentsDirFs, handle.path, {
|
|
13888
14255
|
enabled: aceEnabled,
|
|
13889
|
-
diagnosticLog: log
|
|
14256
|
+
diagnosticLog: log,
|
|
14257
|
+
projectConfigOverlay: oc.projectConfigOverlay
|
|
13890
14258
|
});
|
|
13891
14259
|
} catch (e) {
|
|
13892
14260
|
const msg = e instanceof Error ? e.message : String(e);
|
|
@@ -13973,7 +14341,7 @@ function macroSleep(ms, signal) {
|
|
|
13973
14341
|
if (signal.aborted) {
|
|
13974
14342
|
return Promise.reject(new DOMException("The operation was aborted.", "AbortError"));
|
|
13975
14343
|
}
|
|
13976
|
-
return new Promise((
|
|
14344
|
+
return new Promise((resolve15, reject) => {
|
|
13977
14345
|
const onAbort = () => {
|
|
13978
14346
|
clearTimeout(t);
|
|
13979
14347
|
signal.removeEventListener("abort", onAbort);
|
|
@@ -13981,7 +14349,7 @@ function macroSleep(ms, signal) {
|
|
|
13981
14349
|
};
|
|
13982
14350
|
const t = setTimeout(() => {
|
|
13983
14351
|
signal.removeEventListener("abort", onAbort);
|
|
13984
|
-
|
|
14352
|
+
resolve15();
|
|
13985
14353
|
}, ms);
|
|
13986
14354
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
13987
14355
|
});
|
|
@@ -14174,7 +14542,7 @@ async function runMacroAnalysisOrchestration(deps) {
|
|
|
14174
14542
|
setRowTimed("synthesis_convergence", "succeeded", "No missing artefacts.");
|
|
14175
14543
|
await post();
|
|
14176
14544
|
if (config.synthesisOnly) {
|
|
14177
|
-
return { ok: true, message: "Synthesis-only
|
|
14545
|
+
return { ok: true, message: "Synthesis-only analysis complete.", totalElapsedMs: macroEnd() };
|
|
14178
14546
|
}
|
|
14179
14547
|
if (isAborted(signal)) {
|
|
14180
14548
|
setRowTimed("reference_coverage", "cancelled");
|
|
@@ -14341,7 +14709,7 @@ async function runMacroAnalysisOrchestration(deps) {
|
|
|
14341
14709
|
}
|
|
14342
14710
|
setRowTimed("backend_context_sync", "succeeded", up.message);
|
|
14343
14711
|
await post();
|
|
14344
|
-
return { ok: true, message: "
|
|
14712
|
+
return { ok: true, message: "Analysis complete.", totalElapsedMs: macroEnd() };
|
|
14345
14713
|
} catch (e) {
|
|
14346
14714
|
const msg = e instanceof Error ? e.message : String(e);
|
|
14347
14715
|
return fail(msg);
|
|
@@ -14516,8 +14884,8 @@ function expectedFeatureDetailBasenameFromRow(row2) {
|
|
|
14516
14884
|
}
|
|
14517
14885
|
return `${code}-${slug}.md`;
|
|
14518
14886
|
}
|
|
14519
|
-
function ctxPath(contextDir2,
|
|
14520
|
-
return path27.join(contextDir2,
|
|
14887
|
+
function ctxPath(contextDir2, basename12) {
|
|
14888
|
+
return path27.join(contextDir2, basename12);
|
|
14521
14889
|
}
|
|
14522
14890
|
function pushTarget(targets, stem, outputBasename, taskDescription, contextDir2) {
|
|
14523
14891
|
const meta = STEM_TO_AGENT[stem];
|
|
@@ -14546,11 +14914,11 @@ function discoverDetailMarkdownGroups(contextDir2) {
|
|
|
14546
14914
|
continue;
|
|
14547
14915
|
}
|
|
14548
14916
|
const name = safeStr3(row2.name) || code;
|
|
14549
|
-
const
|
|
14917
|
+
const basename12 = `${code}-${slug}.md`;
|
|
14550
14918
|
pushTarget(
|
|
14551
14919
|
featureTargets,
|
|
14552
14920
|
"agent-md-feature-detail",
|
|
14553
|
-
|
|
14921
|
+
basename12,
|
|
14554
14922
|
`Document feature **${code}** (**${name}**, slug **${slug}**) per \`.gluecharm/context/features-list.json\`: scope, behaviour, main dependencies, entry points, and links to code under the worktree. Write exactly one markdown file at the output path; cite substantive claims with file and line (or range).`,
|
|
14555
14923
|
contextDir2
|
|
14556
14924
|
);
|
|
@@ -15738,8 +16106,8 @@ function formatAjvErrors5(errors) {
|
|
|
15738
16106
|
});
|
|
15739
16107
|
}
|
|
15740
16108
|
var ajv = new import__5.default({ allErrors: true, strict: false });
|
|
15741
|
-
function compileSchema(
|
|
15742
|
-
const schemaPath = path32.join(schemasDir(),
|
|
16109
|
+
function compileSchema(basename12) {
|
|
16110
|
+
const schemaPath = path32.join(schemasDir(), basename12);
|
|
15743
16111
|
const schemaRaw = stripUtf8Bom5(fs33.readFileSync(schemaPath, "utf-8"));
|
|
15744
16112
|
const schema = JSON.parse(schemaRaw);
|
|
15745
16113
|
return ajv.compile(schema);
|
|
@@ -16346,7 +16714,8 @@ async function runClassifierAgent(common, contextDirAbs, targetFilePathPosix, wo
|
|
|
16346
16714
|
executable: common.executable,
|
|
16347
16715
|
diagnosticLog: common.diagnosticLog,
|
|
16348
16716
|
onAgentLaunched: common.onAgentLaunched,
|
|
16349
|
-
signal: common.abortSignal
|
|
16717
|
+
signal: common.abortSignal,
|
|
16718
|
+
...common.openCodeChildEnv ? { childEnv: common.openCodeChildEnv } : {}
|
|
16350
16719
|
});
|
|
16351
16720
|
if (cli.cancelled || common.abortSignal?.aborted) {
|
|
16352
16721
|
return { ok: false, message: "Stopped.", stagingPath: outAbs, cancelled: true };
|
|
@@ -16492,7 +16861,8 @@ async function runMarkdownReferenceAgent(common, contextDirAbs, targetFilePathPo
|
|
|
16492
16861
|
executable: common.executable,
|
|
16493
16862
|
diagnosticLog: common.diagnosticLog,
|
|
16494
16863
|
onAgentLaunched: common.onAgentLaunched,
|
|
16495
|
-
signal: common.abortSignal
|
|
16864
|
+
signal: common.abortSignal,
|
|
16865
|
+
...common.openCodeChildEnv ? { childEnv: common.openCodeChildEnv } : {}
|
|
16496
16866
|
});
|
|
16497
16867
|
if (cli.cancelled || common.abortSignal?.aborted) {
|
|
16498
16868
|
return { ok: false, message: "Stopped.", cancelled: true };
|
|
@@ -16553,7 +16923,8 @@ async function runCoordinationTriageAgent(common, contextDirAbs, targetFilePathP
|
|
|
16553
16923
|
executable: common.executable,
|
|
16554
16924
|
diagnosticLog: common.diagnosticLog,
|
|
16555
16925
|
onAgentLaunched: common.onAgentLaunched,
|
|
16556
|
-
signal: common.abortSignal
|
|
16926
|
+
signal: common.abortSignal,
|
|
16927
|
+
...common.openCodeChildEnv ? { childEnv: common.openCodeChildEnv } : {}
|
|
16557
16928
|
});
|
|
16558
16929
|
if (cli.cancelled || common.abortSignal?.aborted) {
|
|
16559
16930
|
return { ok: false, message: "Stopped.", stagingPath: outAbs, cancelled: true };
|
|
@@ -17286,7 +17657,6 @@ function loadSrsDiscoveryIdMapFromContextDir(contextDir2, log) {
|
|
|
17286
17657
|
}
|
|
17287
17658
|
|
|
17288
17659
|
// src/analysis/contextSrsDiscoveryUpload.ts
|
|
17289
|
-
var UPLOAD_TARGET_FILENAME = "easyspecs-upload-target.json";
|
|
17290
17660
|
var ADAPTIVE_B_INITIAL = 100;
|
|
17291
17661
|
var ADAPTIVE_B_MIN = 1;
|
|
17292
17662
|
var ADAPTIVE_B_MAX = 500;
|
|
@@ -17416,31 +17786,9 @@ function listContextFilesForUpload(contextDir2, excludeBasenames = /* @__PURE__
|
|
|
17416
17786
|
out.sort((a, b) => a.localeCompare(b));
|
|
17417
17787
|
return out;
|
|
17418
17788
|
}
|
|
17419
|
-
function
|
|
17420
|
-
const
|
|
17421
|
-
|
|
17422
|
-
return void 0;
|
|
17423
|
-
}
|
|
17424
|
-
try {
|
|
17425
|
-
const raw = fs38.readFileSync(p, "utf8");
|
|
17426
|
-
const j = JSON.parse(raw);
|
|
17427
|
-
if (!isRecord5(j)) {
|
|
17428
|
-
return void 0;
|
|
17429
|
-
}
|
|
17430
|
-
const aid = j.application_id;
|
|
17431
|
-
const upd = j.updated_at;
|
|
17432
|
-
if (typeof aid !== "string" || aid.trim() === "" || typeof upd !== "string") {
|
|
17433
|
-
return void 0;
|
|
17434
|
-
}
|
|
17435
|
-
const name = j.application_name;
|
|
17436
|
-
return {
|
|
17437
|
-
application_id: aid.trim(),
|
|
17438
|
-
updated_at: upd,
|
|
17439
|
-
...typeof name === "string" && name ? { application_name: name } : {}
|
|
17440
|
-
};
|
|
17441
|
-
} catch {
|
|
17442
|
-
return void 0;
|
|
17443
|
-
}
|
|
17789
|
+
function getEasyspecsProjectIdFromRepoConfig(repoConfig) {
|
|
17790
|
+
const id = repoConfig.easyspecs?.easyspecsProjectId?.trim();
|
|
17791
|
+
return id || void 0;
|
|
17444
17792
|
}
|
|
17445
17793
|
async function validateApplicationExists(requestJson, applicationId) {
|
|
17446
17794
|
const p = `/api/content/application/${encodeURIComponent(applicationId)}`;
|
|
@@ -17596,18 +17944,18 @@ async function runParallelSinglesIntoAccum(requestJson, applicationId, paths, on
|
|
|
17596
17944
|
const recentWaveMs = [];
|
|
17597
17945
|
let idx = 0;
|
|
17598
17946
|
const runOne = async (absPath) => {
|
|
17599
|
-
const
|
|
17947
|
+
const basename12 = path37.basename(absPath);
|
|
17600
17948
|
let content;
|
|
17601
17949
|
try {
|
|
17602
17950
|
content = fs38.readFileSync(absPath, "utf8");
|
|
17603
17951
|
} catch (e) {
|
|
17604
17952
|
const msg = errorMessage(e);
|
|
17605
|
-
logSrs13Failure(log, `read file file=${
|
|
17953
|
+
logSrs13Failure(log, `read file file=${basename12}`, msg);
|
|
17606
17954
|
accum.failed.push({ path: absPath, message: msg });
|
|
17607
17955
|
return;
|
|
17608
17956
|
}
|
|
17609
17957
|
const existingId = resolveExistingId(absPath);
|
|
17610
|
-
const payload = buildSrsDiscoverySavePayload(applicationId,
|
|
17958
|
+
const payload = buildSrsDiscoverySavePayload(applicationId, basename12, content, existingId);
|
|
17611
17959
|
try {
|
|
17612
17960
|
await postSingleCreate(requestJson, payload, log);
|
|
17613
17961
|
accum.succeeded.push(absPath);
|
|
@@ -17621,7 +17969,7 @@ async function runParallelSinglesIntoAccum(requestJson, applicationId, paths, on
|
|
|
17621
17969
|
throw e;
|
|
17622
17970
|
}
|
|
17623
17971
|
const msg = errorMessage(e);
|
|
17624
|
-
logSrs13Failure(log, `POST /api/content/srs_discovery file=${
|
|
17972
|
+
logSrs13Failure(log, `POST /api/content/srs_discovery file=${basename12}`, msg);
|
|
17625
17973
|
accum.failed.push({ path: absPath, message: msg });
|
|
17626
17974
|
}
|
|
17627
17975
|
};
|
|
@@ -17703,18 +18051,18 @@ async function executeContextSrsDiscoveryUploadPhase(filePaths, phaseOpts, accum
|
|
|
17703
18051
|
const items = [];
|
|
17704
18052
|
const chunkPaths = [];
|
|
17705
18053
|
for (const absPath of chunk) {
|
|
17706
|
-
const
|
|
18054
|
+
const basename12 = path37.basename(absPath);
|
|
17707
18055
|
let content;
|
|
17708
18056
|
try {
|
|
17709
18057
|
content = fs38.readFileSync(absPath, "utf8");
|
|
17710
18058
|
} catch (e) {
|
|
17711
18059
|
const msg = errorMessage(e);
|
|
17712
|
-
logSrs13Failure(log, `read file file=${
|
|
18060
|
+
logSrs13Failure(log, `read file file=${basename12}`, msg);
|
|
17713
18061
|
accum.failed.push({ path: absPath, message: msg });
|
|
17714
18062
|
continue;
|
|
17715
18063
|
}
|
|
17716
18064
|
const existingId = resolveExistingId(absPath);
|
|
17717
|
-
items.push(buildSrsDiscoverySavePayloadForBatch(applicationId,
|
|
18065
|
+
items.push(buildSrsDiscoverySavePayloadForBatch(applicationId, basename12, content, existingId));
|
|
17718
18066
|
chunkPaths.push(absPath);
|
|
17719
18067
|
}
|
|
17720
18068
|
if (items.length === 0) {
|
|
@@ -18164,16 +18512,19 @@ function buildMacroOrchestrationDepsHeadless(input) {
|
|
|
18164
18512
|
if (input.runBackendSyncImpl) {
|
|
18165
18513
|
return input.runBackendSyncImpl();
|
|
18166
18514
|
}
|
|
18167
|
-
const wsContextDir = path38.join(repoRoot, ".gluecharm", "context");
|
|
18168
18515
|
const snap = readAnalysisWorkspaceSnapshot(storageContext);
|
|
18169
18516
|
const wtContextDir = snap?.adHocWorktreePath && fs39.existsSync(path38.join(snap.adHocWorktreePath, ".gluecharm", "context")) ? path38.join(snap.adHocWorktreePath, ".gluecharm", "context") : "";
|
|
18170
18517
|
if (!wtContextDir) {
|
|
18171
18518
|
return { ok: false, message: "No worktree context to upload." };
|
|
18172
18519
|
}
|
|
18173
|
-
|
|
18174
|
-
|
|
18520
|
+
let applicationId;
|
|
18521
|
+
try {
|
|
18522
|
+
applicationId = getEasyspecsProjectIdFromRepoConfig(readEasyspecsConfig(repoRoot))?.trim();
|
|
18523
|
+
} catch {
|
|
18524
|
+
applicationId = void 0;
|
|
18525
|
+
}
|
|
18175
18526
|
if (!applicationId) {
|
|
18176
|
-
return { ok: false, message: "Missing easyspecs
|
|
18527
|
+
return { ok: false, message: "Missing easyspecs.easyspecsProjectId in .easyspecs/config.json." };
|
|
18177
18528
|
}
|
|
18178
18529
|
return { ok: false, message: "Upload from CLI requires `easyspecs upload context` (not wired in macro headless default)." };
|
|
18179
18530
|
}
|
|
@@ -18207,14 +18558,14 @@ var RE_MD_SV = /^SV-\d+-.+\.md$/i;
|
|
|
18207
18558
|
var RE_MD_DM_FD = /^DM-\d+_FD-\d+-.+\.md$/i;
|
|
18208
18559
|
var RE_MD_DM = /^DM-\d+-.+\.md$/i;
|
|
18209
18560
|
var RE_MD_TS = /^TS-\d+-.+\.md$/i;
|
|
18210
|
-
function looksLikeCoordinationDetailMarkdownBasename(
|
|
18211
|
-
if (!
|
|
18561
|
+
function looksLikeCoordinationDetailMarkdownBasename(basename12) {
|
|
18562
|
+
if (!basename12 || basename12 !== path39.basename(basename12) || !/\.md$/i.test(basename12)) {
|
|
18212
18563
|
return false;
|
|
18213
18564
|
}
|
|
18214
|
-
if (STAPLE_CONTEXT_MARKDOWN_BASENAMES.has(
|
|
18565
|
+
if (STAPLE_CONTEXT_MARKDOWN_BASENAMES.has(basename12)) {
|
|
18215
18566
|
return false;
|
|
18216
18567
|
}
|
|
18217
|
-
return RE_MD_FE_UC_SC.test(
|
|
18568
|
+
return RE_MD_FE_UC_SC.test(basename12) || RE_MD_FE_UC_SLUG.test(basename12) || RE_MD_FE_UC_PLAIN.test(basename12) || RE_MD_FE_FEATURE.test(basename12) || RE_MD_XP_BH.test(basename12) || RE_MD_XP_VIEW.test(basename12) || RE_MD_SV_ME.test(basename12) || RE_MD_SV.test(basename12) || RE_MD_DM_FD.test(basename12) || RE_MD_DM.test(basename12) || RE_MD_TS.test(basename12);
|
|
18218
18569
|
}
|
|
18219
18570
|
function loadRawFeatureRows(contextDirAbs) {
|
|
18220
18571
|
const p = path39.join(contextDirAbs, "features-list.json");
|
|
@@ -18229,8 +18580,8 @@ function loadRawFeatureRows(contextDirAbs) {
|
|
|
18229
18580
|
return [];
|
|
18230
18581
|
}
|
|
18231
18582
|
}
|
|
18232
|
-
function hintForOrphanFeatureMarkdown(
|
|
18233
|
-
const m = /^FE-(\d+)-(.+)\.md$/i.exec(
|
|
18583
|
+
function hintForOrphanFeatureMarkdown(basename12, featureRows) {
|
|
18584
|
+
const m = /^FE-(\d+)-(.+)\.md$/i.exec(basename12);
|
|
18234
18585
|
if (!m) {
|
|
18235
18586
|
return void 0;
|
|
18236
18587
|
}
|
|
@@ -18242,8 +18593,8 @@ function hintForOrphanFeatureMarkdown(basename11, featureRows) {
|
|
|
18242
18593
|
continue;
|
|
18243
18594
|
}
|
|
18244
18595
|
const expected = expectedFeatureDetailBasenameFromRow(row2);
|
|
18245
|
-
if (expected && expected !==
|
|
18246
|
-
return `features-list row ${code} currently implies detail file ${expected} (slug/name changed \u2014 ${
|
|
18596
|
+
if (expected && expected !== basename12) {
|
|
18597
|
+
return `features-list row ${code} currently implies detail file ${expected} (slug/name changed \u2014 ${basename12} may be stale).`;
|
|
18247
18598
|
}
|
|
18248
18599
|
if (!expected) {
|
|
18249
18600
|
return `features-list row ${code} has no resolvable slug for a detail markdown basename.`;
|
|
@@ -18678,6 +19029,13 @@ async function refreshTokenWithApi(apiBaseUrl, fetchImpl, refreshToken) {
|
|
|
18678
19029
|
const tokens = normalizeTokens(payload);
|
|
18679
19030
|
return { accessToken: tokens.accessToken, refreshToken: tokens.refreshToken };
|
|
18680
19031
|
}
|
|
19032
|
+
function toFetchErrorMessage(e) {
|
|
19033
|
+
if (e && typeof e === "object" && "status" in e && "message" in e) {
|
|
19034
|
+
return e;
|
|
19035
|
+
}
|
|
19036
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
19037
|
+
return { status: 0, message: msg };
|
|
19038
|
+
}
|
|
18681
19039
|
|
|
18682
19040
|
// src/auth/gluecharmContentNegotiation.ts
|
|
18683
19041
|
var GLUECHARM_WS_LEGACY_JSON = "application/vnd.gluecharm.v1.ws-legacy+json";
|
|
@@ -18783,9 +19141,41 @@ var path40 = __toESM(require("node:path"));
|
|
|
18783
19141
|
function defaultSessionPath() {
|
|
18784
19142
|
return path40.join(os2.homedir(), ".easyspecs", "cli-session.json");
|
|
18785
19143
|
}
|
|
19144
|
+
var configSessionPath;
|
|
19145
|
+
function setCliSessionPathFromConfig(absPath) {
|
|
19146
|
+
configSessionPath = absPath?.trim() ? path40.resolve(absPath) : void 0;
|
|
19147
|
+
}
|
|
19148
|
+
function applyCliSessionPathFromRepoConfig(repoRoot, cfg) {
|
|
19149
|
+
const raw = cfg.easyspecs?.cliSessionPath?.trim();
|
|
19150
|
+
if (!raw) {
|
|
19151
|
+
setCliSessionPathFromConfig(void 0);
|
|
19152
|
+
return;
|
|
19153
|
+
}
|
|
19154
|
+
const abs = path40.isAbsolute(raw) ? raw : path40.join(repoRoot, raw);
|
|
19155
|
+
setCliSessionPathFromConfig(abs);
|
|
19156
|
+
}
|
|
19157
|
+
function normalizeCliSessionPathForConfig(repoRoot, raw) {
|
|
19158
|
+
const t = raw.trim();
|
|
19159
|
+
if (!t) {
|
|
19160
|
+
return "";
|
|
19161
|
+
}
|
|
19162
|
+
const resolvedRepo = path40.resolve(repoRoot);
|
|
19163
|
+
const abs = path40.isAbsolute(t) ? path40.normalize(t) : path40.resolve(resolvedRepo, t);
|
|
19164
|
+
const rel = path40.relative(resolvedRepo, abs);
|
|
19165
|
+
if (rel === "") {
|
|
19166
|
+
return abs;
|
|
19167
|
+
}
|
|
19168
|
+
const underRepo = !rel.startsWith("..") && !path40.isAbsolute(rel);
|
|
19169
|
+
if (underRepo) {
|
|
19170
|
+
return rel.split(path40.sep).join("/");
|
|
19171
|
+
}
|
|
19172
|
+
return abs;
|
|
19173
|
+
}
|
|
18786
19174
|
function effectiveCliSessionPath() {
|
|
18787
|
-
|
|
18788
|
-
|
|
19175
|
+
if (configSessionPath) {
|
|
19176
|
+
return configSessionPath;
|
|
19177
|
+
}
|
|
19178
|
+
return defaultSessionPath();
|
|
18789
19179
|
}
|
|
18790
19180
|
function readCliSession() {
|
|
18791
19181
|
const p = effectiveCliSessionPath();
|
|
@@ -18900,8 +19290,8 @@ async function runAceAutoLearnPool(p) {
|
|
|
18900
19290
|
const fifo = [...p.traceAbsolutePaths];
|
|
18901
19291
|
let active = 0;
|
|
18902
19292
|
let wake;
|
|
18903
|
-
const waitTurn = () => new Promise((
|
|
18904
|
-
wake =
|
|
19293
|
+
const waitTurn = () => new Promise((resolve15) => {
|
|
19294
|
+
wake = resolve15;
|
|
18905
19295
|
});
|
|
18906
19296
|
const pump = () => {
|
|
18907
19297
|
wake?.();
|
|
@@ -18992,8 +19382,82 @@ function parseTailFlags(tail) {
|
|
|
18992
19382
|
return { rootKind, worktree };
|
|
18993
19383
|
}
|
|
18994
19384
|
|
|
19385
|
+
// src/cli/parseDoctorFlags.ts
|
|
19386
|
+
var ALLOWED = /* @__PURE__ */ new Set(["--readiness", "--inspect-config"]);
|
|
19387
|
+
function parseDoctorFlags(tail) {
|
|
19388
|
+
for (const t of tail) {
|
|
19389
|
+
if (!ALLOWED.has(t)) {
|
|
19390
|
+
throw new Error(`Unknown doctor flag: ${t}`);
|
|
19391
|
+
}
|
|
19392
|
+
}
|
|
19393
|
+
if (tail.length === 0) {
|
|
19394
|
+
return { readiness: true, inspectConfig: false };
|
|
19395
|
+
}
|
|
19396
|
+
return {
|
|
19397
|
+
readiness: tail.includes("--readiness"),
|
|
19398
|
+
inspectConfig: tail.includes("--inspect-config")
|
|
19399
|
+
};
|
|
19400
|
+
}
|
|
19401
|
+
|
|
19402
|
+
// src/cli/parseAuthLoginTail.ts
|
|
19403
|
+
function extractAuthLoginSessionPathFromTail(tail) {
|
|
19404
|
+
const rest = [];
|
|
19405
|
+
let sessionPath;
|
|
19406
|
+
for (let i = 0; i < tail.length; i += 1) {
|
|
19407
|
+
const a = tail[i] ?? "";
|
|
19408
|
+
if (a === "--session-path") {
|
|
19409
|
+
const v = tail[i + 1];
|
|
19410
|
+
if (v === void 0 || v.startsWith("-")) {
|
|
19411
|
+
throw new Error("--session-path requires a value");
|
|
19412
|
+
}
|
|
19413
|
+
sessionPath = v;
|
|
19414
|
+
i += 1;
|
|
19415
|
+
continue;
|
|
19416
|
+
}
|
|
19417
|
+
rest.push(a);
|
|
19418
|
+
}
|
|
19419
|
+
return { rest, sessionPath };
|
|
19420
|
+
}
|
|
19421
|
+
function stripCiFlag(tail) {
|
|
19422
|
+
return tail.filter((t) => t !== "--ci");
|
|
19423
|
+
}
|
|
19424
|
+
function parseAuthLoginTail(tail) {
|
|
19425
|
+
const tokens = stripCiFlag(tail);
|
|
19426
|
+
let email;
|
|
19427
|
+
let password;
|
|
19428
|
+
for (let i = 0; i < tokens.length; i += 1) {
|
|
19429
|
+
const a = tokens[i] ?? "";
|
|
19430
|
+
if (a === "--email") {
|
|
19431
|
+
const v = tokens[i + 1];
|
|
19432
|
+
if (v === void 0 || v.startsWith("-")) {
|
|
19433
|
+
return { ok: false, error: "--email requires a value" };
|
|
19434
|
+
}
|
|
19435
|
+
email = v;
|
|
19436
|
+
i += 1;
|
|
19437
|
+
continue;
|
|
19438
|
+
}
|
|
19439
|
+
if (a === "--password") {
|
|
19440
|
+
const v = tokens[i + 1];
|
|
19441
|
+
if (v === void 0) {
|
|
19442
|
+
return { ok: false, error: "--password requires a value" };
|
|
19443
|
+
}
|
|
19444
|
+
password = v;
|
|
19445
|
+
i += 1;
|
|
19446
|
+
continue;
|
|
19447
|
+
}
|
|
19448
|
+
return { ok: false, error: `Unexpected argument: ${a}` };
|
|
19449
|
+
}
|
|
19450
|
+
if (!email?.trim()) {
|
|
19451
|
+
return { ok: false, error: "Missing --email (or use --ci with EASYSPECS_EMAIL / EASYSPECS_PASSWORD)" };
|
|
19452
|
+
}
|
|
19453
|
+
if (password === void 0) {
|
|
19454
|
+
return { ok: false, error: "Missing --password (or use --ci with EASYSPECS_EMAIL / EASYSPECS_PASSWORD)" };
|
|
19455
|
+
}
|
|
19456
|
+
return { ok: true, creds: { email: email.trim(), password } };
|
|
19457
|
+
}
|
|
19458
|
+
|
|
18995
19459
|
// src/cli/main.ts
|
|
18996
|
-
var PKG_VERSION = "0.0.
|
|
19460
|
+
var PKG_VERSION = "0.0.7";
|
|
18997
19461
|
function logErr(flags, ...a) {
|
|
18998
19462
|
if (!flags.json) {
|
|
18999
19463
|
console.error(...a);
|
|
@@ -19001,6 +19465,12 @@ function logErr(flags, ...a) {
|
|
|
19001
19465
|
console.error(...a);
|
|
19002
19466
|
}
|
|
19003
19467
|
}
|
|
19468
|
+
function buildDoctorInspectPayload(merged, repoConfig) {
|
|
19469
|
+
return {
|
|
19470
|
+
merged: redactMergedCliSettingsForDump(merged),
|
|
19471
|
+
easyspecsConfig: redactEasyspecsConfigRootForDump(repoConfig)
|
|
19472
|
+
};
|
|
19473
|
+
}
|
|
19004
19474
|
function formatCommand(positionals) {
|
|
19005
19475
|
return positionals.join(" ").trim() || "help";
|
|
19006
19476
|
}
|
|
@@ -19015,18 +19485,21 @@ Global options:
|
|
|
19015
19485
|
--ci Non-interactive; fail fast if configuration is missing
|
|
19016
19486
|
--json Print one JSON summary line on stdout
|
|
19017
19487
|
--verbose Extra stderr logging
|
|
19018
|
-
--api-base-url <url> System Manager API origin
|
|
19019
|
-
--
|
|
19488
|
+
--api-base-url <url> System Manager API origin (overrides config)
|
|
19489
|
+
--session-path <file> Session JSON for this run (overrides easyspecs.cliSessionPath; e.g. extension delegate)
|
|
19490
|
+
--environment production|staging Effective deployment (alias: --env); overrides easyspecs.deploymentEnvironment
|
|
19491
|
+
--promote / --no-promote Copy generated context into workspace after run synthesis (default: promote)
|
|
19020
19492
|
|
|
19021
19493
|
Commands:
|
|
19022
19494
|
help | --help
|
|
19023
19495
|
version
|
|
19024
|
-
doctor
|
|
19025
|
-
auth login
|
|
19026
|
-
|
|
19027
|
-
|
|
19028
|
-
|
|
19029
|
-
|
|
19496
|
+
doctor [--readiness] [--inspect-config]
|
|
19497
|
+
auth login --email <email> --password <password> [--session-path <path>]
|
|
19498
|
+
auth logout | status
|
|
19499
|
+
run synthesis
|
|
19500
|
+
run synthesis resume-missing [--worktree <path>]
|
|
19501
|
+
run synthesis resume-synthesis [--worktree <path>]
|
|
19502
|
+
analysis [--synthesis-only] [--upload] [--skip-upload]
|
|
19030
19503
|
diagnose reference-coverage --root workspace|worktree [--worktree <path>]
|
|
19031
19504
|
diagnose coordination-duplicates --root workspace|worktree [--worktree <path>]
|
|
19032
19505
|
diagnose coverage-report --root workspace|worktree [--worktree <path>]
|
|
@@ -19034,7 +19507,9 @@ Commands:
|
|
|
19034
19507
|
diagnose zero-reference [--worktree <path>]
|
|
19035
19508
|
upload context | upload republish
|
|
19036
19509
|
ace clear | ace learn | ace auto-learn [--worktree <path>]
|
|
19037
|
-
config
|
|
19510
|
+
config init [--overwrite]
|
|
19511
|
+
config set-project-id <easyspecsProjectId>
|
|
19512
|
+
config set-git-remote <url>
|
|
19038
19513
|
`);
|
|
19039
19514
|
}
|
|
19040
19515
|
function parseWorktreeFlag(rest) {
|
|
@@ -19069,18 +19544,23 @@ function resolveAdHocCheckoutRoot(_repoRoot, storage, worktreeFlag) {
|
|
|
19069
19544
|
if (p && fs43.existsSync(path43.join(p, ".git"))) {
|
|
19070
19545
|
return p;
|
|
19071
19546
|
}
|
|
19072
|
-
throw new Error("No analysis checkout: run `easyspecs-cli
|
|
19547
|
+
throw new Error("No analysis checkout: run `easyspecs-cli run synthesis` first or pass `--worktree <path>`.");
|
|
19073
19548
|
}
|
|
19074
19549
|
function requireOpenCode(merged, flags) {
|
|
19075
19550
|
const readiness = getOpenCodeReadiness({
|
|
19076
19551
|
executable: merged.openCodeExecutable,
|
|
19077
|
-
skipCredentialsCheck: merged.openCodeSkipCredentialsCheck
|
|
19552
|
+
skipCredentialsCheck: merged.openCodeSkipCredentialsCheck,
|
|
19553
|
+
providerEnvFromConfig: merged.openCodeChildEnv
|
|
19078
19554
|
});
|
|
19079
19555
|
if (!readiness.installed) {
|
|
19080
|
-
throw new Error(
|
|
19556
|
+
throw new Error(
|
|
19557
|
+
"OpenCode not on PATH (set `easyspecs.openCode.executable` or `easyspecs.openCodeRuntime.executable` in `.easyspecs/config.json`, or install `opencode`)."
|
|
19558
|
+
);
|
|
19081
19559
|
}
|
|
19082
19560
|
if (!readiness.credentialsReady) {
|
|
19083
|
-
throw new Error(
|
|
19561
|
+
throw new Error(
|
|
19562
|
+
"OpenCode credentials not ready: configure provider `apiKey` values under `easyspecs.openCodeRuntime.providers` in `.easyspecs/config.json`, or sign in with OpenCode using your usual shell."
|
|
19563
|
+
);
|
|
19084
19564
|
}
|
|
19085
19565
|
return readiness;
|
|
19086
19566
|
}
|
|
@@ -19142,11 +19622,136 @@ async function main() {
|
|
|
19142
19622
|
const repoRoot = resolveRepoRoot(flags);
|
|
19143
19623
|
setAceCliHeadlessMode(true);
|
|
19144
19624
|
setAceCliWorkspaceRoot(repoRoot);
|
|
19145
|
-
|
|
19146
|
-
|
|
19625
|
+
if (positionals[0] === "config" && positionals[1] === "init") {
|
|
19626
|
+
const tail = positionals.slice(2);
|
|
19627
|
+
const overwrite = tail.includes("--overwrite");
|
|
19628
|
+
const unknown = tail.filter((t) => t !== "--overwrite");
|
|
19629
|
+
if (unknown.length > 0) {
|
|
19630
|
+
logErr(flags, `Unknown arguments for config init: ${unknown.join(", ")}`);
|
|
19631
|
+
process.exit(ExitCode.usage);
|
|
19632
|
+
}
|
|
19633
|
+
try {
|
|
19634
|
+
const r = initEasyspecsConfigFile(repoRoot, {
|
|
19635
|
+
overwrite,
|
|
19636
|
+
warnMigration: (m) => logErr(flags, `[EasySpecs] ${m}`)
|
|
19637
|
+
});
|
|
19638
|
+
if (flags.json) {
|
|
19639
|
+
printJsonLine({
|
|
19640
|
+
command: "config init",
|
|
19641
|
+
durationMs: Date.now() - t0,
|
|
19642
|
+
ok: true,
|
|
19643
|
+
outcome: r.outcome,
|
|
19644
|
+
path: r.path
|
|
19645
|
+
});
|
|
19646
|
+
} else {
|
|
19647
|
+
const msg = r.outcome === "created" ? `Wrote ${r.path}` : r.outcome === "overwritten" ? `Overwrote ${r.path} with defaults (merged legacy cli.json / settings.json when present).` : `Already exists \u2014 ${r.path} (use --overwrite to replace with defaults).`;
|
|
19648
|
+
console.log(msg);
|
|
19649
|
+
}
|
|
19650
|
+
process.exit(ExitCode.ok);
|
|
19651
|
+
} catch (e) {
|
|
19652
|
+
if (e instanceof EasyspecsConfigInvalidJsonError) {
|
|
19653
|
+
console.error(e.message);
|
|
19654
|
+
process.exit(ExitCode.misconfiguration);
|
|
19655
|
+
}
|
|
19656
|
+
throw e;
|
|
19657
|
+
}
|
|
19658
|
+
}
|
|
19659
|
+
if (positionals[0] === "config" && positionals[1] === "set-project-id") {
|
|
19660
|
+
const rest = positionals.slice(2);
|
|
19661
|
+
const id = rest[0]?.trim();
|
|
19662
|
+
const extra = rest.slice(1).filter((t) => t.length > 0);
|
|
19663
|
+
if (!id || extra.length > 0) {
|
|
19664
|
+
logErr(flags, "Usage: easyspecs-cli config set-project-id <easyspecsProjectId>");
|
|
19665
|
+
process.exit(ExitCode.usage);
|
|
19666
|
+
}
|
|
19667
|
+
try {
|
|
19668
|
+
const cfg = updateEasyspecsConfig(
|
|
19669
|
+
repoRoot,
|
|
19670
|
+
{ easyspecs: { easyspecsProjectId: id } },
|
|
19671
|
+
{ warnMigration: (m) => logErr(flags, `[EasySpecs] ${m}`) }
|
|
19672
|
+
);
|
|
19673
|
+
const configJsonPath = easyspecsConfigPath(repoRoot);
|
|
19674
|
+
if (flags.json) {
|
|
19675
|
+
printJsonLine({
|
|
19676
|
+
command: "config set-project-id",
|
|
19677
|
+
durationMs: Date.now() - t0,
|
|
19678
|
+
ok: true,
|
|
19679
|
+
path: configJsonPath,
|
|
19680
|
+
easyspecsProjectId: cfg.easyspecs?.easyspecsProjectId ?? ""
|
|
19681
|
+
});
|
|
19682
|
+
} else {
|
|
19683
|
+
console.log(`Updated ${configJsonPath} \u2014 easyspecs.easyspecsProjectId`);
|
|
19684
|
+
}
|
|
19685
|
+
process.exit(ExitCode.ok);
|
|
19686
|
+
} catch (e) {
|
|
19687
|
+
if (e instanceof EasyspecsConfigInvalidJsonError) {
|
|
19688
|
+
console.error(e.message);
|
|
19689
|
+
process.exit(ExitCode.misconfiguration);
|
|
19690
|
+
}
|
|
19691
|
+
throw e;
|
|
19692
|
+
}
|
|
19693
|
+
}
|
|
19694
|
+
if (positionals[0] === "config" && positionals[1] === "set-git-remote") {
|
|
19695
|
+
const rest = positionals.slice(2);
|
|
19696
|
+
const url = rest[0]?.trim();
|
|
19697
|
+
const extra = rest.slice(1).filter((t) => t.length > 0);
|
|
19698
|
+
if (!url || extra.length > 0) {
|
|
19699
|
+
logErr(flags, "Usage: easyspecs-cli config set-git-remote <url>");
|
|
19700
|
+
process.exit(ExitCode.usage);
|
|
19701
|
+
}
|
|
19702
|
+
try {
|
|
19703
|
+
const cfg = updateEasyspecsConfig(
|
|
19704
|
+
repoRoot,
|
|
19705
|
+
{ easyspecs: { defaultGitRemoteUrl: url } },
|
|
19706
|
+
{ warnMigration: (m) => logErr(flags, `[EasySpecs] ${m}`) }
|
|
19707
|
+
);
|
|
19708
|
+
const path44 = easyspecsConfigPath(repoRoot);
|
|
19709
|
+
if (flags.json) {
|
|
19710
|
+
printJsonLine({
|
|
19711
|
+
command: "config set-git-remote",
|
|
19712
|
+
durationMs: Date.now() - t0,
|
|
19713
|
+
ok: true,
|
|
19714
|
+
path: path44,
|
|
19715
|
+
defaultGitRemoteUrl: cfg.easyspecs?.defaultGitRemoteUrl ?? ""
|
|
19716
|
+
});
|
|
19717
|
+
} else {
|
|
19718
|
+
console.log(`Updated ${path44} \u2014 easyspecs.defaultGitRemoteUrl`);
|
|
19719
|
+
}
|
|
19720
|
+
process.exit(ExitCode.ok);
|
|
19721
|
+
} catch (e) {
|
|
19722
|
+
if (e instanceof EasyspecsConfigInvalidJsonError) {
|
|
19723
|
+
console.error(e.message);
|
|
19724
|
+
process.exit(ExitCode.misconfiguration);
|
|
19725
|
+
}
|
|
19726
|
+
throw e;
|
|
19727
|
+
}
|
|
19728
|
+
}
|
|
19729
|
+
const allowCreateConfig = positionals[0] !== "doctor";
|
|
19730
|
+
let repoConfig;
|
|
19731
|
+
try {
|
|
19732
|
+
repoConfig = ensureEasyspecsConfig(repoRoot, {
|
|
19733
|
+
allowCreate: allowCreateConfig,
|
|
19734
|
+
warnMigration: (m) => logErr(flags, `[EasySpecs] ${m}`)
|
|
19735
|
+
});
|
|
19736
|
+
} catch (e) {
|
|
19737
|
+
if (e instanceof EasyspecsConfigInvalidJsonError) {
|
|
19738
|
+
console.error(e.message);
|
|
19739
|
+
process.exit(ExitCode.misconfiguration);
|
|
19740
|
+
}
|
|
19741
|
+
throw e;
|
|
19742
|
+
}
|
|
19743
|
+
applyCliSessionPathFromRepoConfig(repoRoot, repoConfig);
|
|
19744
|
+
if (flags.sessionPath?.trim()) {
|
|
19745
|
+
const sp = flags.sessionPath.trim();
|
|
19746
|
+
const abs = path43.isAbsolute(sp) ? path43.normalize(sp) : path43.resolve(repoRoot, sp);
|
|
19747
|
+
setCliSessionPathFromConfig(abs);
|
|
19748
|
+
}
|
|
19749
|
+
const apiResolved = initApiBaseUrlForCli(repoRoot, flags, repoConfig);
|
|
19750
|
+
const merged = mergeEasyspecsCliSettings(repoConfig, {
|
|
19147
19751
|
ci: flags.ci,
|
|
19148
19752
|
apiBaseUrl: flags.apiBaseUrl,
|
|
19149
|
-
promote: flags.promote
|
|
19753
|
+
promote: flags.promote,
|
|
19754
|
+
repoRoot
|
|
19150
19755
|
});
|
|
19151
19756
|
const finish = (code, envelope) => {
|
|
19152
19757
|
if (flags.json) {
|
|
@@ -19162,11 +19767,20 @@ async function main() {
|
|
|
19162
19767
|
const pos = positionals;
|
|
19163
19768
|
try {
|
|
19164
19769
|
if (pos[0] === "doctor") {
|
|
19770
|
+
let modes;
|
|
19771
|
+
try {
|
|
19772
|
+
modes = parseDoctorFlags(pos.slice(1));
|
|
19773
|
+
} catch (e) {
|
|
19774
|
+
logErr(flags, e instanceof Error ? e.message : String(e));
|
|
19775
|
+
logErr(flags, "Usage: easyspecs-cli doctor [--readiness] [--inspect-config]");
|
|
19776
|
+
process.exit(ExitCode.usage);
|
|
19777
|
+
}
|
|
19165
19778
|
const agentsDir = resolveOpenCodeAgentsDir();
|
|
19166
19779
|
const agentsOk = fs43.existsSync(agentsDir);
|
|
19167
19780
|
const oc = getOpenCodeReadiness({
|
|
19168
19781
|
executable: merged.openCodeExecutable,
|
|
19169
|
-
skipCredentialsCheck: merged.openCodeSkipCredentialsCheck
|
|
19782
|
+
skipCredentialsCheck: merged.openCodeSkipCredentialsCheck,
|
|
19783
|
+
providerEnvFromConfig: merged.openCodeChildEnv
|
|
19170
19784
|
});
|
|
19171
19785
|
const lines = [
|
|
19172
19786
|
`repoRoot=${repoRoot}`,
|
|
@@ -19174,13 +19788,29 @@ async function main() {
|
|
|
19174
19788
|
`opencode installed=${String(oc.installed)} credentialsReady=${String(oc.credentialsReady)}`,
|
|
19175
19789
|
`agentsDir=${agentsDir} exists=${String(agentsOk)}`
|
|
19176
19790
|
];
|
|
19791
|
+
const inspectPayload = buildDoctorInspectPayload(merged, repoConfig);
|
|
19177
19792
|
if (!flags.json) {
|
|
19178
|
-
|
|
19793
|
+
const parts = [];
|
|
19794
|
+
if (modes.readiness) {
|
|
19795
|
+
parts.push(lines.join("\n"));
|
|
19796
|
+
}
|
|
19797
|
+
if (modes.inspectConfig) {
|
|
19798
|
+
parts.push(JSON.stringify(inspectPayload, null, 2));
|
|
19799
|
+
}
|
|
19800
|
+
console.log(parts.join(parts.length === 2 ? "\n\n" : ""));
|
|
19801
|
+
}
|
|
19802
|
+
const envelope = { ok: true };
|
|
19803
|
+
if (modes.readiness) {
|
|
19804
|
+
envelope.lines = lines;
|
|
19179
19805
|
}
|
|
19180
|
-
|
|
19806
|
+
if (modes.inspectConfig) {
|
|
19807
|
+
envelope.config = inspectPayload;
|
|
19808
|
+
}
|
|
19809
|
+
finish(ExitCode.ok, envelope);
|
|
19181
19810
|
}
|
|
19182
19811
|
if (pos[0] === "config" && pos[1] === "dump") {
|
|
19183
|
-
|
|
19812
|
+
logErr(flags, "[EasySpecs] `config dump` is deprecated; use `easyspecs-cli doctor --inspect-config`.");
|
|
19813
|
+
const redacted = buildDoctorInspectPayload(merged, repoConfig);
|
|
19184
19814
|
if (!flags.json) {
|
|
19185
19815
|
console.log(JSON.stringify(redacted, null, 2));
|
|
19186
19816
|
}
|
|
@@ -19198,33 +19828,121 @@ async function main() {
|
|
|
19198
19828
|
finish(ExitCode.ok, { ok: true, authenticated: Boolean(s) });
|
|
19199
19829
|
}
|
|
19200
19830
|
if (pos[0] === "auth" && pos[1] === "login") {
|
|
19201
|
-
|
|
19202
|
-
|
|
19203
|
-
|
|
19204
|
-
|
|
19205
|
-
|
|
19206
|
-
|
|
19207
|
-
|
|
19208
|
-
|
|
19209
|
-
|
|
19210
|
-
|
|
19211
|
-
|
|
19212
|
-
|
|
19831
|
+
const tailFull = pos.slice(2);
|
|
19832
|
+
let sessionPathRaw;
|
|
19833
|
+
let tailForCreds;
|
|
19834
|
+
try {
|
|
19835
|
+
const extracted = extractAuthLoginSessionPathFromTail(tailFull);
|
|
19836
|
+
tailForCreds = extracted.rest;
|
|
19837
|
+
sessionPathRaw = extracted.sessionPath;
|
|
19838
|
+
} catch (e) {
|
|
19839
|
+
logErr(flags, e instanceof Error ? e.message : String(e));
|
|
19840
|
+
process.exit(ExitCode.usage);
|
|
19841
|
+
}
|
|
19842
|
+
const parsedCli = parseAuthLoginTail(tailForCreds);
|
|
19843
|
+
const envEmail = process.env.EASYSPECS_EMAIL?.trim();
|
|
19844
|
+
const envPassword = process.env.EASYSPECS_PASSWORD?.trim();
|
|
19845
|
+
const useLegacyCiEnv = !parsedCli.ok && (flags.ci || tailFull.includes("--ci")) && Boolean(envEmail) && Boolean(envPassword);
|
|
19846
|
+
let email;
|
|
19847
|
+
let password;
|
|
19848
|
+
if (parsedCli.ok) {
|
|
19849
|
+
email = parsedCli.creds.email;
|
|
19850
|
+
password = parsedCli.creds.password;
|
|
19851
|
+
} else if (useLegacyCiEnv) {
|
|
19852
|
+
email = envEmail;
|
|
19853
|
+
password = envPassword;
|
|
19854
|
+
} else {
|
|
19855
|
+
logErr(flags, parsedCli.error);
|
|
19856
|
+
logErr(
|
|
19857
|
+
flags,
|
|
19858
|
+
"Usage: easyspecs-cli auth login --email <email> --password <password> [--session-path <path>]"
|
|
19859
|
+
);
|
|
19860
|
+
logErr(
|
|
19861
|
+
flags,
|
|
19862
|
+
"Legacy: easyspecs-cli --ci auth login (requires EASYSPECS_EMAIL and EASYSPECS_PASSWORD)"
|
|
19863
|
+
);
|
|
19864
|
+
process.exit(ExitCode.usage);
|
|
19865
|
+
}
|
|
19866
|
+
if (sessionPathRaw !== void 0) {
|
|
19867
|
+
const stored = normalizeCliSessionPathForConfig(repoRoot, sessionPathRaw);
|
|
19868
|
+
const updatedCfg = updateEasyspecsConfig(
|
|
19869
|
+
repoRoot,
|
|
19870
|
+
{ easyspecs: { cliSessionPath: stored } },
|
|
19871
|
+
{ warnMigration: (m) => logErr(flags, `[EasySpecs] ${m}`) }
|
|
19872
|
+
);
|
|
19873
|
+
applyCliSessionPathFromRepoConfig(repoRoot, updatedCfg);
|
|
19874
|
+
}
|
|
19875
|
+
const base = apiResolved;
|
|
19876
|
+
if (!base) {
|
|
19877
|
+
if (!flags.json) {
|
|
19878
|
+
console.error("KO: apiBaseUrl missing (set easyspecs.apiBaseUrl or use --api-base-url / --environment)");
|
|
19213
19879
|
}
|
|
19880
|
+
finish(ExitCode.misconfiguration, {
|
|
19881
|
+
ok: false,
|
|
19882
|
+
error: "apiBaseUrl missing",
|
|
19883
|
+
outcome: "KO"
|
|
19884
|
+
});
|
|
19885
|
+
}
|
|
19886
|
+
try {
|
|
19214
19887
|
const tokens = await loginWithApi(base, fetch, email, password);
|
|
19215
19888
|
writeCliSession({
|
|
19216
19889
|
apiBaseUrl: base,
|
|
19217
19890
|
accessToken: tokens.accessToken,
|
|
19218
19891
|
refreshToken: tokens.refreshToken
|
|
19219
19892
|
});
|
|
19220
|
-
|
|
19893
|
+
if (!flags.json) {
|
|
19894
|
+
console.log("OK");
|
|
19895
|
+
}
|
|
19896
|
+
finish(ExitCode.ok, { ok: true, outcome: "OK", message: "Logged in." });
|
|
19897
|
+
} catch (e) {
|
|
19898
|
+
const err = toFetchErrorMessage(e);
|
|
19899
|
+
const detail = err.message || "Login failed.";
|
|
19900
|
+
if (!flags.json) {
|
|
19901
|
+
console.error(`KO: ${detail}`);
|
|
19902
|
+
}
|
|
19903
|
+
finish(ExitCode.auth, {
|
|
19904
|
+
ok: false,
|
|
19905
|
+
outcome: "KO",
|
|
19906
|
+
error: detail,
|
|
19907
|
+
status: err.status
|
|
19908
|
+
});
|
|
19221
19909
|
}
|
|
19222
|
-
finish(ExitCode.misconfiguration, {
|
|
19223
|
-
ok: false,
|
|
19224
|
-
error: "Interactive auth not implemented; use --ci with EASYSPECS_EMAIL / EASYSPECS_PASSWORD"
|
|
19225
|
-
});
|
|
19226
19910
|
}
|
|
19227
|
-
if (pos[0] === "
|
|
19911
|
+
if (pos[0] === "run" && pos[1] === "synthesis" && pos[2] === "resume-missing") {
|
|
19912
|
+
const storage = createFileBackedWorkspaceState(repoRoot);
|
|
19913
|
+
const { worktree } = parseWorktreeFlag(pos.slice(3));
|
|
19914
|
+
const analysisRoot = resolveAdHocCheckoutRoot(repoRoot, storage, worktree);
|
|
19915
|
+
const poolRes = await runResumeRemediationPool(storage, repoRoot, analysisRoot, merged, flags);
|
|
19916
|
+
if (poolRes.cancelled) {
|
|
19917
|
+
finish(ExitCode.cancelled, { ok: false, error: "Remediation cancelled.", analysisWorktreePath: analysisRoot });
|
|
19918
|
+
}
|
|
19919
|
+
if (!poolRes.indexOk) {
|
|
19920
|
+
finish(ExitCode.validation, {
|
|
19921
|
+
ok: false,
|
|
19922
|
+
error: poolRes.indexError ?? "Index failed after remediation.",
|
|
19923
|
+
analysisWorktreePath: analysisRoot
|
|
19924
|
+
});
|
|
19925
|
+
}
|
|
19926
|
+
finish(ExitCode.ok, { ok: true, analysisWorktreePath: analysisRoot });
|
|
19927
|
+
}
|
|
19928
|
+
if (pos[0] === "run" && pos[1] === "synthesis" && pos[2] === "resume-synthesis") {
|
|
19929
|
+
const storage = createFileBackedWorkspaceState(repoRoot);
|
|
19930
|
+
const { worktree } = parseWorktreeFlag(pos.slice(3));
|
|
19931
|
+
const analysisRoot = resolveAdHocCheckoutRoot(repoRoot, storage, worktree);
|
|
19932
|
+
const poolRes = await runResumeRemediationPool(storage, repoRoot, analysisRoot, merged, flags);
|
|
19933
|
+
if (poolRes.cancelled) {
|
|
19934
|
+
finish(ExitCode.cancelled, { ok: false, error: "Remediation cancelled.", analysisWorktreePath: analysisRoot });
|
|
19935
|
+
}
|
|
19936
|
+
if (!poolRes.indexOk) {
|
|
19937
|
+
finish(ExitCode.validation, {
|
|
19938
|
+
ok: false,
|
|
19939
|
+
error: poolRes.indexError ?? "Index failed after remediation.",
|
|
19940
|
+
analysisWorktreePath: analysisRoot
|
|
19941
|
+
});
|
|
19942
|
+
}
|
|
19943
|
+
finish(ExitCode.ok, { ok: true, analysisWorktreePath: analysisRoot });
|
|
19944
|
+
}
|
|
19945
|
+
if (pos[0] === "run" && pos[1] === "synthesis" && pos.length === 2) {
|
|
19228
19946
|
requireOpenCode(merged, flags);
|
|
19229
19947
|
const agentsDir = resolveOpenCodeAgentsDir();
|
|
19230
19948
|
assertAgentsDirExists(agentsDir);
|
|
@@ -19271,7 +19989,7 @@ async function main() {
|
|
|
19271
19989
|
}
|
|
19272
19990
|
finish(result.cancelled ? ExitCode.cancelled : ExitCode.validation, {
|
|
19273
19991
|
ok: false,
|
|
19274
|
-
error: result.error ?? "
|
|
19992
|
+
error: result.error ?? "run synthesis failed",
|
|
19275
19993
|
cancelled: result.cancelled === true,
|
|
19276
19994
|
analysisWorktreePath: result.retainedWorktree?.path,
|
|
19277
19995
|
adHocRepositoryRoot: result.retainedWorktree?.repoRoot
|
|
@@ -19400,7 +20118,7 @@ async function main() {
|
|
|
19400
20118
|
}
|
|
19401
20119
|
finish(ExitCode.usage, { ok: false, error: `Unknown diagnose subcommand: ${sub ?? ""}` });
|
|
19402
20120
|
}
|
|
19403
|
-
if (pos[0] === "
|
|
20121
|
+
if (pos[0] === "analysis") {
|
|
19404
20122
|
requireOpenCode(merged, flags);
|
|
19405
20123
|
const synthesisOnly = positionals.includes("--synthesis-only");
|
|
19406
20124
|
const wantsUpload = positionals.includes("--upload");
|
|
@@ -19408,7 +20126,7 @@ async function main() {
|
|
|
19408
20126
|
if (wantsUpload && !uploadSession) {
|
|
19409
20127
|
finish(ExitCode.auth, {
|
|
19410
20128
|
ok: false,
|
|
19411
|
-
error: "
|
|
20129
|
+
error: "analysis --upload requires `easyspecs-cli auth login --email \u2026 --password \u2026` (or legacy `--ci` + EASYSPECS_EMAIL/PASSWORD)."
|
|
19412
20130
|
});
|
|
19413
20131
|
}
|
|
19414
20132
|
const skipBackendSync = !wantsUpload;
|
|
@@ -19423,10 +20141,12 @@ async function main() {
|
|
|
19423
20141
|
if (!wtContextDir) {
|
|
19424
20142
|
return { ok: false, message: "No worktree context to upload." };
|
|
19425
20143
|
}
|
|
19426
|
-
const
|
|
19427
|
-
const appId = target?.application_id?.trim() || process.env.EASYSPECS_APPLICATION_ID?.trim();
|
|
20144
|
+
const appId = getEasyspecsProjectIdFromRepoConfig(repoConfig)?.trim();
|
|
19428
20145
|
if (!appId) {
|
|
19429
|
-
return {
|
|
20146
|
+
return {
|
|
20147
|
+
ok: false,
|
|
20148
|
+
message: "Missing easyspecs.easyspecsProjectId in .easyspecs/config.json."
|
|
20149
|
+
};
|
|
19430
20150
|
}
|
|
19431
20151
|
let access = s.accessToken;
|
|
19432
20152
|
const refresh = s.refreshToken;
|
|
@@ -19486,7 +20206,10 @@ async function main() {
|
|
|
19486
20206
|
if (pos[0] === "upload" && (pos[1] === "context" || pos[1] === "republish")) {
|
|
19487
20207
|
const sessRaw = readCliSession();
|
|
19488
20208
|
if (sessRaw === void 0) {
|
|
19489
|
-
finish(ExitCode.auth, {
|
|
20209
|
+
finish(ExitCode.auth, {
|
|
20210
|
+
ok: false,
|
|
20211
|
+
error: "auth login first (`auth login --email \u2026 --password \u2026`, or legacy `--ci` + env)"
|
|
20212
|
+
});
|
|
19490
20213
|
}
|
|
19491
20214
|
const sess = sessRaw;
|
|
19492
20215
|
let ctxDir = path43.join(repoRoot, ".gluecharm", "context");
|
|
@@ -19501,16 +20224,18 @@ async function main() {
|
|
|
19501
20224
|
if (!wt) {
|
|
19502
20225
|
finish(ExitCode.misconfiguration, {
|
|
19503
20226
|
ok: false,
|
|
19504
|
-
error: "upload republish requires an analysis worktree with .gluecharm/context (run
|
|
20227
|
+
error: "upload republish requires an analysis worktree with .gluecharm/context (`easyspecs-cli run synthesis` first), or set EASYSPECS_UPLOAD_CONTEXT_DIR."
|
|
19505
20228
|
});
|
|
19506
20229
|
}
|
|
19507
20230
|
ctxDir = wt;
|
|
19508
20231
|
}
|
|
19509
20232
|
}
|
|
19510
|
-
const
|
|
19511
|
-
const appIdRaw = target?.application_id?.trim() || process.env.EASYSPECS_APPLICATION_ID?.trim();
|
|
20233
|
+
const appIdRaw = getEasyspecsProjectIdFromRepoConfig(repoConfig)?.trim();
|
|
19512
20234
|
if (!appIdRaw) {
|
|
19513
|
-
finish(ExitCode.misconfiguration, {
|
|
20235
|
+
finish(ExitCode.misconfiguration, {
|
|
20236
|
+
ok: false,
|
|
20237
|
+
error: "Missing easyspecs.easyspecsProjectId in .easyspecs/config.json."
|
|
20238
|
+
});
|
|
19514
20239
|
}
|
|
19515
20240
|
const applicationId = appIdRaw;
|
|
19516
20241
|
let access = sess.accessToken;
|
|
@@ -19617,40 +20342,6 @@ async function main() {
|
|
|
19617
20342
|
cancelled: pool.cancelled
|
|
19618
20343
|
});
|
|
19619
20344
|
}
|
|
19620
|
-
if (pos[0] === "analyze" && pos[1] === "resume-missing") {
|
|
19621
|
-
const storage = createFileBackedWorkspaceState(repoRoot);
|
|
19622
|
-
const { worktree } = parseWorktreeFlag(pos.slice(2));
|
|
19623
|
-
const analysisRoot = resolveAdHocCheckoutRoot(repoRoot, storage, worktree);
|
|
19624
|
-
const poolRes = await runResumeRemediationPool(storage, repoRoot, analysisRoot, merged, flags);
|
|
19625
|
-
if (poolRes.cancelled) {
|
|
19626
|
-
finish(ExitCode.cancelled, { ok: false, error: "Remediation cancelled.", analysisWorktreePath: analysisRoot });
|
|
19627
|
-
}
|
|
19628
|
-
if (!poolRes.indexOk) {
|
|
19629
|
-
finish(ExitCode.validation, {
|
|
19630
|
-
ok: false,
|
|
19631
|
-
error: poolRes.indexError ?? "Index failed after remediation.",
|
|
19632
|
-
analysisWorktreePath: analysisRoot
|
|
19633
|
-
});
|
|
19634
|
-
}
|
|
19635
|
-
finish(ExitCode.ok, { ok: true, analysisWorktreePath: analysisRoot });
|
|
19636
|
-
}
|
|
19637
|
-
if (pos[0] === "analyze" && pos[1] === "resume-synthesis") {
|
|
19638
|
-
const storage = createFileBackedWorkspaceState(repoRoot);
|
|
19639
|
-
const { worktree } = parseWorktreeFlag(pos.slice(2));
|
|
19640
|
-
const analysisRoot = resolveAdHocCheckoutRoot(repoRoot, storage, worktree);
|
|
19641
|
-
const poolRes = await runResumeRemediationPool(storage, repoRoot, analysisRoot, merged, flags);
|
|
19642
|
-
if (poolRes.cancelled) {
|
|
19643
|
-
finish(ExitCode.cancelled, { ok: false, error: "Remediation cancelled.", analysisWorktreePath: analysisRoot });
|
|
19644
|
-
}
|
|
19645
|
-
if (!poolRes.indexOk) {
|
|
19646
|
-
finish(ExitCode.validation, {
|
|
19647
|
-
ok: false,
|
|
19648
|
-
error: poolRes.indexError ?? "Index failed after remediation.",
|
|
19649
|
-
analysisWorktreePath: analysisRoot
|
|
19650
|
-
});
|
|
19651
|
-
}
|
|
19652
|
-
finish(ExitCode.ok, { ok: true, analysisWorktreePath: analysisRoot });
|
|
19653
|
-
}
|
|
19654
20345
|
printHelp();
|
|
19655
20346
|
finish(ExitCode.usage, { ok: false, error: `unknown command: ${cmd}` });
|
|
19656
20347
|
} catch (e) {
|