@moda-ai/cli 1.42.0 → 1.43.1
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/dist/{cli-pr6s56fc.js → cli-141ca3yv.js} +138 -78
- package/dist/{cli-xsmsjny3.js → cli-5tsqk3jt.js} +2 -2
- package/dist/{cli-rp912ypf.js → cli-8c60k2p4.js} +7 -2
- package/dist/{cli-yy8fwg1a.js → cli-j2fapt3g.js} +2 -2
- package/dist/{cli-dyeywy9d.js → cli-rycpwqzm.js} +1 -1
- package/dist/cli.js +29 -12
- package/dist/{harness-github-actions-1qt4sgxd.js → harness-github-actions-pg0azf3h.js} +2 -2
- package/dist/{harness-191xt7bq.js → harness-sqngqjrd.js} +2 -2
- package/dist/{index-ah6yf5x2.js → index-cnfwmzew.js} +5 -5
- package/dist/prompt-source-mcp.js +2 -2
- package/dist/{provision-gabtks29.js → provision-02wqtkvm.js} +3 -3
- package/package.json +1 -1
- package/skills/integration/index.json +2 -2
- package/skills/moda-cli/SKILL.md +11 -1
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
resolvePromptSource,
|
|
14
14
|
safePromptEvidencePath,
|
|
15
15
|
scanHarness
|
|
16
|
-
} from "./cli-
|
|
16
|
+
} from "./cli-5tsqk3jt.js";
|
|
17
17
|
import {
|
|
18
18
|
SKILL_SOURCE_HARNESS,
|
|
19
19
|
SKILL_SOURCE_INTEGRATION_BUNDLED,
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
import {
|
|
27
27
|
isAuthSessionValid,
|
|
28
28
|
loadAuthSession
|
|
29
|
-
} from "./cli-
|
|
29
|
+
} from "./cli-rycpwqzm.js";
|
|
30
30
|
import {
|
|
31
31
|
CliInputError,
|
|
32
32
|
createCommandContext,
|
|
@@ -43,7 +43,7 @@ import {
|
|
|
43
43
|
resolveTenantId,
|
|
44
44
|
secretFilePathFromRef,
|
|
45
45
|
validateConfig
|
|
46
|
-
} from "./cli-
|
|
46
|
+
} from "./cli-8c60k2p4.js";
|
|
47
47
|
import {
|
|
48
48
|
__commonJS,
|
|
49
49
|
__require,
|
|
@@ -5586,6 +5586,11 @@ var REPLAY_MODEL_ALLOWLIST = [
|
|
|
5586
5586
|
var DEFAULT_POLL_INTERVAL_MS = 15000;
|
|
5587
5587
|
var DEFAULT_WAIT_TIMEOUT_MS = 2 * 60 * 60 * 1000;
|
|
5588
5588
|
var TERMINAL_RUN_STATUSES = new Set(["completed", "skipped", "error"]);
|
|
5589
|
+
var FALLBACK_SUCCESS_CRITERIA = [
|
|
5590
|
+
"The agent understands the user request",
|
|
5591
|
+
"The agent uses tools appropriately when needed",
|
|
5592
|
+
"The agent provides a helpful final answer"
|
|
5593
|
+
];
|
|
5589
5594
|
async function runPromptAb(flags, profileOptions, context) {
|
|
5590
5595
|
validateConfig();
|
|
5591
5596
|
const tenantId = flags["tenant-id"] || resolveApiTenantId(profileOptions);
|
|
@@ -5626,61 +5631,78 @@ async function runPromptAb(flags, profileOptions, context) {
|
|
|
5626
5631
|
prod: resolvePromptArmSpec(baselineSource, "baseline"),
|
|
5627
5632
|
proposed: resolvePromptArmSpec(candidateSource, "candidate")
|
|
5628
5633
|
};
|
|
5629
|
-
const replaySetId = await ensureReplaySet(plan, flags, tenantId, profileOptions);
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
seedsPerCase,
|
|
5635
|
-
assistantModel: assistantModel || undefined,
|
|
5636
|
-
promotePrimary: flags["no-promote"] !== "true",
|
|
5637
|
-
...plan.kind === "existing" ? replayCasePin(plan.caseIds) : {}
|
|
5638
|
-
})
|
|
5639
|
-
}, profileOptions, { timeoutMs: 120000, retries: 0 });
|
|
5640
|
-
if (context.outputMode === "human")
|
|
5641
|
-
warnIfQueued(enqueue);
|
|
5642
|
-
const noWait = flags.wait === "false" || flags["no-wait"] === "true";
|
|
5643
|
-
if (noWait) {
|
|
5644
|
-
context.output.writeData({
|
|
5645
|
-
replaySetId,
|
|
5646
|
-
runId: enqueue.runId,
|
|
5647
|
-
status: enqueue.status,
|
|
5648
|
-
message: enqueue.message ?? "Replay comparison queued",
|
|
5649
|
-
plannedPlayouts
|
|
5650
|
-
});
|
|
5651
|
-
return;
|
|
5634
|
+
const { setId: replaySetId, caseSources, warnings } = await ensureReplaySet(plan, flags, tenantId, profileOptions);
|
|
5635
|
+
if (context.outputMode === "human") {
|
|
5636
|
+
for (const warning of warnings)
|
|
5637
|
+
process.stderr.write(`Warning: ${warning}
|
|
5638
|
+
`);
|
|
5652
5639
|
}
|
|
5653
|
-
const
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5640
|
+
const writeOptions = warnings.length ? { warnings } : undefined;
|
|
5641
|
+
try {
|
|
5642
|
+
const enqueue = await callControlAPI(`/tenants/${encodeURIComponent(tenantId)}/replay-sets/${encodeURIComponent(replaySetId)}/run`, {
|
|
5643
|
+
method: "POST",
|
|
5644
|
+
body: JSON.stringify({
|
|
5645
|
+
promptArms,
|
|
5646
|
+
seedsPerCase,
|
|
5647
|
+
assistantModel: assistantModel || undefined,
|
|
5648
|
+
promotePrimary: flags.promote === "true" && flags["no-promote"] !== "true",
|
|
5649
|
+
...plan.kind === "existing" ? replayCasePin(plan.caseIds) : {}
|
|
5650
|
+
})
|
|
5651
|
+
}, profileOptions, { timeoutMs: 120000, retries: 0 });
|
|
5652
|
+
if (context.outputMode === "human")
|
|
5653
|
+
warnIfQueued(enqueue);
|
|
5654
|
+
const noWait = flags.wait === "false" || flags["no-wait"] === "true";
|
|
5655
|
+
if (noWait) {
|
|
5656
|
+
context.output.writeData({
|
|
5657
|
+
replaySetId,
|
|
5658
|
+
...caseSources ? { caseSources } : {},
|
|
5659
|
+
...warnings.length ? { warnings } : {},
|
|
5660
|
+
runId: enqueue.runId,
|
|
5661
|
+
status: enqueue.status,
|
|
5662
|
+
message: enqueue.message ?? "Replay comparison queued",
|
|
5663
|
+
plannedPlayouts
|
|
5664
|
+
}, writeOptions);
|
|
5665
|
+
return;
|
|
5661
5666
|
}
|
|
5662
|
-
|
|
5663
|
-
|
|
5667
|
+
const deadline = Date.now() + timeoutMs;
|
|
5668
|
+
let latest = null;
|
|
5669
|
+
while (Date.now() < deadline) {
|
|
5670
|
+
latest = await fetchLatestRun(tenantId, replaySetId, enqueue.runId, profileOptions);
|
|
5671
|
+
const status = latest.run?.status ?? "";
|
|
5672
|
+
const runId = latest.run?.runId ?? "";
|
|
5673
|
+
if (TERMINAL_RUN_STATUSES.has(status) && runId === enqueue.runId) {
|
|
5674
|
+
break;
|
|
5675
|
+
}
|
|
5676
|
+
if (context.outputMode === "human") {
|
|
5677
|
+
process.stderr.write(`Waiting for replay run (${waitLabel(latest.run)})...
|
|
5664
5678
|
`);
|
|
5679
|
+
}
|
|
5680
|
+
await sleep(pollIntervalMs);
|
|
5665
5681
|
}
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
+
if (!latest?.run || latest.run.runId !== enqueue.runId || !TERMINAL_RUN_STATUSES.has(latest.run.status)) {
|
|
5683
|
+
throw new Error(`Timed out after ${timeoutMs}ms waiting for replay run ${enqueue.runId} to finish`);
|
|
5684
|
+
}
|
|
5685
|
+
const result = {
|
|
5686
|
+
replaySetId,
|
|
5687
|
+
...caseSources ? { caseSources } : {},
|
|
5688
|
+
...warnings.length ? { warnings } : {},
|
|
5689
|
+
plannedPlayouts,
|
|
5690
|
+
runId: latest.run.runId,
|
|
5691
|
+
status: latest.run.status,
|
|
5692
|
+
verdict: formatVerdict(latest),
|
|
5693
|
+
run: { ...latest.run },
|
|
5694
|
+
cases: latest.cases.map((row) => ({ ...row }))
|
|
5695
|
+
};
|
|
5696
|
+
if (context.outputMode === "human") {
|
|
5697
|
+
printHumanVerdict(result);
|
|
5698
|
+
}
|
|
5699
|
+
context.output.writeData(result, writeOptions);
|
|
5700
|
+
} catch (error) {
|
|
5701
|
+
if (warnings.length && error && typeof error === "object") {
|
|
5702
|
+
Object.assign(error, { warnings });
|
|
5703
|
+
}
|
|
5704
|
+
throw error;
|
|
5682
5705
|
}
|
|
5683
|
-
context.output.writeData(result);
|
|
5684
5706
|
}
|
|
5685
5707
|
function warnIfQueued(enqueue) {
|
|
5686
5708
|
const { runsAhead, maxActiveRuns } = enqueue;
|
|
@@ -5793,7 +5815,7 @@ async function planReplaySet(flags, tenantId, profileOptions) {
|
|
|
5793
5815
|
const snapshot = await fetchReplaySetCases(tenantId, existingSetId, profileOptions);
|
|
5794
5816
|
return { kind: "existing", setId: existingSetId, cases: snapshot?.ids.length ?? null, caseIds: snapshot?.ids };
|
|
5795
5817
|
}
|
|
5796
|
-
const conversations = parseCsv(flags.traces ?? flags.conversations ?? flags["conversation-ids"]);
|
|
5818
|
+
const conversations = [...new Set(parseCsv(flags.traces ?? flags.conversations ?? flags["conversation-ids"]))];
|
|
5797
5819
|
if (conversations.length > MAX_REPLAY_TRACES) {
|
|
5798
5820
|
throw new CliInputError(`--traces has ${conversations.length} ids; the limit is ${MAX_REPLAY_TRACES} per replay set, so nothing was sent.`, "Split the traces across several runs, or use --auto-generate.");
|
|
5799
5821
|
}
|
|
@@ -5861,9 +5883,9 @@ function rerunWithYes(command, positionals, flags) {
|
|
|
5861
5883
|
}
|
|
5862
5884
|
async function ensureReplaySet(plan, flags, tenantId, profileOptions) {
|
|
5863
5885
|
if (plan.kind === "existing")
|
|
5864
|
-
return plan.setId;
|
|
5886
|
+
return { setId: plan.setId, warnings: [] };
|
|
5865
5887
|
if (plan.kind === "traces") {
|
|
5866
|
-
return
|
|
5888
|
+
return createSetFromTraces(plan.traces, flags, tenantId, profileOptions);
|
|
5867
5889
|
}
|
|
5868
5890
|
const caseCount = plan.cases;
|
|
5869
5891
|
const lookbackDays = parsePositiveInt(flags["lookback-days"], 30, 365, "--lookback-days");
|
|
@@ -5875,7 +5897,7 @@ async function ensureReplaySet(plan, flags, tenantId, profileOptions) {
|
|
|
5875
5897
|
if (!generated?.id) {
|
|
5876
5898
|
throw new Error("Auto-generate did not return a replay set id");
|
|
5877
5899
|
}
|
|
5878
|
-
return generated.id;
|
|
5900
|
+
return { setId: generated.id, warnings: [] };
|
|
5879
5901
|
}
|
|
5880
5902
|
function parseTraceRef(ref) {
|
|
5881
5903
|
const match = /^(.+)@(\d+)$/.exec(ref.trim());
|
|
@@ -5883,38 +5905,75 @@ function parseTraceRef(ref) {
|
|
|
5883
5905
|
return { conversationId: ref.trim() };
|
|
5884
5906
|
return { conversationId: match[1], startMsgIndex: Number(match[2]) };
|
|
5885
5907
|
}
|
|
5886
|
-
async function
|
|
5887
|
-
const
|
|
5888
|
-
const
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
5908
|
+
async function createSetFromTraces(conversationIds, flags, tenantId, profileOptions) {
|
|
5909
|
+
const refs = [...new Set(conversationIds)].map(parseTraceRef);
|
|
5910
|
+
const traces = [...new Set(refs.map((ref) => ref.conversationId))];
|
|
5911
|
+
const startByConversation = new Map;
|
|
5912
|
+
for (const ref of refs) {
|
|
5913
|
+
if (ref.startMsgIndex !== undefined)
|
|
5914
|
+
startByConversation.set(ref.conversationId, ref.startMsgIndex);
|
|
5915
|
+
}
|
|
5916
|
+
const name = (flags.name ?? flags["set-name"] ?? `Prompt A/B ${traces.length} trace(s)`).trim();
|
|
5917
|
+
const base = `/tenants/${encodeURIComponent(tenantId)}/replay-sets`;
|
|
5918
|
+
let set = null;
|
|
5919
|
+
let unavailable = null;
|
|
5920
|
+
try {
|
|
5921
|
+
set = await callControlAPI(`${base}/auto-generate`, { method: "POST", body: JSON.stringify({ name, conversationIds: traces }) }, profileOptions, { timeoutMs: 300000, retries: 0 });
|
|
5922
|
+
if (!set?.id)
|
|
5923
|
+
throw new Error("Auto-generate did not return a replay set id");
|
|
5924
|
+
} catch (error) {
|
|
5925
|
+
const status = error?.statusCode;
|
|
5926
|
+
if (status === 401 || status === 403)
|
|
5927
|
+
throw error;
|
|
5928
|
+
unavailable = error instanceof Error ? error.message : String(error);
|
|
5929
|
+
set = null;
|
|
5930
|
+
}
|
|
5931
|
+
const distilledIds = new Set((set?.cases ?? []).map((c) => String(c?.sourceConversationId ?? "")).filter(Boolean));
|
|
5932
|
+
const distilled = traces.filter((id) => distilledIds.has(id));
|
|
5933
|
+
const fallback = traces.filter((id) => !distilledIds.has(id));
|
|
5934
|
+
if (!set) {
|
|
5935
|
+
set = await callControlAPI(base, { method: "POST", body: JSON.stringify({ name, description: "Created by moda prompts ab" }) }, profileOptions);
|
|
5936
|
+
}
|
|
5937
|
+
const requestedIndex = new Map(traces.map((id, index) => [id, index]));
|
|
5938
|
+
for (const existing of set.cases ?? []) {
|
|
5939
|
+
const conversationId = String(existing?.sourceConversationId ?? "");
|
|
5940
|
+
const index = requestedIndex.get(conversationId);
|
|
5941
|
+
const startMsgIndex = startByConversation.get(conversationId);
|
|
5942
|
+
const update = {};
|
|
5943
|
+
if (fallback.length && index !== undefined && existing.position !== index)
|
|
5944
|
+
update.position = index;
|
|
5945
|
+
if (startMsgIndex !== undefined)
|
|
5946
|
+
update.sourceStartMsgIndex = startMsgIndex;
|
|
5947
|
+
if (!Object.keys(update).length)
|
|
5948
|
+
continue;
|
|
5949
|
+
await callControlAPI(`${base}/${encodeURIComponent(set.id)}/cases/${encodeURIComponent(existing.id)}`, { method: "PUT", body: JSON.stringify(update) }, profileOptions);
|
|
5950
|
+
}
|
|
5951
|
+
for (const conversationId of fallback) {
|
|
5895
5952
|
const scenario = await loadScenarioFromConversation(conversationId);
|
|
5896
|
-
await callControlAPI(
|
|
5953
|
+
await callControlAPI(`${base}/${encodeURIComponent(set.id)}/cases`, {
|
|
5897
5954
|
method: "POST",
|
|
5898
5955
|
body: JSON.stringify({
|
|
5899
5956
|
title: conversationId,
|
|
5900
5957
|
scenario,
|
|
5901
5958
|
sourceConversationId: conversationId,
|
|
5902
|
-
...
|
|
5903
|
-
successCriteria:
|
|
5904
|
-
|
|
5905
|
-
"The agent uses tools appropriately when needed",
|
|
5906
|
-
"The agent provides a helpful final answer"
|
|
5907
|
-
],
|
|
5908
|
-
position: position++
|
|
5959
|
+
...startByConversation.has(conversationId) ? { sourceStartMsgIndex: startByConversation.get(conversationId) } : {},
|
|
5960
|
+
successCriteria: FALLBACK_SUCCESS_CRITERIA,
|
|
5961
|
+
position: requestedIndex.get(conversationId)
|
|
5909
5962
|
})
|
|
5910
5963
|
}, profileOptions);
|
|
5911
5964
|
}
|
|
5912
|
-
|
|
5965
|
+
const warnings = [];
|
|
5966
|
+
if (fallback.length) {
|
|
5967
|
+
const why = unavailable ? `Moda could not distill these traces (${unavailable.slice(0, 600)})` : "Moda could not distill a scenario for these traces";
|
|
5968
|
+
warnings.push(`${why}, so ${fallback.length} of ${traces.length} case(s) use only the opening user message and three generic ` + `success criteria, which long traces pass easily: ${fallback.slice(0, 10).join(", ")}${fallback.length > 10 ? ", …" : ""}. ` + "Edit their scenario/criteria in the dashboard, or pass --set-id with a curated set.");
|
|
5969
|
+
}
|
|
5970
|
+
return { setId: set.id, caseSources: { distilled, fallback }, warnings };
|
|
5913
5971
|
}
|
|
5914
5972
|
async function loadScenarioFromConversation(conversationId) {
|
|
5915
5973
|
try {
|
|
5916
|
-
const data = await callDataAPI(`/conversations/${encodeURIComponent(conversationId)}/context?msg_index=0&window=
|
|
5917
|
-
const
|
|
5974
|
+
const data = await callDataAPI(`/conversations/${encodeURIComponent(conversationId)}/context?msg_index=0&window=5`);
|
|
5975
|
+
const messages = data.context?.messages ?? data.messages ?? [];
|
|
5976
|
+
const firstUser = messages.find((message) => message.role === "user" && String(message.content ?? "").trim());
|
|
5918
5977
|
const opening = String(firstUser?.content ?? "").trim();
|
|
5919
5978
|
if (opening) {
|
|
5920
5979
|
return `The user says: "${opening}"
|
|
@@ -6446,6 +6505,7 @@ var PROMPT_WRITE_SUBCOMMAND_FLAGS = {
|
|
|
6446
6505
|
"lookback-days",
|
|
6447
6506
|
"no-promote",
|
|
6448
6507
|
"no-wait",
|
|
6508
|
+
"promote",
|
|
6449
6509
|
"poll-interval",
|
|
6450
6510
|
"replay-set-id",
|
|
6451
6511
|
"seeds-per-case",
|
|
@@ -6647,7 +6707,7 @@ async function runPromptSyncExclusive(flags, profileOptions, options) {
|
|
|
6647
6707
|
const analyzedDefinitions = new Map;
|
|
6648
6708
|
if (flags["no-analyze"] !== "true") {
|
|
6649
6709
|
options.onProgress?.("Analyzing prompt sources before sync.");
|
|
6650
|
-
const { analyzeHarnessPrompts } = await import("./harness-
|
|
6710
|
+
const { analyzeHarnessPrompts } = await import("./harness-sqngqjrd.js");
|
|
6651
6711
|
const result = await analyzeHarnessPrompts({
|
|
6652
6712
|
rootDir: process.cwd(),
|
|
6653
6713
|
existing: established.flatMap((prompt) => prompt.sourceDefinition ? [prompt.sourceDefinition.source] : []),
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
resolveTenantId,
|
|
26
26
|
shouldInventoryFile,
|
|
27
27
|
stringOption
|
|
28
|
-
} from "./cli-
|
|
28
|
+
} from "./cli-8c60k2p4.js";
|
|
29
29
|
import {
|
|
30
30
|
__commonJS,
|
|
31
31
|
__require,
|
|
@@ -184813,7 +184813,7 @@ async function runHarnessCommand(context) {
|
|
|
184813
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.");
|
|
184814
184814
|
}
|
|
184815
184815
|
if (context.flags["github-actions"] === "true") {
|
|
184816
|
-
const { runGithubActionsAnalyze } = await import("./harness-github-actions-
|
|
184816
|
+
const { runGithubActionsAnalyze } = await import("./harness-github-actions-pg0azf3h.js");
|
|
184817
184817
|
const result = await runGithubActionsAnalyze(rootDir, {
|
|
184818
184818
|
writeReport: (report2) => {
|
|
184819
184819
|
const normalized = normalizeHarnessReport(report2);
|
|
@@ -1213,7 +1213,7 @@ function createCliOutput(options) {
|
|
|
1213
1213
|
if (options.quiet || state.terminal)
|
|
1214
1214
|
return;
|
|
1215
1215
|
const agentError = errorToAgentError(error);
|
|
1216
|
-
const envelope = createAgentErrorEnvelope(options.command || "unknown", agentError, state.runId);
|
|
1216
|
+
const envelope = createAgentErrorEnvelope(options.command || "unknown", agentError, state.runId, errorWarnings(error));
|
|
1217
1217
|
if (options.mode === "agent-stream") {
|
|
1218
1218
|
ensureStarted();
|
|
1219
1219
|
if (error instanceof CliInputRequiredError) {
|
|
@@ -1315,11 +1315,16 @@ function agentEnvelopeFits(command, data, options = {}) {
|
|
|
1315
1315
|
const envelope = createAgentEnvelope({ command, status: "ok", data, ...options });
|
|
1316
1316
|
return !envelope.truncation && Buffer.byteLength(JSON.stringify(envelope), "utf8") <= maxBytes;
|
|
1317
1317
|
}
|
|
1318
|
-
function
|
|
1318
|
+
function errorWarnings(error) {
|
|
1319
|
+
const warnings = error?.warnings;
|
|
1320
|
+
return Array.isArray(warnings) && warnings.length ? warnings.filter((w) => typeof w === "string") : undefined;
|
|
1321
|
+
}
|
|
1322
|
+
function createAgentErrorEnvelope(command, error, runId, warnings) {
|
|
1319
1323
|
return createAgentEnvelope({
|
|
1320
1324
|
command,
|
|
1321
1325
|
status: "error",
|
|
1322
1326
|
data: null,
|
|
1327
|
+
warnings: warnings ?? [],
|
|
1323
1328
|
meta: runId ? { run_id: runId } : undefined,
|
|
1324
1329
|
summary: {
|
|
1325
1330
|
text: error.message,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
authFetch,
|
|
3
3
|
getCachedLoginContext
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-rycpwqzm.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-8c60k2p4.js";
|
|
19
19
|
|
|
20
20
|
// src/init/tenant.ts
|
|
21
21
|
import { randomUUID } from "node:crypto";
|
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
runPromptsCommand,
|
|
9
9
|
runSkillsCommand,
|
|
10
10
|
runStatusCommand
|
|
11
|
-
} from "./cli-
|
|
11
|
+
} from "./cli-141ca3yv.js";
|
|
12
12
|
import {
|
|
13
13
|
ApiError,
|
|
14
14
|
HARNESS_REPORT_APPROVAL_PATH,
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
terminalStyles,
|
|
38
38
|
unknownSignalsSubcommandError,
|
|
39
39
|
validateHarnessReport
|
|
40
|
-
} from "./cli-
|
|
40
|
+
} from "./cli-5tsqk3jt.js";
|
|
41
41
|
import"./cli-ssfq84k5.js";
|
|
42
42
|
import {
|
|
43
43
|
authFetch,
|
|
@@ -46,7 +46,7 @@ import {
|
|
|
46
46
|
loadAuthSession,
|
|
47
47
|
login,
|
|
48
48
|
revokeCliSessionToken
|
|
49
|
-
} from "./cli-
|
|
49
|
+
} from "./cli-rycpwqzm.js";
|
|
50
50
|
import {
|
|
51
51
|
AGENT_ERROR_CODES,
|
|
52
52
|
CliAccessError,
|
|
@@ -95,7 +95,7 @@ import {
|
|
|
95
95
|
validateConfig,
|
|
96
96
|
wasOutputCancelled,
|
|
97
97
|
writeSecretJsonFile
|
|
98
|
-
} from "./cli-
|
|
98
|
+
} from "./cli-8c60k2p4.js";
|
|
99
99
|
import {
|
|
100
100
|
__require
|
|
101
101
|
} from "./cli-0v6na3yp.js";
|
|
@@ -151,7 +151,7 @@ var WorldStateSchema = z.object({
|
|
|
151
151
|
var ContextSchema = z.object({
|
|
152
152
|
conversation_id: z.string(),
|
|
153
153
|
msg_index: z.number().min(0).optional(),
|
|
154
|
-
window: z.number().
|
|
154
|
+
window: z.number().int().min(0).optional(),
|
|
155
155
|
all: boolFlag(),
|
|
156
156
|
from: z.number().int().min(0).optional(),
|
|
157
157
|
max_messages: z.number().int().min(1).max(5000).optional()
|
|
@@ -8194,6 +8194,8 @@ function pageMessages(page) {
|
|
|
8194
8194
|
const messages = asRecord(page.context)?.messages ?? page.messages;
|
|
8195
8195
|
return (Array.isArray(messages) ? messages : []).map((m) => asRecord(m) ?? {});
|
|
8196
8196
|
}
|
|
8197
|
+
var CONTEXT_MAX_WINDOW = 5;
|
|
8198
|
+
var CONTEXT_ALL_MAX_MESSAGES = 5000;
|
|
8197
8199
|
async function readFullTranscript(conversationId, opts = {}) {
|
|
8198
8200
|
const start = opts.from ?? 0;
|
|
8199
8201
|
const requested = opts.maxMessages ?? FULL_TRANSCRIPT_DEFAULT_MAX_MESSAGES;
|
|
@@ -8579,13 +8581,26 @@ async function runCommand(command, positional, flags, positionals = positional ?
|
|
|
8579
8581
|
const query2 = new URLSearchParams;
|
|
8580
8582
|
if (params.msg_index !== undefined)
|
|
8581
8583
|
query2.set("msg_index", params.msg_index.toString());
|
|
8582
|
-
|
|
8583
|
-
|
|
8584
|
+
const window = params.window === undefined ? undefined : Math.min(params.window, CONTEXT_MAX_WINDOW);
|
|
8585
|
+
if (window !== undefined)
|
|
8586
|
+
query2.set("window", window.toString());
|
|
8584
8587
|
const queryString = query2.toString() ? `?${query2.toString()}` : "";
|
|
8585
8588
|
const data = await callDataAPI(`/conversations/${params.conversation_id}/context${queryString}`);
|
|
8586
8589
|
const ctxRecord = asRecord(data) ?? {};
|
|
8587
8590
|
const warnings = notFoundWarning("trace", params.conversation_id, asNumber(ctxRecord.total_messages) === 0);
|
|
8588
|
-
|
|
8591
|
+
const nextCommands = [];
|
|
8592
|
+
if (params.window !== undefined && params.window > CONTEXT_MAX_WINDOW) {
|
|
8593
|
+
const center = asNumber(asRecord(ctxRecord.context)?.center_index) ?? params.msg_index ?? 0;
|
|
8594
|
+
const span = Math.min(params.window * 2 + 1, CONTEXT_ALL_MAX_MESSAGES);
|
|
8595
|
+
const from = Math.max(0, center - Math.floor((span - 1) / 2));
|
|
8596
|
+
const wide = `moda context ${shellArg(params.conversation_id)} --all --from=${from} --max-messages=${span}`;
|
|
8597
|
+
warnings.push(`--window=${params.window} is above the maximum of ${CONTEXT_MAX_WINDOW}, so this shows ±${CONTEXT_MAX_WINDOW} messages. For a wider slice run: ${wide}`);
|
|
8598
|
+
nextCommands.push({ command: wide, purpose: `Read ±${params.window} messages around the anchor.`, mutability: "read", requires_approval: false });
|
|
8599
|
+
}
|
|
8600
|
+
context.output.writeData(data, {
|
|
8601
|
+
...warnings.length > 0 ? { warnings } : {},
|
|
8602
|
+
...nextCommands.length > 0 ? { nextCommands } : {}
|
|
8603
|
+
});
|
|
8589
8604
|
break;
|
|
8590
8605
|
}
|
|
8591
8606
|
case "audit":
|
|
@@ -9360,7 +9375,7 @@ var commandRegistry = createCommandRegistry([
|
|
|
9360
9375
|
resetApiRequestCountBeforeRun: true,
|
|
9361
9376
|
telemetry: "result",
|
|
9362
9377
|
handler: async (context) => {
|
|
9363
|
-
const { runInit } = await import("./index-
|
|
9378
|
+
const { runInit } = await import("./index-cnfwmzew.js");
|
|
9364
9379
|
if (context.outputMode === "agent-stream") {
|
|
9365
9380
|
context.output.writeEvent({
|
|
9366
9381
|
event: "started",
|
|
@@ -9401,7 +9416,7 @@ var commandRegistry = createCommandRegistry([
|
|
|
9401
9416
|
resetApiRequestCountBeforeRun: true,
|
|
9402
9417
|
telemetry: "result-and-error",
|
|
9403
9418
|
handler: async (context) => {
|
|
9404
|
-
const { runProvision } = await import("./provision-
|
|
9419
|
+
const { runProvision } = await import("./provision-02wqtkvm.js");
|
|
9405
9420
|
return runProvision(context, {
|
|
9406
9421
|
resumeCommand: buildResumeCommand("provision", context.rawFlags)
|
|
9407
9422
|
});
|
|
@@ -9828,6 +9843,7 @@ var commandRegistry = createCommandRegistry([
|
|
|
9828
9843
|
description: "Get windowed trace context (messages around one turn), or the whole trace with --all",
|
|
9829
9844
|
examples: [
|
|
9830
9845
|
"moda context <conversation_id> --window=3",
|
|
9846
|
+
"moda context <conversation_id> --msg-index=40 --window=0",
|
|
9831
9847
|
"moda context <conversation_id> --all",
|
|
9832
9848
|
"moda context <conversation_id> --all --from=500 --max-messages=500"
|
|
9833
9849
|
],
|
|
@@ -10125,11 +10141,12 @@ var commandRegistry = createCommandRegistry([
|
|
|
10125
10141
|
flags: [
|
|
10126
10142
|
{ name: "--baseline=<path>", description: "Prompt file to treat as the control." },
|
|
10127
10143
|
{ name: "--candidate=<path>", description: "Prompt file to treat as the variant." },
|
|
10128
|
-
{ name: "--traces=<ids>", description: "Comma-separated trace ids (conversation_id values) to replay, at most 100. Legacy alias: --conversations=<ids>." },
|
|
10144
|
+
{ name: "--traces=<ids>", description: "Comma-separated trace ids (conversation_id values) to replay, at most 100. Each case uses Moda's distilled scenario and success criteria for the trace; a trace that cannot be distilled falls back to its opening user message with generic criteria, and the run warns. Legacy alias: --conversations=<ids>." },
|
|
10129
10145
|
{ name: "--cases=<n>", description: "Cases to auto-generate (default 5, max 100)." },
|
|
10130
10146
|
{ name: "--seeds=<n>", description: "Repeats per case per arm (default 3, max 10)." },
|
|
10131
10147
|
{ name: "--model=<slug>", description: "Assistant model for both arms; must be in the replay allowlist unless --allow-any-model." },
|
|
10132
|
-
{ name: "--yes", description: "Confirm a run above 200 planned playouts (cases x seeds x 2 arms), or one whose case count is unknown." }
|
|
10148
|
+
{ name: "--yes", description: "Confirm a run above 200 planned playouts (cases x seeds x 2 arms), or one whose case count is unknown." },
|
|
10149
|
+
{ name: "--promote", description: "Make this run's replay set the tenant's primary replay set. Off by default, so an ad-hoc A/B never replaces it." }
|
|
10133
10150
|
],
|
|
10134
10151
|
examples: [
|
|
10135
10152
|
"moda prompts ab --baseline=prompts/agent.prompt.md --candidate=prompts/agent-v2.prompt.md --traces=conv_1,conv_2"
|
|
@@ -42,8 +42,8 @@ import {
|
|
|
42
42
|
writeHarnessAnalyzeResult,
|
|
43
43
|
writeHarnessArtifacts,
|
|
44
44
|
writeHumanProgress
|
|
45
|
-
} from "./cli-
|
|
46
|
-
import"./cli-
|
|
45
|
+
} from "./cli-5tsqk3jt.js";
|
|
46
|
+
import"./cli-8c60k2p4.js";
|
|
47
47
|
import"./cli-0v6na3yp.js";
|
|
48
48
|
export {
|
|
49
49
|
writeHumanProgress,
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
initPrompts,
|
|
4
4
|
runPromptSync,
|
|
5
5
|
runSkillSync
|
|
6
|
-
} from "./cli-
|
|
6
|
+
} from "./cli-141ca3yv.js";
|
|
7
7
|
import {
|
|
8
8
|
codingAgentDisplayName,
|
|
9
9
|
describeCodingAgentEvent,
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
runHarnessCommand,
|
|
23
23
|
startRemoteAnalyze,
|
|
24
24
|
stripAnsi
|
|
25
|
-
} from "./cli-
|
|
25
|
+
} from "./cli-5tsqk3jt.js";
|
|
26
26
|
import {
|
|
27
27
|
bundledSkillsDir,
|
|
28
28
|
installIntegrationSkill,
|
|
@@ -34,14 +34,14 @@ import {
|
|
|
34
34
|
} from "./cli-ssfq84k5.js";
|
|
35
35
|
import {
|
|
36
36
|
selectTenantAndCreateKey
|
|
37
|
-
} from "./cli-
|
|
37
|
+
} from "./cli-j2fapt3g.js";
|
|
38
38
|
import {
|
|
39
39
|
ConnectCodeError,
|
|
40
40
|
connectWithCode,
|
|
41
41
|
loadAuthSession,
|
|
42
42
|
loadToken,
|
|
43
43
|
login
|
|
44
|
-
} from "./cli-
|
|
44
|
+
} from "./cli-rycpwqzm.js";
|
|
45
45
|
import {
|
|
46
46
|
CliAuthError,
|
|
47
47
|
CliInputError,
|
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
createCommandContext,
|
|
50
50
|
resolveIngestUrl,
|
|
51
51
|
resolveModaBaseUrl
|
|
52
|
-
} from "./cli-
|
|
52
|
+
} from "./cli-8c60k2p4.js";
|
|
53
53
|
import"./cli-0v6na3yp.js";
|
|
54
54
|
|
|
55
55
|
// src/init/index.ts
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
selectTenantAndCreateKey
|
|
3
|
-
} from "./cli-
|
|
3
|
+
} from "./cli-j2fapt3g.js";
|
|
4
4
|
import {
|
|
5
5
|
loadAuthSession
|
|
6
|
-
} from "./cli-
|
|
6
|
+
} from "./cli-rycpwqzm.js";
|
|
7
7
|
import {
|
|
8
8
|
CliAuthError,
|
|
9
9
|
resolveIngestUrl,
|
|
10
10
|
resolveModaBaseUrl,
|
|
11
11
|
stringOption
|
|
12
|
-
} from "./cli-
|
|
12
|
+
} from "./cli-8c60k2p4.js";
|
|
13
13
|
import"./cli-0v6na3yp.js";
|
|
14
14
|
|
|
15
15
|
// src/provision.ts
|
package/package.json
CHANGED
package/skills/moda-cli/SKILL.md
CHANGED
|
@@ -442,7 +442,9 @@ fail instead of being clamped.
|
|
|
442
442
|
|
|
443
443
|
`--window=N` on `context`, `frustrations --include-window` and
|
|
444
444
|
`tool-failure-detail --include-window` is a message half-width (1–5), not a
|
|
445
|
-
time window.
|
|
445
|
+
time window. On `context`, `--window=0` returns only the anchor message (plus
|
|
446
|
+
`total_messages`), and a value above 5 is clamped to 5 with a warning that
|
|
447
|
+
prints the `--all --from --max-messages` command for a wider slice.
|
|
446
448
|
|
|
447
449
|
### Schema introspection
|
|
448
450
|
|
|
@@ -631,6 +633,7 @@ Filters: `--search`, `--cluster-id`, `--user-id`, `--time-range`
|
|
|
631
633
|
moda context <conversation_id> # default window around middle
|
|
632
634
|
moda context <conversation_id> --msg-index=5 # center on message 5
|
|
633
635
|
moda context <conversation_id> --window=3 # 3 messages each side (max 5)
|
|
636
|
+
moda context <conversation_id> --msg-index=40 --window=0 # just message 40 + total_messages
|
|
634
637
|
moda context <conversation_id> --all # whole trace in order, first 500 messages
|
|
635
638
|
moda context <conversation_id> --all --from=500 --max-messages=500 # continue (max 5000)
|
|
636
639
|
```
|
|
@@ -767,6 +770,13 @@ earlier turns as history);
|
|
|
767
770
|
`anthropic/claude-haiku-4-5`, `google/gemini-2.5-flash`,
|
|
768
771
|
`google/gemini-2.5-pro` unless you pass `--allow-any-model`.
|
|
769
772
|
|
|
773
|
+
`prompts ab --traces=<ids>` builds one case per trace from Moda's distilled
|
|
774
|
+
scenario and success criteria for that trace. A trace Moda cannot distill
|
|
775
|
+
falls back to its opening user message with three generic criteria (which long
|
|
776
|
+
traces pass easily); the run warns and lists it under `caseSources.fallback`.
|
|
777
|
+
`prompts ab` never makes its replay set the tenant's primary set unless you
|
|
778
|
+
pass `--promote`.
|
|
779
|
+
|
|
770
780
|
Runtime code should render synced prompts through the SDK:
|
|
771
781
|
|
|
772
782
|
```typescript
|