@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.
@@ -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
+ };
@@ -5,8 +5,8 @@ import {
5
5
  inspectCodeSelectors,
6
6
  inspectPythonSelectors,
7
7
  safePromptEvidencePath
8
- } from "./cli-x0x0n35w.js";
9
- import"./cli-xrs02c0t.js";
8
+ } from "./cli-9250ckvg.js";
9
+ import"./cli-ac3p2byq.js";
10
10
  import {
11
11
  __commonJS,
12
12
  __toESM
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  selectTenantAndCreateKey
3
- } from "./cli-h4k23fb0.js";
3
+ } from "./cli-sq6g0tk5.js";
4
4
  import {
5
5
  loadAuthSession
6
- } from "./cli-7kbzqact.js";
6
+ } from "./cli-kxwm7y62.js";
7
7
  import {
8
8
  CliAuthError,
9
9
  resolveIngestUrl,
10
10
  resolveModaBaseUrl,
11
11
  stringOption
12
- } from "./cli-xrs02c0t.js";
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.50.0",
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-10T14:07:17.742Z",
4
- "cli_version": "1.50.0",
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.0",
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.0
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
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: moda-cli
3
- version: 2.7.0
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
- hit=$(moda search "double charge" --limit=1 | jq -r '.results[0]')
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
- idx=$(echo "$hit" | jq -r '.message_index')
553
- moda context "$cid" --msg-index="$idx"
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 `diff` are read-only. `sync` uploads prompt versions and writes
780
- `.moda/prompts.lock.json`. `promote` moves a remote `dev`, `staging`, or
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
- moda search "rate limit exceeded" --limit=1 \
1139
- | jq -r '.results[0] | "\(.conversation_id) \(.message_index)"' \
1140
- | xargs -n2 sh -c 'moda context "$0" --msg-index="$1"'
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