@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
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Version of the canonicalization below. Bump on ANY change to the hashed payload. */
|
|
2
|
+
export declare const PROMPT_HASH_VERSION: 1;
|
|
3
|
+
/** The typed-source definition fields that participate in the hash. */
|
|
4
|
+
export interface PromptHashSourceDefinition {
|
|
5
|
+
kind: string;
|
|
6
|
+
source: unknown;
|
|
7
|
+
sourceHash?: string;
|
|
8
|
+
dependencies?: unknown;
|
|
9
|
+
coverage?: unknown;
|
|
10
|
+
unresolved?: unknown;
|
|
11
|
+
}
|
|
12
|
+
/** Hashed prompt fields; anything else on the object is ignored. */
|
|
13
|
+
export interface PromptHashInput {
|
|
14
|
+
key: string;
|
|
15
|
+
content: string;
|
|
16
|
+
systemPrompt?: string | null;
|
|
17
|
+
messages?: unknown[] | null;
|
|
18
|
+
variables?: unknown[] | null;
|
|
19
|
+
variablesSchema?: Record<string, unknown> | null;
|
|
20
|
+
modelConfig?: Record<string, unknown> | null;
|
|
21
|
+
toolRefs?: unknown[] | null;
|
|
22
|
+
responseSchema?: Record<string, unknown> | null;
|
|
23
|
+
sourceDefinition?: PromptHashSourceDefinition | null;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The subset of a typed source definition that is hashed: text/messages hash
|
|
27
|
+
* their extracted source; builders/templates also hash dependency
|
|
28
|
+
* fingerprints and coverage, so a fragment edit mints a new version.
|
|
29
|
+
*/
|
|
30
|
+
export declare function promptSourceHashPayload(definition: PromptHashSourceDefinition): Record<string, unknown>;
|
|
31
|
+
/** JSON.stringify with every object's keys sorted by localeCompare, recursively. */
|
|
32
|
+
export declare function stableJson(value: unknown): string;
|
|
33
|
+
/** The exact string that is hashed (exposed for debugging hash mismatches). */
|
|
34
|
+
export declare function promptContentHashPayload(prompt: PromptHashInput): string;
|
|
35
|
+
/** Lowercase hex SHA-256 of {@link promptContentHashPayload}: the lockfile `contentHash`. */
|
|
36
|
+
export declare function computePromptContentHash(prompt: PromptHashInput): string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PROMPT_HASH_VERSION,
|
|
3
|
+
computePromptContentHash,
|
|
4
|
+
promptContentHashPayload,
|
|
5
|
+
promptSourceHashPayload,
|
|
6
|
+
stableJson
|
|
7
|
+
} from "./cli-mm48br00.js";
|
|
8
|
+
import"./cli-0v6na3yp.js";
|
|
9
|
+
export {
|
|
10
|
+
stableJson,
|
|
11
|
+
promptSourceHashPayload,
|
|
12
|
+
promptContentHashPayload,
|
|
13
|
+
computePromptContentHash,
|
|
14
|
+
PROMPT_HASH_VERSION
|
|
15
|
+
};
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
selectTenantAndCreateKey
|
|
3
|
-
} from "./cli-
|
|
3
|
+
} from "./cli-sq6g0tk5.js";
|
|
4
4
|
import {
|
|
5
5
|
loadAuthSession
|
|
6
|
-
} from "./cli-
|
|
6
|
+
} from "./cli-kxwm7y62.js";
|
|
7
7
|
import {
|
|
8
8
|
CliAuthError,
|
|
9
9
|
resolveIngestUrl,
|
|
10
10
|
resolveModaBaseUrl,
|
|
11
11
|
stringOption
|
|
12
|
-
} from "./cli-
|
|
12
|
+
} from "./cli-ac3p2byq.js";
|
|
13
13
|
import"./cli-0v6na3yp.js";
|
|
14
14
|
|
|
15
15
|
// src/provision.ts
|
package/package.json
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moda-ai/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.54.0",
|
|
4
4
|
"description": "CLI for Moda - AI agent analytics and observability",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"cli": "./dist/cli.js",
|
|
8
8
|
"moda": "./dist/cli.js"
|
|
9
9
|
},
|
|
10
|
+
"exports": {
|
|
11
|
+
"./prompt-hash": {
|
|
12
|
+
"types": "./dist/prompt-hash.d.ts",
|
|
13
|
+
"import": "./dist/prompt-hash.js"
|
|
14
|
+
},
|
|
15
|
+
"./package.json": "./package.json",
|
|
16
|
+
"./*": "./*"
|
|
17
|
+
},
|
|
10
18
|
"files": [
|
|
11
19
|
"dist/**/*.js",
|
|
12
20
|
"dist/**/*.d.ts",
|
|
@@ -21,7 +29,7 @@
|
|
|
21
29
|
"scripts": {
|
|
22
30
|
"bundle:skills": "bun scripts/bundle-skills.ts",
|
|
23
31
|
"export:admin-manifest": "bun scripts/export-admin-command-manifest.ts",
|
|
24
|
-
"build": "bun run bundle:skills && tsc --noEmit && bun build ./src/cli.ts ./src/prompt-source-mcp.ts --target=node --format=esm --outdir=dist --splitting --external @inquirer/prompts --external open --external zod",
|
|
32
|
+
"build": "bun run bundle:skills && tsc --noEmit && tsc -p tsconfig.prompt-hash.json && bun build ./src/cli.ts ./src/prompt-source-mcp.ts ./src/prompt-hash.ts --target=node --format=esm --outdir=dist --splitting --external @inquirer/prompts --external open --external zod",
|
|
25
33
|
"dev": "tsc --watch",
|
|
26
34
|
"typecheck": "tsc --noEmit",
|
|
27
35
|
"test": "bun run bundle:skills && vitest run",
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": "moda.skill_index.v1",
|
|
3
|
-
"bundled_at": "2026-10-
|
|
4
|
-
"cli_version": "1.
|
|
3
|
+
"bundled_at": "2026-10-12T07:41:12.130Z",
|
|
4
|
+
"cli_version": "1.54.0",
|
|
5
5
|
"skills": [
|
|
6
6
|
{
|
|
7
7
|
"id": "integration-cloudflare-think",
|
|
8
|
-
"version": "1.1.
|
|
8
|
+
"version": "1.1.1",
|
|
9
9
|
"summary": "Instrument Think on Workers with AI SDK 7, prompt versions, and acknowledged JSON export.",
|
|
10
10
|
"targets": {
|
|
11
11
|
"language": "node",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: integration-cloudflare-think
|
|
3
3
|
name: "Integrate Moda with Cloudflare Think"
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.1
|
|
5
5
|
category: integration
|
|
6
6
|
targets:
|
|
7
7
|
language: node
|
|
@@ -94,7 +94,10 @@ the correct definition was registered.
|
|
|
94
94
|
Keep memory and variable substitutions separate from reusable template
|
|
95
95
|
versions. Think adds instructions/tools: verify actual system instructions
|
|
96
96
|
on each model span as well as the registry definition.
|
|
97
|
-
Reference: https://docs.moda.dev/prompt-management/attribution
|
|
97
|
+
Reference: https://docs.moda.dev/prompt-management/attribution#cloudflare-think-and-ai-sdk-7
|
|
98
|
+
and, for `.moda/prompts.yml` `sources:` mappings, https://docs.moda.dev/prompt-management/workflow#map-prompts-defined-in-code.
|
|
99
|
+
Without the `prompt` option no trace carries a prompt version, so prompt fixes
|
|
100
|
+
land `UNROUTED` ("top share 0%").
|
|
98
101
|
|
|
99
102
|
## 5. Validate through the original application route
|
|
100
103
|
|
package/skills/moda-cli/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: moda-cli
|
|
3
|
-
version: 2.
|
|
3
|
+
version: 2.8.0
|
|
4
4
|
description: Query Moda's AI agent trace analytics and manage code-first prompt versions from the terminal — semantic/keyword/hybrid message search, overview KPIs, topic clusters, message context, user frustration detections, tool failures, custom signals, false-positive review of detections, and moda prompts status/sync/promote. Use when the user asks about moda, modaflows, trace or conversation analytics, prompt management, user frustrations, agent observability, tool failure debugging, custom signals, marking a detection as a false positive, wants to find traces or tool calls about a topic, or wants to investigate how their AI agent is performing.
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -458,6 +458,8 @@ fail instead of being clamped.
|
|
|
458
458
|
time window. On `context`, `--window=0` returns only the anchor message (plus
|
|
459
459
|
`total_messages`), and a value above 5 is clamped to 5 with a warning that
|
|
460
460
|
prints the `--all --from --max-messages` command for a wider slice.
|
|
461
|
+
`--metadata-only` returns only the summary and `total_messages`, with no
|
|
462
|
+
messages.
|
|
461
463
|
|
|
462
464
|
### Schema introspection
|
|
463
465
|
|
|
@@ -546,11 +548,13 @@ compare scores across modes.
|
|
|
546
548
|
Hand the anchors straight to `moda context`:
|
|
547
549
|
|
|
548
550
|
```bash
|
|
549
|
-
# Find, then read the exact turn
|
|
550
|
-
|
|
551
|
+
# Find, then read the exact turn. --json prints the bare payload; piped output
|
|
552
|
+
# without it is the agent envelope, where results sit under .data.results.
|
|
553
|
+
hit=$(moda search "double charge" --limit=1 --json | jq -c '.results[0] // empty')
|
|
551
554
|
cid=$(echo "$hit" | jq -r '.conversation_id')
|
|
552
|
-
|
|
553
|
-
|
|
555
|
+
# Trace-level fallback hits (match_grain: "trace") have no message_index.
|
|
556
|
+
idx=$(echo "$hit" | jq -r '.message_index // empty')
|
|
557
|
+
moda context "$cid" ${idx:+--msg-index="$idx"}
|
|
554
558
|
```
|
|
555
559
|
|
|
556
560
|
### 2. Overview (start here for health questions)
|
|
@@ -647,6 +651,7 @@ moda context <conversation_id> # default window around middle
|
|
|
647
651
|
moda context <conversation_id> --msg-index=5 # center on message 5
|
|
648
652
|
moda context <conversation_id> --window=3 # 3 messages each side (max 5)
|
|
649
653
|
moda context <conversation_id> --msg-index=40 --window=0 # just message 40 + total_messages
|
|
654
|
+
moda context <conversation_id> --metadata-only # summary + total_messages, no messages
|
|
650
655
|
moda context <conversation_id> --all # whole trace in order, first 500 messages
|
|
651
656
|
moda context <conversation_id> --all --from=500 --max-messages=500 # continue (max 5000)
|
|
652
657
|
```
|
|
@@ -768,17 +773,63 @@ dropped and `truncation.data.full_output_path` holds every example. Agent output
|
|
|
768
773
|
Use these only when working on the code-first prompt registry.
|
|
769
774
|
|
|
770
775
|
```bash
|
|
771
|
-
moda prompts init # create .moda/prompts.yml
|
|
772
|
-
moda prompts status # read-only local status
|
|
776
|
+
moda prompts init # create .moda/prompts.yml (version 2)
|
|
777
|
+
moda prompts status # read-only local status + manifest warnings
|
|
773
778
|
moda prompts diff # only changed/new/deleted since last sync
|
|
779
|
+
moda prompts migrate --dry-run # preview a version 1 -> 2 manifest rewrite
|
|
780
|
+
moda prompts migrate # apply it (atomic; comments kept)
|
|
781
|
+
moda prompts sync --dry-run # preview discovery + what would upload
|
|
774
782
|
moda prompts sync # upload changed prompt versions
|
|
783
|
+
moda prompts sync --from-harness # register mappings from .moda/harness-report.json first
|
|
775
784
|
moda prompts sync --watch # sync when local prompt hashes change
|
|
776
785
|
moda prompts promote support.triage --label=prod --version=pver_abc123
|
|
777
786
|
```
|
|
778
787
|
|
|
779
|
-
`status` and `
|
|
780
|
-
`.moda/prompts.lock.json`. `promote` moves a remote `dev`,
|
|
781
|
-
`prod` label to an existing version.
|
|
788
|
+
`status`, `diff` and `migrate --dry-run` are read-only. `sync` uploads prompt
|
|
789
|
+
versions and writes `.moda/prompts.lock.json`. `promote` moves a remote `dev`,
|
|
790
|
+
`staging`, or `prod` label to an existing version.
|
|
791
|
+
|
|
792
|
+
`.moda/prompts.yml` (version 2) has two ways to point at prompts:
|
|
793
|
+
|
|
794
|
+
```yaml
|
|
795
|
+
version: 2
|
|
796
|
+
prompt_paths: # exact fast-glob patterns from the repo root
|
|
797
|
+
- "prompts/**/*.prompt.md"
|
|
798
|
+
- "!prompts/archive/**"
|
|
799
|
+
sources: # prompts defined in code or config, mapped in place
|
|
800
|
+
- key: support.system # stable registry key (also the lockfile key)
|
|
801
|
+
path: src/agent.ts
|
|
802
|
+
selector: { symbol: SYSTEM_PROMPT } # or { pointer: /support/prompt } for JSON/YAML
|
|
803
|
+
- key: support.build
|
|
804
|
+
path: src/prompt.py
|
|
805
|
+
selector: { symbol: build_prompt }
|
|
806
|
+
kind: builder # text | messages | template | builder
|
|
807
|
+
dependencies:
|
|
808
|
+
- path: config/policy.txt
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
- `prompts status` returns `zeroMatchPatterns` (globs that match nothing),
|
|
812
|
+
`legacyOnlyFiles` and `legacyManifest`. A non-empty `legacyOnlyFiles` means a
|
|
813
|
+
manifest from an older CLI: those files used to sync (old discovery matched
|
|
814
|
+
`*.prompt.*` anywhere) but match nothing now. Run `moda prompts migrate
|
|
815
|
+
--dry-run`, then `moda prompts migrate`; it adds them as explicit paths so
|
|
816
|
+
their keys and lockfile entries are unchanged (`--discover` also scans for
|
|
817
|
+
code-defined prompts, but lists unverified ones under `pendingSources`
|
|
818
|
+
instead of adding them; verify those with `moda harness analyze
|
|
819
|
+
--experimental --concern=prompts`, then `sync --from-harness`). `moda
|
|
820
|
+
doctor` reports the same condition on its `prompts_discovered` check.
|
|
821
|
+
- `sync --from-harness` registers what resolves and lists the rest in
|
|
822
|
+
`harnessImport.skipped` with reasons; it fails only when nothing resolves
|
|
823
|
+
(regenerate with `moda harness analyze --experimental --concern=prompts`).
|
|
824
|
+
- Lockfile `contentHash` is `computePromptContentHash` from
|
|
825
|
+
`@moda-ai/cli/prompt-hash` (`PROMPT_HASH_VERSION` 1). Don't reimplement it.
|
|
826
|
+
|
|
827
|
+
To attribute runtime calls, stamp the lock entry `{ key, promptId, versionId }`
|
|
828
|
+
on telemetry. With Cloudflare Think / AI SDK 7, pass
|
|
829
|
+
`prompt: lock.prompts['<key>']` to `createThinkTelemetry` (`moda-ai/think`) or
|
|
830
|
+
`createAI7Telemetry` (`moda-ai/ai7`). A `moda fix` that lands `UNROUTED` with
|
|
831
|
+
"top share 0%" means the evidence carries no prompt version: wire this up,
|
|
832
|
+
then check `moda prompts status`.
|
|
782
833
|
|
|
783
834
|
`prompts ab` and `prompts propose --gate` run paid replays. Before sending
|
|
784
835
|
anything they compute planned playouts (cases × seeds × 2 arms) and print it
|
|
@@ -1128,16 +1179,17 @@ and archiving an active custom signal (pause it, or delete a draft).
|
|
|
1128
1179
|
|
|
1129
1180
|
```bash
|
|
1130
1181
|
# Semantic: find the moment a user expressed an intent, in their own words
|
|
1131
|
-
moda search "user wants to cancel subscription" --mode=semantic --limit=5 \
|
|
1182
|
+
moda search "user wants to cancel subscription" --mode=semantic --limit=5 --json \
|
|
1132
1183
|
| jq -r '.results[] | "\(.conversation_id) @\(.message_index) \(.snippet)"'
|
|
1133
1184
|
|
|
1134
1185
|
# Keyword: locate every tool call/result mentioning an exact identifier
|
|
1135
1186
|
moda search "stripe.refunds.create" --mode=keyword --limit=10
|
|
1136
1187
|
|
|
1137
|
-
# Search, then open the top hit at the exact turn
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
|
1188
|
+
# Search, then open the top message-level hit at the exact turn (skips
|
|
1189
|
+
# trace-level fallback hits, which have no message_index)
|
|
1190
|
+
moda search "rate limit exceeded" --limit=5 --json \
|
|
1191
|
+
| jq -r 'first(.results[] | select(.message_index != null)) | "\(.conversation_id) \(.message_index)"' \
|
|
1192
|
+
| xargs -r -n2 sh -c 'moda context "$0" --msg-index="$1"'
|
|
1141
1193
|
```
|
|
1142
1194
|
|
|
1143
1195
|
### Daily health check
|