@moda-ai/cli 1.1.1 → 1.2.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.
Files changed (59) hide show
  1. package/README.md +36 -0
  2. package/dist/agent.d.ts +5 -0
  3. package/dist/agent.js +477 -0
  4. package/dist/analyst-tui.d.ts +81 -0
  5. package/dist/analyst-tui.js +314 -0
  6. package/dist/api-client.d.ts +4 -0
  7. package/dist/api-client.js +20 -3
  8. package/dist/auth.d.ts +22 -3
  9. package/dist/auth.js +230 -66
  10. package/dist/cli.d.ts +20 -3
  11. package/dist/cli.js +768 -93
  12. package/dist/command-context.d.ts +34 -0
  13. package/dist/command-context.js +38 -0
  14. package/dist/command-registry.d.ts +22 -0
  15. package/dist/command-registry.js +15 -0
  16. package/dist/config.d.ts +40 -1
  17. package/dist/config.js +70 -3
  18. package/dist/doctor.d.ts +79 -0
  19. package/dist/doctor.js +1102 -0
  20. package/dist/errors.d.ts +5 -0
  21. package/dist/errors.js +9 -0
  22. package/dist/harness-report.d.ts +138 -0
  23. package/dist/harness-report.js +1464 -0
  24. package/dist/harness.d.ts +233 -0
  25. package/dist/harness.js +3264 -0
  26. package/dist/init/index.d.ts +30 -1
  27. package/dist/init/index.js +383 -23
  28. package/dist/init/rules.d.ts +5 -1
  29. package/dist/init/rules.js +22 -16
  30. package/dist/init/sdk-guide.d.ts +3 -0
  31. package/dist/init/sdk-guide.js +397 -0
  32. package/dist/init/tenant.js +12 -3
  33. package/dist/keys.d.ts +47 -0
  34. package/dist/keys.js +136 -0
  35. package/dist/output.d.ts +118 -0
  36. package/dist/output.js +228 -0
  37. package/dist/production-intelligence.d.ts +134 -0
  38. package/dist/production-intelligence.js +1113 -0
  39. package/dist/profile-commands.d.ts +10 -0
  40. package/dist/profile-commands.js +252 -0
  41. package/dist/profiles.d.ts +90 -0
  42. package/dist/profiles.js +432 -0
  43. package/dist/prompts.d.ts +6 -0
  44. package/dist/prompts.js +368 -0
  45. package/dist/schemas.d.ts +4 -4
  46. package/dist/skills.d.ts +25 -0
  47. package/dist/skills.js +468 -0
  48. package/dist/sync.d.ts +5 -0
  49. package/dist/sync.js +27 -0
  50. package/dist/telemetry.d.ts +18 -0
  51. package/dist/telemetry.js +63 -0
  52. package/dist/tui.d.ts +40 -0
  53. package/dist/tui.js +387 -0
  54. package/dist/workspace.d.ts +12 -0
  55. package/dist/workspace.js +1294 -0
  56. package/hooks/moda-snapshot.sh +41 -0
  57. package/package.json +10 -7
  58. package/skills/moda-cli/SKILL.md +48 -4
  59. package/skills/integrate-moda/SKILL.md +0 -63
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env bash
2
+ # Moda shadow workspace hook for coding agents.
3
+ # Triggered by Claude Code, Codex, and Cursor lifecycle/tool matchers.
4
+ #
5
+ # Claude Code passes hook context as a JSON object on stdin (per the Claude
6
+ # Code hooks reference): session_id, tool_use_id, prompt, hook_event_name,
7
+ # etc. We forward that stdin straight through to `moda workspace snapshot
8
+ # --hook-stdin`, which parses it server-side so the CLI sees the same
9
+ # correlation keys (session_id, tool_use_id, prompt_sha) the ingest worker
10
+ # will later join on. The previous version read $CLAUDE_SESSION_ID and
11
+ # $CLAUDE_PROMPT_HASH env vars, but Claude never sets those — so session_id
12
+ # and prompt-level joins were unrecoverable. Reading stdin fixes that.
13
+ #
14
+ # Runs `moda workspace snapshot` in the background so the hook never blocks
15
+ # Claude; redirects all output to /dev/null so user-visible output stays
16
+ # clean; always exits 0 so a transient failure can't break the user session.
17
+
18
+ set +e
19
+ case "${1:-}" in
20
+ claude|claude_code|codex|cursor)
21
+ PROVIDER="$1"
22
+ EVENT="${2:-UserPromptSubmit}"
23
+ ;;
24
+ *)
25
+ PROVIDER="claude_code"
26
+ EVENT="${1:-UserPromptSubmit}"
27
+ ;;
28
+ esac
29
+ MODA_SNAPSHOT_BIN="${MODA_BIN:-moda}"
30
+
31
+ # Buffer the hook JSON once so the background subshell sees it after this
32
+ # script's stdin is closed by Claude.
33
+ PAYLOAD="$(cat)"
34
+
35
+ (
36
+ printf '%s' "$PAYLOAD" \
37
+ | "$MODA_SNAPSHOT_BIN" workspace snapshot --provider "$PROVIDER" --event "$EVENT" --json --hook-stdin \
38
+ > /dev/null 2>&1
39
+ ) &
40
+
41
+ exit 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moda-ai/cli",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "CLI for Moda - AI agent analytics and observability",
5
5
  "type": "module",
6
6
  "bin": {
@@ -11,6 +11,7 @@
11
11
  "dist/**/*.js",
12
12
  "dist/**/*.d.ts",
13
13
  "!dist/__tests__",
14
+ "hooks/**",
14
15
  "skills/**/SKILL.md",
15
16
  "README.md",
16
17
  ".env.example"
@@ -20,16 +21,16 @@
20
21
  },
21
22
  "scripts": {
22
23
  "build": "tsc",
23
- "prepublishOnly": "tsc",
24
24
  "dev": "tsc --watch",
25
25
  "typecheck": "tsc --noEmit",
26
26
  "test": "vitest run",
27
- "test:ci": "vitest run",
28
- "test:watch": "vitest"
27
+ "test:watch": "vitest",
28
+ "lint": "eslint ."
29
29
  },
30
30
  "repository": {
31
31
  "type": "git",
32
- "url": "https://github.com/ModaLabs/moda-cli.git"
32
+ "url": "https://github.com/ModaLabs/modaobservability.git",
33
+ "directory": "apps/moda-cli"
33
34
  },
34
35
  "keywords": [
35
36
  "moda",
@@ -43,7 +44,7 @@
43
44
  "license": "MIT",
44
45
  "homepage": "https://docs.moda.dev/data-api/cli",
45
46
  "bugs": {
46
- "url": "https://github.com/ModaLabs/moda-cli/issues"
47
+ "url": "https://github.com/ModaLabs/ModaObservability/issues"
47
48
  },
48
49
  "dependencies": {
49
50
  "@inquirer/prompts": "^8.4.1",
@@ -51,9 +52,11 @@
51
52
  "zod": "^3.24.1"
52
53
  },
53
54
  "devDependencies": {
55
+ "@moda/eslint-config": "*",
54
56
  "@types/node": "^22.10.5",
57
+ "eslint": "^9.17.0",
55
58
  "typescript": "^5.7.2",
56
- "vitest": "^3.0.0"
59
+ "vitest": "^4.0.14"
57
60
  },
58
61
  "engines": {
59
62
  "node": ">=18.0.0"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: moda-cli
3
- description: Query Moda's AI agent conversation analytics from the terminal — overview KPIs, topic clusters, conversation search, message context, user frustration detections, tool failures, agent jobs (per-run outcomes), recurring workflows, and active loop detections. Use when the user asks about moda, modaflows, conversation analytics, user frustrations, agent observability, tool failure debugging, why an agent run partially completed or looped, or wants to investigate how their AI agent is performing.
3
+ description: Query Moda's AI agent conversation analytics and manage code-first prompt versions from the terminal — overview KPIs, topic clusters, conversation search, message context, user frustration detections, tool failures, agent jobs, recurring workflows, active loop detections, and moda prompts status/sync/promote. Use when the user asks about moda, modaflows, conversation analytics, prompt management, user frustrations, agent observability, tool failure debugging, why an agent run partially completed or looped, or wants to investigate how their AI agent is performing.
4
4
  ---
5
5
 
6
6
  # Moda CLI
@@ -9,7 +9,9 @@ description: Query Moda's AI agent conversation analytics from the terminal —
9
9
 
10
10
  Wraps the `moda` CLI so the agent can query a Moda tenant's conversation
11
11
  analytics directly. Every command returns JSON on stdout; pipe to `jq` to
12
- filter. Read-only — no command in this skill modifies data.
12
+ filter. Analytics commands are read-only. Prompt management includes both
13
+ read-only commands (`prompts status`, `prompts diff`) and commands that sync
14
+ or promote remote state (`prompts sync`, `prompts promote`).
13
15
 
14
16
  ## When to use
15
17
 
@@ -20,10 +22,13 @@ Activate this skill when the user wants to:
20
22
  - Investigate which tools are failing and why
21
23
  - Browse conversation topics (clusters)
22
24
  - Search conversations by content, user, environment, or time range
25
+ - Manage code-first prompt versions when the user explicitly asks for prompt
26
+ sync, prompt status, or prompt promotion
23
27
 
24
28
  **Do not** activate for: writing code that calls the Moda Data API directly
25
- (use the API docs instead), instrumenting an app with the Moda SDK (different
26
- skill / docs), or any modification action — this CLI is read-only.
29
+ (use the API docs instead), changing application instrumentation unless the
30
+ user explicitly asks for SDK setup, or modifying prompt registry state unless
31
+ the user specifically asked for `moda prompts sync` or `moda prompts promote`.
27
32
 
28
33
  ## Required inputs
29
34
 
@@ -196,6 +201,41 @@ agent re-ran the same action 378 times. Use the `loop_signature_human`
196
201
  field to recognize cross-conversation patterns (one tool definition bug
197
202
  will produce identical signatures across many users).
198
203
 
204
+ ### 10. Prompt management
205
+
206
+ Use these only when working on the code-first prompt registry.
207
+
208
+ ```bash
209
+ moda prompts init # create .moda/prompts.yml
210
+ moda prompts status # read-only local status
211
+ moda prompts diff # read-only local diff/status
212
+ moda prompts sync # upload changed prompt versions
213
+ moda prompts sync --watch # sync when local prompt hashes change
214
+ moda prompts promote support.triage --label=prod --version=pver_abc123
215
+ ```
216
+
217
+ `status` and `diff` are read-only. `sync` uploads prompt versions and writes
218
+ `.moda/prompts.lock.json`. `promote` moves a remote `dev`, `staging`, or
219
+ `prod` label to an existing version.
220
+
221
+ Runtime code should render synced prompts through the SDK:
222
+
223
+ ```typescript
224
+ const rendered = Moda.prompt("support.triage").render({
225
+ ticket: { text: userMessage },
226
+ });
227
+ ```
228
+
229
+ ```python
230
+ rendered = moda.prompt("support.triage").render({
231
+ "ticket": {"text": user_message},
232
+ })
233
+ ```
234
+
235
+ Do not copy prompt text from the dashboard into source code. The repo prompt
236
+ files are the source of truth; the dashboard is for visibility, usage, labels,
237
+ and future evals.
238
+
199
239
  ## Common workflow recipes
200
240
 
201
241
  ### Daily health check
@@ -314,6 +354,10 @@ npx: `npx -p @moda-ai/cli moda <command>`.
314
354
  | `moda run <run_id>` | One execution + its side-effect receipts |
315
355
  | `moda loops` | Currently-active loop detections |
316
356
  | `moda loop <detection_id>` | One loop signature with blast radius |
357
+ | `moda prompts status` | Read-only local prompt status |
358
+ | `moda prompts diff` | Read-only local prompt diff/status |
359
+ | `moda prompts sync` | Upload changed prompt versions and update lockfile |
360
+ | `moda prompts promote <key>` | Move a remote prompt label |
317
361
 
318
362
  Common flags across most commands: `--days-back=N` (1–90), `--limit=N`,
319
363
  `--offset=N`, `--time-range=<range>`. Runs commands also accept
@@ -1,63 +0,0 @@
1
- ---
2
- name: integrate-moda
3
- description: Integrate the Moda SDK into this project for LLM observability. Use when the user asks to add Moda, set up observability, or instrument LLM calls.
4
- ---
5
-
6
- # Integrate Moda SDK
7
-
8
- Moda auto-instruments LLM calls (OpenAI, Anthropic) via OpenTelemetry.
9
- After `Moda.init()`, all LLM calls are captured automatically — no wrappers needed.
10
-
11
- ## Steps
12
-
13
- 1. Install the SDK: `npm install moda-ai` (or bun/yarn/pnpm equivalent)
14
- 2. Ensure `MODA_API_KEY` is set in the environment
15
- 3. Initialize once at app startup, before any LLM client is created:
16
-
17
- ```typescript
18
- import { Moda } from 'moda-ai';
19
- await Moda.init(process.env.MODA_API_KEY!);
20
- ```
21
-
22
- Python: `import moda; moda.init()`
23
-
24
- 4. Set conversation ID before LLM calls to group multi-turn conversations.
25
- Without this, each call appears as a separate conversation in the dashboard.
26
-
27
- ```typescript
28
- Moda.conversationId = sessionId;
29
- Moda.userId = userId; // optional but recommended
30
- ```
31
-
32
- For concurrent requests, use scoped context:
33
- ```typescript
34
- import { withConversationId } from 'moda-ai';
35
- await withConversationId(sessionId, async () => {
36
- await openai.chat.completions.create({ ... });
37
- });
38
- ```
39
-
40
- Python: `moda.conversation_id = session_id` or `with moda.set_conversation_id(session_id):`
41
-
42
- 5. Flush pending traces before process exit: `await Moda.flush();`
43
-
44
- ## Vercel AI SDK
45
-
46
- When using the `ai` package, auto-instrumentation does not cover it. Pass telemetry config:
47
- ```typescript
48
- const result = await generateText({
49
- model: openai('gpt-4o'),
50
- prompt: 'Hello',
51
- experimental_telemetry: Moda.getVercelAITelemetry(),
52
- });
53
- ```
54
-
55
- ## Rules
56
-
57
- - Initialize Moda before creating any LLM client instances
58
- - Place `Moda.init()` in the app entry point, not in individual route handlers
59
- - Set `conversationId` per request/session, not globally
60
- - Use `withConversationId` in server environments handling concurrent requests
61
- - Call `Moda.flush()` in graceful shutdown handlers and before `process.exit()`
62
- - Do not wrap LLM calls — auto-instrumentation handles OpenAI and Anthropic automatically
63
- - Do not import or configure OpenTelemetry manually — Moda manages its own provider