@moda-ai/cli 1.50.0 → 1.54.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 +14 -2
- package/dist/{cli-x0x0n35w.js → cli-9250ckvg.js} +19 -15
- package/dist/{cli-jqfm8dp4.js → cli-a2jq9yd5.js} +386 -83
- package/dist/{cli-xrs02c0t.js → cli-ac3p2byq.js} +3 -1
- package/dist/{cli-7kbzqact.js → cli-kxwm7y62.js} +1 -1
- package/dist/cli-mm48br00.js +47 -0
- package/dist/{cli-h4k23fb0.js → cli-sq6g0tk5.js} +2 -2
- package/dist/cli.js +175 -41
- package/dist/{harness-github-actions-q9kewzb6.js → harness-github-actions-075xzdvp.js} +2 -2
- package/dist/{harness-7gr0xbtc.js → harness-sd44jsaw.js} +2 -2
- package/dist/{index-z0jpjcsm.js → index-hn9t95tr.js} +6 -5
- package/dist/prompt-hash.d.ts +36 -0
- package/dist/prompt-hash.js +15 -0
- package/dist/prompt-source-mcp.js +2 -2
- package/dist/{provision-qkazpt0c.js → provision-d1dfj6as.js} +3 -3
- package/package.json +10 -2
- package/skills/integration/index.json +3 -3
- package/skills/integration/integration-cloudflare-think/SKILL.md +5 -2
- package/skills/moda-cli/SKILL.md +67 -15
|
@@ -534,9 +534,11 @@ function writeSecretJsonFile(path, value) {
|
|
|
534
534
|
// src/errors.ts
|
|
535
535
|
class CliInputError extends Error {
|
|
536
536
|
usage;
|
|
537
|
-
|
|
537
|
+
reason;
|
|
538
|
+
constructor(message, usage, reason) {
|
|
538
539
|
super(message);
|
|
539
540
|
this.usage = usage;
|
|
541
|
+
this.reason = reason;
|
|
540
542
|
this.name = "CliInputError";
|
|
541
543
|
}
|
|
542
544
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// src/prompt-hash.ts
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
var PROMPT_HASH_VERSION = 1;
|
|
4
|
+
function promptSourceHashPayload(definition) {
|
|
5
|
+
return {
|
|
6
|
+
kind: definition.kind,
|
|
7
|
+
source: definition.source,
|
|
8
|
+
...["text", "messages"].includes(definition.kind) ? {
|
|
9
|
+
sourceHash: definition.sourceHash
|
|
10
|
+
} : ["builder", "template"].includes(definition.kind) ? {
|
|
11
|
+
sourceHash: definition.sourceHash,
|
|
12
|
+
dependencies: definition.dependencies,
|
|
13
|
+
coverage: definition.coverage,
|
|
14
|
+
unresolved: definition.unresolved
|
|
15
|
+
} : {}
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function stableJson(value) {
|
|
19
|
+
return JSON.stringify(sortJson(value));
|
|
20
|
+
}
|
|
21
|
+
function sortJson(value) {
|
|
22
|
+
if (Array.isArray(value))
|
|
23
|
+
return value.map(sortJson);
|
|
24
|
+
if (value && typeof value === "object") {
|
|
25
|
+
return Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, item]) => [key, sortJson(item)]));
|
|
26
|
+
}
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
function promptContentHashPayload(prompt) {
|
|
30
|
+
return stableJson({
|
|
31
|
+
key: prompt.key,
|
|
32
|
+
content: prompt.content,
|
|
33
|
+
systemPrompt: prompt.systemPrompt ?? null,
|
|
34
|
+
messages: prompt.messages ?? [],
|
|
35
|
+
variables: prompt.variables ?? [],
|
|
36
|
+
variablesSchema: prompt.variablesSchema ?? {},
|
|
37
|
+
modelConfig: prompt.modelConfig ?? {},
|
|
38
|
+
toolRefs: prompt.toolRefs ?? [],
|
|
39
|
+
responseSchema: prompt.responseSchema ?? null,
|
|
40
|
+
...prompt.sourceDefinition ? { sourceDefinition: promptSourceHashPayload(prompt.sourceDefinition) } : {}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function computePromptContentHash(prompt) {
|
|
44
|
+
return createHash("sha256").update(promptContentHashPayload(prompt)).digest("hex");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export { PROMPT_HASH_VERSION, promptSourceHashPayload, stableJson, promptContentHashPayload, computePromptContentHash };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
authFetch,
|
|
3
3
|
getCachedLoginContext
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-kxwm7y62.js";
|
|
5
5
|
import {
|
|
6
6
|
CliAccessError,
|
|
7
7
|
CliInputError,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
resolveTenantIdFromActiveProfile,
|
|
16
16
|
saveCliConfig,
|
|
17
17
|
writeSecretJsonFile
|
|
18
|
-
} from "./cli-
|
|
18
|
+
} from "./cli-ac3p2byq.js";
|
|
19
19
|
|
|
20
20
|
// src/init/tenant.ts
|
|
21
21
|
import { randomUUID } from "node:crypto";
|
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
runPromptsCommand,
|
|
9
9
|
runSkillsCommand,
|
|
10
10
|
runStatusCommand
|
|
11
|
-
} from "./cli-
|
|
11
|
+
} from "./cli-a2jq9yd5.js";
|
|
12
|
+
import"./cli-mm48br00.js";
|
|
12
13
|
import {
|
|
13
14
|
ApiError,
|
|
14
15
|
HARNESS_REPORT_APPROVAL_PATH,
|
|
@@ -37,7 +38,7 @@ import {
|
|
|
37
38
|
terminalStyles,
|
|
38
39
|
unknownSignalsSubcommandError,
|
|
39
40
|
validateHarnessReport
|
|
40
|
-
} from "./cli-
|
|
41
|
+
} from "./cli-9250ckvg.js";
|
|
41
42
|
import"./cli-ssfq84k5.js";
|
|
42
43
|
import {
|
|
43
44
|
authFetch,
|
|
@@ -46,7 +47,7 @@ import {
|
|
|
46
47
|
loadAuthSession,
|
|
47
48
|
login,
|
|
48
49
|
revokeCliSessionToken
|
|
49
|
-
} from "./cli-
|
|
50
|
+
} from "./cli-kxwm7y62.js";
|
|
50
51
|
import {
|
|
51
52
|
AGENT_ERROR_CODES,
|
|
52
53
|
CliAccessError,
|
|
@@ -97,7 +98,7 @@ import {
|
|
|
97
98
|
validateConfig,
|
|
98
99
|
wasOutputCancelled,
|
|
99
100
|
writeSecretJsonFile
|
|
100
|
-
} from "./cli-
|
|
101
|
+
} from "./cli-ac3p2byq.js";
|
|
101
102
|
import {
|
|
102
103
|
__require
|
|
103
104
|
} from "./cli-0v6na3yp.js";
|
|
@@ -150,11 +151,20 @@ var WorldStateSchema = z.object({
|
|
|
150
151
|
format: z.enum(["frames", "fold-inputs"]).optional(),
|
|
151
152
|
message_count: z.number().min(1).max(1e6).optional()
|
|
152
153
|
});
|
|
154
|
+
var lenientBoolFlag = () => z.preprocess((val) => {
|
|
155
|
+
const text = String(val).toLowerCase();
|
|
156
|
+
if (["true", "1", "yes", "on"].includes(text))
|
|
157
|
+
return true;
|
|
158
|
+
if (["false", "0", "no", "off"].includes(text))
|
|
159
|
+
return false;
|
|
160
|
+
return val;
|
|
161
|
+
}, z.boolean()).optional();
|
|
153
162
|
var ContextSchema = z.object({
|
|
154
|
-
conversation_id: z.string(),
|
|
155
|
-
msg_index: z.number().min(0).optional(),
|
|
163
|
+
conversation_id: z.string().min(1),
|
|
164
|
+
msg_index: z.number().int().min(0).optional(),
|
|
156
165
|
window: z.number().int().min(0).optional(),
|
|
157
|
-
|
|
166
|
+
metadata_only: lenientBoolFlag(),
|
|
167
|
+
all: lenientBoolFlag(),
|
|
158
168
|
from: z.number().int().min(0).optional(),
|
|
159
169
|
max_messages: z.number().int().min(1).max(5000).optional()
|
|
160
170
|
});
|
|
@@ -1991,6 +2001,20 @@ function nextCommandsFor(fix) {
|
|
|
1991
2001
|
}
|
|
1992
2002
|
];
|
|
1993
2003
|
case "UNROUTED":
|
|
2004
|
+
return [
|
|
2005
|
+
{
|
|
2006
|
+
command: `moda fix ${fix.id} --packet`,
|
|
2007
|
+
purpose: "Read the investigation packet — this fix is deliverable as diagnosis.",
|
|
2008
|
+
mutability: "read",
|
|
2009
|
+
requires_approval: false
|
|
2010
|
+
},
|
|
2011
|
+
{
|
|
2012
|
+
command: "moda prompts status",
|
|
2013
|
+
purpose: "If the reason says evidence carries no prompt version: check the prompt lockfile, then pass prompt: lock.prompts['<key>'] to createThinkTelemetry / createAI7Telemetry (docs.moda.dev/prompt-management/attribution).",
|
|
2014
|
+
mutability: "read",
|
|
2015
|
+
requires_approval: false
|
|
2016
|
+
}
|
|
2017
|
+
];
|
|
1994
2018
|
case "NO_EVIDENCE":
|
|
1995
2019
|
case "BLOCKED_COVERAGE":
|
|
1996
2020
|
case "NO_HEADROOM":
|
|
@@ -3534,6 +3558,11 @@ function stripTelemetryFlag(flags) {
|
|
|
3534
3558
|
function isTelemetryDisabled(flags) {
|
|
3535
3559
|
return flags[TELEMETRY_FLAG] === "true" || process.env.MODA_CLI_TELEMETRY === "0" || process.env.DO_NOT_TRACK === "1";
|
|
3536
3560
|
}
|
|
3561
|
+
var VALIDATION_REASON_MAX = 128;
|
|
3562
|
+
function sanitizeValidationReason(reason) {
|
|
3563
|
+
const cleaned = reason?.replace(/[^A-Za-z0-9_.:-]/g, "_").slice(0, VALIDATION_REASON_MAX);
|
|
3564
|
+
return cleaned ? cleaned : undefined;
|
|
3565
|
+
}
|
|
3537
3566
|
function sanitizedFlagNames(flags) {
|
|
3538
3567
|
return Object.keys(stripTelemetryFlag(flags)).sort();
|
|
3539
3568
|
}
|
|
@@ -3541,6 +3570,7 @@ async function sendCliUsageTelemetry(input) {
|
|
|
3541
3570
|
if (!input.apiKey || isTelemetryDisabled(input.flags)) {
|
|
3542
3571
|
return;
|
|
3543
3572
|
}
|
|
3573
|
+
const validationReason = sanitizeValidationReason(input.validationReason);
|
|
3544
3574
|
const controller = new AbortController;
|
|
3545
3575
|
const timeout = setTimeout(() => controller.abort(), TELEMETRY_TIMEOUT_MS);
|
|
3546
3576
|
if (typeof timeout.unref === "function") {
|
|
@@ -3558,6 +3588,7 @@ async function sendCliUsageTelemetry(input) {
|
|
|
3558
3588
|
command: input.command.slice(0, 64),
|
|
3559
3589
|
status: input.status,
|
|
3560
3590
|
error_type: input.errorType,
|
|
3591
|
+
...validationReason ? { validation_reason: validationReason } : {},
|
|
3561
3592
|
exit_code: input.exitCode,
|
|
3562
3593
|
duration_ms: Math.max(0, Math.round(input.durationMs)),
|
|
3563
3594
|
api_request_count: Math.max(0, Math.round(input.apiRequestCount)),
|
|
@@ -6663,7 +6694,7 @@ function frustrationFindings(data, daysBack, evidenceRefs) {
|
|
|
6663
6694
|
id: "action_frustration_window",
|
|
6664
6695
|
title: "Read the frustration window.",
|
|
6665
6696
|
rationale: "The user quote and nearby turns reveal what confused or blocked the user.",
|
|
6666
|
-
command: conversationId ? `moda context ${conversationId}${anchorIndex !== null ? ` --msg-index=${anchorIndex}` : ""} --window=3` : `moda frustrations --days-back=${daysBack} --include-window`,
|
|
6697
|
+
command: conversationId ? `moda context ${shellWord(conversationId)}${anchorIndex !== null ? ` --msg-index=${anchorIndex}` : ""} --window=3` : `moda frustrations --days-back=${daysBack} --include-window`,
|
|
6667
6698
|
mutability: "read",
|
|
6668
6699
|
requiresApproval: false
|
|
6669
6700
|
}]
|
|
@@ -7750,7 +7781,7 @@ function parseArgs(argv) {
|
|
|
7750
7781
|
if (!endOfOptions && arg === "--" && command !== "") {
|
|
7751
7782
|
endOfOptions = true;
|
|
7752
7783
|
} else if (!endOfOptions && arg.startsWith("--")) {
|
|
7753
|
-
i = parseFlag(args, i, flags, command === "", bareFlags);
|
|
7784
|
+
i = parseFlag(args, i, flags, command === "", bareFlags, command);
|
|
7754
7785
|
} else if (!endOfOptions && command !== "" && /^-[A-Za-z]/.test(arg)) {
|
|
7755
7786
|
shortFlags.push(arg);
|
|
7756
7787
|
} else if (command === "") {
|
|
@@ -7790,7 +7821,10 @@ var GLOBAL_BOOLEAN_FLAGS = new Set([
|
|
|
7790
7821
|
"tui",
|
|
7791
7822
|
"no-tui"
|
|
7792
7823
|
]);
|
|
7793
|
-
|
|
7824
|
+
var COMMAND_BOOLEAN_FLAGS = {
|
|
7825
|
+
context: new Set(["all", "metadata-only"])
|
|
7826
|
+
};
|
|
7827
|
+
function parseFlag(args, index, flags, beforeCommand, bareFlags, command = "") {
|
|
7794
7828
|
const set = (key2, value, bare) => {
|
|
7795
7829
|
flags[key2] = value;
|
|
7796
7830
|
const at = bareFlags.indexOf(key2);
|
|
@@ -7811,6 +7845,10 @@ function parseFlag(args, index, flags, beforeCommand, bareFlags) {
|
|
|
7811
7845
|
set(key, "true", true);
|
|
7812
7846
|
return index;
|
|
7813
7847
|
}
|
|
7848
|
+
if (!beforeCommand && COMMAND_BOOLEAN_FLAGS[command]?.has(key.replace(/_/g, "-")) && next !== "true" && next !== "false") {
|
|
7849
|
+
set(key, "true", true);
|
|
7850
|
+
return index;
|
|
7851
|
+
}
|
|
7814
7852
|
if (next !== undefined && !next.startsWith("--")) {
|
|
7815
7853
|
set(key, next, false);
|
|
7816
7854
|
return index + 1;
|
|
@@ -7903,7 +7941,7 @@ Commands:
|
|
|
7903
7941
|
traces --sort=longest Sort traces: recent (default), longest, slowest
|
|
7904
7942
|
search "<query>" Search trace messages (keyword/semantic/hybrid)
|
|
7905
7943
|
world-state <conversation_id> Get a trace's world state (slots/threads/events)
|
|
7906
|
-
context <conversation_id> Get windowed trace context
|
|
7944
|
+
context <conversation_id> Get windowed trace context (--metadata-only: summary + counts only)
|
|
7907
7945
|
context <conversation_id> --all Whole transcript in order (first 500; --from=N --max-messages=N to continue)
|
|
7908
7946
|
audit <conversation_id|trace_id> Raw span audit (spans, hierarchy, orphans, duplicates)
|
|
7909
7947
|
frustrations Frustration detections (same data as emotions --family=frustration)
|
|
@@ -7940,9 +7978,10 @@ Commands:
|
|
|
7940
7978
|
--signal=conversations = --signal=traces. <conversation_id> is the trace ID.
|
|
7941
7979
|
|
|
7942
7980
|
Prompt management:
|
|
7943
|
-
prompts init Create .moda/prompts.yml
|
|
7944
|
-
prompts status Show local prompt changes
|
|
7981
|
+
prompts init Create .moda/prompts.yml (version 2: prompt_paths + sources)
|
|
7982
|
+
prompts status Show local prompt changes; warns on globs that match nothing
|
|
7945
7983
|
prompts diff Only changed/new/deleted prompts since last sync
|
|
7984
|
+
prompts migrate [--dry-run] Rewrite a version 1 .moda/prompts.yml to version 2
|
|
7946
7985
|
prompts sync Analyze prompt sources and upload versions
|
|
7947
7986
|
prompts sync --watch Upload again when prompt files change
|
|
7948
7987
|
prompts list|show|proposals|usage|replay-runs|decide
|
|
@@ -8736,7 +8775,7 @@ function parseCommandFlags(schema, args, command, options = {}) {
|
|
|
8736
8775
|
]);
|
|
8737
8776
|
const unknown = Object.keys(args).filter((key) => !known.has(key));
|
|
8738
8777
|
if (unknown.includes("dry_run")) {
|
|
8739
|
-
throw new CliInputError(`'moda ${command}' has no dry-run mode, so nothing was sent.`, `Remove --dry-run to run it for real. Commands with a real dry-run: sync, registry push, harness sync/delete, prompts sync/decide, skills sync/policy, signals <write subcommands>, problem-reopen
|
|
8778
|
+
throw new CliInputError(`'moda ${command}' has no dry-run mode, so nothing was sent.`, `Remove --dry-run to run it for real. Commands with a real dry-run: sync, registry push, harness sync/delete, prompts sync/decide, skills sync/policy, signals <write subcommands>, problem-reopen.`, "unsupported_dry_run");
|
|
8740
8779
|
}
|
|
8741
8780
|
if (unknown.length > 0) {
|
|
8742
8781
|
const flagKeys = schemaKeys.filter((key) => key !== options.positionalKey);
|
|
@@ -8751,7 +8790,7 @@ function parseCommandFlags(schema, args, command, options = {}) {
|
|
|
8751
8790
|
return close ? `Did you mean --${close.candidate.replace(/_/g, "-")}?` : "";
|
|
8752
8791
|
}).filter(Boolean);
|
|
8753
8792
|
const names = unknown.map((key) => `--${key.replace(/_/g, "-")}`).join(", ");
|
|
8754
|
-
throw new CliInputError(`Unknown flag${unknown.length > 1 ? "s" : ""} ${names} for 'moda ${command}'.`, [...hints, `Valid flags: ${valid.join(", ") || "(none)"}. Run 'moda ${command} --help'.`].join(" "));
|
|
8793
|
+
throw new CliInputError(`Unknown flag${unknown.length > 1 ? "s" : ""} ${names} for 'moda ${command}'.`, [...hints, `Valid flags: ${valid.join(", ") || "(none)"}. Run 'moda ${command} --help'.`].join(" "), `unknown_flag:${unknown[0].replace(/_/g, "-")}`);
|
|
8755
8794
|
}
|
|
8756
8795
|
return schema.parse(args);
|
|
8757
8796
|
}
|
|
@@ -8941,7 +8980,7 @@ function assertHandParsedFlags(command, flags, positionals) {
|
|
|
8941
8980
|
} catch (error) {
|
|
8942
8981
|
if (command !== "feedback" || !(error instanceof CliInputError))
|
|
8943
8982
|
throw error;
|
|
8944
|
-
throw new CliInputError(/nothing was sent/i.test(error.message) ? error.message : `${error.message} Nothing was sent.`, `${error.usage ?? ""} Id flags (--<name>-id=ID) are attached as refs; put other detail in the note. ${FEEDBACK_USAGE}`.trim());
|
|
8983
|
+
throw new CliInputError(/nothing was sent/i.test(error.message) ? error.message : `${error.message} Nothing was sent.`, `${error.usage ?? ""} Id flags (--<name>-id=ID) are attached as refs; put other detail in the note. ${FEEDBACK_USAGE}`.trim(), error.reason);
|
|
8945
8984
|
}
|
|
8946
8985
|
}
|
|
8947
8986
|
var PROFILE_MANAGING_COMMANDS = new Set(["profiles", "auth", "init", "provision", "status", "config", "keys", "manifest", "agent", "doctor"]);
|
|
@@ -8975,6 +9014,66 @@ function processingDisabledWarning(data, family) {
|
|
|
8975
9014
|
`${family === "emotion" ? "Emotion" : "Frustration"} analysis is disabled for this tenant (${setting} = false), ` + "so zero results do NOT mean users are not frustrated. Enable it in Settings → Account → Signal processing; " + "only traces ingested after enabling are analyzed."
|
|
8976
9015
|
];
|
|
8977
9016
|
}
|
|
9017
|
+
var CONTEXT_USAGE = "Usage: moda context <conversation_id> [--msg-index=N] [--window=0-5 | --metadata-only]";
|
|
9018
|
+
var CONTEXT_ALL_USAGE = "Usage: moda context <conversation_id> --all [--from=N] [--max-messages=N]";
|
|
9019
|
+
var CONTEXT_MAX_WINDOW = 5;
|
|
9020
|
+
var EMPTY_ANCHOR_VALUES = new Set(["", "null", "undefined", "none"]);
|
|
9021
|
+
function parseContextRequest(positional, rawFlags) {
|
|
9022
|
+
const flags = {};
|
|
9023
|
+
const flagIds = [];
|
|
9024
|
+
for (const [rawKey, value] of Object.entries(rawFlags)) {
|
|
9025
|
+
const key = rawKey.replace(/_/g, "-");
|
|
9026
|
+
if (key === "conversation-id") {
|
|
9027
|
+
if (value !== "true")
|
|
9028
|
+
flagIds.push(value);
|
|
9029
|
+
} else if (flags[key] !== undefined && flags[key] !== value) {
|
|
9030
|
+
throw new CliInputError(`Got two different values for --${key} (both spellings were passed), so nothing was read.`, CONTEXT_USAGE, "flag_conflict");
|
|
9031
|
+
} else {
|
|
9032
|
+
flags[key] = value;
|
|
9033
|
+
}
|
|
9034
|
+
}
|
|
9035
|
+
const flagId = flagIds[0];
|
|
9036
|
+
const warnings = [];
|
|
9037
|
+
if (new Set([...positional !== undefined ? [positional] : [], ...flagIds]).size > 1) {
|
|
9038
|
+
throw new CliInputError("Got two different trace ids (from the positional and --conversation-id), so nothing was read.", CONTEXT_USAGE, "flag_conflict");
|
|
9039
|
+
}
|
|
9040
|
+
const conversationId = positional ?? flagId;
|
|
9041
|
+
if (!conversationId) {
|
|
9042
|
+
throw new CliInputError("<conversation_id> is required", CONTEXT_USAGE, "missing_positional");
|
|
9043
|
+
}
|
|
9044
|
+
const msgIndex = flags["msg-index"];
|
|
9045
|
+
if (msgIndex !== undefined && EMPTY_ANCHOR_VALUES.has(msgIndex.trim().toLowerCase())) {
|
|
9046
|
+
delete flags["msg-index"];
|
|
9047
|
+
warnings.push(`--msg-index had no value (${JSON.stringify(msgIndex)}), so the window is centered on the middle of the trace. ` + "Trace-level search hits have no message_index; pass one only when the hit has it.");
|
|
9048
|
+
}
|
|
9049
|
+
const args = { ...flagsToArgs(flags), conversation_id: conversationId };
|
|
9050
|
+
const params = parseCommandFlags(ContextSchema, args, "context", { positionalKey: "conversation_id" });
|
|
9051
|
+
if (params.metadata_only === true && params.window !== undefined) {
|
|
9052
|
+
throw new CliInputError("--metadata-only reads no messages, so it cannot be combined with --window; drop --window.", CONTEXT_USAGE, "flag_conflict");
|
|
9053
|
+
}
|
|
9054
|
+
if (params.all === true) {
|
|
9055
|
+
if (params.msg_index !== undefined || flags.window !== undefined || params.metadata_only === true) {
|
|
9056
|
+
throw new CliInputError("--all reads the whole trace; drop --msg-index/--window/--metadata-only.", CONTEXT_ALL_USAGE, "flag_conflict");
|
|
9057
|
+
}
|
|
9058
|
+
} else if (params.from !== undefined || params.max_messages !== undefined) {
|
|
9059
|
+
throw new CliInputError("--from and --max-messages page the whole trace and need --all.", CONTEXT_ALL_USAGE, "flag_conflict");
|
|
9060
|
+
}
|
|
9061
|
+
return { params, warnings };
|
|
9062
|
+
}
|
|
9063
|
+
async function readContextMetadataOnly(contextPath, query2) {
|
|
9064
|
+
try {
|
|
9065
|
+
return await callDataAPI(`${contextPath}?${query2.toString()}`);
|
|
9066
|
+
} catch (error) {
|
|
9067
|
+
if (!(error instanceof ApiError) || error.statusCode !== 400 || !/metadata_only/.test(error.message))
|
|
9068
|
+
throw error;
|
|
9069
|
+
const legacy = new URLSearchParams(query2);
|
|
9070
|
+
legacy.delete("metadata_only");
|
|
9071
|
+
legacy.set("window", "0");
|
|
9072
|
+
const data = asRecord(await callDataAPI(`${contextPath}?${legacy.toString()}`)) ?? {};
|
|
9073
|
+
const ctx = asRecord(data.context) ?? {};
|
|
9074
|
+
return { ...data, metadata_only: true, context: { ...ctx, messages: [] } };
|
|
9075
|
+
}
|
|
9076
|
+
}
|
|
8978
9077
|
var FULL_TRANSCRIPT_DEFAULT_MAX_MESSAGES = 500;
|
|
8979
9078
|
var CONTEXT_RANGE_PAGE_SIZE = 200;
|
|
8980
9079
|
var LEGACY_WINDOW_MAX_MESSAGES = 100;
|
|
@@ -9001,7 +9100,6 @@ function pageMessages(page) {
|
|
|
9001
9100
|
const messages = asRecord(page.context)?.messages ?? page.messages;
|
|
9002
9101
|
return (Array.isArray(messages) ? messages : []).map((m) => asRecord(m) ?? {});
|
|
9003
9102
|
}
|
|
9004
|
-
var CONTEXT_MAX_WINDOW = 5;
|
|
9005
9103
|
var CONTEXT_ALL_MAX_MESSAGES = 5000;
|
|
9006
9104
|
async function readFullTranscript(conversationId, opts = {}) {
|
|
9007
9105
|
const start = opts.from ?? 0;
|
|
@@ -9360,40 +9458,37 @@ async function runCommand(command, positional, flags, positionals = positional ?
|
|
|
9360
9458
|
break;
|
|
9361
9459
|
}
|
|
9362
9460
|
case "context": {
|
|
9363
|
-
|
|
9364
|
-
throw new CliInputError("<conversation_id> is required", "Usage: moda context <conversation_id> [--msg-index=N] [--window=N]");
|
|
9365
|
-
}
|
|
9366
|
-
const args = flagsToArgs(flags, "conversation_id", positional);
|
|
9367
|
-
const params = parseCommandFlags(ContextSchema, args, command, { positionalKey: "conversation_id" });
|
|
9461
|
+
const { params, warnings: inputWarnings } = parseContextRequest(positional, flags);
|
|
9368
9462
|
if (params.all === true) {
|
|
9369
|
-
if (params.msg_index !== undefined || flags.window !== undefined) {
|
|
9370
|
-
throw new CliInputError("--all reads the whole trace; drop --msg-index/--window.", "Usage: moda context <conversation_id> --all [--from=N] [--max-messages=N]");
|
|
9371
|
-
}
|
|
9372
9463
|
const agentMode = context.output.mode === "agent" || context.output.mode === "agent-stream";
|
|
9373
9464
|
const full = await readFullTranscript(params.conversation_id, {
|
|
9374
9465
|
from: params.from,
|
|
9375
9466
|
maxMessages: params.max_messages,
|
|
9376
9467
|
fits: agentMode ? (page) => agentEnvelopeFits(command, page.data, { warnings: page.warnings, nextCommands: page.nextCommands }) : undefined
|
|
9377
9468
|
});
|
|
9469
|
+
const fullWarnings = [...inputWarnings, ...full.warnings];
|
|
9378
9470
|
context.output.writeData(full.data, {
|
|
9379
|
-
...
|
|
9471
|
+
...fullWarnings.length > 0 ? { warnings: fullWarnings } : {},
|
|
9380
9472
|
...full.nextCommands.length > 0 ? { nextCommands: full.nextCommands } : {}
|
|
9381
9473
|
});
|
|
9382
9474
|
break;
|
|
9383
9475
|
}
|
|
9384
|
-
if (params.from !== undefined || params.max_messages !== undefined) {
|
|
9385
|
-
throw new CliInputError("--from and --max-messages page the whole trace and need --all.", "Usage: moda context <conversation_id> --all [--from=N] [--max-messages=N]");
|
|
9386
|
-
}
|
|
9387
9476
|
const query2 = new URLSearchParams;
|
|
9388
9477
|
if (params.msg_index !== undefined)
|
|
9389
9478
|
query2.set("msg_index", params.msg_index.toString());
|
|
9479
|
+
if (params.metadata_only === true)
|
|
9480
|
+
query2.set("metadata_only", "1");
|
|
9390
9481
|
const window = params.window === undefined ? undefined : Math.min(params.window, CONTEXT_MAX_WINDOW);
|
|
9391
9482
|
if (window !== undefined)
|
|
9392
9483
|
query2.set("window", window.toString());
|
|
9393
9484
|
const queryString = query2.toString() ? `?${query2.toString()}` : "";
|
|
9394
|
-
const
|
|
9485
|
+
const contextPath = `/conversations/${encodeURIComponent(params.conversation_id)}/context`;
|
|
9486
|
+
const data = params.metadata_only === true ? await readContextMetadataOnly(contextPath, query2) : await callDataAPI(`${contextPath}${queryString}`);
|
|
9395
9487
|
const ctxRecord = asRecord(data) ?? {};
|
|
9396
|
-
const warnings =
|
|
9488
|
+
const warnings = [
|
|
9489
|
+
...inputWarnings,
|
|
9490
|
+
...notFoundWarning("trace", params.conversation_id, asNumber(ctxRecord.total_messages) === 0)
|
|
9491
|
+
];
|
|
9397
9492
|
const nextCommands = [];
|
|
9398
9493
|
if (params.window !== undefined && params.window > CONTEXT_MAX_WINDOW) {
|
|
9399
9494
|
const center = asNumber(asRecord(ctxRecord.context)?.center_index) ?? params.msg_index ?? 0;
|
|
@@ -10053,7 +10148,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
|
|
|
10053
10148
|
function telemetryCommandName(definition) {
|
|
10054
10149
|
return definition.telemetryCommand ?? definition.name;
|
|
10055
10150
|
}
|
|
10056
|
-
var OFFLINE_PROMPTS_SUBCOMMANDS = new Set(["init", "status", "diff"]);
|
|
10151
|
+
var OFFLINE_PROMPTS_SUBCOMMANDS = new Set(["init", "status", "diff", "migrate"]);
|
|
10057
10152
|
function legacyCommand(metadata) {
|
|
10058
10153
|
return {
|
|
10059
10154
|
...metadata,
|
|
@@ -10147,7 +10242,7 @@ var commandRegistry = createCommandRegistry([
|
|
|
10147
10242
|
resetApiRequestCountBeforeRun: true,
|
|
10148
10243
|
telemetry: "result",
|
|
10149
10244
|
handler: async (context) => {
|
|
10150
|
-
const { runInit } = await import("./index-
|
|
10245
|
+
const { runInit } = await import("./index-hn9t95tr.js");
|
|
10151
10246
|
if (context.outputMode === "agent-stream") {
|
|
10152
10247
|
context.output.writeEvent({
|
|
10153
10248
|
event: "started",
|
|
@@ -10188,7 +10283,7 @@ var commandRegistry = createCommandRegistry([
|
|
|
10188
10283
|
resetApiRequestCountBeforeRun: true,
|
|
10189
10284
|
telemetry: "result-and-error",
|
|
10190
10285
|
handler: async (context) => {
|
|
10191
|
-
const { runProvision } = await import("./provision-
|
|
10286
|
+
const { runProvision } = await import("./provision-d1dfj6as.js");
|
|
10192
10287
|
return runProvision(context, {
|
|
10193
10288
|
resumeCommand: buildResumeCommand("provision", context.rawFlags)
|
|
10194
10289
|
});
|
|
@@ -10652,6 +10747,7 @@ var commandRegistry = createCommandRegistry([
|
|
|
10652
10747
|
examples: [
|
|
10653
10748
|
"moda context <conversation_id> --window=3",
|
|
10654
10749
|
"moda context <conversation_id> --msg-index=40 --window=0",
|
|
10750
|
+
"moda context <conversation_id> --metadata-only # summary + total_messages, no messages",
|
|
10655
10751
|
"moda context <conversation_id> --all",
|
|
10656
10752
|
"moda context <conversation_id> --all --from=500 --max-messages=500"
|
|
10657
10753
|
],
|
|
@@ -10900,18 +10996,18 @@ var commandRegistry = createCommandRegistry([
|
|
|
10900
10996
|
legacyCommand({
|
|
10901
10997
|
name: "prompts",
|
|
10902
10998
|
description: "Manage prompt versions and labels",
|
|
10903
|
-
examples: ["moda prompts init", "moda prompts status", "moda prompts sync", "moda prompts ab --baseline=old.md --candidate=new.md"],
|
|
10999
|
+
examples: ["moda prompts init", "moda prompts status", "moda prompts migrate --dry-run", "moda prompts sync", "moda prompts ab --baseline=old.md --candidate=new.md"],
|
|
10904
11000
|
subcommands: [
|
|
10905
11001
|
{
|
|
10906
11002
|
name: "init",
|
|
10907
|
-
description: "Create .moda/prompts.yml in the current directory (never overwrites)",
|
|
11003
|
+
description: "Create a version 2 .moda/prompts.yml in the current directory (never overwrites). prompt_paths are exact fast-glob patterns from the repository root; sources: maps prompts defined in code (key, path, selector.symbol|pointer, kind, dependencies).",
|
|
10908
11004
|
usage: "moda prompts init [--from-harness=<report>]",
|
|
10909
|
-
flags: [{ name: "--from-harness=<report>", description: "Register verified source mappings from a harness report; source files stay in place." }],
|
|
11005
|
+
flags: [{ name: "--from-harness=<report>", description: "Register verified source mappings from a harness report (older reports are normalized; prompts without a promptSource are mapped from sourcePath when unambiguous). Unresolvable prompts are returned in imported.skipped with reasons; source files stay in place." }],
|
|
10910
11006
|
examples: ["moda prompts init", "cd /path/to/project && moda prompts init"]
|
|
10911
11007
|
},
|
|
10912
11008
|
{
|
|
10913
11009
|
name: "status",
|
|
10914
|
-
description: "Show prompt files that changed since the last sync",
|
|
11010
|
+
description: "Show prompt files that changed since the last sync. Also reports prompt_paths patterns that match no files (zeroMatchPatterns) and files only older CLIs discovered (legacyOnlyFiles), with a warning pointing at `moda prompts migrate`.",
|
|
10915
11011
|
usage: "moda prompts status",
|
|
10916
11012
|
examples: ["moda prompts status"]
|
|
10917
11013
|
},
|
|
@@ -10921,6 +11017,16 @@ var commandRegistry = createCommandRegistry([
|
|
|
10921
11017
|
usage: "moda prompts diff",
|
|
10922
11018
|
examples: ["moda prompts diff"]
|
|
10923
11019
|
},
|
|
11020
|
+
{
|
|
11021
|
+
name: "migrate",
|
|
11022
|
+
description: "Rewrite .moda/prompts.yml to version 2: keeps every pattern and source, adds explicit paths for prompt files only the older repo-wide discovery matched (so their lockfile keys keep resolving), and ensures a sources: list. Comments are kept; the write is atomic.",
|
|
11023
|
+
usage: "moda prompts migrate [--dry-run] [--discover]",
|
|
11024
|
+
flags: [
|
|
11025
|
+
{ name: "--dry-run", description: "Print the migrated manifest without writing it." },
|
|
11026
|
+
{ name: "--discover", description: "Also scan for code-defined prompts (deterministic, no agent calls). Adds only mappings that need no semantic verification; other candidates are listed under pendingSources with the command that verifies them." }
|
|
11027
|
+
],
|
|
11028
|
+
examples: ["moda prompts migrate --dry-run", "moda prompts migrate", "moda prompts migrate --discover"]
|
|
11029
|
+
},
|
|
10924
11030
|
{
|
|
10925
11031
|
name: "sync",
|
|
10926
11032
|
description: "Analyze prompt sources and upload verified versions to Moda Cloud",
|
|
@@ -10929,7 +11035,7 @@ var commandRegistry = createCommandRegistry([
|
|
|
10929
11035
|
{ name: "--analyst=local-scan|claude|codex|cursor|auto", description: "Defaults to auto: deterministic discovery, installed-agent extension, and independent verification. Use local-scan for no agent calls." },
|
|
10930
11036
|
{ name: "--assist=none", description: "Disable agent fallback, including with an explicit analyst." },
|
|
10931
11037
|
{ name: "--no-analyze", description: "Skip discovery and sync only configured sources." },
|
|
10932
|
-
{ name: "--from-harness=<report>", description: "Read and register harness prompt source mappings before sync." },
|
|
11038
|
+
{ name: "--from-harness=<report>", description: "Read and register harness prompt source mappings before sync; unresolvable prompts are listed in harnessImport.skipped. Fails only when none resolve (regenerate with `moda harness analyze --experimental --concern=prompts`)." },
|
|
10933
11039
|
{ name: "--allow-untrack", description: "Explicitly remove missing keys from local tracking; registry history remains." },
|
|
10934
11040
|
{ name: "--watch", description: "Analyze before syncing; re-upload when mapped prompt files change." },
|
|
10935
11041
|
{ name: "--dry-run", description: "Preview without saving mappings or registry versions; deterministic unless an analyst is explicitly selected." }
|
|
@@ -11062,7 +11168,15 @@ var commandRegistry = createCommandRegistry([
|
|
|
11062
11168
|
}
|
|
11063
11169
|
]);
|
|
11064
11170
|
function classifyCliError(error) {
|
|
11065
|
-
if (error instanceof
|
|
11171
|
+
if (error instanceof CliAuthError)
|
|
11172
|
+
return "auth_error";
|
|
11173
|
+
if (error instanceof CliAccessError)
|
|
11174
|
+
return "access_error";
|
|
11175
|
+
if (error instanceof ApiError && error.statusCode === 401)
|
|
11176
|
+
return "auth_error";
|
|
11177
|
+
if (error instanceof ApiError && error.statusCode === 403)
|
|
11178
|
+
return "access_error";
|
|
11179
|
+
if (error instanceof z2.ZodError || error instanceof CliInputError || error instanceof CliInputRequiredError) {
|
|
11066
11180
|
return "validation_error";
|
|
11067
11181
|
}
|
|
11068
11182
|
if (error instanceof ApiError || isApiLikeError(error)) {
|
|
@@ -11073,6 +11187,21 @@ function classifyCliError(error) {
|
|
|
11073
11187
|
}
|
|
11074
11188
|
return "unknown_error";
|
|
11075
11189
|
}
|
|
11190
|
+
function cliValidationReason(error) {
|
|
11191
|
+
if (error instanceof z2.ZodError) {
|
|
11192
|
+
const issue = error.issues[0];
|
|
11193
|
+
if (!issue)
|
|
11194
|
+
return "zod";
|
|
11195
|
+
const path = issue.path.join(".") || "_";
|
|
11196
|
+
return issue.code === "invalid_enum_value" ? `bad_enum:${path}` : `zod:${path}:${issue.code}`;
|
|
11197
|
+
}
|
|
11198
|
+
if (error instanceof CliInputRequiredError)
|
|
11199
|
+
return "input_required";
|
|
11200
|
+
if (error instanceof CliInputError) {
|
|
11201
|
+
return error.reason ?? (/^<[^>]+> is required/.test(error.message) ? "missing_positional" : "input_error");
|
|
11202
|
+
}
|
|
11203
|
+
return;
|
|
11204
|
+
}
|
|
11076
11205
|
function printCliError(error) {
|
|
11077
11206
|
if (error instanceof CliInputError) {
|
|
11078
11207
|
safeWriteStderr(`Error: ${error.message}
|
|
@@ -11256,6 +11385,7 @@ async function dispatchParsedCommandInner(parsed, startedAt) {
|
|
|
11256
11385
|
flags: commandFlags,
|
|
11257
11386
|
status: "error",
|
|
11258
11387
|
errorType: classifyCliError(error),
|
|
11388
|
+
validationReason: cliValidationReason(error),
|
|
11259
11389
|
exitCode: exitCodeForError(error),
|
|
11260
11390
|
durationMs: Date.now() - startedAt,
|
|
11261
11391
|
apiRequestCount: getApiRequestCount(),
|
|
@@ -11316,6 +11446,7 @@ async function dispatchParsedCommandInner(parsed, startedAt) {
|
|
|
11316
11446
|
flags: commandFlags,
|
|
11317
11447
|
status: "error",
|
|
11318
11448
|
errorType: classifyCliError(error),
|
|
11449
|
+
validationReason: cliValidationReason(error),
|
|
11319
11450
|
exitCode: exitCodeForError(error),
|
|
11320
11451
|
durationMs: Date.now() - startedAt,
|
|
11321
11452
|
apiRequestCount: getApiRequestCount(),
|
|
@@ -11383,6 +11514,7 @@ export {
|
|
|
11383
11514
|
runCommand,
|
|
11384
11515
|
resolveTailSignal,
|
|
11385
11516
|
printCliError,
|
|
11517
|
+
parseContextRequest,
|
|
11386
11518
|
parseCommandFlags,
|
|
11387
11519
|
parseArgs,
|
|
11388
11520
|
initFlagsForContext,
|
|
@@ -11391,6 +11523,7 @@ export {
|
|
|
11391
11523
|
detectCallerAgent,
|
|
11392
11524
|
describeLinearLink,
|
|
11393
11525
|
commandRegistry,
|
|
11526
|
+
cliValidationReason,
|
|
11394
11527
|
classifyCliError,
|
|
11395
11528
|
capProblemsBlocks,
|
|
11396
11529
|
buildResumeCommand,
|
|
@@ -11398,5 +11531,6 @@ export {
|
|
|
11398
11531
|
TAIL_LIMITS,
|
|
11399
11532
|
LEGACY_WINDOW_MAX_MESSAGES,
|
|
11400
11533
|
FULL_TRANSCRIPT_DEFAULT_MAX_MESSAGES,
|
|
11401
|
-
CliInputError
|
|
11534
|
+
CliInputError,
|
|
11535
|
+
CONTEXT_MAX_WINDOW
|
|
11402
11536
|
};
|
|
@@ -42,8 +42,8 @@ import {
|
|
|
42
42
|
writeHarnessAnalyzeResult,
|
|
43
43
|
writeHarnessArtifacts,
|
|
44
44
|
writeHumanProgress
|
|
45
|
-
} from "./cli-
|
|
46
|
-
import"./cli-
|
|
45
|
+
} from "./cli-9250ckvg.js";
|
|
46
|
+
import"./cli-ac3p2byq.js";
|
|
47
47
|
import"./cli-0v6na3yp.js";
|
|
48
48
|
export {
|
|
49
49
|
writeHumanProgress,
|
|
@@ -3,7 +3,8 @@ import {
|
|
|
3
3
|
initPrompts,
|
|
4
4
|
runPromptSync,
|
|
5
5
|
runSkillSync
|
|
6
|
-
} from "./cli-
|
|
6
|
+
} from "./cli-a2jq9yd5.js";
|
|
7
|
+
import"./cli-mm48br00.js";
|
|
7
8
|
import {
|
|
8
9
|
codingAgentDisplayName,
|
|
9
10
|
describeCodingAgentEvent,
|
|
@@ -22,7 +23,7 @@ import {
|
|
|
22
23
|
runHarnessCommand,
|
|
23
24
|
startRemoteAnalyze,
|
|
24
25
|
stripAnsi
|
|
25
|
-
} from "./cli-
|
|
26
|
+
} from "./cli-9250ckvg.js";
|
|
26
27
|
import {
|
|
27
28
|
bundledSkillsDir,
|
|
28
29
|
installIntegrationSkill,
|
|
@@ -34,14 +35,14 @@ import {
|
|
|
34
35
|
} from "./cli-ssfq84k5.js";
|
|
35
36
|
import {
|
|
36
37
|
selectTenantAndCreateKey
|
|
37
|
-
} from "./cli-
|
|
38
|
+
} from "./cli-sq6g0tk5.js";
|
|
38
39
|
import {
|
|
39
40
|
ConnectCodeError,
|
|
40
41
|
connectWithCode,
|
|
41
42
|
loadAuthSession,
|
|
42
43
|
loadToken,
|
|
43
44
|
login
|
|
44
|
-
} from "./cli-
|
|
45
|
+
} from "./cli-kxwm7y62.js";
|
|
45
46
|
import {
|
|
46
47
|
CliAuthError,
|
|
47
48
|
CliInputError,
|
|
@@ -49,7 +50,7 @@ import {
|
|
|
49
50
|
createCommandContext,
|
|
50
51
|
resolveIngestUrl,
|
|
51
52
|
resolveModaBaseUrl
|
|
52
|
-
} from "./cli-
|
|
53
|
+
} from "./cli-ac3p2byq.js";
|
|
53
54
|
import"./cli-0v6na3yp.js";
|
|
54
55
|
|
|
55
56
|
// src/init/index.ts
|