@moda-ai/cli 1.38.0 → 1.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/dist/{cli-3kcy61fr.js → cli-a7ypptsf.js} +515 -59
- package/dist/{cli-kegd748v.js → cli-dyeywy9d.js} +1 -1
- package/dist/{cli-q79sq80a.js → cli-rp912ypf.js} +163 -21
- package/dist/{cli-07tv75te.js → cli-xsmsjny3.js} +696 -139
- package/dist/{cli-k38j2fpq.js → cli-yy8fwg1a.js} +2 -2
- package/dist/cli.js +2522 -263
- package/dist/{harness-n2xgzz31.js → harness-191xt7bq.js} +2 -2
- package/dist/{harness-github-actions-qz5d22rz.js → harness-github-actions-1qt4sgxd.js} +2 -2
- package/dist/{index-hwfe7gs8.js → index-qgc37efj.js} +5 -5
- package/dist/prompt-source-mcp.js +2 -2
- package/dist/{provision-64c2n9aw.js → provision-gabtks29.js} +3 -3
- package/package.json +1 -1
- package/skills/integration/index.json +2 -2
- package/skills/moda-cli/SKILL.md +239 -20
|
@@ -19,12 +19,13 @@ import {
|
|
|
19
19
|
redactDeep,
|
|
20
20
|
redactString,
|
|
21
21
|
resolveApiKey,
|
|
22
|
+
resolveApiTenantId,
|
|
22
23
|
resolveIngestUrl,
|
|
23
24
|
resolveModaBaseUrl,
|
|
24
25
|
resolveTenantId,
|
|
25
26
|
shouldInventoryFile,
|
|
26
27
|
stringOption
|
|
27
|
-
} from "./cli-
|
|
28
|
+
} from "./cli-rp912ypf.js";
|
|
28
29
|
import {
|
|
29
30
|
__commonJS,
|
|
30
31
|
__require,
|
|
@@ -9157,7 +9158,7 @@ var require_source_map_support = __commonJS((exports, module) => {
|
|
|
9157
9158
|
|
|
9158
9159
|
// ../../node_modules/.bun/typescript@5.9.3/node_modules/typescript/lib/typescript.js
|
|
9159
9160
|
var require_typescript = __commonJS((exports, module) => {
|
|
9160
|
-
var __dirname = "/home/runner/
|
|
9161
|
+
var __dirname = "/home/runner/_work/ModaObservability/ModaObservability/node_modules/.bun/typescript@5.9.3/node_modules/typescript/lib", __filename = "/home/runner/_work/ModaObservability/ModaObservability/node_modules/.bun/typescript@5.9.3/node_modules/typescript/lib/typescript.js";
|
|
9161
9162
|
/*! *****************************************************************************
|
|
9162
9163
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
9163
9164
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
|
@@ -9453,7 +9454,7 @@ var require_typescript = __commonJS((exports, module) => {
|
|
|
9453
9454
|
commandLineOptionOfCustomType: () => commandLineOptionOfCustomType,
|
|
9454
9455
|
commentPragmas: () => commentPragmas,
|
|
9455
9456
|
commonOptionsWithBuild: () => commonOptionsWithBuild,
|
|
9456
|
-
compact: () =>
|
|
9457
|
+
compact: () => compact2,
|
|
9457
9458
|
compareBooleans: () => compareBooleans,
|
|
9458
9459
|
compareDataObjects: () => compareDataObjects,
|
|
9459
9460
|
compareDiagnostics: () => compareDiagnostics,
|
|
@@ -11973,7 +11974,7 @@ var require_typescript = __commonJS((exports, module) => {
|
|
|
11973
11974
|
}
|
|
11974
11975
|
return true;
|
|
11975
11976
|
}
|
|
11976
|
-
function
|
|
11977
|
+
function compact2(array) {
|
|
11977
11978
|
let result;
|
|
11978
11979
|
if (array !== undefined) {
|
|
11979
11980
|
for (let i = 0;i < array.length; i++) {
|
|
@@ -93165,7 +93166,7 @@ ${lanes.join(`
|
|
|
93165
93166
|
if (!links2.hasReportedStatementInAmbientContext) {
|
|
93166
93167
|
return links2.hasReportedStatementInAmbientContext = grammarErrorOnFirstToken(node, Diagnostics.Statements_are_not_allowed_in_ambient_contexts);
|
|
93167
93168
|
}
|
|
93168
|
-
}
|
|
93169
|
+
}
|
|
93169
93170
|
}
|
|
93170
93171
|
return false;
|
|
93171
93172
|
}
|
|
@@ -97630,7 +97631,7 @@ ${lanes.join(`
|
|
|
97630
97631
|
const savedPendingExpressions = pendingExpressions;
|
|
97631
97632
|
pendingExpressions = undefined;
|
|
97632
97633
|
node = factory2.updateBinaryExpression(node, visitNode(node.left, assignmentTargetVisitor, isExpression), node.operatorToken, visitNode(node.right, visitor, isExpression));
|
|
97633
|
-
const expr = some(pendingExpressions) ? factory2.inlineExpressions(
|
|
97634
|
+
const expr = some(pendingExpressions) ? factory2.inlineExpressions(compact2([...pendingExpressions, node])) : node;
|
|
97634
97635
|
pendingExpressions = savedPendingExpressions;
|
|
97635
97636
|
return expr;
|
|
97636
97637
|
}
|
|
@@ -102629,7 +102630,7 @@ ${lanes.join(`
|
|
|
102629
102630
|
], 2));
|
|
102630
102631
|
setParentRecursive(requireStatement, false);
|
|
102631
102632
|
statements = insertStatementAfterCustomPrologue(statements.slice(), requireStatement);
|
|
102632
|
-
}
|
|
102633
|
+
}
|
|
102633
102634
|
}
|
|
102634
102635
|
}
|
|
102635
102636
|
if (statements !== visited.statements) {
|
|
@@ -107434,14 +107435,14 @@ ${lanes.join(`
|
|
|
107434
107435
|
}
|
|
107435
107436
|
}
|
|
107436
107437
|
function createImportCallExpressionAMD(arg, containsLexicalThis) {
|
|
107437
|
-
const
|
|
107438
|
+
const resolve5 = factory2.createUniqueName("resolve");
|
|
107438
107439
|
const reject = factory2.createUniqueName("reject");
|
|
107439
107440
|
const parameters = [
|
|
107440
|
-
factory2.createParameterDeclaration(undefined, undefined,
|
|
107441
|
+
factory2.createParameterDeclaration(undefined, undefined, resolve5),
|
|
107441
107442
|
factory2.createParameterDeclaration(undefined, undefined, reject)
|
|
107442
107443
|
];
|
|
107443
107444
|
const body = factory2.createBlock([
|
|
107444
|
-
factory2.createExpressionStatement(factory2.createCallExpression(factory2.createIdentifier("require"), undefined, [factory2.createArrayLiteralExpression([arg || factory2.createOmittedExpression()]),
|
|
107445
|
+
factory2.createExpressionStatement(factory2.createCallExpression(factory2.createIdentifier("require"), undefined, [factory2.createArrayLiteralExpression([arg || factory2.createOmittedExpression()]), resolve5, reject]))
|
|
107445
107446
|
]);
|
|
107446
107447
|
let func;
|
|
107447
107448
|
if (languageVersion >= 2) {
|
|
@@ -110422,7 +110423,7 @@ ${lanes.join(`
|
|
|
110422
110423
|
let parameterProperties;
|
|
110423
110424
|
if (ctor) {
|
|
110424
110425
|
const oldDiag2 = getSymbolAccessibilityDiagnostic;
|
|
110425
|
-
parameterProperties =
|
|
110426
|
+
parameterProperties = compact2(flatMap(ctor.parameters, (param) => {
|
|
110426
110427
|
if (!hasSyntacticModifier(param, 31) || shouldStripInternal(param))
|
|
110427
110428
|
return;
|
|
110428
110429
|
getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(param);
|
|
@@ -141755,7 +141756,7 @@ ${newComment.split(`
|
|
|
141755
141756
|
}
|
|
141756
141757
|
const checker = context.program.getTypeChecker();
|
|
141757
141758
|
const trackChanges = (cb) => ts_textChanges_exports.ChangeTracker.with(context, cb);
|
|
141758
|
-
return
|
|
141759
|
+
return compact2([
|
|
141759
141760
|
getDeclarationSiteFix(context, expression, errorCode, checker, trackChanges),
|
|
141760
141761
|
getUseSiteFix(context, expression, errorCode, checker, trackChanges)
|
|
141761
141762
|
]);
|
|
@@ -160749,7 +160750,7 @@ ${content}
|
|
|
160749
160750
|
const lastToken = last(children);
|
|
160750
160751
|
const separateLastToken = separateTrailingSemicolon && lastToken.kind === 27;
|
|
160751
160752
|
const rightChildren = children.slice(splitTokenIndex + 1, separateLastToken ? children.length - 1 : undefined);
|
|
160752
|
-
const result =
|
|
160753
|
+
const result = compact2([
|
|
160753
160754
|
leftChildren.length ? createSyntaxList2(leftChildren) : undefined,
|
|
160754
160755
|
splitToken,
|
|
160755
160756
|
rightChildren.length ? createSyntaxList2(rightChildren) : undefined
|
|
@@ -165453,7 +165454,7 @@ ${options.prefix}` : `
|
|
|
165453
165454
|
commandLineOptionOfCustomType: () => commandLineOptionOfCustomType,
|
|
165454
165455
|
commentPragmas: () => commentPragmas,
|
|
165455
165456
|
commonOptionsWithBuild: () => commonOptionsWithBuild,
|
|
165456
|
-
compact: () =>
|
|
165457
|
+
compact: () => compact2,
|
|
165457
165458
|
compareBooleans: () => compareBooleans,
|
|
165458
165459
|
compareDataObjects: () => compareDataObjects,
|
|
165459
165460
|
compareDiagnostics: () => compareDiagnostics,
|
|
@@ -177616,8 +177617,8 @@ Additional information: BADCLIENT: Bad error code, ${badCode} not found in range
|
|
|
177616
177617
|
installPackage(options) {
|
|
177617
177618
|
this.packageInstallId++;
|
|
177618
177619
|
const request = { kind: "installPackage", ...options, id: this.packageInstallId };
|
|
177619
|
-
const promise = new Promise((
|
|
177620
|
-
(this.packageInstalledPromise ?? (this.packageInstalledPromise = /* @__PURE__ */ new Map)).set(this.packageInstallId, { resolve:
|
|
177620
|
+
const promise = new Promise((resolve5, reject) => {
|
|
177621
|
+
(this.packageInstalledPromise ?? (this.packageInstalledPromise = /* @__PURE__ */ new Map)).set(this.packageInstallId, { resolve: resolve5, reject });
|
|
177621
177622
|
});
|
|
177622
177623
|
this.installer.send(request);
|
|
177623
177624
|
return promise;
|
|
@@ -177886,14 +177887,18 @@ import {
|
|
|
177886
177887
|
lstatSync as lstatSync7,
|
|
177887
177888
|
mkdtempSync,
|
|
177888
177889
|
mkdirSync as mkdirSync4,
|
|
177889
|
-
readFileSync as
|
|
177890
|
+
readFileSync as readFileSync13,
|
|
177890
177891
|
readdirSync,
|
|
177891
177892
|
writeFileSync as writeFileSync4,
|
|
177892
177893
|
rmSync
|
|
177893
177894
|
} from "node:fs";
|
|
177894
|
-
import { basename as basename4, delimiter, dirname as dirname5, join as join4, relative as relative6, resolve as
|
|
177895
|
+
import { basename as basename4, delimiter, dirname as dirname5, join as join4, relative as relative6, resolve as resolve11, sep as sep2 } from "node:path";
|
|
177895
177896
|
import { confirm as confirm2, select } from "@inquirer/prompts";
|
|
177896
177897
|
|
|
177898
|
+
// src/parity-commands.ts
|
|
177899
|
+
import { readFileSync } from "node:fs";
|
|
177900
|
+
import { resolve } from "node:path";
|
|
177901
|
+
|
|
177897
177902
|
// src/api-client.ts
|
|
177898
177903
|
var REQUEST_TIMEOUT_MS = 30000;
|
|
177899
177904
|
var MAX_RETRIES = 3;
|
|
@@ -177918,6 +177923,12 @@ class NetworkError extends Error {
|
|
|
177918
177923
|
this.name = "NetworkError";
|
|
177919
177924
|
}
|
|
177920
177925
|
}
|
|
177926
|
+
function networkErrorMessage(error, url) {
|
|
177927
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
177928
|
+
const cause = error instanceof Error ? error.cause : undefined;
|
|
177929
|
+
const code = typeof cause?.code === "string" ? `: ${cause.code}` : "";
|
|
177930
|
+
return `Network error: ${message} (could not reach ${url.split("?")[0]}${code})`;
|
|
177931
|
+
}
|
|
177921
177932
|
function isRetryable(status) {
|
|
177922
177933
|
return status === 429 || status >= 500;
|
|
177923
177934
|
}
|
|
@@ -177932,7 +177943,8 @@ async function callControlAPI(endpoint, options = {}, profileOptions = {}, reque
|
|
|
177932
177943
|
}
|
|
177933
177944
|
async function callModaAPI(url, options, profileOptions = {}, requestOptions = {}) {
|
|
177934
177945
|
const timeoutMs = requestOptions.timeoutMs ?? REQUEST_TIMEOUT_MS;
|
|
177935
|
-
const
|
|
177946
|
+
const method = (options.method ?? "GET").toUpperCase();
|
|
177947
|
+
const maxRetries = requestOptions.retries ?? (method === "GET" || method === "HEAD" ? MAX_RETRIES : 0);
|
|
177936
177948
|
const initialNetworkRetryBudget = requestOptions.retryOnceOnNetworkError ? 1 : 0;
|
|
177937
177949
|
let networkRetryBudget = initialNetworkRetryBudget;
|
|
177938
177950
|
let connectionClose = false;
|
|
@@ -177963,12 +177975,17 @@ async function callModaAPI(url, options, profileOptions = {}, requestOptions = {
|
|
|
177963
177975
|
}
|
|
177964
177976
|
throw error;
|
|
177965
177977
|
}
|
|
177966
|
-
|
|
177978
|
+
if (response.status === 204)
|
|
177979
|
+
return null;
|
|
177980
|
+
if (typeof response.text !== "function")
|
|
177981
|
+
return response.json();
|
|
177982
|
+
const text = await response.text();
|
|
177983
|
+
return text.trim() === "" ? null : JSON.parse(text);
|
|
177967
177984
|
} catch (error) {
|
|
177968
177985
|
if (error instanceof ApiError)
|
|
177969
177986
|
throw error;
|
|
177970
177987
|
const isAbort = error instanceof DOMException && error.name === "AbortError";
|
|
177971
|
-
const wrapped = isAbort ? new Error(`Request timed out after ${timeoutMs}ms: ${url}`) : new NetworkError(
|
|
177988
|
+
const wrapped = isAbort ? new Error(`Request timed out after ${timeoutMs}ms: ${url}`) : new NetworkError(networkErrorMessage(error, url));
|
|
177972
177989
|
if (attempt < maxRetries) {
|
|
177973
177990
|
continue;
|
|
177974
177991
|
}
|
|
@@ -177992,6 +178009,459 @@ function resetApiRequestCount() {
|
|
|
177992
178009
|
apiRequestCount = 0;
|
|
177993
178010
|
}
|
|
177994
178011
|
|
|
178012
|
+
// src/parity-commands.ts
|
|
178013
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
178014
|
+
var WINDOWS = ["24h", "7d", "30d", "90d"];
|
|
178015
|
+
function profileOptions(context) {
|
|
178016
|
+
return { profile: context.profile, env: context.env };
|
|
178017
|
+
}
|
|
178018
|
+
function requireKey(context) {
|
|
178019
|
+
if (!resolveApiKey(profileOptions(context))) {
|
|
178020
|
+
throw new CliInputError(`No Moda API key found for moda ${context.command}.`, "Set MODA_API_KEY, run `moda auth login --api-key`, or select a profile with an API key.");
|
|
178021
|
+
}
|
|
178022
|
+
}
|
|
178023
|
+
function requireTenant(context) {
|
|
178024
|
+
const key = resolveApiKey(profileOptions(context));
|
|
178025
|
+
const keyTenant = key ? embeddedTenantIdFromApiKey(key) : undefined;
|
|
178026
|
+
const flagTenant = context.flags["tenant-id"];
|
|
178027
|
+
if (flagTenant && keyTenant && flagTenant !== keyTenant) {
|
|
178028
|
+
throw new CliInputError(`--tenant-id=${flagTenant} does not match this API key's tenant (${keyTenant}), so nothing was sent.`, "Drop --tenant-id (the key names its tenant) or use a key for that tenant.");
|
|
178029
|
+
}
|
|
178030
|
+
const tenantId = flagTenant || resolveApiTenantId(profileOptions(context));
|
|
178031
|
+
if (!tenantId) {
|
|
178032
|
+
throw new CliInputError("Could not determine the tenant.", "Use a signed API key (it names its tenant), set MODA_TENANT_ID, or pass --tenant-id=<id>.");
|
|
178033
|
+
}
|
|
178034
|
+
return tenantId;
|
|
178035
|
+
}
|
|
178036
|
+
function assertFlags(command, flags, allowed) {
|
|
178037
|
+
if (command.startsWith("signals "))
|
|
178038
|
+
allowed = [...allowed, "tenant-id"];
|
|
178039
|
+
const globals = [
|
|
178040
|
+
"agent",
|
|
178041
|
+
"json",
|
|
178042
|
+
"human",
|
|
178043
|
+
"prose",
|
|
178044
|
+
"quiet",
|
|
178045
|
+
"verbose",
|
|
178046
|
+
"yes",
|
|
178047
|
+
"profile",
|
|
178048
|
+
"progress",
|
|
178049
|
+
"format",
|
|
178050
|
+
"no-telemetry",
|
|
178051
|
+
"no-update-check",
|
|
178052
|
+
"help",
|
|
178053
|
+
"version",
|
|
178054
|
+
"json-schemas",
|
|
178055
|
+
"stream",
|
|
178056
|
+
"no-stream",
|
|
178057
|
+
"tui",
|
|
178058
|
+
"no-tui"
|
|
178059
|
+
];
|
|
178060
|
+
const known = new Set([...allowed, ...globals]);
|
|
178061
|
+
const unknown = Object.keys(flags).filter((flag) => !known.has(flag));
|
|
178062
|
+
if (unknown.includes("dry-run")) {
|
|
178063
|
+
throw new CliInputError(`'moda ${command}' has no dry-run mode, so nothing was sent.`, "Remove --dry-run to run it for real.");
|
|
178064
|
+
}
|
|
178065
|
+
if (unknown.length > 0) {
|
|
178066
|
+
throw new CliInputError(`Unknown flag${unknown.length > 1 ? "s" : ""} ${unknown.map((flag) => `--${flag}`).join(", ")} for 'moda ${command}'.`, `Valid flags: ${allowed.map((flag) => `--${flag}`).join(", ") || "(none)"}.`);
|
|
178067
|
+
}
|
|
178068
|
+
}
|
|
178069
|
+
function assertPositionals(command, positionals, max, usage) {
|
|
178070
|
+
if (positionals.length > max) {
|
|
178071
|
+
throw new CliInputError(`Unexpected argument${positionals.length - max > 1 ? "s" : ""} '${positionals.slice(max).join(" ")}' for 'moda ${command}', so nothing was sent.`, `Usage: ${usage}`);
|
|
178072
|
+
}
|
|
178073
|
+
}
|
|
178074
|
+
function oneOf(name, value, allowed) {
|
|
178075
|
+
if (value === undefined)
|
|
178076
|
+
return;
|
|
178077
|
+
if (!allowed.includes(value)) {
|
|
178078
|
+
throw new CliInputError(`--${name} must be one of ${allowed.join(", ")} (got '${value}').`);
|
|
178079
|
+
}
|
|
178080
|
+
return value;
|
|
178081
|
+
}
|
|
178082
|
+
function csv(value) {
|
|
178083
|
+
if (value === undefined)
|
|
178084
|
+
return;
|
|
178085
|
+
const items = value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
178086
|
+
return items.length > 0 ? items : undefined;
|
|
178087
|
+
}
|
|
178088
|
+
function readBodyFile(flags, cwd) {
|
|
178089
|
+
if (!flags.file)
|
|
178090
|
+
return {};
|
|
178091
|
+
if (flags.file === "true")
|
|
178092
|
+
throw new CliInputError("Missing path for --file.");
|
|
178093
|
+
let parsed;
|
|
178094
|
+
try {
|
|
178095
|
+
parsed = JSON.parse(readFileSync(resolve(cwd, flags.file), "utf8"));
|
|
178096
|
+
} catch (error) {
|
|
178097
|
+
throw new CliInputError(`Could not read --file ${flags.file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
178098
|
+
}
|
|
178099
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
178100
|
+
throw new CliInputError("--file must contain a JSON object (the request body).");
|
|
178101
|
+
}
|
|
178102
|
+
return parsed;
|
|
178103
|
+
}
|
|
178104
|
+
function compact(value) {
|
|
178105
|
+
return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined));
|
|
178106
|
+
}
|
|
178107
|
+
var LLM_WRITE_TIMEOUT_MS = 180000;
|
|
178108
|
+
async function send(context, plane, method, endpoint, body, options = {}) {
|
|
178109
|
+
const init = { method, ...body !== undefined ? { body: JSON.stringify(body) } : {} };
|
|
178110
|
+
if (method !== "GET" && context.dryRun) {
|
|
178111
|
+
context.output.writeData({
|
|
178112
|
+
dryRun: true,
|
|
178113
|
+
planned: { method, endpoint: plane === "data" ? `/api/v1/data${endpoint}` : `/api${endpoint}`, ...body !== undefined ? { body } : {} }
|
|
178114
|
+
}, { summary: { text: `Dry run: would ${method} ${endpoint}. Nothing was sent.`, confidence: "high" } });
|
|
178115
|
+
return;
|
|
178116
|
+
}
|
|
178117
|
+
const requestOptions = method === "GET" ? {} : { retries: 0, ...options.slow ? { timeoutMs: LLM_WRITE_TIMEOUT_MS } : {} };
|
|
178118
|
+
const data = plane === "data" ? await callDataAPI(endpoint, init, requestOptions) : await callControlAPI(endpoint, init, profileOptions(context), requestOptions);
|
|
178119
|
+
context.output.writeData(data ?? { ok: true });
|
|
178120
|
+
}
|
|
178121
|
+
var USER_COHORTS = ["all", "power_users", "heavy_tool_users", "frustrated", "at_risk", "new_this_week", "silent_sufferers"];
|
|
178122
|
+
var USER_SORTS = ["last_seen", "health_score", "conversation_count", "frustration_max"];
|
|
178123
|
+
var HEALTH = ["healthy", "at_risk", "frustrated"];
|
|
178124
|
+
async function runUsersCommand(context) {
|
|
178125
|
+
const flags = context.flags;
|
|
178126
|
+
assertFlags("users", flags, [
|
|
178127
|
+
"window",
|
|
178128
|
+
"page",
|
|
178129
|
+
"page-size",
|
|
178130
|
+
"search",
|
|
178131
|
+
"cohort",
|
|
178132
|
+
"sort",
|
|
178133
|
+
"order",
|
|
178134
|
+
"health-status",
|
|
178135
|
+
"min-health",
|
|
178136
|
+
"max-health",
|
|
178137
|
+
"min-conversations",
|
|
178138
|
+
"min-tool-failures",
|
|
178139
|
+
"tenant-id"
|
|
178140
|
+
]);
|
|
178141
|
+
if (context.positionals.length > 0) {
|
|
178142
|
+
throw new CliInputError(`'moda users' takes no arguments. For one user use 'moda user <user_id>'.`);
|
|
178143
|
+
}
|
|
178144
|
+
requireKey(context);
|
|
178145
|
+
const tenantId = requireTenant(context);
|
|
178146
|
+
const query = new URLSearchParams(compact({
|
|
178147
|
+
window: oneOf("window", flags.window, WINDOWS),
|
|
178148
|
+
page: flags.page,
|
|
178149
|
+
pageSize: flags["page-size"],
|
|
178150
|
+
search: flags.search,
|
|
178151
|
+
cohort: oneOf("cohort", flags.cohort, USER_COHORTS),
|
|
178152
|
+
sortBy: oneOf("sort", flags.sort, USER_SORTS),
|
|
178153
|
+
sortOrder: oneOf("order", flags.order, ["asc", "desc"]),
|
|
178154
|
+
healthStatus: csv(flags["health-status"])?.map((value) => oneOf("health-status", value, HEALTH)).join(","),
|
|
178155
|
+
minHealthScore: flags["min-health"],
|
|
178156
|
+
maxHealthScore: flags["max-health"],
|
|
178157
|
+
minConversations: flags["min-conversations"],
|
|
178158
|
+
minToolFailures: flags["min-tool-failures"]
|
|
178159
|
+
}));
|
|
178160
|
+
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
178161
|
+
await send(context, "control", "GET", `/tenants/${encodeURIComponent(tenantId)}/users${suffix}`);
|
|
178162
|
+
return { exitCode: 0 };
|
|
178163
|
+
}
|
|
178164
|
+
async function runUserCommand(context) {
|
|
178165
|
+
const flags = context.flags;
|
|
178166
|
+
assertFlags("user", flags, ["window", "activity-cursor", "tenant-id"]);
|
|
178167
|
+
assertPositionals("user", context.positionals, 1, "moda user <user_id> [--window=24h|7d|30d|90d]");
|
|
178168
|
+
const userId = context.positionals[0];
|
|
178169
|
+
if (!userId)
|
|
178170
|
+
throw new CliInputError("<user_id> is required.", "Usage: moda user <user_id> [--window=24h|7d|30d|90d]");
|
|
178171
|
+
requireKey(context);
|
|
178172
|
+
const tenantId = requireTenant(context);
|
|
178173
|
+
const query = new URLSearchParams(compact({
|
|
178174
|
+
window: oneOf("window", flags.window, WINDOWS),
|
|
178175
|
+
activityCursor: flags["activity-cursor"]
|
|
178176
|
+
}));
|
|
178177
|
+
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
178178
|
+
await send(context, "control", "GET", `/tenants/${encodeURIComponent(tenantId)}/users/${encodeURIComponent(userId)}${suffix}`);
|
|
178179
|
+
return { exitCode: 0 };
|
|
178180
|
+
}
|
|
178181
|
+
async function runProblemReopenCommand(context) {
|
|
178182
|
+
assertFlags("problem-reopen", context.flags, ["reason", "dry-run"]);
|
|
178183
|
+
assertPositionals("problem-reopen", context.positionals, 1, "moda problem-reopen <problem_id> [--reason=TEXT]");
|
|
178184
|
+
const problemId = context.positionals[0];
|
|
178185
|
+
const usage = "Usage: moda problem-reopen <problem_id> [--reason=TEXT]";
|
|
178186
|
+
if (!problemId || !UUID_RE.test(problemId))
|
|
178187
|
+
throw new CliInputError("<problem_id> (UUID) is required.", usage);
|
|
178188
|
+
const reason = context.flags.reason;
|
|
178189
|
+
if (reason !== undefined && reason.length > 500)
|
|
178190
|
+
throw new CliInputError("--reason must be 500 characters or fewer.");
|
|
178191
|
+
requireKey(context);
|
|
178192
|
+
await send(context, "data", "POST", `/problems/${problemId}/reopen`, compact({ reason }));
|
|
178193
|
+
return { exitCode: 0 };
|
|
178194
|
+
}
|
|
178195
|
+
var SIGNAL_FIELD_FLAGS = [
|
|
178196
|
+
"name",
|
|
178197
|
+
"description",
|
|
178198
|
+
"pass-criteria",
|
|
178199
|
+
"fail-criteria",
|
|
178200
|
+
"polarity",
|
|
178201
|
+
"locus",
|
|
178202
|
+
"tool-names",
|
|
178203
|
+
"keyword-hints",
|
|
178204
|
+
"use-case-id",
|
|
178205
|
+
"message-types",
|
|
178206
|
+
"note",
|
|
178207
|
+
"file"
|
|
178208
|
+
];
|
|
178209
|
+
function signalBody(flags, cwd) {
|
|
178210
|
+
const fromFile = readBodyFile(flags, cwd);
|
|
178211
|
+
const scope = compact({
|
|
178212
|
+
toolNames: csv(flags["tool-names"]),
|
|
178213
|
+
keywordHints: csv(flags["keyword-hints"]),
|
|
178214
|
+
useCaseId: flags["use-case-id"],
|
|
178215
|
+
messageTypes: csv(flags["message-types"])
|
|
178216
|
+
});
|
|
178217
|
+
return {
|
|
178218
|
+
...fromFile,
|
|
178219
|
+
...compact({
|
|
178220
|
+
name: flags.name,
|
|
178221
|
+
description: flags.description,
|
|
178222
|
+
passCriteria: flags["pass-criteria"],
|
|
178223
|
+
failCriteria: flags["fail-criteria"],
|
|
178224
|
+
polarity: oneOf("polarity", flags.polarity, ["violation", "expectation"]),
|
|
178225
|
+
locus: oneOf("locus", flags.locus, ["agent", "tool_output", "user_input"]),
|
|
178226
|
+
note: flags.note
|
|
178227
|
+
}),
|
|
178228
|
+
...Object.keys(scope).length > 0 ? { scope: { ...fromFile.scope ?? {}, ...scope } } : {}
|
|
178229
|
+
};
|
|
178230
|
+
}
|
|
178231
|
+
var SIGNAL_USAGE = [
|
|
178232
|
+
"moda signals list custom signals",
|
|
178233
|
+
'moda signals draft --note="…" AI-draft criteria from a description',
|
|
178234
|
+
"moda signals create --name --description --pass-criteria --fail-criteria [--polarity --locus --tool-names=a,b] [--file=body.json]",
|
|
178235
|
+
"moda signals update <id> [same flags] edit a signal",
|
|
178236
|
+
"moda signals activate|pause|delete <id> (delete: drafts only; archive is dashboard-only)",
|
|
178237
|
+
"moda signals examples <id> add|update|remove --conversation-id=ID [--label=fits|does_not_fit --note --msg-index]",
|
|
178238
|
+
'moda signals refine <id> --request="…" propose a criteria edit',
|
|
178239
|
+
"moda signals revise <id> --conversation-ids=a,b re-derive criteria from labelled traces",
|
|
178240
|
+
"moda signals proposals <id> | accept <id> <proposal_id> | reject <id> <proposal_id>",
|
|
178241
|
+
"moda signals search <id> [--mode=wizard|full] | search-status <id> <search_id> | search-stop <id> <search_id>",
|
|
178242
|
+
"moda signals preview --file=detector.json [--conversation-ids=a,b --max-examples=N]",
|
|
178243
|
+
"All write subcommands accept --dry-run (prints the request, sends nothing)."
|
|
178244
|
+
].join(`
|
|
178245
|
+
`);
|
|
178246
|
+
async function runSignalsManagementCommand(sub, context) {
|
|
178247
|
+
const flags = context.flags;
|
|
178248
|
+
const args = context.positionals.slice(1);
|
|
178249
|
+
const arity = {
|
|
178250
|
+
draft: 0,
|
|
178251
|
+
create: 0,
|
|
178252
|
+
preview: 0,
|
|
178253
|
+
update: 1,
|
|
178254
|
+
activate: 1,
|
|
178255
|
+
pause: 1,
|
|
178256
|
+
delete: 1,
|
|
178257
|
+
examples: 2,
|
|
178258
|
+
refine: 1,
|
|
178259
|
+
revise: 1,
|
|
178260
|
+
proposals: 1,
|
|
178261
|
+
accept: 2,
|
|
178262
|
+
reject: 2,
|
|
178263
|
+
search: 1,
|
|
178264
|
+
"search-status": 2,
|
|
178265
|
+
"search-stop": 2
|
|
178266
|
+
};
|
|
178267
|
+
if (sub in arity)
|
|
178268
|
+
assertPositionals(`signals ${sub}`, args, arity[sub], SIGNAL_USAGE.split(`
|
|
178269
|
+
`)[0]);
|
|
178270
|
+
const base = () => `/tenants/${encodeURIComponent(requireTenant(context))}/custom-signals`;
|
|
178271
|
+
const id = (index = 0, what = "a signal id") => {
|
|
178272
|
+
const value = args[index];
|
|
178273
|
+
if (!value)
|
|
178274
|
+
throw new CliInputError(`moda signals ${sub} needs ${what}.`, `Usage:
|
|
178275
|
+
${SIGNAL_USAGE}`);
|
|
178276
|
+
return encodeURIComponent(value);
|
|
178277
|
+
};
|
|
178278
|
+
const start = () => requireKey(context);
|
|
178279
|
+
switch (sub) {
|
|
178280
|
+
case "draft": {
|
|
178281
|
+
assertFlags("signals draft", flags, ["note", "file", "dry-run"]);
|
|
178282
|
+
const body = { ...readBodyFile(flags, context.cwd), ...compact({ note: flags.note }) };
|
|
178283
|
+
if (!body.note)
|
|
178284
|
+
throw new CliInputError("--note is required (describe what the signal should catch).");
|
|
178285
|
+
start();
|
|
178286
|
+
await send(context, "control", "POST", `${base()}/draft`, body, { slow: true });
|
|
178287
|
+
return { exitCode: 0 };
|
|
178288
|
+
}
|
|
178289
|
+
case "create": {
|
|
178290
|
+
assertFlags("signals create", flags, [...SIGNAL_FIELD_FLAGS, "dry-run"]);
|
|
178291
|
+
const body = signalBody(flags, context.cwd);
|
|
178292
|
+
const missing = ["name", "description", "passCriteria", "failCriteria"].filter((field) => !body[field]);
|
|
178293
|
+
if (missing.length > 0) {
|
|
178294
|
+
throw new CliInputError(`Missing ${missing.join(", ")} for signals create.`, 'Pass --name --description --pass-criteria --fail-criteria, or a --file with those fields. Tip: `moda signals draft --note="…"` drafts them.');
|
|
178295
|
+
}
|
|
178296
|
+
start();
|
|
178297
|
+
await send(context, "control", "POST", base(), body);
|
|
178298
|
+
return { exitCode: 0 };
|
|
178299
|
+
}
|
|
178300
|
+
case "update": {
|
|
178301
|
+
assertFlags("signals update", flags, [...SIGNAL_FIELD_FLAGS, "dry-run"]);
|
|
178302
|
+
const signalId = id();
|
|
178303
|
+
const body = signalBody(flags, context.cwd);
|
|
178304
|
+
if (Object.keys(body).length === 0)
|
|
178305
|
+
throw new CliInputError("Nothing to update: pass at least one field flag or --file.");
|
|
178306
|
+
start();
|
|
178307
|
+
await send(context, "control", "PATCH", `${base()}/${signalId}`, body);
|
|
178308
|
+
return { exitCode: 0 };
|
|
178309
|
+
}
|
|
178310
|
+
case "activate":
|
|
178311
|
+
case "pause": {
|
|
178312
|
+
assertFlags(`signals ${sub}`, flags, ["dry-run"]);
|
|
178313
|
+
const signalId = id();
|
|
178314
|
+
start();
|
|
178315
|
+
await send(context, "control", "POST", `${base()}/${signalId}/${sub}`);
|
|
178316
|
+
return { exitCode: 0 };
|
|
178317
|
+
}
|
|
178318
|
+
case "delete": {
|
|
178319
|
+
assertFlags("signals delete", flags, ["dry-run"]);
|
|
178320
|
+
const signalId = id();
|
|
178321
|
+
start();
|
|
178322
|
+
await send(context, "control", "DELETE", `${base()}/${signalId}`);
|
|
178323
|
+
return { exitCode: 0 };
|
|
178324
|
+
}
|
|
178325
|
+
case "examples": {
|
|
178326
|
+
const signalId = id();
|
|
178327
|
+
const action = args[1];
|
|
178328
|
+
const conversationId = flags["conversation-id"];
|
|
178329
|
+
if (!action || !["add", "update", "remove"].includes(action)) {
|
|
178330
|
+
throw new CliInputError("Usage: moda signals examples <id> add|update|remove --conversation-id=ID …");
|
|
178331
|
+
}
|
|
178332
|
+
if (!conversationId)
|
|
178333
|
+
throw new CliInputError("--conversation-id is required.");
|
|
178334
|
+
if (action === "add") {
|
|
178335
|
+
assertFlags("signals examples add", flags, ["conversation-id", "label", "note", "msg-index", "msg-dedup-token", "criteria", "verdict", "dry-run"]);
|
|
178336
|
+
const label = oneOf("label", flags.label, ["fits", "does_not_fit"]);
|
|
178337
|
+
if (!label)
|
|
178338
|
+
throw new CliInputError("--label=fits|does_not_fit is required.");
|
|
178339
|
+
start();
|
|
178340
|
+
await send(context, "control", "POST", `${base()}/${signalId}/examples`, compact({
|
|
178341
|
+
conversationId,
|
|
178342
|
+
label,
|
|
178343
|
+
source: "api",
|
|
178344
|
+
note: flags.note,
|
|
178345
|
+
msgIndex: flags["msg-index"] !== undefined ? Number(flags["msg-index"]) : undefined,
|
|
178346
|
+
msgDedupToken: flags["msg-dedup-token"],
|
|
178347
|
+
criteria: oneOf("criteria", flags.criteria, ["pass", "fail"]),
|
|
178348
|
+
verdict: oneOf("verdict", flags.verdict, ["accept", "reject"])
|
|
178349
|
+
}));
|
|
178350
|
+
} else if (action === "update") {
|
|
178351
|
+
assertFlags("signals examples update", flags, ["conversation-id", "label", "note", "blurb", "dry-run"]);
|
|
178352
|
+
const body = compact({ label: oneOf("label", flags.label, ["fits", "does_not_fit"]), note: flags.note, blurb: flags.blurb });
|
|
178353
|
+
if (Object.keys(body).length === 0)
|
|
178354
|
+
throw new CliInputError("Nothing to update: pass --label, --note, or --blurb.");
|
|
178355
|
+
start();
|
|
178356
|
+
await send(context, "control", "PATCH", `${base()}/${signalId}/examples/${encodeURIComponent(conversationId)}`, body);
|
|
178357
|
+
} else {
|
|
178358
|
+
assertFlags("signals examples remove", flags, ["conversation-id", "dry-run"]);
|
|
178359
|
+
start();
|
|
178360
|
+
await send(context, "control", "DELETE", `${base()}/${signalId}/examples/${encodeURIComponent(conversationId)}`);
|
|
178361
|
+
}
|
|
178362
|
+
return { exitCode: 0 };
|
|
178363
|
+
}
|
|
178364
|
+
case "refine": {
|
|
178365
|
+
assertFlags("signals refine", flags, ["request", "dry-run"]);
|
|
178366
|
+
const signalId = id();
|
|
178367
|
+
const request = flags.request;
|
|
178368
|
+
if (!request || request.length > 2000)
|
|
178369
|
+
throw new CliInputError("--request (1–2000 characters) is required.");
|
|
178370
|
+
start();
|
|
178371
|
+
await send(context, "control", "POST", `${base()}/${signalId}/refine`, { request }, { slow: true });
|
|
178372
|
+
return { exitCode: 0 };
|
|
178373
|
+
}
|
|
178374
|
+
case "revise": {
|
|
178375
|
+
assertFlags("signals revise", flags, ["conversation-ids", "dry-run"]);
|
|
178376
|
+
const signalId = id();
|
|
178377
|
+
const conversationIds = csv(flags["conversation-ids"]);
|
|
178378
|
+
if (!conversationIds)
|
|
178379
|
+
throw new CliInputError("--conversation-ids=a,b is required.");
|
|
178380
|
+
start();
|
|
178381
|
+
await send(context, "control", "POST", `${base()}/${signalId}/revise`, { conversationIds }, { slow: true });
|
|
178382
|
+
return { exitCode: 0 };
|
|
178383
|
+
}
|
|
178384
|
+
case "proposals": {
|
|
178385
|
+
assertFlags("signals proposals", flags, []);
|
|
178386
|
+
const signalId = id();
|
|
178387
|
+
start();
|
|
178388
|
+
await send(context, "control", "GET", `${base()}/${signalId}/proposals`);
|
|
178389
|
+
return { exitCode: 0 };
|
|
178390
|
+
}
|
|
178391
|
+
case "accept":
|
|
178392
|
+
case "reject": {
|
|
178393
|
+
assertFlags(`signals ${sub}`, flags, ["dry-run"]);
|
|
178394
|
+
const signalId = id();
|
|
178395
|
+
const proposalId = id(1, "a proposal id (see `moda signals proposals <id>`)");
|
|
178396
|
+
start();
|
|
178397
|
+
await send(context, "control", "POST", `${base()}/${signalId}/proposals/${proposalId}/${sub}`);
|
|
178398
|
+
return { exitCode: 0 };
|
|
178399
|
+
}
|
|
178400
|
+
case "search": {
|
|
178401
|
+
assertFlags("signals search", flags, ["mode", "exclude-conversation-ids", "dry-run"]);
|
|
178402
|
+
const signalId = id();
|
|
178403
|
+
start();
|
|
178404
|
+
await send(context, "control", "POST", `${base()}/${signalId}/search`, compact({
|
|
178405
|
+
mode: oneOf("mode", flags.mode, ["wizard", "full"]),
|
|
178406
|
+
excludeConversationIds: csv(flags["exclude-conversation-ids"])
|
|
178407
|
+
}), { slow: true });
|
|
178408
|
+
return { exitCode: 0 };
|
|
178409
|
+
}
|
|
178410
|
+
case "search-status":
|
|
178411
|
+
case "search-stop": {
|
|
178412
|
+
assertFlags(`signals ${sub}`, flags, sub === "search-stop" ? ["dry-run"] : []);
|
|
178413
|
+
const signalId = id();
|
|
178414
|
+
const searchId = id(1, "a search id (returned by `moda signals search <id>`)");
|
|
178415
|
+
start();
|
|
178416
|
+
await send(context, "control", sub === "search-stop" ? "POST" : "GET", `${base()}/${signalId}/searches/${searchId}${sub === "search-stop" ? "/stop" : ""}`);
|
|
178417
|
+
return { exitCode: 0 };
|
|
178418
|
+
}
|
|
178419
|
+
case "preview": {
|
|
178420
|
+
assertFlags("signals preview", flags, ["file", "conversation-ids", "max-examples"]);
|
|
178421
|
+
const body = readBodyFile(flags, context.cwd);
|
|
178422
|
+
if (!body.detector)
|
|
178423
|
+
throw new CliInputError('--file must contain {"detector": {...}} (optionally scope).');
|
|
178424
|
+
start();
|
|
178425
|
+
await send(context, "control", "POST", `${base()}/detector-preview`, {
|
|
178426
|
+
...body,
|
|
178427
|
+
...compact({
|
|
178428
|
+
conversationIds: csv(flags["conversation-ids"]),
|
|
178429
|
+
maxExamples: flags["max-examples"] !== undefined ? Number(flags["max-examples"]) : undefined
|
|
178430
|
+
})
|
|
178431
|
+
});
|
|
178432
|
+
return { exitCode: 0 };
|
|
178433
|
+
}
|
|
178434
|
+
default:
|
|
178435
|
+
throw unknownSignalsSubcommandError(sub, args);
|
|
178436
|
+
}
|
|
178437
|
+
}
|
|
178438
|
+
var SIGNALS_MANAGEMENT_SUBCOMMANDS = new Set([
|
|
178439
|
+
"draft",
|
|
178440
|
+
"create",
|
|
178441
|
+
"update",
|
|
178442
|
+
"activate",
|
|
178443
|
+
"pause",
|
|
178444
|
+
"delete",
|
|
178445
|
+
"examples",
|
|
178446
|
+
"refine",
|
|
178447
|
+
"revise",
|
|
178448
|
+
"proposals",
|
|
178449
|
+
"accept",
|
|
178450
|
+
"reject",
|
|
178451
|
+
"search",
|
|
178452
|
+
"search-status",
|
|
178453
|
+
"search-stop",
|
|
178454
|
+
"preview"
|
|
178455
|
+
]);
|
|
178456
|
+
function unknownSignalsSubcommandError(sub, args = []) {
|
|
178457
|
+
if (sub === "archive") {
|
|
178458
|
+
const id = args[0] ?? "<signal_id>";
|
|
178459
|
+
return new CliInputError(`Unknown signals subcommand 'archive': archiving a signal is dashboard-only, so nothing was sent.`, `To stop a signal from running, pause it: moda signals pause ${id}. Drafts can be deleted with moda signals delete ${id}.`);
|
|
178460
|
+
}
|
|
178461
|
+
return new CliInputError(`Unknown signals subcommand '${sub}', so nothing was sent. Valid subcommands: ${[...SIGNALS_MANAGEMENT_SUBCOMMANDS].join(", ")}.`, `Bare 'moda signals' lists custom signals; 'moda signal <signal_id>' opens one. Usage:
|
|
178462
|
+
${SIGNAL_USAGE}`);
|
|
178463
|
+
}
|
|
178464
|
+
|
|
177995
178465
|
// src/analyst-tui.ts
|
|
177996
178466
|
class AnalystTui {
|
|
177997
178467
|
state;
|
|
@@ -178096,16 +178566,16 @@ class AnalystTui {
|
|
|
178096
178566
|
this.active = false;
|
|
178097
178567
|
}
|
|
178098
178568
|
pushTimeline(label, message) {
|
|
178099
|
-
const
|
|
178100
|
-
if (!
|
|
178569
|
+
const compact2 = compactWhitespace(message);
|
|
178570
|
+
if (!compact2)
|
|
178101
178571
|
return;
|
|
178102
178572
|
const last = this.state.timeline.at(-1);
|
|
178103
|
-
if (last?.label === label && last.message ===
|
|
178573
|
+
if (last?.label === label && last.message === compact2)
|
|
178104
178574
|
return;
|
|
178105
178575
|
this.state.timeline.push({
|
|
178106
178576
|
time: timeOfDay(new Date),
|
|
178107
178577
|
label,
|
|
178108
|
-
message:
|
|
178578
|
+
message: compact2
|
|
178109
178579
|
});
|
|
178110
178580
|
if (this.state.timeline.length > 80)
|
|
178111
178581
|
this.state.timeline.splice(0, this.state.timeline.length - 80);
|
|
@@ -178281,7 +178751,7 @@ function stripAnsi(value) {
|
|
|
178281
178751
|
}
|
|
178282
178752
|
|
|
178283
178753
|
// src/harness-remote.ts
|
|
178284
|
-
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as
|
|
178754
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
178285
178755
|
import { join as join2 } from "node:path";
|
|
178286
178756
|
|
|
178287
178757
|
// src/markdown-terminal.ts
|
|
@@ -178429,10 +178899,10 @@ import {
|
|
|
178429
178899
|
existsSync,
|
|
178430
178900
|
lstatSync,
|
|
178431
178901
|
mkdirSync,
|
|
178432
|
-
readFileSync,
|
|
178902
|
+
readFileSync as readFileSync2,
|
|
178433
178903
|
writeFileSync
|
|
178434
178904
|
} from "node:fs";
|
|
178435
|
-
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
178905
|
+
import { basename, dirname, join, relative, resolve as resolve2 } from "node:path";
|
|
178436
178906
|
import { confirm } from "@inquirer/prompts";
|
|
178437
178907
|
var HARNESS_REPORT_SCHEMA_VERSION = "harness_report.v0.1";
|
|
178438
178908
|
var HARNESS_REPORT_VALIDATION_SCHEMA_VERSION = "harness_report_validation.v0.1";
|
|
@@ -178950,12 +179420,12 @@ function loadHarnessReportForSync(rootDir, reportPath, options) {
|
|
|
178950
179420
|
`));
|
|
178951
179421
|
}
|
|
178952
179422
|
const approvalPath = join(rootDir, HARNESS_REPORT_APPROVAL_PATH);
|
|
178953
|
-
const approval = existsSync(approvalPath) ? JSON.parse(
|
|
179423
|
+
const approval = existsSync(approvalPath) ? JSON.parse(readFileSync2(approvalPath, "utf8")) : null;
|
|
178954
179424
|
const approved = approval?.schemaVersion === HARNESS_REPORT_APPROVAL_SCHEMA_VERSION && approval.reportId === report.reportId && approval.reportHash === hashHarnessReport(report) && approval.approved === true;
|
|
178955
179425
|
return { report, validation, approval, approved };
|
|
178956
179426
|
}
|
|
178957
179427
|
function readHarnessReport(reportPath) {
|
|
178958
|
-
return normalizeHarnessReport(JSON.parse(
|
|
179428
|
+
return normalizeHarnessReport(JSON.parse(readFileSync2(reportPath, "utf8")));
|
|
178959
179429
|
}
|
|
178960
179430
|
function normalizeHarnessReport(value) {
|
|
178961
179431
|
const report = cloneJson(value);
|
|
@@ -179546,7 +180016,7 @@ function limitReportEvidence(claims, citations) {
|
|
|
179546
180016
|
};
|
|
179547
180017
|
}
|
|
179548
180018
|
function resolveHarnessReportPath(rootDir, value) {
|
|
179549
|
-
return
|
|
180019
|
+
return resolve2(rootDir, value && value !== "true" ? value : HARNESS_REPORT_PATH);
|
|
179550
180020
|
}
|
|
179551
180021
|
function writeHarnessReportArtifacts(options) {
|
|
179552
180022
|
const written = [];
|
|
@@ -179683,14 +180153,14 @@ function upsertCitation(citations, citationIndex, evidence, rootDir) {
|
|
|
179683
180153
|
function citationExcerpt(rootDir, path, line) {
|
|
179684
180154
|
if (isUnsafeCitationPath(path))
|
|
179685
180155
|
return {};
|
|
179686
|
-
const absPath =
|
|
180156
|
+
const absPath = resolve2(rootDir, path);
|
|
179687
180157
|
if (!isInside(rootDir, absPath) || !existsSync(absPath))
|
|
179688
180158
|
return {};
|
|
179689
180159
|
try {
|
|
179690
180160
|
const stat = lstatSync(absPath);
|
|
179691
180161
|
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 128 * 1024)
|
|
179692
180162
|
return {};
|
|
179693
|
-
const lines =
|
|
180163
|
+
const lines = readFileSync2(absPath, "utf8").split(/\r?\n/);
|
|
179694
180164
|
const selected = line ? lines[line - 1] : lines.find((candidate) => candidate.trim().length > 0);
|
|
179695
180165
|
if (!selected)
|
|
179696
180166
|
return {};
|
|
@@ -179828,7 +180298,7 @@ function validateCitation(citation, rootDir, errors, warnings, options) {
|
|
|
179828
180298
|
errors.push(`Citation ${citation.id} points to an unsafe path.`);
|
|
179829
180299
|
return;
|
|
179830
180300
|
}
|
|
179831
|
-
const absPath =
|
|
180301
|
+
const absPath = resolve2(rootDir, citation.path);
|
|
179832
180302
|
if (!isInside(rootDir, absPath)) {
|
|
179833
180303
|
errors.push(`Citation ${citation.id} points outside the harness root.`);
|
|
179834
180304
|
return;
|
|
@@ -179847,7 +180317,7 @@ function validateCitation(citation, rootDir, errors, warnings, options) {
|
|
|
179847
180317
|
}
|
|
179848
180318
|
if (!stat.isFile())
|
|
179849
180319
|
errors.push(`Citation ${citation.id} does not point to a file.`);
|
|
179850
|
-
const lines =
|
|
180320
|
+
const lines = readFileSync2(absPath, "utf8").split(/\r?\n/);
|
|
179851
180321
|
if (citation.line !== undefined) {
|
|
179852
180322
|
const lineCount = lines.length;
|
|
179853
180323
|
if (citation.line < 1 || citation.line > lineCount) {
|
|
@@ -179898,7 +180368,7 @@ function isSecretishPath2(path) {
|
|
|
179898
180368
|
return name === ".env" || name.startsWith(".env.") || name.includes("secret") || name.includes("private-key") || name.endsWith(".pem");
|
|
179899
180369
|
}
|
|
179900
180370
|
function isInside(rootDir, absPath) {
|
|
179901
|
-
const rel = relative(
|
|
180371
|
+
const rel = relative(resolve2(rootDir), resolve2(absPath));
|
|
179902
180372
|
return rel === "" || !rel.startsWith("..") && !rel.startsWith("/");
|
|
179903
180373
|
}
|
|
179904
180374
|
function writeJson(path, value) {
|
|
@@ -179958,7 +180428,7 @@ function readRemoteRunState(rootDir) {
|
|
|
179958
180428
|
if (!existsSync2(path))
|
|
179959
180429
|
return;
|
|
179960
180430
|
try {
|
|
179961
|
-
const parsed = JSON.parse(
|
|
180431
|
+
const parsed = JSON.parse(readFileSync3(path, "utf8"));
|
|
179962
180432
|
if (!parsed || typeof parsed.run_id !== "string" || parsed.run_id.length === 0)
|
|
179963
180433
|
return;
|
|
179964
180434
|
return {
|
|
@@ -180317,8 +180787,8 @@ async function remoteAnalyzeFetch(url, apiKey, init, timeoutMs) {
|
|
|
180317
180787
|
}
|
|
180318
180788
|
|
|
180319
180789
|
// src/harness-artifact-bodies.ts
|
|
180320
|
-
import { existsSync as existsSync3, lstatSync as lstatSync2, readFileSync as
|
|
180321
|
-
import { basename as basename2, dirname as dirname2, isAbsolute, relative as relative2, resolve as
|
|
180790
|
+
import { existsSync as existsSync3, lstatSync as lstatSync2, readFileSync as readFileSync4, realpathSync } from "node:fs";
|
|
180791
|
+
import { basename as basename2, dirname as dirname2, isAbsolute, relative as relative2, resolve as resolve3 } from "node:path";
|
|
180322
180792
|
var MAX_SCANNED_FILE_BYTES2 = 512 * 1024;
|
|
180323
180793
|
var SNAPSHOT_BUDGET_SKIP_REASONS = new Set([
|
|
180324
180794
|
"file too large for harness scan",
|
|
@@ -180381,13 +180851,13 @@ function readBoundedRepoText(absPath, rootDir) {
|
|
|
180381
180851
|
return;
|
|
180382
180852
|
}
|
|
180383
180853
|
try {
|
|
180384
|
-
return
|
|
180854
|
+
return readFileSync4(absPath, "utf8");
|
|
180385
180855
|
} catch {
|
|
180386
180856
|
return;
|
|
180387
180857
|
}
|
|
180388
180858
|
}
|
|
180389
180859
|
function readRepoRelativeText(rootDir, relPath) {
|
|
180390
|
-
return readBoundedRepoText(
|
|
180860
|
+
return readBoundedRepoText(resolve3(rootDir, relPath), rootDir);
|
|
180391
180861
|
}
|
|
180392
180862
|
function isDedicatedToolFilePath(path) {
|
|
180393
180863
|
return /(^|\/)tools?\//i.test(path) && /\.(ts|tsx|js|mjs|py)$/i.test(path);
|
|
@@ -180414,8 +180884,8 @@ function extractToolBodyFromText(text, toolName) {
|
|
|
180414
180884
|
const normalizedName = toolName.replace(/\s+/g, "").toLowerCase();
|
|
180415
180885
|
for (let index = 0;index < lines.length; index += 1) {
|
|
180416
180886
|
const line = lines[index];
|
|
180417
|
-
const
|
|
180418
|
-
const mentionsTool =
|
|
180887
|
+
const compact2 = line.replace(/\s+/g, "").toLowerCase();
|
|
180888
|
+
const mentionsTool = compact2.includes(normalizedName) || compact2.includes(`def${normalizedName}`);
|
|
180419
180889
|
if (!mentionsTool)
|
|
180420
180890
|
continue;
|
|
180421
180891
|
if (line.includes("function_tool") || line.includes("tool(") || line.includes("createTool") || line.includes("functionTool") || line.includes("dynamicTool") || line.includes("new Tool") || line.includes("def ")) {
|
|
@@ -180428,14 +180898,14 @@ function annotatedSourceCandidates(sourcePath, annotation) {
|
|
|
180428
180898
|
const explicitSourcePath = normalizePath2(sourcePath) !== normalizePath2(annotation.evidence.path);
|
|
180429
180899
|
if (!explicitSourcePath) {
|
|
180430
180900
|
return [
|
|
180431
|
-
|
|
180432
|
-
|
|
180901
|
+
resolve3(annotation.rootDir, sourcePath),
|
|
180902
|
+
resolve3(dirname2(annotation.sourceAbsPath), sourcePath),
|
|
180433
180903
|
annotation.sourceAbsPath
|
|
180434
180904
|
];
|
|
180435
180905
|
}
|
|
180436
|
-
const rootAbs =
|
|
180437
|
-
const candidates = walkAncestorDirs(dirname2(annotation.sourceAbsPath), rootAbs).map((dir) =>
|
|
180438
|
-
candidates.push(
|
|
180906
|
+
const rootAbs = resolve3(annotation.rootDir);
|
|
180907
|
+
const candidates = walkAncestorDirs(dirname2(annotation.sourceAbsPath), rootAbs).map((dir) => resolve3(dir, sourcePath));
|
|
180908
|
+
candidates.push(resolve3(annotation.rootDir, sourcePath));
|
|
180439
180909
|
return candidates;
|
|
180440
180910
|
}
|
|
180441
180911
|
function readAnnotatedSourceText(sourcePath, annotation) {
|
|
@@ -180516,9 +180986,9 @@ function readSourcePathRelativeToEvidence(artifact, rootDir) {
|
|
|
180516
180986
|
const evidencePath = firstEvidencePath(artifact);
|
|
180517
180987
|
if (!evidencePath)
|
|
180518
180988
|
return;
|
|
180519
|
-
const rootAbs =
|
|
180520
|
-
for (const dir of walkAncestorDirs(dirname2(
|
|
180521
|
-
const text = readBoundedRepoText(
|
|
180989
|
+
const rootAbs = resolve3(rootDir);
|
|
180990
|
+
for (const dir of walkAncestorDirs(dirname2(resolve3(rootDir, evidencePath)), rootAbs)) {
|
|
180991
|
+
const text = readBoundedRepoText(resolve3(dir, artifact.sourcePath), rootDir);
|
|
180522
180992
|
if (text !== undefined)
|
|
180523
180993
|
return text;
|
|
180524
180994
|
}
|
|
@@ -180548,7 +181018,7 @@ function enrichScanCaptureMetadata(graph) {
|
|
|
180548
181018
|
|
|
180549
181019
|
// src/harness-candidates.ts
|
|
180550
181020
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
180551
|
-
import { basename as basename3, dirname as dirname3, extname, resolve as
|
|
181021
|
+
import { basename as basename3, dirname as dirname3, extname, resolve as resolve4 } from "node:path";
|
|
180552
181022
|
var EXCERPT_MAX_CHARS = 240;
|
|
180553
181023
|
var MAX_CANDIDATES_PER_FILE_PER_SIGNAL = 20;
|
|
180554
181024
|
var MIN_PROMPT_LITERAL_CHARS = 160;
|
|
@@ -181076,7 +181546,7 @@ function detectHarnessCandidatesInFiles(files) {
|
|
|
181076
181546
|
function detectHarnessCandidates(rootDir) {
|
|
181077
181547
|
const startedAt = Date.now();
|
|
181078
181548
|
const skipped = [];
|
|
181079
|
-
const root =
|
|
181549
|
+
const root = resolve4(rootDir);
|
|
181080
181550
|
const inventory = inventoryFiles(root, skipped, {
|
|
181081
181551
|
includeFile: (path) => PROMPT_DOC_EXTENSIONS.has(extname(path).toLowerCase()) || [".json", ".yaml", ".yml"].includes(extname(path).toLowerCase()) || extname(path).toLowerCase() === ".rs" && RUST_PROMPT_PATH_HINT.test(path)
|
|
181082
181552
|
});
|
|
@@ -181102,7 +181572,7 @@ function detectHarnessCandidates(rootDir) {
|
|
|
181102
181572
|
return redactDeep(report);
|
|
181103
181573
|
}
|
|
181104
181574
|
function writeHarnessCandidatesReport(report, outPath) {
|
|
181105
|
-
const target =
|
|
181575
|
+
const target = resolve4(outPath);
|
|
181106
181576
|
mkdirSync3(dirname3(target), { recursive: true });
|
|
181107
181577
|
writeFileSync3(target, `${JSON.stringify(report, null, 2)}
|
|
181108
181578
|
`, "utf8");
|
|
@@ -181162,8 +181632,8 @@ import { extname as extname8 } from "node:path";
|
|
|
181162
181632
|
// src/prompt-sources.ts
|
|
181163
181633
|
var import_typescript2 = __toESM(require_typescript(), 1);
|
|
181164
181634
|
import { createHash as createHash2 } from "node:crypto";
|
|
181165
|
-
import { lstatSync as lstatSync4, readFileSync as
|
|
181166
|
-
import { extname as extname3, isAbsolute as isAbsolute2, relative as relative3, resolve as
|
|
181635
|
+
import { lstatSync as lstatSync4, readFileSync as readFileSync7, realpathSync as realpathSync4 } from "node:fs";
|
|
181636
|
+
import { extname as extname3, isAbsolute as isAbsolute2, relative as relative3, resolve as resolve7 } from "node:path";
|
|
181167
181637
|
|
|
181168
181638
|
// src/prompt-frameworks.ts
|
|
181169
181639
|
var PYTHON_AGENT_MODULES = [
|
|
@@ -181184,15 +181654,15 @@ var TYPESCRIPT_AGENT_MODULES = [
|
|
|
181184
181654
|
|
|
181185
181655
|
// src/prompt-source-code.ts
|
|
181186
181656
|
var import_typescript = __toESM(require_typescript(), 1);
|
|
181187
|
-
import { existsSync as existsSync4, lstatSync as lstatSync3, readFileSync as
|
|
181188
|
-
import { dirname as dirname4, extname as extname2, join as join3, resolve as
|
|
181657
|
+
import { existsSync as existsSync4, lstatSync as lstatSync3, readFileSync as readFileSync5, realpathSync as realpathSync2 } from "node:fs";
|
|
181658
|
+
import { dirname as dirname4, extname as extname2, join as join3, resolve as resolve5 } from "node:path";
|
|
181189
181659
|
var EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
181190
181660
|
var MAX_BYTES = 2 * 1024 * 1024;
|
|
181191
181661
|
var MAX_DEPTH = 32;
|
|
181192
181662
|
var MAX_FILES = 256;
|
|
181193
181663
|
var MAX_GRAPH_BYTES = 16 * 1024 * 1024;
|
|
181194
181664
|
function extractCodeSource(rootDir, sourcePath, symbol, forceDependencyGraph = false) {
|
|
181195
|
-
const state = { root:
|
|
181665
|
+
const state = { root: resolve5(rootDir), files: [], unresolved: [], visiting: new Set, importsVisited: new Set, parsed: new Map, assignments: new Map, bytesRead: 0 };
|
|
181196
181666
|
const file = safeFile(state.root, state.root, sourcePath);
|
|
181197
181667
|
const parsed = parseFile(file, state);
|
|
181198
181668
|
const target = symbol ? findSymbol(parsed, symbol) : findInstructionCandidate(parsed);
|
|
@@ -181225,7 +181695,7 @@ function parseFile(filePath, state) {
|
|
|
181225
181695
|
const cached = state.parsed.get(path);
|
|
181226
181696
|
if (cached)
|
|
181227
181697
|
return cached;
|
|
181228
|
-
const text =
|
|
181698
|
+
const text = readFileSync5(path, "utf8");
|
|
181229
181699
|
state.bytesRead += Buffer.byteLength(text);
|
|
181230
181700
|
state.files.push(path);
|
|
181231
181701
|
const scriptKind = extname2(path) === ".json" ? import_typescript.default.ScriptKind.JSON : /\.tsx?$/.test(extname2(path)) ? import_typescript.default.ScriptKind.TSX : import_typescript.default.ScriptKind.JSX;
|
|
@@ -181240,7 +181710,7 @@ function parseFile(filePath, state) {
|
|
|
181240
181710
|
function safeFile(root, base, requested) {
|
|
181241
181711
|
if (requested.includes("\x00"))
|
|
181242
181712
|
throw new Error(`Prompt source path contains NUL: ${requested}`);
|
|
181243
|
-
const candidate =
|
|
181713
|
+
const candidate = resolve5(base, requested);
|
|
181244
181714
|
let cursor = candidate;
|
|
181245
181715
|
while (cursor !== root) {
|
|
181246
181716
|
let stat2;
|
|
@@ -181256,7 +181726,7 @@ function safeFile(root, base, requested) {
|
|
|
181256
181726
|
break;
|
|
181257
181727
|
cursor = next;
|
|
181258
181728
|
}
|
|
181259
|
-
const rootReal =
|
|
181729
|
+
const rootReal = resolve5(root);
|
|
181260
181730
|
let real;
|
|
181261
181731
|
try {
|
|
181262
181732
|
real = requireRealpath(candidate);
|
|
@@ -181593,7 +182063,7 @@ function isBindingMutated(file, name) {
|
|
|
181593
182063
|
function moduleSpecifier(from, specifier) {
|
|
181594
182064
|
if (!specifier.startsWith("."))
|
|
181595
182065
|
return;
|
|
181596
|
-
const base =
|
|
182066
|
+
const base = resolve5(dirname4(from), specifier);
|
|
181597
182067
|
const stripped = /\.(?:js|jsx|mjs|cjs)$/.test(base) ? base.slice(0, base.lastIndexOf(".")) : base;
|
|
181598
182068
|
for (const candidate of [base, stripped, ...EXTENSIONS.map((ext) => `${base}${ext}`), ...EXTENSIONS.map((ext) => `${stripped}${ext}`), ...EXTENSIONS.map((ext) => join3(base, `index${ext}`)), ...EXTENSIONS.map((ext) => join3(stripped, `index${ext}`))])
|
|
181599
182069
|
if (existsSync4(candidate) && lstatSync3(candidate).isFile())
|
|
@@ -181613,7 +182083,7 @@ function nodeRange(file, node) {
|
|
|
181613
182083
|
};
|
|
181614
182084
|
}
|
|
181615
182085
|
function inspectCodeSelectors(rootDir, sourcePath, symbol) {
|
|
181616
|
-
const state = { root:
|
|
182086
|
+
const state = { root: resolve5(rootDir), files: [], unresolved: [], visiting: new Set, importsVisited: new Set, parsed: new Map, assignments: new Map, bytesRead: 0 };
|
|
181617
182087
|
const parsed = parseFile(safeFile(state.root, state.root, sourcePath), state);
|
|
181618
182088
|
if (symbol) {
|
|
181619
182089
|
const node = findSymbol(parsed, symbol);
|
|
@@ -181663,8 +182133,8 @@ function referenceNames(node) {
|
|
|
181663
182133
|
|
|
181664
182134
|
// src/prompt-source-python.ts
|
|
181665
182135
|
import { spawnSync } from "node:child_process";
|
|
181666
|
-
import { readFileSync as
|
|
181667
|
-
import { resolve as
|
|
182136
|
+
import { readFileSync as readFileSync6, realpathSync as realpathSync3 } from "node:fs";
|
|
182137
|
+
import { resolve as resolve6 } from "node:path";
|
|
181668
182138
|
var PYTHON_AGENT_MODULES_LITERAL = JSON.stringify(PYTHON_AGENT_MODULES);
|
|
181669
182139
|
var SELECTOR_HELPER = String.raw`import ast,json,os,sys
|
|
181670
182140
|
request=json.loads(sys.stdin.read()); root=os.path.realpath(request['root']); path=os.path.abspath(request['path']); wanted=request.get('symbol')
|
|
@@ -181725,7 +182195,7 @@ else:
|
|
|
181725
182195
|
print(json.dumps({'candidates':found},ensure_ascii=False))`;
|
|
181726
182196
|
function inspectPythonSelectors(rootDir, sourcePath, symbol) {
|
|
181727
182197
|
const root = realpathSync3(rootDir);
|
|
181728
|
-
const absolute =
|
|
182198
|
+
const absolute = resolve6(root, sourcePath);
|
|
181729
182199
|
const result = spawnSync("python3", ["-I", "-c", SELECTOR_HELPER], {
|
|
181730
182200
|
input: JSON.stringify({ root, path: absolute, ...symbol ? { symbol } : {} }),
|
|
181731
182201
|
encoding: "utf8",
|
|
@@ -181870,7 +182340,7 @@ except SystemExit: pass
|
|
|
181870
182340
|
except Exception as error: print(json.dumps({'candidates':[],'error':str(error)}))`;
|
|
181871
182341
|
function discoverPythonPromptSources(rootDir, sourcePath) {
|
|
181872
182342
|
const result = spawnSync("python3", ["-I", "-c", DISCOVERY_HELPER], {
|
|
181873
|
-
input: JSON.stringify({ root: rootDir, path:
|
|
182343
|
+
input: JSON.stringify({ root: rootDir, path: resolve6(rootDir, sourcePath) }),
|
|
181874
182344
|
encoding: "utf8",
|
|
181875
182345
|
maxBuffer: 4 * 1024 * 1024,
|
|
181876
182346
|
timeout: 1e4
|
|
@@ -182130,7 +182600,7 @@ except Exception as e:
|
|
|
182130
182600
|
function extractPythonSource(rootDir, sourcePath, symbol, _forceDependencyGraph = false) {
|
|
182131
182601
|
let raw = "";
|
|
182132
182602
|
try {
|
|
182133
|
-
raw =
|
|
182603
|
+
raw = readFileSync6(sourcePath, "utf8");
|
|
182134
182604
|
} catch {}
|
|
182135
182605
|
const result = spawnSync("python3", ["-I", "-c", HELPER], {
|
|
182136
182606
|
input: JSON.stringify({ root: rootDir, path: sourcePath, symbol, force: _forceDependencyGraph }),
|
|
@@ -182224,7 +182694,7 @@ function resolvePromptSource(rootDir, source) {
|
|
|
182224
182694
|
} else if (source.selector?.symbol) {
|
|
182225
182695
|
throw new Error(`${sourcePath}: symbol selectors require a JavaScript, TypeScript, or Python source file`);
|
|
182226
182696
|
} else if (ext === ".json" || ext === ".yaml" || ext === ".yml" || hasPointer || source.kind === "messages") {
|
|
182227
|
-
const parsed = parseStructured(
|
|
182697
|
+
const parsed = parseStructured(readFileSync7(sourceAbs, "utf8"), sourcePath, ext);
|
|
182228
182698
|
const selected = hasPointer ? jsonPointer(parsed, source.selector.pointer, sourcePath) : parsed;
|
|
182229
182699
|
const selectedField = source.selector?.pointer?.split("/").at(-1)?.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
182230
182700
|
const inferredKind = !source.kind && selectedField && /^(?:template|system_template|instance_template)$/.test(selectedField) ? "template" : source.kind;
|
|
@@ -182234,7 +182704,7 @@ function resolvePromptSource(rootDir, source) {
|
|
|
182234
182704
|
messages = structured.messages;
|
|
182235
182705
|
kind = structured.kind;
|
|
182236
182706
|
} else {
|
|
182237
|
-
const raw =
|
|
182707
|
+
const raw = readFileSync7(sourceAbs, "utf8");
|
|
182238
182708
|
if (ext === ".md" && /\.prompt\.md$/i.test(sourcePath)) {
|
|
182239
182709
|
const legacy = parseLegacyMarkdown(raw);
|
|
182240
182710
|
content = legacy.content;
|
|
@@ -182257,7 +182727,7 @@ function resolvePromptSource(rootDir, source) {
|
|
|
182257
182727
|
const depAbs = safePath(root, dependency.path);
|
|
182258
182728
|
files.add(depAbs);
|
|
182259
182729
|
if (typeof dependency.selector?.pointer === "string") {
|
|
182260
|
-
const parsed = parseStructured(
|
|
182730
|
+
const parsed = parseStructured(readFileSync7(depAbs, "utf8"), dependency.path, extname3(depAbs).toLowerCase());
|
|
182261
182731
|
jsonPointer(parsed, dependency.selector.pointer, dependency.path);
|
|
182262
182732
|
} else if (dependency.selector?.symbol && CODE_EXTENSIONS2.has(extname3(depAbs).toLowerCase())) {
|
|
182263
182733
|
const dep = extname3(depAbs).toLowerCase() === ".py" ? extractPythonSource(root, depAbs, dependency.selector.symbol) : extractCodeSource(root, depAbs, dependency.selector.symbol);
|
|
@@ -182280,7 +182750,7 @@ function resolvePromptSource(rootDir, source) {
|
|
|
182280
182750
|
assertSafeMaterializedContent(content, sourcePath);
|
|
182281
182751
|
else
|
|
182282
182752
|
assertSafeMaterializedContent(materialized, sourcePath);
|
|
182283
|
-
const dependencies = [...files].sort().map((path) => ({ path: relative3(root, path).replaceAll("\\", "/"), contentHash: sha256(
|
|
182753
|
+
const dependencies = [...files].sort().map((path) => ({ path: relative3(root, path).replaceAll("\\", "/"), contentHash: sha256(readFileSync7(path)) }));
|
|
182284
182754
|
const sourceHash = sha256(JSON.stringify({ kind, content, systemPrompt: systemPrompt ?? null, messages: messages ?? null }));
|
|
182285
182755
|
const sourceDefinition = {
|
|
182286
182756
|
schemaVersion: 1,
|
|
@@ -182350,7 +182820,7 @@ function discoverStructuredPromptSources(rootDir, sourcePath) {
|
|
|
182350
182820
|
const ext = extname3(file).toLowerCase();
|
|
182351
182821
|
if (![".json", ".yaml", ".yml"].includes(ext))
|
|
182352
182822
|
return [];
|
|
182353
|
-
const value = parseStructured(
|
|
182823
|
+
const value = parseStructured(readFileSync7(file, "utf8"), sourcePath, ext);
|
|
182354
182824
|
const sources = [];
|
|
182355
182825
|
const base = sourcePath.replace(/\.[^.]+$/, "").replace(/[^A-Za-z0-9_.-]+/g, ".");
|
|
182356
182826
|
const dedicatedPath = /(^|\/)prompts?(?:\/|\.[^/]+$)|\.prompt\.[^.]+$/i.test(sourcePath);
|
|
@@ -182413,14 +182883,14 @@ function discoverCodePromptCandidates(rootDir, sourcePath) {
|
|
|
182413
182883
|
addName(candidate.symbol, candidate.knownBuilder === true);
|
|
182414
182884
|
modelInputs.add(candidate.symbol);
|
|
182415
182885
|
}
|
|
182416
|
-
for (const match of
|
|
182886
|
+
for (const match of readFileSync7(file, "utf8").matchAll(/^(?:(?:async\s+)?def\s+([A-Za-z_]\w*)|([A-Za-z_]\w*)\s*=\s*([^\n#]+))/gm)) {
|
|
182417
182887
|
const name = match[1] ?? match[2];
|
|
182418
182888
|
const rhs = match[3] ?? "";
|
|
182419
182889
|
if (name && isPromptName2(name) && (match[1] || /['"`\[({+]/.test(rhs) || /^[A-Za-z_]\w*\s*$/.test(rhs)))
|
|
182420
182890
|
addName(name, Boolean(match[1]));
|
|
182421
182891
|
}
|
|
182422
182892
|
} else {
|
|
182423
|
-
const sf = import_typescript2.default.createSourceFile(file,
|
|
182893
|
+
const sf = import_typescript2.default.createSourceFile(file, readFileSync7(file, "utf8"), import_typescript2.default.ScriptTarget.Latest, true, import_typescript2.default.ScriptKind.TSX);
|
|
182424
182894
|
const agentConstructors = new Set;
|
|
182425
182895
|
for (const statement of sf.statements) {
|
|
182426
182896
|
if (!import_typescript2.default.isImportDeclaration(statement) || !import_typescript2.default.isStringLiteral(statement.moduleSpecifier) || !TYPESCRIPT_AGENT_MODULES.includes(statement.moduleSpecifier.text))
|
|
@@ -182602,13 +183072,13 @@ function jsonPointer(value, pointer, path) {
|
|
|
182602
183072
|
return current;
|
|
182603
183073
|
}
|
|
182604
183074
|
function safeRoot(dir) {
|
|
182605
|
-
const root = realpathSync4(
|
|
183075
|
+
const root = realpathSync4(resolve7(dir));
|
|
182606
183076
|
if (!lstatSync4(root).isDirectory())
|
|
182607
183077
|
throw new Error(`Prompt source root is not a directory: ${dir}`);
|
|
182608
183078
|
return root;
|
|
182609
183079
|
}
|
|
182610
183080
|
function safePath(root, requested) {
|
|
182611
|
-
const candidate =
|
|
183081
|
+
const candidate = resolve7(root, requested);
|
|
182612
183082
|
rejectSymlinkPath(root, candidate, requested);
|
|
182613
183083
|
const real = realpathSync4(candidate);
|
|
182614
183084
|
if (!(real === root || real.startsWith(`${root}/`)))
|
|
@@ -182654,12 +183124,12 @@ function sha256(input) {
|
|
|
182654
183124
|
}
|
|
182655
183125
|
|
|
182656
183126
|
// src/prompt-source-verification/index.ts
|
|
182657
|
-
import { readFileSync as
|
|
183127
|
+
import { readFileSync as readFileSync11 } from "node:fs";
|
|
182658
183128
|
import { z } from "zod";
|
|
182659
183129
|
|
|
182660
183130
|
// src/prompt-source-validation.ts
|
|
182661
183131
|
import { existsSync as existsSync5, lstatSync as lstatSync5 } from "node:fs";
|
|
182662
|
-
import { extname as extname4, relative as relative4, resolve as
|
|
183132
|
+
import { extname as extname4, relative as relative4, resolve as resolve8 } from "node:path";
|
|
182663
183133
|
function checkPromptMapping(rootDir, unknownMapping) {
|
|
182664
183134
|
const repairs = [];
|
|
182665
183135
|
const unresolved = [];
|
|
@@ -182675,10 +183145,10 @@ function checkPromptMapping(rootDir, unknownMapping) {
|
|
|
182675
183145
|
if (JSON.stringify(normalized) !== JSON.stringify(sourceValue))
|
|
182676
183146
|
repairs.push("Omitted empty selector/dependency containers");
|
|
182677
183147
|
const source = validatePromptSource(normalized);
|
|
182678
|
-
const absolute =
|
|
183148
|
+
const absolute = resolve8(rootDir, source.path);
|
|
182679
183149
|
if (!existsSync5(absolute) || !lstatSync5(absolute).isFile())
|
|
182680
183150
|
throw new Error(`${source.path}: source path is unavailable`);
|
|
182681
|
-
const rel = relative4(
|
|
183151
|
+
const rel = relative4(resolve8(rootDir), absolute).replaceAll("\\", "/");
|
|
182682
183152
|
if (rel !== source.path)
|
|
182683
183153
|
repairs.push(`normalized path to ${rel}`);
|
|
182684
183154
|
let selected = { ...source, path: rel };
|
|
@@ -182743,23 +183213,23 @@ function isPromptDefinitionPath(path) {
|
|
|
182743
183213
|
}
|
|
182744
183214
|
|
|
182745
183215
|
// src/prompt-source-verification/evidence.ts
|
|
182746
|
-
import { readFileSync as
|
|
183216
|
+
import { readFileSync as readFileSync10 } from "node:fs";
|
|
182747
183217
|
import { extname as extname7 } from "node:path";
|
|
182748
183218
|
|
|
182749
183219
|
// src/prompt-source-verification/paths.ts
|
|
182750
183220
|
import { lstatSync as lstatSync6, realpathSync as realpathSync5 } from "node:fs";
|
|
182751
|
-
import { isAbsolute as isAbsolute3, relative as relative5, resolve as
|
|
183221
|
+
import { isAbsolute as isAbsolute3, relative as relative5, resolve as resolve9, sep } from "node:path";
|
|
182752
183222
|
function safePromptEvidencePath(rootDir, path) {
|
|
182753
183223
|
const root = realpathSync5(rootDir);
|
|
182754
183224
|
if (!path || isAbsolute3(path))
|
|
182755
183225
|
throw new Error("Evidence path must be repository-relative");
|
|
182756
|
-
const absolute =
|
|
183226
|
+
const absolute = resolve9(root, path);
|
|
182757
183227
|
const rel = relative5(root, absolute);
|
|
182758
183228
|
if (!rel || rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute3(rel))
|
|
182759
183229
|
throw new Error("Evidence escapes repository");
|
|
182760
183230
|
let current = root;
|
|
182761
183231
|
for (const part of rel.split(sep)) {
|
|
182762
|
-
current =
|
|
183232
|
+
current = resolve9(current, part);
|
|
182763
183233
|
if (lstatSync6(current).isSymbolicLink())
|
|
182764
183234
|
throw new Error("Evidence path is symlinked");
|
|
182765
183235
|
}
|
|
@@ -182773,14 +183243,14 @@ function safePromptEvidencePath(rootDir, path) {
|
|
|
182773
183243
|
var import_typescript3 = __toESM(require_typescript(), 1);
|
|
182774
183244
|
import { execFileSync } from "node:child_process";
|
|
182775
183245
|
import { extname as extname5 } from "node:path";
|
|
182776
|
-
import { readFileSync as
|
|
183246
|
+
import { readFileSync as readFileSync8 } from "node:fs";
|
|
182777
183247
|
function proveSink(root, sink) {
|
|
182778
183248
|
const file = safePromptEvidencePath(root, sink.path);
|
|
182779
183249
|
const cache = new Map;
|
|
182780
183250
|
if (!cache.has(file)) {
|
|
182781
183251
|
if (extname5(file) === ".py") {
|
|
182782
183252
|
try {
|
|
182783
|
-
const rows = JSON.parse(execFileSync("python3", ["-I", "-c", PYTHON_PROOF], { input:
|
|
183253
|
+
const rows = JSON.parse(execFileSync("python3", ["-I", "-c", PYTHON_PROOF], { input: readFileSync8(file, "utf8"), encoding: "utf8", timeout: 1e4, maxBuffer: 2 * 1024 * 1024 }));
|
|
182784
183254
|
cache.set(file, new Map(Object.entries(rows).map(([line, proof]) => [Number(line), proof])));
|
|
182785
183255
|
} catch {
|
|
182786
183256
|
cache.set(file, new Map);
|
|
@@ -182947,7 +183417,7 @@ print(json.dumps(rows))
|
|
|
182947
183417
|
`;
|
|
182948
183418
|
|
|
182949
183419
|
// src/prompt-source-location.ts
|
|
182950
|
-
import { readFileSync as
|
|
183420
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
182951
183421
|
import { extname as extname6 } from "node:path";
|
|
182952
183422
|
function structuredExcerpt(text, source) {
|
|
182953
183423
|
if (source.selector?.pointer === undefined)
|
|
@@ -183001,7 +183471,7 @@ function promptDefinitionExcerpt(rootDir, source) {
|
|
|
183001
183471
|
return;
|
|
183002
183472
|
return { ...extraction.range, text: extraction.sourceText, ...extraction.declarationKind ? { declarationKind: extraction.declarationKind } : {} };
|
|
183003
183473
|
}
|
|
183004
|
-
const text =
|
|
183474
|
+
const text = readFileSync9(file, "utf8");
|
|
183005
183475
|
return structuredExcerpt(text, source);
|
|
183006
183476
|
}
|
|
183007
183477
|
function promptDefinitionRange(rootDir, source) {
|
|
@@ -183028,7 +183498,7 @@ function reviewEvidence(rootDir, source, evidence) {
|
|
|
183028
183498
|
for (const item of evidence) {
|
|
183029
183499
|
let text;
|
|
183030
183500
|
try {
|
|
183031
|
-
text =
|
|
183501
|
+
text = readFileSync10(safePromptEvidencePath(rootDir, item.path), "utf8");
|
|
183032
183502
|
} catch (error) {
|
|
183033
183503
|
if (item.kind === "model_endpoint")
|
|
183034
183504
|
return { valid: false, endpointVerified: false, reason: error instanceof Error ? error.message : String(error) };
|
|
@@ -183143,7 +183613,7 @@ async function independentlyVerifyPromptSource(rootDir, source, verifier) {
|
|
|
183143
183613
|
let priorJudgment;
|
|
183144
183614
|
try {
|
|
183145
183615
|
const before = JSON.stringify(checked.resolved.sourceDefinition);
|
|
183146
|
-
const sourceBytes =
|
|
183616
|
+
const sourceBytes = readFileSync11(safePromptEvidencePath(rootDir, source.path), "utf8");
|
|
183147
183617
|
const instruction = promptVerificationInstruction(checked.source, checked.sourceHash, promptDefinitionExcerpt(rootDir, checked.source));
|
|
183148
183618
|
for (let attempt = 0;attempt < 2; attempt++) {
|
|
183149
183619
|
const repair = attempt ? `
|
|
@@ -183174,7 +183644,7 @@ ${output}` : "";
|
|
|
183174
183644
|
}
|
|
183175
183645
|
if (reviewed.truncated || reviewed.sourceHash !== checked.sourceHash)
|
|
183176
183646
|
return pending("Verifier output is truncated or cites a different source hash", reviewed.evidence, reviewed.role, normalizeUsage(undefined, false));
|
|
183177
|
-
if (before !== snapshot() ||
|
|
183647
|
+
if (before !== snapshot() || readFileSync11(safePromptEvidencePath(rootDir, source.path), "utf8") !== sourceBytes)
|
|
183178
183648
|
return pending("Source changed during verification", reviewed.evidence, reviewed.role, normalizeUsage(undefined, false));
|
|
183179
183649
|
if (reviewed.role === "non_prompt")
|
|
183180
183650
|
return { status: "rejected", reason: reviewed.reason, evidence: reviewed.evidence, sourceHash: checked.sourceHash, role: reviewed.role, usage: normalizeUsage(undefined, false) };
|
|
@@ -183534,8 +184004,8 @@ function applyPromptDiscovery(graph, discovery) {
|
|
|
183534
184004
|
}
|
|
183535
184005
|
|
|
183536
184006
|
// src/harness-candidate-promotion.ts
|
|
183537
|
-
import { readFileSync as
|
|
183538
|
-
import { resolve as
|
|
184007
|
+
import { readFileSync as readFileSync12 } from "node:fs";
|
|
184008
|
+
import { resolve as resolve10 } from "node:path";
|
|
183539
184009
|
var PROMOTED_CONFIDENCE = {
|
|
183540
184010
|
high: 0.85,
|
|
183541
184011
|
medium: 0.6
|
|
@@ -183565,7 +184035,7 @@ function readFileLines(rootDir, path, cache) {
|
|
|
183565
184035
|
return cached;
|
|
183566
184036
|
let lines;
|
|
183567
184037
|
try {
|
|
183568
|
-
lines =
|
|
184038
|
+
lines = readFileSync12(resolve10(rootDir, path), "utf8").split(/\r?\n/);
|
|
183569
184039
|
} catch {
|
|
183570
184040
|
lines = null;
|
|
183571
184041
|
}
|
|
@@ -184043,9 +184513,46 @@ var SCHEMA_VERSION = "harness.v0.1";
|
|
|
184043
184513
|
var REPORT_JSON_BEGIN = "MODA_HARNESS_REPORT_JSON_BEGIN";
|
|
184044
184514
|
var REPORT_JSON_END = "MODA_HARNESS_REPORT_JSON_END";
|
|
184045
184515
|
var EXTERNAL_ANALYST_ADAPTERS = ["claude", "codex", "cursor"];
|
|
184516
|
+
var HARNESS_FAMILY_FLAGS = [
|
|
184517
|
+
"agent-id",
|
|
184518
|
+
"allow-no-agents",
|
|
184519
|
+
"analyst",
|
|
184520
|
+
"analyst-command",
|
|
184521
|
+
"analyst-model",
|
|
184522
|
+
"assist",
|
|
184523
|
+
"concern",
|
|
184524
|
+
"dry-run",
|
|
184525
|
+
"experimental",
|
|
184526
|
+
"from",
|
|
184527
|
+
"from-report",
|
|
184528
|
+
"github-actions",
|
|
184529
|
+
"harness",
|
|
184530
|
+
"limit",
|
|
184531
|
+
"local",
|
|
184532
|
+
"no-remote",
|
|
184533
|
+
"offset",
|
|
184534
|
+
"out",
|
|
184535
|
+
"path",
|
|
184536
|
+
"remote",
|
|
184537
|
+
"report",
|
|
184538
|
+
"run",
|
|
184539
|
+
"run-id",
|
|
184540
|
+
"shards",
|
|
184541
|
+
"summary",
|
|
184542
|
+
"sync",
|
|
184543
|
+
"tenant",
|
|
184544
|
+
"tenant-id",
|
|
184545
|
+
"to",
|
|
184546
|
+
"version"
|
|
184547
|
+
];
|
|
184548
|
+
var HARNESS_DRY_RUN_SUBCOMMANDS = new Set(["scan", "sync", "delete", "analyze", "validate-report", "candidates"]);
|
|
184046
184549
|
async function runHarnessCommand(context) {
|
|
184047
184550
|
const subcommand = context.positionals[0] ?? "scan";
|
|
184048
|
-
|
|
184551
|
+
assertFlags(`harness ${subcommand}`, context.flags, HARNESS_FAMILY_FLAGS);
|
|
184552
|
+
if (context.dryRun && !HARNESS_DRY_RUN_SUBCOMMANDS.has(subcommand)) {
|
|
184553
|
+
throw new CliInputError(`'moda harness ${subcommand}' has no dry-run mode, so nothing was sent.`, `Remove --dry-run to run it for real. Harness commands with a real dry-run: ${[...HARNESS_DRY_RUN_SUBCOMMANDS].join(", ")}.`);
|
|
184554
|
+
}
|
|
184555
|
+
const rootDir = resolve11(context.cwd, context.flags.path ?? ".");
|
|
184049
184556
|
const selectedAgentId = selectedRuntimeAgentId(context.flags);
|
|
184050
184557
|
const tenant = resolveHarnessTenant(context.flags, context);
|
|
184051
184558
|
const scanPlan = buildCommandScanPlan(context, rootDir);
|
|
@@ -184097,6 +184604,10 @@ async function runHarnessCommand(context) {
|
|
|
184097
184604
|
if (!approved && !context.dryRun) {
|
|
184098
184605
|
throw new CliInputError("Harness report is not approved; refusing to sync.", "Run `moda harness validate-report`, review the report, then run `moda harness approve --yes` before syncing.");
|
|
184099
184606
|
}
|
|
184607
|
+
const wouldRefuse = context.dryRun ? [
|
|
184608
|
+
...approved ? [] : ["Harness report is not approved; the real sync would refuse. Run `moda harness approve --yes` first."],
|
|
184609
|
+
...syncQualityRefusal(report.graph, context.flags)
|
|
184610
|
+
] : [];
|
|
184100
184611
|
if (!context.dryRun)
|
|
184101
184612
|
assertHarnessGraphSyncQuality(report.graph, context.flags);
|
|
184102
184613
|
const syncGraph2 = graphForReport(report.graph);
|
|
@@ -184128,7 +184639,7 @@ async function runHarnessCommand(context) {
|
|
|
184128
184639
|
reportHash: approval.reportHash
|
|
184129
184640
|
} : undefined
|
|
184130
184641
|
};
|
|
184131
|
-
const response2 = await syncHarnessWithRemote(context, syncBody);
|
|
184642
|
+
const response2 = wouldRefuse.length > 0 ? undefined : await syncHarnessWithRemote(context, syncBody);
|
|
184132
184643
|
const statePath2 = response2 && !context.dryRun ? writeHarnessSyncState(rootDir, {
|
|
184133
184644
|
schemaVersion: "sync_state.v0.1",
|
|
184134
184645
|
updatedAt: new Date().toISOString(),
|
|
@@ -184168,17 +184679,19 @@ async function runHarnessCommand(context) {
|
|
|
184168
184679
|
remote: response2 ?? plannedDryRunRemote(plan2),
|
|
184169
184680
|
written: written2,
|
|
184170
184681
|
syncState: statePath2 ? { path: statePath2 } : undefined,
|
|
184171
|
-
dryRun: context.dryRun
|
|
184172
|
-
|
|
184173
|
-
|
|
184682
|
+
dryRun: context.dryRun,
|
|
184683
|
+
...wouldRefuse.length > 0 ? { wouldRefuse } : {}
|
|
184684
|
+
}, wouldRefuse.length > 0 ? { warnings: wouldRefuse, status: "error" } : undefined);
|
|
184685
|
+
return { exitCode: wouldRefuse.length > 0 ? 1 : 0 };
|
|
184174
184686
|
}
|
|
184175
184687
|
const graph = scanHarness({
|
|
184176
184688
|
rootDir,
|
|
184177
|
-
dryRun:
|
|
184689
|
+
dryRun: false,
|
|
184178
184690
|
tenantId: tenant?.tenantId,
|
|
184179
184691
|
tenantSource: tenant?.source,
|
|
184180
184692
|
pathWasExplicit: context.flags.path !== undefined
|
|
184181
184693
|
});
|
|
184694
|
+
const scanWouldRefuse = context.dryRun ? syncQualityRefusal(graph, context.flags) : [];
|
|
184182
184695
|
if (!context.dryRun)
|
|
184183
184696
|
assertHarnessGraphSyncQuality(graph, context.flags);
|
|
184184
184697
|
const syncGraph = graphForSync(graph);
|
|
@@ -184196,7 +184709,7 @@ async function runHarnessCommand(context) {
|
|
|
184196
184709
|
const written = context.dryRun ? [] : writeHarnessArtifacts(graph, rootDir, {
|
|
184197
184710
|
summary: context.flags.summary === "true"
|
|
184198
184711
|
});
|
|
184199
|
-
const response = await syncHarnessWithRemote(context, {
|
|
184712
|
+
const response = scanWouldRefuse.length > 0 ? undefined : await syncHarnessWithRemote(context, {
|
|
184200
184713
|
graph: syncGraph,
|
|
184201
184714
|
graphHash: localGraphHash,
|
|
184202
184715
|
sourceCommit
|
|
@@ -184225,20 +184738,21 @@ async function runHarnessCommand(context) {
|
|
|
184225
184738
|
remote: response ?? plannedDryRunRemote(plan),
|
|
184226
184739
|
written,
|
|
184227
184740
|
syncState: statePath ? { path: statePath } : undefined,
|
|
184228
|
-
dryRun: context.dryRun
|
|
184229
|
-
|
|
184230
|
-
|
|
184741
|
+
dryRun: context.dryRun,
|
|
184742
|
+
...scanWouldRefuse.length > 0 ? { wouldRefuse: scanWouldRefuse } : {}
|
|
184743
|
+
}, scanWouldRefuse.length > 0 ? { warnings: scanWouldRefuse, status: "error" } : undefined);
|
|
184744
|
+
return { exitCode: scanWouldRefuse.length > 0 ? 1 : 0 };
|
|
184231
184745
|
}
|
|
184232
184746
|
case "delete": {
|
|
184233
184747
|
const idOrKey = context.positionals[1] ?? (context.flags.harness && context.flags.harness !== "true" ? context.flags.harness : undefined);
|
|
184234
184748
|
if (!idOrKey) {
|
|
184235
184749
|
throw new CliInputError("Missing harness id or key to delete.", "Usage: moda harness delete <harness-id-or-key> [--yes]");
|
|
184236
184750
|
}
|
|
184237
|
-
const
|
|
184238
|
-
if (!resolveApiKey(
|
|
184751
|
+
const profileOptions2 = { profile: context.profile, env: context.env };
|
|
184752
|
+
if (!resolveApiKey(profileOptions2) && !context.dryRun) {
|
|
184239
184753
|
throw new CliInputError("No Moda API key found for harness delete.", "Run `moda init` first, set MODA_API_KEY, or select a profile with an API key.");
|
|
184240
184754
|
}
|
|
184241
|
-
const identity3 = describeSyncIdentity(
|
|
184755
|
+
const identity3 = describeSyncIdentity(profileOptions2);
|
|
184242
184756
|
if (identity3) {
|
|
184243
184757
|
const label = identity3.tenantSource === "api-key" ? describeSyncTenantLabel(identity3) : describeSyncTenantLabel({
|
|
184244
184758
|
tenantId: tenant?.tenantId ?? identity3.tenantId,
|
|
@@ -184256,7 +184770,7 @@ async function runHarnessCommand(context) {
|
|
|
184256
184770
|
return { exitCode: 0 };
|
|
184257
184771
|
}
|
|
184258
184772
|
await confirmHarnessDelete(context, idOrKey);
|
|
184259
|
-
const response = await callControlAPI(`/harnesses/${encodeURIComponent(idOrKey)}`, { method: "DELETE" },
|
|
184773
|
+
const response = await callControlAPI(`/harnesses/${encodeURIComponent(idOrKey)}`, { method: "DELETE" }, profileOptions2);
|
|
184260
184774
|
writeHumanProgress(context, `Deleted harness ${response.harnessKey ?? idOrKey} from tenant ${response.tenantId ?? "unknown"} ` + `(${response.deleted?.versions ?? 0} versions, ${response.deleted?.agents ?? 0} agents, ` + `${response.deleted?.artifacts ?? 0} artifacts, ${response.deleted?.relationships ?? 0} relationships).`);
|
|
184261
184775
|
context.output.writeData({ ...response, dryRun: false });
|
|
184262
184776
|
return { exitCode: 0 };
|
|
@@ -184299,7 +184813,7 @@ async function runHarnessCommand(context) {
|
|
|
184299
184813
|
throw new CliInputError("Focused remote prompt analysis is not supported yet.", "Use local --analyst=claude|codex|cursor|local-scan, or drop --concern for a full remote report.");
|
|
184300
184814
|
}
|
|
184301
184815
|
if (context.flags["github-actions"] === "true") {
|
|
184302
|
-
const { runGithubActionsAnalyze } = await import("./harness-github-actions-
|
|
184816
|
+
const { runGithubActionsAnalyze } = await import("./harness-github-actions-1qt4sgxd.js");
|
|
184303
184817
|
const result = await runGithubActionsAnalyze(rootDir, {
|
|
184304
184818
|
writeReport: (report2) => {
|
|
184305
184819
|
const normalized = normalizeHarnessReport(report2);
|
|
@@ -184441,7 +184955,7 @@ async function runHarnessCommand(context) {
|
|
|
184441
184955
|
throw new CliInputError("Missing output path for --out.", "Usage: moda harness candidates --out=<file>");
|
|
184442
184956
|
}
|
|
184443
184957
|
if (outFlag && !context.dryRun) {
|
|
184444
|
-
written.push(writeHarnessCandidatesReport(report,
|
|
184958
|
+
written.push(writeHarnessCandidatesReport(report, resolve11(context.cwd, outFlag)));
|
|
184445
184959
|
}
|
|
184446
184960
|
writeHumanProgress(context, `Harness candidates: ${report.stats.candidateCount} candidates across ${report.stats.filesWithCandidates} files (${report.stats.filesScanned} scanned, ${report.stats.filesPerSecond.toLocaleString()} files/sec).`);
|
|
184447
184961
|
context.output.writeData({ scanPlan, ...report, written, dryRun: context.dryRun });
|
|
@@ -184529,8 +185043,43 @@ async function runHarnessCommand(context) {
|
|
|
184529
185043
|
});
|
|
184530
185044
|
return { exitCode: 0 };
|
|
184531
185045
|
}
|
|
185046
|
+
case "list":
|
|
185047
|
+
case "show":
|
|
185048
|
+
case "versions":
|
|
185049
|
+
case "diff": {
|
|
185050
|
+
const readFlags = { list: ["limit", "offset"], show: ["version"], versions: ["limit", "offset"], diff: ["from", "to"] };
|
|
185051
|
+
assertFlags(`harness ${subcommand}`, context.flags, [...readFlags[subcommand], "path"]);
|
|
185052
|
+
assertPositionals(`harness ${subcommand}`, context.positionals, subcommand === "list" ? 1 : 2, `moda harness ${subcommand}${subcommand === "list" ? "" : " <harness-id-or-key>"}`);
|
|
185053
|
+
for (const flag of readFlags[subcommand]) {
|
|
185054
|
+
if (context.flags[flag] === "true")
|
|
185055
|
+
throw new CliInputError(`--${flag} needs a value.`);
|
|
185056
|
+
}
|
|
185057
|
+
const profileOptions2 = { profile: context.profile, env: context.env };
|
|
185058
|
+
if (!resolveApiKey(profileOptions2)) {
|
|
185059
|
+
throw new CliInputError(`No Moda API key found for harness ${subcommand}.`, "Set MODA_API_KEY, run `moda auth login --api-key`, or select a profile with an API key.");
|
|
185060
|
+
}
|
|
185061
|
+
const query = new URLSearchParams;
|
|
185062
|
+
const idOrKey = context.positionals[1];
|
|
185063
|
+
if (subcommand !== "list" && !idOrKey) {
|
|
185064
|
+
throw new CliInputError(`Missing harness id or key for harness ${subcommand}.`, `Usage: moda harness ${subcommand} <harness-id-or-key>${subcommand === "diff" ? " [--from=<versionId>] [--to=<versionId>]" : ""}. List them with \`moda harness list\`.`);
|
|
185065
|
+
}
|
|
185066
|
+
if ((subcommand === "list" || subcommand === "versions") && context.flags.limit)
|
|
185067
|
+
query.set("limit", context.flags.limit);
|
|
185068
|
+
if ((subcommand === "list" || subcommand === "versions") && context.flags.offset)
|
|
185069
|
+
query.set("offset", context.flags.offset);
|
|
185070
|
+
if (subcommand === "show" && context.flags.version)
|
|
185071
|
+
query.set("versionId", context.flags.version);
|
|
185072
|
+
if (subcommand === "diff" && context.flags.from)
|
|
185073
|
+
query.set("from", context.flags.from);
|
|
185074
|
+
if (subcommand === "diff" && context.flags.to)
|
|
185075
|
+
query.set("to", context.flags.to);
|
|
185076
|
+
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
185077
|
+
const path = subcommand === "list" ? `/harnesses${suffix}` : `/harnesses/${encodeURIComponent(idOrKey)}${subcommand === "show" ? "" : `/${subcommand}`}${suffix}`;
|
|
185078
|
+
context.output.writeData(await callControlAPI(path, {}, profileOptions2));
|
|
185079
|
+
return { exitCode: 0 };
|
|
185080
|
+
}
|
|
184532
185081
|
default:
|
|
184533
|
-
throw new CliInputError(`Unknown harness command '${subcommand}'.`, "Usage: moda harness analyze|pull|validate-report|approve|scan|candidates|sync|delete|agents|graph|explain|write-summary|status");
|
|
185082
|
+
throw new CliInputError(`Unknown harness command '${subcommand}'.`, "Usage: moda harness analyze|pull|validate-report|approve|scan|candidates|sync|delete|list|show|versions|diff|agents|graph|explain|write-summary|status");
|
|
184534
185083
|
}
|
|
184535
185084
|
}
|
|
184536
185085
|
function writeHarnessAnalyzeResult(context, payload) {
|
|
@@ -184598,7 +185147,7 @@ async function runPromptConcernAnalysis(context, rootDir, scanPlan, tenant) {
|
|
|
184598
185147
|
const manifest = join4(rootDir, ".moda/prompts.yml");
|
|
184599
185148
|
let existing = [];
|
|
184600
185149
|
if (existsSync6(manifest)) {
|
|
184601
|
-
const document = $parseDocument(
|
|
185150
|
+
const document = $parseDocument(readFileSync13(manifest, "utf8"));
|
|
184602
185151
|
if (document.errors.length)
|
|
184603
185152
|
throw new CliInputError("Invalid prompt manifest.", document.errors[0].message);
|
|
184604
185153
|
existing = document.toJS({ maxAliasCount: 20 })?.sources ?? [];
|
|
@@ -184827,7 +185376,7 @@ function buildExternalAnalystEnv(env) {
|
|
|
184827
185376
|
return next;
|
|
184828
185377
|
}
|
|
184829
185378
|
function readExternalAnalystReport(rootDir, result, adapter, concern) {
|
|
184830
|
-
const reportPath =
|
|
185379
|
+
const reportPath = resolve11(rootDir, HARNESS_REPORT_PATH);
|
|
184831
185380
|
if (existsSync6(reportPath))
|
|
184832
185381
|
return repairExternalAnalystReport(readHarnessReport(reportPath), rootDir, { concern });
|
|
184833
185382
|
const output = [
|
|
@@ -184842,7 +185391,7 @@ function readExternalAnalystReport(rootDir, result, adapter, concern) {
|
|
|
184842
185391
|
return parsed;
|
|
184843
185392
|
let debugHint = "";
|
|
184844
185393
|
try {
|
|
184845
|
-
const debugPath =
|
|
185394
|
+
const debugPath = resolve11(rootDir, MODA_DIR, "analyst-debug.log");
|
|
184846
185395
|
mkdirSync4(dirname5(debugPath), { recursive: true });
|
|
184847
185396
|
writeFileSync4(debugPath, [
|
|
184848
185397
|
`# analyst=${adapter} status=${result.status} signal=${result.signal} timedOut=${result.timedOut} maxBufferExceeded=${result.maxBufferExceeded}`,
|
|
@@ -185073,12 +185622,12 @@ function repairCitationLines(report, rootDir) {
|
|
|
185073
185622
|
if (citation.type !== "file" && citation.type !== "generated_doc" || !citation.path || !citation.excerpt)
|
|
185074
185623
|
continue;
|
|
185075
185624
|
const excerpt = citation.excerpt;
|
|
185076
|
-
const candidatePath =
|
|
185625
|
+
const candidatePath = resolve11(rootDir, citation.path);
|
|
185077
185626
|
if (!existsSync6(candidatePath))
|
|
185078
185627
|
continue;
|
|
185079
185628
|
let text;
|
|
185080
185629
|
try {
|
|
185081
|
-
text =
|
|
185630
|
+
text = readFileSync13(candidatePath, "utf8");
|
|
185082
185631
|
} catch {
|
|
185083
185632
|
continue;
|
|
185084
185633
|
}
|
|
@@ -185678,8 +186227,8 @@ function resolveExternalHarnessAnalystInvocation(options) {
|
|
|
185678
186227
|
}
|
|
185679
186228
|
function createPromptAnalystIsolation(adapter, rootDir) {
|
|
185680
186229
|
const moduleDir = dirname5(fileURLToPath(import.meta.url));
|
|
185681
|
-
const bundled =
|
|
185682
|
-
const source =
|
|
186230
|
+
const bundled = resolve11(moduleDir, "prompt-source-mcp.js");
|
|
186231
|
+
const source = resolve11(moduleDir, "prompt-source-mcp.ts");
|
|
185683
186232
|
const bundledServer = existsSync6(bundled);
|
|
185684
186233
|
const serverPath = bundledServer ? bundled : source;
|
|
185685
186234
|
const command = bundledServer ? process.execPath : resolveBunRuntime();
|
|
@@ -186188,11 +186737,11 @@ function splitCommandLine(commandLine) {
|
|
|
186188
186737
|
return commandLine.trim().split(/\s+/).filter(Boolean);
|
|
186189
186738
|
}
|
|
186190
186739
|
function truncateText(value, maxLength) {
|
|
186191
|
-
const
|
|
186192
|
-
return
|
|
186740
|
+
const compact2 = value.replace(/\s+/g, " ").trim();
|
|
186741
|
+
return compact2.length > maxLength ? `${compact2.slice(0, maxLength - 1)}...` : compact2;
|
|
186193
186742
|
}
|
|
186194
186743
|
function scanHarness(options = {}) {
|
|
186195
|
-
const rootDir =
|
|
186744
|
+
const rootDir = resolve11(options.rootDir ?? process.cwd());
|
|
186196
186745
|
const skipped = [];
|
|
186197
186746
|
const files = inventoryFiles(rootDir, skipped);
|
|
186198
186747
|
const annotations = files.flatMap((file) => parseAnnotations(file));
|
|
@@ -186294,7 +186843,7 @@ function collectSnapshotInputs(rootDir, maxFiles, maxTextBytes) {
|
|
|
186294
186843
|
let text = "";
|
|
186295
186844
|
if (isTextFile(path)) {
|
|
186296
186845
|
try {
|
|
186297
|
-
text =
|
|
186846
|
+
text = readFileSync13(current, "utf8");
|
|
186298
186847
|
inventoryTextBytes += Buffer.byteLength(text, "utf8");
|
|
186299
186848
|
} catch {
|
|
186300
186849
|
return;
|
|
@@ -186307,7 +186856,7 @@ function collectSnapshotInputs(rootDir, maxFiles, maxTextBytes) {
|
|
|
186307
186856
|
return inputs;
|
|
186308
186857
|
}
|
|
186309
186858
|
function buildSourceSnapshot(rootDir) {
|
|
186310
|
-
const root =
|
|
186859
|
+
const root = resolve11(rootDir);
|
|
186311
186860
|
const maxFiles = numericEnv("MODA_HARNESS_MAX_FILES", DEFAULT_MAX_INVENTORY_FILES);
|
|
186312
186861
|
const maxTextBytes = numericEnv("MODA_HARNESS_MAX_TEXT_BYTES", DEFAULT_MAX_INVENTORY_TEXT_BYTES);
|
|
186313
186862
|
const inputs = collectSnapshotInputs(root, maxFiles, maxTextBytes);
|
|
@@ -186517,8 +187066,8 @@ function plannedDryRunRemote(plan) {
|
|
|
186517
187066
|
}
|
|
186518
187067
|
async function syncHarnessWithRemote(context, body) {
|
|
186519
187068
|
assertHarnessGraphSyncSize(body.graph);
|
|
186520
|
-
const
|
|
186521
|
-
const hasApiKey = Boolean(resolveApiKey(
|
|
187069
|
+
const profileOptions2 = { profile: context.profile, env: context.env };
|
|
187070
|
+
const hasApiKey = Boolean(resolveApiKey(profileOptions2));
|
|
186522
187071
|
if (context.dryRun && !hasApiKey)
|
|
186523
187072
|
return;
|
|
186524
187073
|
return await callControlAPI("/harnesses/sync", {
|
|
@@ -186527,14 +187076,14 @@ async function syncHarnessWithRemote(context, body) {
|
|
|
186527
187076
|
...body,
|
|
186528
187077
|
dryRun: context.dryRun
|
|
186529
187078
|
})
|
|
186530
|
-
},
|
|
187079
|
+
}, profileOptions2);
|
|
186531
187080
|
}
|
|
186532
187081
|
function readHarnessSyncState(rootDir) {
|
|
186533
187082
|
const path = join4(rootDir, SYNC_STATE_PATH);
|
|
186534
187083
|
if (!existsSync6(path))
|
|
186535
187084
|
return;
|
|
186536
187085
|
try {
|
|
186537
|
-
const parsed = JSON.parse(
|
|
187086
|
+
const parsed = JSON.parse(readFileSync13(path, "utf8"));
|
|
186538
187087
|
if (!isRecord3(parsed) || parsed.schemaVersion !== "sync_state.v0.1") {
|
|
186539
187088
|
return;
|
|
186540
187089
|
}
|
|
@@ -186651,7 +187200,7 @@ function findFresherHarnessReports(rootDir) {
|
|
|
186651
187200
|
return fresher.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
186652
187201
|
}
|
|
186653
187202
|
function warnFresherSubdirHarnessReports(context, rootDir, explicitReport) {
|
|
186654
|
-
const explicitReportPath = explicitReport && explicitReport !== "true" ? normalizePath3(relative6(rootDir,
|
|
187203
|
+
const explicitReportPath = explicitReport && explicitReport !== "true" ? normalizePath3(relative6(rootDir, resolve11(rootDir, explicitReport))) : undefined;
|
|
186655
187204
|
if (explicitReportPath && explicitReportPath !== normalizePath3(HARNESS_REPORT_PATH))
|
|
186656
187205
|
return;
|
|
186657
187206
|
let fresher;
|
|
@@ -186668,7 +187217,7 @@ function warnFresherSubdirHarnessReports(context, rootDir, explicitReport) {
|
|
|
186668
187217
|
writeHarnessNotice(context, `A fresher harness report exists at ${newest.path} (this directory has ${rootState}). If you meant that report, re-run with --path=${subdir}.`);
|
|
186669
187218
|
}
|
|
186670
187219
|
function readHarnessGraph(manifestPath) {
|
|
186671
|
-
return JSON.parse(
|
|
187220
|
+
return JSON.parse(readFileSync13(manifestPath, "utf8"));
|
|
186672
187221
|
}
|
|
186673
187222
|
function writeHarnessArtifacts(graph, rootDir, options = {}) {
|
|
186674
187223
|
const modaDir = join4(rootDir, MODA_DIR);
|
|
@@ -186780,6 +187329,14 @@ function renderFrameworkAndProviderLines(graph) {
|
|
|
186780
187329
|
}
|
|
186781
187330
|
return lines;
|
|
186782
187331
|
}
|
|
187332
|
+
function syncQualityRefusal(graph, flags) {
|
|
187333
|
+
try {
|
|
187334
|
+
assertHarnessGraphSyncQuality(graph, flags);
|
|
187335
|
+
return [];
|
|
187336
|
+
} catch (error) {
|
|
187337
|
+
return [`The real sync would refuse: ${error instanceof Error ? error.message : String(error)}`];
|
|
187338
|
+
}
|
|
187339
|
+
}
|
|
186783
187340
|
function assertHarnessGraphSyncQuality(graph, flags) {
|
|
186784
187341
|
if (flags["allow-no-agents"] === "true")
|
|
186785
187342
|
return;
|
|
@@ -186845,7 +187402,7 @@ function explainAgent(graph, agent) {
|
|
|
186845
187402
|
}
|
|
186846
187403
|
function inventoryFiles(rootDir, skipped, options = {}) {
|
|
186847
187404
|
const files = [];
|
|
186848
|
-
const rootReal =
|
|
187405
|
+
const rootReal = resolve11(rootDir);
|
|
186849
187406
|
const maxFiles = numericEnv("MODA_HARNESS_MAX_FILES", DEFAULT_MAX_INVENTORY_FILES);
|
|
186850
187407
|
const maxTextBytes = numericEnv("MODA_HARNESS_MAX_TEXT_BYTES", DEFAULT_MAX_INVENTORY_TEXT_BYTES);
|
|
186851
187408
|
let textBytes = 0;
|
|
@@ -186899,7 +187456,7 @@ function inventoryFiles(rootDir, skipped, options = {}) {
|
|
|
186899
187456
|
recordSkipped(skipped, { path: rel, reason: "scan text budget exceeded" });
|
|
186900
187457
|
} else {
|
|
186901
187458
|
try {
|
|
186902
|
-
item.text =
|
|
187459
|
+
item.text = readFileSync13(current, "utf8");
|
|
186903
187460
|
textBytes += Buffer.byteLength(item.text, "utf8");
|
|
186904
187461
|
} catch {
|
|
186905
187462
|
recordSkipped(skipped, { path: rel, reason: "text read failed" });
|
|
@@ -187206,7 +187763,7 @@ function maybeAddPromptArtifact(graph, file) {
|
|
|
187206
187763
|
if (!isPrompt)
|
|
187207
187764
|
return;
|
|
187208
187765
|
const id = stableId2("prompt", file.path);
|
|
187209
|
-
const text = file.text ??
|
|
187766
|
+
const text = file.text ?? readFileSync13(file.absPath, "utf8");
|
|
187210
187767
|
upsertArtifact(graph, {
|
|
187211
187768
|
id,
|
|
187212
187769
|
type: "prompt",
|
|
@@ -187787,7 +188344,7 @@ function detectProviderPackagesInManifests(rootDir) {
|
|
|
187787
188344
|
const packageJsonPath = join4(rootDir, "package.json");
|
|
187788
188345
|
if (existsSync6(packageJsonPath)) {
|
|
187789
188346
|
try {
|
|
187790
|
-
const deps = packageDependencyNames(
|
|
188347
|
+
const deps = packageDependencyNames(readFileSync13(packageJsonPath, "utf8"));
|
|
187791
188348
|
for (const provider of PROVIDER_CATALOG) {
|
|
187792
188349
|
for (const name of provider.packageNames) {
|
|
187793
188350
|
if (deps.has(name))
|
|
@@ -187799,7 +188356,7 @@ function detectProviderPackagesInManifests(rootDir) {
|
|
|
187799
188356
|
const pyprojectPath = join4(rootDir, "pyproject.toml");
|
|
187800
188357
|
if (existsSync6(pyprojectPath)) {
|
|
187801
188358
|
try {
|
|
187802
|
-
const deps = pyprojectDependencyNames(
|
|
188359
|
+
const deps = pyprojectDependencyNames(readFileSync13(pyprojectPath, "utf8"));
|
|
187803
188360
|
for (const provider of PROVIDER_CATALOG) {
|
|
187804
188361
|
for (const name of provider.packageNames) {
|
|
187805
188362
|
if (deps.has(name.toLowerCase()))
|
|
@@ -188182,7 +188739,7 @@ function upsertDeployment(graph, next) {
|
|
|
188182
188739
|
}
|
|
188183
188740
|
function contentHashForAnnotatedSource(sourcePath, annotation) {
|
|
188184
188741
|
const bodyAnnotation = annotation;
|
|
188185
|
-
const rootCandidate =
|
|
188742
|
+
const rootCandidate = resolve11(annotation.rootDir, sourcePath);
|
|
188186
188743
|
const candidates = [
|
|
188187
188744
|
rootCandidate,
|
|
188188
188745
|
...annotatedSourceCandidates(sourcePath, bodyAnnotation).filter((c) => c !== rootCandidate)
|
|
@@ -188216,7 +188773,7 @@ function readSmallTextFileForHash(absPath, rootDir) {
|
|
|
188216
188773
|
if (!isTextFile(rel))
|
|
188217
188774
|
return;
|
|
188218
188775
|
try {
|
|
188219
|
-
return
|
|
188776
|
+
return readFileSync13(absPath, "utf8");
|
|
188220
188777
|
} catch {
|
|
188221
188778
|
return;
|
|
188222
188779
|
}
|
|
@@ -188309,4 +188866,4 @@ function hashText(text) {
|
|
|
188309
188866
|
return createHash4("sha256").update(text).digest("hex");
|
|
188310
188867
|
}
|
|
188311
188868
|
|
|
188312
|
-
export { ApiError, callDataAPI, callControlAPI, getApiRequestCount, resetApiRequestCount, $parseDocument, $stringify, require_typescript, inspectCodeSelectors, inspectPythonSelectors, resolvePromptSource, shouldColorTerminalOutput, terminalStyles, stripAnsi2 as stripAnsi, renderMarkdownForTerminal, HARNESS_REPORT_PATH, HARNESS_REPORT_APPROVAL_PATH, HARNESS_ANALYZE_CONCERNS, validateHarnessReport, readHarnessReport, hashHarnessReport, hashStableJson, startRemoteAnalyze, pollRemoteAnalyzeUntilDone, isRecoverableRemoteRun, checkPromptMapping, safePromptEvidencePath, discoverHarnessPromptSources, renderDoctorHuman, renderStatusHuman, renderInitBanner, renderInitStep, renderInitNote, renderInitSetupPlan, renderInitComplete, runHarnessCommand, writeHarnessAnalyzeResult, emitWrittenArtifacts, analyzeHarnessPrompts, repairExternalAnalystReport, deriveRelationshipsFromGraph, mergeDeterministicArtifacts, describeCodingAgentEvent, analystEventProgress, isRetryableExternalAnalystFailure, sleep, summarizeInvalidAnalystReport, isDeterministicLocalAnalyst, resolveHarnessAnalyzeConcern, detectAvailableCodingAgents, codingAgentDisplayName, runCodingAgent, resolveAnalystModel, renderExternalHarnessAnalystPrompt, CONCERN_CANDIDATE_KINDS, SEED_CANDIDATE_KIND_LABELS, renderAnalystCandidateLines, renderAnalystSeedLines, truncateText, scanHarness, summarizeHarness, buildSourceSnapshot, writeHumanProgress, readHarnessSyncState, describeSyncIdentity, describeSyncTenantLabel, findFresherHarnessReports, writeHarnessArtifacts, assertHarnessGraphSyncQuality, graphForSync, inventoryFiles, numericEnv, numericEnvAllowZero, computeDeterministicFloor, stableId2 as stableId, titleFromId2 as titleFromId, promptNameFromPath };
|
|
188869
|
+
export { ApiError, callDataAPI, callControlAPI, getApiRequestCount, resetApiRequestCount, $parseDocument, $stringify, require_typescript, inspectCodeSelectors, inspectPythonSelectors, resolvePromptSource, assertFlags, assertPositionals, runUsersCommand, runUserCommand, runProblemReopenCommand, runSignalsManagementCommand, SIGNALS_MANAGEMENT_SUBCOMMANDS, unknownSignalsSubcommandError, shouldColorTerminalOutput, terminalStyles, stripAnsi2 as stripAnsi, renderMarkdownForTerminal, HARNESS_REPORT_PATH, HARNESS_REPORT_APPROVAL_PATH, HARNESS_ANALYZE_CONCERNS, validateHarnessReport, readHarnessReport, hashHarnessReport, hashStableJson, startRemoteAnalyze, pollRemoteAnalyzeUntilDone, isRecoverableRemoteRun, checkPromptMapping, safePromptEvidencePath, discoverHarnessPromptSources, renderDoctorHuman, renderStatusHuman, renderInitBanner, renderInitStep, renderInitNote, renderInitSetupPlan, renderInitComplete, runHarnessCommand, writeHarnessAnalyzeResult, emitWrittenArtifacts, analyzeHarnessPrompts, repairExternalAnalystReport, deriveRelationshipsFromGraph, mergeDeterministicArtifacts, describeCodingAgentEvent, analystEventProgress, isRetryableExternalAnalystFailure, sleep, summarizeInvalidAnalystReport, isDeterministicLocalAnalyst, resolveHarnessAnalyzeConcern, detectAvailableCodingAgents, codingAgentDisplayName, runCodingAgent, resolveAnalystModel, renderExternalHarnessAnalystPrompt, CONCERN_CANDIDATE_KINDS, SEED_CANDIDATE_KIND_LABELS, renderAnalystCandidateLines, renderAnalystSeedLines, truncateText, scanHarness, summarizeHarness, buildSourceSnapshot, writeHumanProgress, readHarnessSyncState, describeSyncIdentity, describeSyncTenantLabel, findFresherHarnessReports, writeHarnessArtifacts, assertHarnessGraphSyncQuality, graphForSync, inventoryFiles, numericEnv, numericEnvAllowZero, computeDeterministicFloor, stableId2 as stableId, titleFromId2 as titleFromId, promptNameFromPath };
|