@moda-ai/cli 1.55.4 → 1.55.5
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 +7 -0
- package/dist/{cli-73v8mqh1.js → cli-dw1zrtvn.js} +41 -31
- package/dist/{cli-9v0c1xe1.js → cli-tzqez7mw.js} +36 -19
- package/dist/{cli-9kyw5qx0.js → cli-vxdtfys2.js} +4 -2
- package/dist/{cli-zp7a97sp.js → cli-xtj2m4hs.js} +29 -1
- package/dist/{cli-t5v7mhvj.js → cli-zbpetb7v.js} +6 -1
- package/dist/cli.js +216 -64
- package/dist/{harness-github-actions-5syjp1sz.js → harness-github-actions-f3xffdf7.js} +8 -2
- package/dist/{harness-x6kaz47j.js → harness-sqkgk49d.js} +2 -2
- package/dist/{index-8vvznb36.js → index-025z9q34.js} +8 -5
- package/dist/prompt-source-mcp.js +2 -2
- package/dist/{provision-2z73642d.js → provision-69h38y7d.js} +3 -3
- package/package.json +1 -1
- package/skills/integration/index.json +2 -2
- package/skills/moda-cli/SKILL.md +12 -7
package/README.md
CHANGED
|
@@ -127,6 +127,13 @@ Legacy aliases (same behavior, kept for existing scripts): `moda conversations`
|
|
|
127
127
|
`moda cluster-conversations` = `moda cluster-traces`, `--conversations` = `--traces`
|
|
128
128
|
(`moda problem`, `moda prompts ab`), `--signal=conversations` = `--signal=traces`.
|
|
129
129
|
|
|
130
|
+
Flag aliases: `moda context --message-index=N` = `--msg-index=N`, and
|
|
131
|
+
`moda users --limit=N` = `--page-size=N`. Each command rejects a flag it does
|
|
132
|
+
not take, and time windows differ by command: `--days-back=N` (a whole number,
|
|
133
|
+
1-90) on the overview, Problem and detection commands, `--time-range` on
|
|
134
|
+
`traces`, `search` and `clusters`. Boolean flags accept `true`/`false`, `1`/`0`,
|
|
135
|
+
`yes`/`no` and `on`/`off`.
|
|
136
|
+
|
|
130
137
|
Prompt management:
|
|
131
138
|
|
|
132
139
|
```bash
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
safePromptEvidencePath,
|
|
22
22
|
scanHarness,
|
|
23
23
|
setPlatformTenantOverride
|
|
24
|
-
} from "./cli-
|
|
24
|
+
} from "./cli-tzqez7mw.js";
|
|
25
25
|
import {
|
|
26
26
|
SKILL_SOURCE_HARNESS,
|
|
27
27
|
SKILL_SOURCE_INTEGRATION_BUNDLED,
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
import {
|
|
35
35
|
isAuthSessionValid,
|
|
36
36
|
loadAuthSession
|
|
37
|
-
} from "./cli-
|
|
37
|
+
} from "./cli-zbpetb7v.js";
|
|
38
38
|
import {
|
|
39
39
|
CliInputError,
|
|
40
40
|
EXIT_ERROR,
|
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
getModaPaths,
|
|
46
46
|
isLoopbackBaseUrl,
|
|
47
47
|
loadProfileConfig,
|
|
48
|
+
recordApiRequest,
|
|
48
49
|
resolveApiKey,
|
|
49
50
|
resolveApiTenantId,
|
|
50
51
|
resolveIngestUrl,
|
|
@@ -53,7 +54,7 @@ import {
|
|
|
53
54
|
resolveTenantId,
|
|
54
55
|
secretFilePathFromRef,
|
|
55
56
|
validateConfig
|
|
56
|
-
} from "./cli-
|
|
57
|
+
} from "./cli-xtj2m4hs.js";
|
|
57
58
|
import {
|
|
58
59
|
__commonJS,
|
|
59
60
|
__require,
|
|
@@ -6659,7 +6660,7 @@ async function runPromptsCommand(input, legacyFlags, legacyProfileOptions) {
|
|
|
6659
6660
|
await runPromptRegistryRead(subcommand, positionals, flags, profileOptions, context);
|
|
6660
6661
|
break;
|
|
6661
6662
|
default:
|
|
6662
|
-
throw new
|
|
6663
|
+
throw new CliInputError(`Unknown prompts command '${subcommand}'. Use init, status, diff, migrate, sync, promote, ab, propose, list, show, proposals, usage, replay-runs, or decide.`, undefined, "unknown_subcommand");
|
|
6663
6664
|
}
|
|
6664
6665
|
return 0;
|
|
6665
6666
|
}
|
|
@@ -6668,7 +6669,7 @@ async function initPrompts(options = {}) {
|
|
|
6668
6669
|
const manifestPath = resolve4(cwd, MANIFEST_PATH);
|
|
6669
6670
|
const lockPath = resolve4(cwd, LOCK_PATH);
|
|
6670
6671
|
if (existsSync2(MODA_DIR) && lstatSync(MODA_DIR).isSymbolicLink())
|
|
6671
|
-
throw new
|
|
6672
|
+
throw new CliInputError(".moda must not be a symlink.");
|
|
6672
6673
|
mkdirSync(MODA_DIR, { recursive: true });
|
|
6673
6674
|
let created = false;
|
|
6674
6675
|
if (!existsSync2(MANIFEST_PATH)) {
|
|
@@ -6751,7 +6752,7 @@ async function runPromptSyncExclusive(flags, profileOptions, options) {
|
|
|
6751
6752
|
const analyzedDefinitions = new Map;
|
|
6752
6753
|
if (flags["no-analyze"] !== "true") {
|
|
6753
6754
|
options.onProgress?.("Analyzing prompt sources before sync.");
|
|
6754
|
-
const { analyzeHarnessPrompts } = await import("./harness-
|
|
6755
|
+
const { analyzeHarnessPrompts } = await import("./harness-sqkgk49d.js");
|
|
6755
6756
|
const result = await analyzeHarnessPrompts({
|
|
6756
6757
|
rootDir: process.cwd(),
|
|
6757
6758
|
existing: established.flatMap((prompt) => prompt.sourceDefinition ? [prompt.sourceDefinition.source] : []),
|
|
@@ -6782,7 +6783,7 @@ async function runPromptSyncExclusive(flags, profileOptions, options) {
|
|
|
6782
6783
|
const attribution = checkPromptAttribution(process.cwd(), prompts.map((prompt) => prompt.key));
|
|
6783
6784
|
const brokenAttribution = attribution.references.filter((reference) => reference.status === "missing");
|
|
6784
6785
|
if (brokenAttribution.length) {
|
|
6785
|
-
throw new
|
|
6786
|
+
throw new CliInputError(`Prompt attribution keys are absent from this sync: ${brokenAttribution.map((reference) => `'${reference.key}' at ${reference.path}:${reference.line}`).join(", ")}. Map the referenced key to its verified source in .moda/prompts.yml, or update the runtime lookup to the intended mapped key. No prompt versions were uploaded.`);
|
|
6786
6787
|
}
|
|
6787
6788
|
for (const prompt of prompts) {
|
|
6788
6789
|
const analyzed = analyzedDefinitions.get(prompt.key);
|
|
@@ -6793,7 +6794,7 @@ async function runPromptSyncExclusive(flags, profileOptions, options) {
|
|
|
6793
6794
|
const previousLockHash = hashFile(LOCK_PATH);
|
|
6794
6795
|
const missing = Object.keys(previous?.prompts ?? {}).filter((key) => !prompts.some((prompt) => prompt.key === key));
|
|
6795
6796
|
if (missing.length && flags["allow-untrack"] !== "true") {
|
|
6796
|
-
throw new
|
|
6797
|
+
throw new CliInputError(`Previously synced prompts are absent: ${missing.join(", ")}. Restore their sources, or use --allow-untrack to explicitly remove local tracking.`);
|
|
6797
6798
|
}
|
|
6798
6799
|
const sourceCommit = getGitCommit();
|
|
6799
6800
|
const manifestHash = manifestUpdate === undefined ? originalManifestHash : sha256(manifestUpdate);
|
|
@@ -6888,11 +6889,11 @@ async function promotePrompt(positionals, flags, profileOptions, context) {
|
|
|
6888
6889
|
const label = flags.label;
|
|
6889
6890
|
const versionId = flags.version || flags["version-id"];
|
|
6890
6891
|
if (!key)
|
|
6891
|
-
throw new
|
|
6892
|
+
throw new CliInputError("Usage: moda prompts promote <prompt_key> --label=prod --version=<version_id>", undefined, "missing_positional");
|
|
6892
6893
|
if (!label)
|
|
6893
|
-
throw new
|
|
6894
|
+
throw new CliInputError("Missing required flag: --label=dev|staging|prod");
|
|
6894
6895
|
if (!versionId)
|
|
6895
|
-
throw new
|
|
6896
|
+
throw new CliInputError("Missing required flag: --version=<version_id>");
|
|
6896
6897
|
const response = await callControlAPI(`/prompts/${encodeURIComponent(key)}/labels`, {
|
|
6897
6898
|
method: "POST",
|
|
6898
6899
|
body: JSON.stringify({ label, versionId })
|
|
@@ -6951,9 +6952,9 @@ function discoverManifestPrompts(manifest, extraSources = []) {
|
|
|
6951
6952
|
for (const pattern of manifest.promptPaths) {
|
|
6952
6953
|
const positive = pattern.startsWith("!") ? pattern.slice(1) : pattern;
|
|
6953
6954
|
if (isAbsolute3(positive) || positive.split(/[\\/]/).includes(".."))
|
|
6954
|
-
throw new
|
|
6955
|
+
throw new CliInputError(`Prompt pattern must stay inside the repository: ${pattern}`);
|
|
6955
6956
|
if (!pattern.startsWith("!") && !import_fast_glob.default.isDynamicPattern(pattern) && !existsSync2(resolve4(root, pattern))) {
|
|
6956
|
-
throw new
|
|
6957
|
+
throw new CliInputError(`Configured prompt file is missing: ${pattern}`);
|
|
6957
6958
|
}
|
|
6958
6959
|
}
|
|
6959
6960
|
const paths = import_fast_glob.default.sync(manifest.promptPaths, {
|
|
@@ -6979,7 +6980,7 @@ function discoverManifestPrompts(manifest, extraSources = []) {
|
|
|
6979
6980
|
const seen = new Set;
|
|
6980
6981
|
for (const prompt of prompts) {
|
|
6981
6982
|
if (seen.has(prompt.key))
|
|
6982
|
-
throw new
|
|
6983
|
+
throw new CliInputError(`Duplicate prompt key '${prompt.key}'. Give each source a unique stable key.`);
|
|
6983
6984
|
seen.add(prompt.key);
|
|
6984
6985
|
}
|
|
6985
6986
|
return prompts.sort((a, b) => a.key.localeCompare(b.key));
|
|
@@ -7081,7 +7082,7 @@ async function migratePromptManifest(options = {}) {
|
|
|
7081
7082
|
let addedSources = [];
|
|
7082
7083
|
let pendingSources = [];
|
|
7083
7084
|
if (options.discover) {
|
|
7084
|
-
const { analyzeHarnessPrompts } = await import("./harness-
|
|
7085
|
+
const { analyzeHarnessPrompts } = await import("./harness-sqkgk49d.js");
|
|
7085
7086
|
const result = await analyzeHarnessPrompts({
|
|
7086
7087
|
rootDir: root,
|
|
7087
7088
|
existing: manifest.sources,
|
|
@@ -7167,14 +7168,14 @@ function assertContainedSource(root, path) {
|
|
|
7167
7168
|
const abs = resolve4(root, path);
|
|
7168
7169
|
const rel = relative(realpathSync(root), realpathSync(abs));
|
|
7169
7170
|
if (rel === ".." || rel.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) || isAbsolute3(rel))
|
|
7170
|
-
throw new
|
|
7171
|
+
throw new CliInputError(`Prompt source escapes repository: ${path}`);
|
|
7171
7172
|
let cursor = abs;
|
|
7172
7173
|
while (cursor !== resolve4(root)) {
|
|
7173
7174
|
if (lstatSync(cursor).isSymbolicLink())
|
|
7174
|
-
throw new
|
|
7175
|
+
throw new CliInputError(`Prompt source uses a symlink: ${path}`);
|
|
7175
7176
|
const next = dirname2(cursor);
|
|
7176
7177
|
if (next === cursor)
|
|
7177
|
-
throw new
|
|
7178
|
+
throw new CliInputError(`Prompt source escapes repository: ${path}`);
|
|
7178
7179
|
cursor = next;
|
|
7179
7180
|
}
|
|
7180
7181
|
}
|
|
@@ -7184,8 +7185,13 @@ function parsePromptFile(absPath) {
|
|
|
7184
7185
|
if (absPath.endsWith(".json")) {
|
|
7185
7186
|
const document = $parseDocument(raw, { uniqueKeys: true });
|
|
7186
7187
|
if (document.errors.length)
|
|
7187
|
-
throw new
|
|
7188
|
-
|
|
7188
|
+
throw new CliInputError(`${sourcePath}: ${document.errors[0].message}`);
|
|
7189
|
+
let parsed;
|
|
7190
|
+
try {
|
|
7191
|
+
parsed = JSON.parse(raw);
|
|
7192
|
+
} catch (err) {
|
|
7193
|
+
throw new CliInputError(`${sourcePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
7194
|
+
}
|
|
7189
7195
|
const key2 = parsed.key || keyFromPath(sourcePath);
|
|
7190
7196
|
const hasContent = typeof parsed.content === "string" && parsed.content.trim().length > 0;
|
|
7191
7197
|
const hasSystemPrompt = typeof parsed.systemPrompt === "string" && parsed.systemPrompt.trim().length > 0;
|
|
@@ -7197,7 +7203,7 @@ function parsePromptFile(absPath) {
|
|
|
7197
7203
|
return typeof content2 === "string" ? content2.trim().length > 0 : Array.isArray(content2) && content2.some((part) => part && typeof part === "object" && part.type === "text" && typeof part.text === "string" && part.text.trim().length > 0);
|
|
7198
7204
|
});
|
|
7199
7205
|
if (!hasContent && !hasSystemPrompt && !hasMessages && !hasTemplate) {
|
|
7200
|
-
throw new
|
|
7206
|
+
throw new CliInputError(`${sourcePath}: prompt JSON requires non-empty content, systemPrompt, messages, or a text template.`);
|
|
7201
7207
|
}
|
|
7202
7208
|
const content = hasContent ? parsed.content : hasSystemPrompt ? parsed.systemPrompt : hasMessages ? JSON.stringify(parsed.messages, null, 2) : parsed.template;
|
|
7203
7209
|
return normalizePrompt({ ...parsed, key: key2, name: parsed.name || key2, sourcePath, content });
|
|
@@ -7239,23 +7245,23 @@ function readManifest(root = process.cwd()) {
|
|
|
7239
7245
|
assertContainedSource(root, MANIFEST_PATH);
|
|
7240
7246
|
const doc = $parseDocument(readFileSync(resolve4(root, MANIFEST_PATH), "utf8"), { uniqueKeys: true });
|
|
7241
7247
|
if (doc.errors.length)
|
|
7242
|
-
throw new
|
|
7248
|
+
throw new CliInputError(`Invalid ${MANIFEST_PATH}: ${doc.errors[0].message}`);
|
|
7243
7249
|
const parsed = doc.toJS({ maxAliasCount: 20 });
|
|
7244
7250
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || ![1, 2].includes(parsed.version))
|
|
7245
|
-
throw new
|
|
7251
|
+
throw new CliInputError(`${MANIFEST_PATH} requires version: 1 or 2.`);
|
|
7246
7252
|
if (Object.keys(parsed).some((key) => !["version", "prompt_paths", "sources"].includes(key)))
|
|
7247
|
-
throw new
|
|
7253
|
+
throw new CliInputError("Unknown prompt manifest field. Use version, prompt_paths, and sources.");
|
|
7248
7254
|
if (parsed.prompt_paths !== undefined && (!Array.isArray(parsed.prompt_paths) || parsed.prompt_paths.some((p) => typeof p !== "string" || !p.trim())))
|
|
7249
|
-
throw new
|
|
7255
|
+
throw new CliInputError("prompt_paths must be an array of nonempty patterns.");
|
|
7250
7256
|
if (parsed.sources !== undefined && !Array.isArray(parsed.sources))
|
|
7251
|
-
throw new
|
|
7257
|
+
throw new CliInputError("sources must be an array of prompt source descriptors.");
|
|
7252
7258
|
const sources = parsed.sources ?? [];
|
|
7253
7259
|
const seen = new Set;
|
|
7254
7260
|
for (const source of sources) {
|
|
7255
7261
|
if (!source || typeof source.key !== "string" || !source.key.trim() || typeof source.path !== "string" || !source.path.trim())
|
|
7256
|
-
throw new
|
|
7262
|
+
throw new CliInputError("Every prompt source requires a stable key and path.");
|
|
7257
7263
|
if (seen.has(source.key))
|
|
7258
|
-
throw new
|
|
7264
|
+
throw new CliInputError(`Duplicate prompt source key '${source.key}'.`);
|
|
7259
7265
|
seen.add(source.key);
|
|
7260
7266
|
}
|
|
7261
7267
|
return { version: parsed.version, promptPaths: parsed.prompt_paths ?? (parsed.version === 1 ? DEFAULT_PROMPT_PATHS : []), sources };
|
|
@@ -7354,7 +7360,7 @@ function mergePromptSources(existingSources, sources) {
|
|
|
7354
7360
|
for (const source of sources) {
|
|
7355
7361
|
const existing = merged.get(source.key);
|
|
7356
7362
|
if (existing && stableJson(existing) !== stableJson(source)) {
|
|
7357
|
-
throw new
|
|
7363
|
+
throw new CliInputError(`Harness source '${source.key}' conflicts with an existing mapping. Edit ${MANIFEST_PATH} explicitly to change its source; no mappings were imported.`);
|
|
7358
7364
|
}
|
|
7359
7365
|
merged.set(source.key, source);
|
|
7360
7366
|
}
|
|
@@ -7364,7 +7370,7 @@ function atomicWrite(path, content) {
|
|
|
7364
7370
|
mkdirSync(dirname2(path), { recursive: true });
|
|
7365
7371
|
assertContainedSource(process.cwd(), dirname2(path));
|
|
7366
7372
|
if (existsSync2(path) && lstatSync(path).isSymbolicLink())
|
|
7367
|
-
throw new
|
|
7373
|
+
throw new CliInputError(`Refusing to overwrite symlink: ${path}`);
|
|
7368
7374
|
const temp = `${path}.${process.pid}.tmp`;
|
|
7369
7375
|
try {
|
|
7370
7376
|
writeFileSync2(temp, content, { flag: "wx" });
|
|
@@ -7409,7 +7415,7 @@ function writeLock(prompts, synced) {
|
|
|
7409
7415
|
}
|
|
7410
7416
|
function assertReplayablePrompt(prompt) {
|
|
7411
7417
|
if (prompt.sourceDefinition && ["builder", "template"].includes(prompt.sourceDefinition.kind)) {
|
|
7412
|
-
throw new
|
|
7418
|
+
throw new CliInputError(`Prompt '${prompt.key}' is a ${prompt.sourceDefinition.kind}. Run its renderer with controlled inputs; source code cannot be replayed as final instructions.`);
|
|
7413
7419
|
}
|
|
7414
7420
|
}
|
|
7415
7421
|
function parseFrontmatter(raw) {
|
|
@@ -7636,6 +7642,7 @@ async function fetchSkills(status) {
|
|
|
7636
7642
|
const timeout = setTimeout(() => controller.abort(), SKILLS_REQUEST_TIMEOUT_MS);
|
|
7637
7643
|
let response;
|
|
7638
7644
|
try {
|
|
7645
|
+
recordApiRequest();
|
|
7639
7646
|
response = await fetch(url, {
|
|
7640
7647
|
headers: { Authorization: `Bearer ${apiKey}` },
|
|
7641
7648
|
signal: controller.signal
|
|
@@ -7673,6 +7680,7 @@ async function skillRunsRequest(url) {
|
|
|
7673
7680
|
const timeout = setTimeout(() => controller.abort(), SKILLS_REQUEST_TIMEOUT_MS);
|
|
7674
7681
|
let response;
|
|
7675
7682
|
try {
|
|
7683
|
+
recordApiRequest();
|
|
7676
7684
|
response = await fetch(url, {
|
|
7677
7685
|
headers: { Authorization: `Bearer ${apiKey}` },
|
|
7678
7686
|
signal: controller.signal
|
|
@@ -8281,6 +8289,7 @@ async function generateSkills(flags) {
|
|
|
8281
8289
|
};
|
|
8282
8290
|
if (tenantId)
|
|
8283
8291
|
headers["X-Moda-Tenant-Id"] = tenantId;
|
|
8292
|
+
recordApiRequest();
|
|
8284
8293
|
const response = await fetch(endpoint, {
|
|
8285
8294
|
method: "POST",
|
|
8286
8295
|
headers,
|
|
@@ -9044,6 +9053,7 @@ async function cloudDataFlowChecks(ingestUrl, apiKey) {
|
|
|
9044
9053
|
async function ingestReachabilityCheck(ingestUrl, apiKey) {
|
|
9045
9054
|
const url = `${ingestUrl.replace(/\/+$/, "")}/`;
|
|
9046
9055
|
try {
|
|
9056
|
+
recordApiRequest();
|
|
9047
9057
|
const response = await fetch(url, {
|
|
9048
9058
|
method: "GET",
|
|
9049
9059
|
headers: { Authorization: `Bearer ${apiKey}` },
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
CliAccessError,
|
|
2
3
|
CliInputError,
|
|
3
4
|
CliInputRequiredError,
|
|
4
5
|
DEFAULT_MAX_INVENTORY_FILES,
|
|
@@ -16,6 +17,7 @@ import {
|
|
|
16
17
|
isSkippedPathPrefix,
|
|
17
18
|
isTextFile,
|
|
18
19
|
packSnapshot,
|
|
20
|
+
recordApiRequest,
|
|
19
21
|
redactDeep,
|
|
20
22
|
redactString,
|
|
21
23
|
resolveApiKey,
|
|
@@ -25,7 +27,7 @@ import {
|
|
|
25
27
|
resolveTenantId,
|
|
26
28
|
shouldInventoryFile,
|
|
27
29
|
stringOption
|
|
28
|
-
} from "./cli-
|
|
30
|
+
} from "./cli-xtj2m4hs.js";
|
|
29
31
|
import {
|
|
30
32
|
__commonJS,
|
|
31
33
|
__require,
|
|
@@ -177929,7 +177931,6 @@ var REQUEST_TIMEOUT_MS = 30000;
|
|
|
177929
177931
|
var MAX_RETRIES = 3;
|
|
177930
177932
|
var INITIAL_BACKOFF_MS = 500;
|
|
177931
177933
|
var NETWORK_RETRY_DELAY_MS = 1000;
|
|
177932
|
-
var apiRequestCount = 0;
|
|
177933
177934
|
|
|
177934
177935
|
class ApiError extends Error {
|
|
177935
177936
|
statusCode;
|
|
@@ -178004,7 +178005,6 @@ function isRetryable(status) {
|
|
|
178004
178005
|
return status === 429 || status >= 500;
|
|
178005
178006
|
}
|
|
178006
178007
|
async function callDataAPI(endpoint, init = { method: "GET" }, requestOptions = {}) {
|
|
178007
|
-
apiRequestCount++;
|
|
178008
178008
|
const url = `${resolveModaBaseUrl()}/api/v1/data${endpoint}`;
|
|
178009
178009
|
return callModaAPI(url, init, {}, requestOptions);
|
|
178010
178010
|
}
|
|
@@ -178028,6 +178028,7 @@ async function callModaAPI(url, options, profileOptions = {}, requestOptions = {
|
|
|
178028
178028
|
const controller = new AbortController;
|
|
178029
178029
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
178030
178030
|
try {
|
|
178031
|
+
recordApiRequest();
|
|
178031
178032
|
const response = await fetch(url, {
|
|
178032
178033
|
...options,
|
|
178033
178034
|
headers: {
|
|
@@ -178073,12 +178074,6 @@ async function callModaAPI(url, options, profileOptions = {}, requestOptions = {
|
|
|
178073
178074
|
}
|
|
178074
178075
|
throw new NetworkError(`Request retries exhausted: ${url}`);
|
|
178075
178076
|
}
|
|
178076
|
-
function getApiRequestCount() {
|
|
178077
|
-
return apiRequestCount;
|
|
178078
|
-
}
|
|
178079
|
-
function resetApiRequestCount() {
|
|
178080
|
-
apiRequestCount = 0;
|
|
178081
|
-
}
|
|
178082
178077
|
|
|
178083
178078
|
// src/parity-commands.ts
|
|
178084
178079
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -178200,6 +178195,7 @@ async function runUsersCommand(context) {
|
|
|
178200
178195
|
"window",
|
|
178201
178196
|
"page",
|
|
178202
178197
|
"page-size",
|
|
178198
|
+
"limit",
|
|
178203
178199
|
"search",
|
|
178204
178200
|
"cohort",
|
|
178205
178201
|
"sort",
|
|
@@ -178214,12 +178210,15 @@ async function runUsersCommand(context) {
|
|
|
178214
178210
|
if (context.positionals.length > 0) {
|
|
178215
178211
|
throw new CliInputError(`'moda users' takes no arguments. For one user use 'moda user <user_id>'.`);
|
|
178216
178212
|
}
|
|
178213
|
+
if (flags.limit !== undefined && flags["page-size"] !== undefined && flags.limit !== flags["page-size"]) {
|
|
178214
|
+
throw new CliInputError(`Got --limit=${flags.limit} and --page-size=${flags["page-size"]}; they are the same flag for 'moda users', so nothing was sent.`, "Pass only one of --limit / --page-size.", "flag_conflict");
|
|
178215
|
+
}
|
|
178217
178216
|
requireKey(context);
|
|
178218
178217
|
const tenantId = requireTenant(context);
|
|
178219
178218
|
const query = new URLSearchParams(compact({
|
|
178220
178219
|
window: oneOf("window", flags.window, WINDOWS),
|
|
178221
178220
|
page: flags.page,
|
|
178222
|
-
pageSize: flags["page-size"],
|
|
178221
|
+
pageSize: flags["page-size"] ?? flags.limit,
|
|
178223
178222
|
search: flags.search,
|
|
178224
178223
|
cohort: oneOf("cohort", flags.cohort, USER_COHORTS),
|
|
178225
178224
|
sortBy: oneOf("sort", flags.sort, USER_SORTS),
|
|
@@ -178495,19 +178494,36 @@ async function runSignalsManagementCommand(sub, context) {
|
|
|
178495
178494
|
if (!body.detector)
|
|
178496
178495
|
throw new CliInputError('--file must contain {"detector": {...}} (optionally scope).');
|
|
178497
178496
|
start();
|
|
178498
|
-
|
|
178499
|
-
|
|
178500
|
-
|
|
178501
|
-
|
|
178502
|
-
|
|
178503
|
-
|
|
178504
|
-
|
|
178497
|
+
try {
|
|
178498
|
+
await send(context, "control", "POST", `${base()}/detector-preview`, {
|
|
178499
|
+
...body,
|
|
178500
|
+
...compact({
|
|
178501
|
+
conversationIds: csv(flags["conversation-ids"]),
|
|
178502
|
+
maxExamples: flags["max-examples"] !== undefined ? Number(flags["max-examples"]) : undefined
|
|
178503
|
+
})
|
|
178504
|
+
});
|
|
178505
|
+
} catch (error) {
|
|
178506
|
+
if (isTenantFeatureNotFound(error)) {
|
|
178507
|
+
throw new CliAccessError("The signal builder is not enabled for this tenant, so `moda signals preview` is unavailable (the API answered 404).", { guidance: "Ask Moda to enable the signal-builder feature for this tenant. Other `moda signals` subcommands still work." });
|
|
178508
|
+
}
|
|
178509
|
+
throw error;
|
|
178510
|
+
}
|
|
178505
178511
|
return { exitCode: 0 };
|
|
178506
178512
|
}
|
|
178507
178513
|
default:
|
|
178508
178514
|
throw unknownSignalsSubcommandError(sub, args);
|
|
178509
178515
|
}
|
|
178510
178516
|
}
|
|
178517
|
+
function isTenantFeatureNotFound(error) {
|
|
178518
|
+
if (!(error instanceof ApiError) || error.statusCode !== 404)
|
|
178519
|
+
return false;
|
|
178520
|
+
try {
|
|
178521
|
+
const body = JSON.parse(error.responseBody);
|
|
178522
|
+
return body.message === "Not Found" && body.error === undefined;
|
|
178523
|
+
} catch {
|
|
178524
|
+
return false;
|
|
178525
|
+
}
|
|
178526
|
+
}
|
|
178511
178527
|
var SIGNALS_MANAGEMENT_SUBCOMMANDS = new Set([
|
|
178512
178528
|
"draft",
|
|
178513
178529
|
"create",
|
|
@@ -180841,6 +180857,7 @@ async function remoteAnalyzeFetch(url, apiKey, init, timeoutMs) {
|
|
|
180841
180857
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
180842
180858
|
let response;
|
|
180843
180859
|
try {
|
|
180860
|
+
recordApiRequest();
|
|
180844
180861
|
response = await fetch(url, {
|
|
180845
180862
|
...init,
|
|
180846
180863
|
headers: { Authorization: `Bearer ${apiKey}`, ...init.headers ?? {} },
|
|
@@ -184897,7 +184914,7 @@ async function runHarnessCommand(context) {
|
|
|
184897
184914
|
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.");
|
|
184898
184915
|
}
|
|
184899
184916
|
if (context.flags["github-actions"] === "true") {
|
|
184900
|
-
const { runGithubActionsAnalyze } = await import("./harness-github-actions-
|
|
184917
|
+
const { runGithubActionsAnalyze } = await import("./harness-github-actions-f3xffdf7.js");
|
|
184901
184918
|
const result = await runGithubActionsAnalyze(rootDir, {
|
|
184902
184919
|
writeReport: (report2) => {
|
|
184903
184920
|
const normalized = normalizeHarnessReport(report2);
|
|
@@ -188942,4 +188959,4 @@ function hashText(text) {
|
|
|
188942
188959
|
return createHash4("sha256").update(text).digest("hex");
|
|
188943
188960
|
}
|
|
188944
188961
|
|
|
188945
|
-
export { isPlatformApiKey, setPlatformTenantOverride, apiKeyHeaders, ApiError, callDataAPI, callControlAPI,
|
|
188962
|
+
export { isPlatformApiKey, setPlatformTenantOverride, apiKeyHeaders, ApiError, callDataAPI, callControlAPI, $isSeq, $parseDocument, $stringify, require_typescript, inspectCodeSelectors, inspectPythonSelectors, resolvePromptSource, backfillPromptSource, HARNESS_REPORT_PATH, HARNESS_REPORT_APPROVAL_PATH, HARNESS_ANALYZE_CONCERNS, validateHarnessReport, readHarnessReport, normalizeHarnessReport, hashHarnessReport, hashStableJson, assertFlags, assertPositionals, runUsersCommand, runUserCommand, runProblemReopenCommand, runSignalsManagementCommand, SIGNALS_MANAGEMENT_SUBCOMMANDS, unknownSignalsSubcommandError, shouldColorTerminalOutput, terminalStyles, stripAnsi2 as stripAnsi, renderMarkdownForTerminal, 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 };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
authFetch,
|
|
3
3
|
getCachedLoginContext
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-zbpetb7v.js";
|
|
5
5
|
import {
|
|
6
6
|
CliAccessError,
|
|
7
7
|
CliInputError,
|
|
@@ -9,13 +9,14 @@ import {
|
|
|
9
9
|
embeddedTenantIdFromApiKey,
|
|
10
10
|
getModaDir,
|
|
11
11
|
loadCliConfig,
|
|
12
|
+
recordApiRequest,
|
|
12
13
|
resolveApiKeyFromActiveProfile,
|
|
13
14
|
resolveIngestUrl,
|
|
14
15
|
resolveModaBaseUrl,
|
|
15
16
|
resolveTenantIdFromActiveProfile,
|
|
16
17
|
saveCliConfig,
|
|
17
18
|
writeSecretJsonFile
|
|
18
|
-
} from "./cli-
|
|
19
|
+
} from "./cli-xtj2m4hs.js";
|
|
19
20
|
|
|
20
21
|
// src/init/tenant.ts
|
|
21
22
|
import { randomUUID } from "node:crypto";
|
|
@@ -114,6 +115,7 @@ function bootstrapLabel(custom) {
|
|
|
114
115
|
var embeddedTenantId = embeddedTenantIdFromApiKey;
|
|
115
116
|
async function isStoredKeyLive(key, options = {}) {
|
|
116
117
|
try {
|
|
118
|
+
recordApiRequest();
|
|
117
119
|
const response = await fetch(`${resolveModaBaseUrl(options)}/api/v1/data/overview`, {
|
|
118
120
|
method: "GET",
|
|
119
121
|
headers: { "x-api-key": key },
|
|
@@ -647,6 +647,18 @@ function validateConfig() {
|
|
|
647
647
|
}
|
|
648
648
|
}
|
|
649
649
|
|
|
650
|
+
// src/api-request-count.ts
|
|
651
|
+
var apiRequestCount = 0;
|
|
652
|
+
function recordApiRequest() {
|
|
653
|
+
apiRequestCount++;
|
|
654
|
+
}
|
|
655
|
+
function getApiRequestCount() {
|
|
656
|
+
return apiRequestCount;
|
|
657
|
+
}
|
|
658
|
+
function resetApiRequestCount() {
|
|
659
|
+
apiRequestCount = 0;
|
|
660
|
+
}
|
|
661
|
+
|
|
650
662
|
// ../../packages/harness-snapshot/src/policy.ts
|
|
651
663
|
var MAX_SCANNED_FILE_BYTES = 512 * 1024;
|
|
652
664
|
var DEFAULT_MAX_INVENTORY_FILES = 12000;
|
|
@@ -1863,6 +1875,22 @@ function extractSuggestedCommands(text) {
|
|
|
1863
1875
|
function flagEnabled(flags, key) {
|
|
1864
1876
|
return flags[key] === "true";
|
|
1865
1877
|
}
|
|
1878
|
+
var BOOLEAN_TRUE_WORDS = new Set(["true", "yes", "1", "on"]);
|
|
1879
|
+
var BOOLEAN_FALSE_WORDS = new Set(["false", "no", "0", "off"]);
|
|
1880
|
+
function parseBooleanFlagValue(value) {
|
|
1881
|
+
if (typeof value === "boolean")
|
|
1882
|
+
return value;
|
|
1883
|
+
if (typeof value === "number")
|
|
1884
|
+
return value === 1 ? true : value === 0 ? false : undefined;
|
|
1885
|
+
if (typeof value !== "string")
|
|
1886
|
+
return;
|
|
1887
|
+
const text = value.trim().toLowerCase();
|
|
1888
|
+
if (BOOLEAN_TRUE_WORDS.has(text))
|
|
1889
|
+
return true;
|
|
1890
|
+
if (BOOLEAN_FALSE_WORDS.has(text))
|
|
1891
|
+
return false;
|
|
1892
|
+
return;
|
|
1893
|
+
}
|
|
1866
1894
|
function stringOption(value) {
|
|
1867
1895
|
if (value === undefined || value === null)
|
|
1868
1896
|
return;
|
|
@@ -1907,4 +1935,4 @@ function createCommandContext(input, options = {}) {
|
|
|
1907
1935
|
};
|
|
1908
1936
|
}
|
|
1909
1937
|
|
|
1910
|
-
export { PROD_BASE_URL, DEFAULT_INGEST_URL, getModaPaths, getModaDir, isLoopbackBaseUrl, assertValidProfileName, describeBaseUrlSource, loadProfileConfig, saveProfileConfig, getActiveProfile, setActiveProfile, upsertProfile, clearStoredApiKeyCredentials, secretFilePathFromRef, resolveSecretReference, resolveApiKeyFromActiveProfile, resolveTenantIdFromActiveProfile, ensureSecretFilePermissions, writeSecretJsonFile, CliInputError, CliAccessError, CliInputRequiredError, CliAuthError, CliCancellationError, isNetworkLikeError, isApiLikeError, VERSION, MODA_BASE_URL, loadCliConfig, saveCliConfig, resolveApiKey, embeddedTenantIdFromApiKey, resolveIngestUrl2 as resolveIngestUrl, resolveTenantId, resolveApiTenantId, resolveModaBaseUrl, validateConfig, MAX_SCANNED_FILE_BYTES, DEFAULT_MAX_INVENTORY_FILES, DEFAULT_MAX_INVENTORY_TEXT_BYTES, MAX_RECORDED_SKIPS, SKIPPED_DIRS, isSkippedDir, isSkippedPathPrefix, isEvalLikePath, shouldInventoryFile, isTextFile, isSecretishPath, SECRET_KEYS, redactDeep, redactString, packSnapshot, EXIT_OK, EXIT_ERROR, EXIT_DEGRADED, EXIT_AUTH_REQUIRED, EXIT_INPUT_REQUIRED, EXIT_CANCELLED, AGENT_ERROR_CODES, wasOutputCancelled, safeWriteStdout, safeWriteStderr, explicitOutputMode, resolveOutputMode, createCliOutput, agentEnvelopeFits, agentMaxOutputBytes, stringOption, createCommandContext };
|
|
1938
|
+
export { PROD_BASE_URL, DEFAULT_INGEST_URL, getModaPaths, getModaDir, isLoopbackBaseUrl, assertValidProfileName, describeBaseUrlSource, loadProfileConfig, saveProfileConfig, getActiveProfile, setActiveProfile, upsertProfile, clearStoredApiKeyCredentials, secretFilePathFromRef, resolveSecretReference, resolveApiKeyFromActiveProfile, resolveTenantIdFromActiveProfile, ensureSecretFilePermissions, writeSecretJsonFile, CliInputError, CliAccessError, CliInputRequiredError, CliAuthError, CliCancellationError, isNetworkLikeError, isApiLikeError, VERSION, MODA_BASE_URL, loadCliConfig, saveCliConfig, resolveApiKey, embeddedTenantIdFromApiKey, resolveIngestUrl2 as resolveIngestUrl, resolveTenantId, resolveApiTenantId, resolveModaBaseUrl, validateConfig, recordApiRequest, getApiRequestCount, resetApiRequestCount, MAX_SCANNED_FILE_BYTES, DEFAULT_MAX_INVENTORY_FILES, DEFAULT_MAX_INVENTORY_TEXT_BYTES, MAX_RECORDED_SKIPS, SKIPPED_DIRS, isSkippedDir, isSkippedPathPrefix, isEvalLikePath, shouldInventoryFile, isTextFile, isSecretishPath, SECRET_KEYS, redactDeep, redactString, packSnapshot, EXIT_OK, EXIT_ERROR, EXIT_DEGRADED, EXIT_AUTH_REQUIRED, EXIT_INPUT_REQUIRED, EXIT_CANCELLED, AGENT_ERROR_CODES, wasOutputCancelled, safeWriteStdout, safeWriteStderr, explicitOutputMode, resolveOutputMode, createCliOutput, agentEnvelopeFits, agentMaxOutputBytes, parseBooleanFlagValue, stringOption, createCommandContext };
|
|
@@ -3,11 +3,12 @@ import {
|
|
|
3
3
|
CliInputError,
|
|
4
4
|
getModaPaths,
|
|
5
5
|
loadProfileConfig,
|
|
6
|
+
recordApiRequest,
|
|
6
7
|
resolveModaBaseUrl,
|
|
7
8
|
saveProfileConfig,
|
|
8
9
|
secretFilePathFromRef,
|
|
9
10
|
writeSecretJsonFile
|
|
10
|
-
} from "./cli-
|
|
11
|
+
} from "./cli-xtj2m4hs.js";
|
|
11
12
|
import {
|
|
12
13
|
__require
|
|
13
14
|
} from "./cli-0v6na3yp.js";
|
|
@@ -179,6 +180,7 @@ function postCliSessionEndpoint(path, token, timeoutMs, opts = {}) {
|
|
|
179
180
|
return;
|
|
180
181
|
}
|
|
181
182
|
const requestFn = url.protocol === "https:" ? httpsRequest : httpRequest;
|
|
183
|
+
recordApiRequest();
|
|
182
184
|
const req = requestFn(url, {
|
|
183
185
|
method: "POST",
|
|
184
186
|
headers: { Authorization: `Bearer ${token}` },
|
|
@@ -345,6 +347,7 @@ async function connectWithCode(code, options = {}) {
|
|
|
345
347
|
}
|
|
346
348
|
let response;
|
|
347
349
|
try {
|
|
350
|
+
recordApiRequest();
|
|
348
351
|
response = await fetch(`${resolveModaBaseUrl(options)}/api/cli/auth/connect`, {
|
|
349
352
|
method: "POST",
|
|
350
353
|
headers: { "Content-Type": "application/json" },
|
|
@@ -594,6 +597,7 @@ async function login(screen = "login", options = {}) {
|
|
|
594
597
|
async function exchangeCodeForSession(code) {
|
|
595
598
|
let response;
|
|
596
599
|
try {
|
|
600
|
+
recordApiRequest();
|
|
597
601
|
response = await fetch(`${resolveModaBaseUrl(storageOptions)}/api/cli/auth/exchange`, {
|
|
598
602
|
method: "POST",
|
|
599
603
|
headers: { "Content-Type": "application/json" },
|
|
@@ -798,6 +802,7 @@ async function authFetch(path, options = {}, authOptions = {}) {
|
|
|
798
802
|
let url = `${baseUrl}${path}`;
|
|
799
803
|
const MAX_REDIRECTS = 5;
|
|
800
804
|
for (let hop = 0;; hop++) {
|
|
805
|
+
recordApiRequest();
|
|
801
806
|
const response = await fetch(url, { ...options, headers, redirect: "manual" });
|
|
802
807
|
if (response.status < 300 || response.status >= 400) {
|
|
803
808
|
if (response.status === 401 && isModaCtSession(session)) {
|