@moda-ai/cli 1.55.8 → 1.55.9
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 +1 -1
- package/dist/{cli-j125g80g.js → cli-4af3thx7.js} +784 -24
- package/dist/{cli-a0adscdx.js → cli-sjc132j8.js} +3 -3
- package/dist/cli.js +5 -5
- package/dist/{harness-github-actions-t4m8q3wn.js → harness-github-actions-73a08nct.js} +1 -1
- package/dist/{harness-kpskdj9x.js → harness-yshh2pgj.js} +1 -1
- package/dist/{index-zdbe66yn.js → index-f3k9jgrt.js} +6 -3
- package/dist/prompt-source-mcp.js +1 -1
- package/package.json +7 -6
- package/skills/integration/index.json +2 -2
- package/skills/moda-cli/SKILL.md +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# moda-cli
|
|
2
2
|
|
|
3
|
-
CLI for [Moda](https://moda.dev)
|
|
3
|
+
CLI for [Moda](https://moda.dev): production monitoring and evals for AI agents.
|
|
4
4
|
|
|
5
5
|
Query your trace analytics from the terminal. A trace is the full record of one agent run: every message, tool call, and step that shares one `conversation_id` (the trace ID).
|
|
6
6
|
|
|
@@ -193384,6 +193384,766 @@ function assertHarnessGraphSyncSize(graph) {
|
|
|
193384
193384
|
`));
|
|
193385
193385
|
}
|
|
193386
193386
|
}
|
|
193387
|
+
// ../../packages/messaging/messaging.json
|
|
193388
|
+
var messaging_default = {
|
|
193389
|
+
$schema: "./messaging.schema.json",
|
|
193390
|
+
version: "1.0.2",
|
|
193391
|
+
locked_on: "2026-10-14",
|
|
193392
|
+
approved_by: "mo",
|
|
193393
|
+
source: "Branding project docs/positioning.md v1.0.2",
|
|
193394
|
+
canonical_strings: {
|
|
193395
|
+
version: "1.0.2",
|
|
193396
|
+
locked_on: "2026-10-14",
|
|
193397
|
+
approved_by: "mo",
|
|
193398
|
+
strings: [
|
|
193399
|
+
{
|
|
193400
|
+
id: "one_liner",
|
|
193401
|
+
source: "approved",
|
|
193402
|
+
text: "Moda gives engineers the infrastructure to monitor AI agents in production, find the mistakes they keep repeating, and test every change against real traces before it ships.",
|
|
193403
|
+
match: "exact",
|
|
193404
|
+
surfaces: [
|
|
193405
|
+
"apps/moda-frontend/components/landing/hero.tsx (subhead under the H1)",
|
|
193406
|
+
"apps/moda-frontend/lib/site.ts SITE_DESCRIPTION",
|
|
193407
|
+
"apps/moda-frontend/lib/agent-md.ts MODA_POSITIONING",
|
|
193408
|
+
"apps/moda-frontend/components/seo/json-ld.tsx Organization, WebSite and SoftwareApplication description",
|
|
193409
|
+
"apps/moda-frontend/content/llms/homepage.md",
|
|
193410
|
+
"apps/moda-frontend/app/llms.txt/route.ts (summary line)",
|
|
193411
|
+
"docs/index.mdx frontmatter description",
|
|
193412
|
+
"AGENTS.md and .cursorrules (What Moda Is)",
|
|
193413
|
+
"Y Combinator company page one-liner"
|
|
193414
|
+
]
|
|
193415
|
+
},
|
|
193416
|
+
{
|
|
193417
|
+
id: "category_label",
|
|
193418
|
+
source: "approved",
|
|
193419
|
+
text: "Production monitoring and evals for AI agents.",
|
|
193420
|
+
match: "contains_ci",
|
|
193421
|
+
surfaces: [
|
|
193422
|
+
"apps/moda-frontend/components/landing/hero.tsx (eyebrow above the H1)",
|
|
193423
|
+
"every bio, package description and directory listing below"
|
|
193424
|
+
]
|
|
193425
|
+
},
|
|
193426
|
+
{
|
|
193427
|
+
id: "tagline_h1",
|
|
193428
|
+
source: "approved",
|
|
193429
|
+
text: "Your agents should never make the same mistake twice.",
|
|
193430
|
+
match: "exact",
|
|
193431
|
+
surfaces: [
|
|
193432
|
+
"apps/moda-frontend/components/landing/hero.tsx H1",
|
|
193433
|
+
"apps/moda-frontend/lib/agent-md.ts MODA_TAGLINE",
|
|
193434
|
+
"Y Combinator company page headline"
|
|
193435
|
+
]
|
|
193436
|
+
},
|
|
193437
|
+
{
|
|
193438
|
+
id: "page_title",
|
|
193439
|
+
source: "approved",
|
|
193440
|
+
text: "Moda - Production monitoring and evals for AI agents",
|
|
193441
|
+
match: "exact",
|
|
193442
|
+
max_chars: 60,
|
|
193443
|
+
surfaces: [
|
|
193444
|
+
"apps/moda-frontend/app/layout.tsx metadata.title default",
|
|
193445
|
+
"apps/moda-frontend/app/page.tsx metadata.title",
|
|
193446
|
+
"og:title and twitter:title on the homepage"
|
|
193447
|
+
]
|
|
193448
|
+
},
|
|
193449
|
+
{
|
|
193450
|
+
id: "faq_lead",
|
|
193451
|
+
source: "approved",
|
|
193452
|
+
text: "Moda helps engineers make sure their agents never make the same mistake twice.",
|
|
193453
|
+
match: "contains_ci",
|
|
193454
|
+
surfaces: [
|
|
193455
|
+
"apps/moda-frontend/lib/faq.ts first answer (also emitted as FAQPage JSON-LD)",
|
|
193456
|
+
"apps/moda-frontend/content/llms/faq.md"
|
|
193457
|
+
]
|
|
193458
|
+
},
|
|
193459
|
+
{
|
|
193460
|
+
id: "meta_description",
|
|
193461
|
+
source: "derived",
|
|
193462
|
+
text: "Production monitoring and evals for AI agents. Find the mistakes your agents keep repeating and test every change against real traces before it ships.",
|
|
193463
|
+
match: "exact",
|
|
193464
|
+
max_chars: 160,
|
|
193465
|
+
surfaces: [
|
|
193466
|
+
"apps/moda-frontend/app/layout.tsx metadata.description, openGraph.description, twitter.description",
|
|
193467
|
+
"apps/moda-frontend/app/page.tsx metadata.description, openGraph.description, twitter.description"
|
|
193468
|
+
]
|
|
193469
|
+
},
|
|
193470
|
+
{
|
|
193471
|
+
id: "bio",
|
|
193472
|
+
source: "derived",
|
|
193473
|
+
text: "Production monitoring and evals for AI agents. Your agents should never make the same mistake twice.",
|
|
193474
|
+
match: "exact",
|
|
193475
|
+
max_chars: 120,
|
|
193476
|
+
surfaces: [
|
|
193477
|
+
"X @modaflows bio",
|
|
193478
|
+
"GitHub org ModaLabs bio",
|
|
193479
|
+
"LinkedIn tagline",
|
|
193480
|
+
"Crunchbase short description",
|
|
193481
|
+
"Product Hunt, G2 and other directory taglines"
|
|
193482
|
+
]
|
|
193483
|
+
},
|
|
193484
|
+
{
|
|
193485
|
+
id: "long_description",
|
|
193486
|
+
source: "derived",
|
|
193487
|
+
text: "Moda gives engineers the infrastructure to monitor AI agents in production, find the mistakes they keep repeating, and test every change against real traces before it ships. Agents fail in ways that never throw an error: frustrated users, failing tools, lazy or hallucinated answers. Moda reads every production trace end to end, detects these failures, and groups them into problems ranked by how many users they affect, with the traces behind each one. When your team changes a prompt, tool, or model, Moda replays the change against those traces and shows whether it worked, then keeps monitoring after release. Works with any model provider through SDKs, OpenTelemetry, or HTTP. Backed by Y Combinator.",
|
|
193488
|
+
match: "exact",
|
|
193489
|
+
surfaces: [
|
|
193490
|
+
"LinkedIn About",
|
|
193491
|
+
"Crunchbase full description",
|
|
193492
|
+
"Y Combinator company page description",
|
|
193493
|
+
"GitHub org profile README (profile/README.md)",
|
|
193494
|
+
"press boilerplate"
|
|
193495
|
+
]
|
|
193496
|
+
},
|
|
193497
|
+
{
|
|
193498
|
+
id: "sdk_node_description",
|
|
193499
|
+
source: "derived",
|
|
193500
|
+
text: "Official Node.js/TypeScript SDK for Moda: production monitoring and evals for AI agents.",
|
|
193501
|
+
match: "exact",
|
|
193502
|
+
surfaces: [
|
|
193503
|
+
"npm moda-ai package.json description",
|
|
193504
|
+
"GitHub repo description for the Node SDK"
|
|
193505
|
+
]
|
|
193506
|
+
},
|
|
193507
|
+
{
|
|
193508
|
+
id: "sdk_python_description",
|
|
193509
|
+
source: "derived",
|
|
193510
|
+
text: "Official Python SDK for Moda: production monitoring and evals for AI agents.",
|
|
193511
|
+
match: "exact",
|
|
193512
|
+
surfaces: [
|
|
193513
|
+
"PyPI moda-ai summary (pyproject.toml description)",
|
|
193514
|
+
"GitHub moda-python repo description"
|
|
193515
|
+
]
|
|
193516
|
+
},
|
|
193517
|
+
{
|
|
193518
|
+
id: "cli_description",
|
|
193519
|
+
source: "derived",
|
|
193520
|
+
text: "CLI for Moda: production monitoring and evals for AI agents.",
|
|
193521
|
+
match: "exact",
|
|
193522
|
+
surfaces: [
|
|
193523
|
+
"apps/moda-cli/package.json description",
|
|
193524
|
+
"apps/moda-cli/README.md first line",
|
|
193525
|
+
"apps/moda-cli/src/tui.ts banner subtitle"
|
|
193526
|
+
]
|
|
193527
|
+
},
|
|
193528
|
+
{
|
|
193529
|
+
id: "mcp_intro",
|
|
193530
|
+
source: "derived",
|
|
193531
|
+
text: "Moda is production monitoring and evals for AI agents: it ingests your agents' production traces (one trace = one complete agent run) and turns them into ranked problems, detections, and replayable tests.",
|
|
193532
|
+
match: "exact",
|
|
193533
|
+
surfaces: [
|
|
193534
|
+
"apps/moda-mcp/src/instructions.ts SERVER_INSTRUCTIONS first sentence"
|
|
193535
|
+
]
|
|
193536
|
+
},
|
|
193537
|
+
{
|
|
193538
|
+
id: "init_prompt_line",
|
|
193539
|
+
source: "derived",
|
|
193540
|
+
text: "Add the Moda SDK to this project so its AI agents are monitored in production.",
|
|
193541
|
+
match: "exact",
|
|
193542
|
+
surfaces: [
|
|
193543
|
+
"apps/moda-cli/src/init/sdk-integration.ts prompt header",
|
|
193544
|
+
"apps/moda-onboarding-evals/prompts/integrate.md first line"
|
|
193545
|
+
]
|
|
193546
|
+
},
|
|
193547
|
+
{
|
|
193548
|
+
id: "schema_service_type",
|
|
193549
|
+
source: "derived",
|
|
193550
|
+
text: "Production monitoring and evals for AI agents",
|
|
193551
|
+
match: "exact",
|
|
193552
|
+
surfaces: [
|
|
193553
|
+
"apps/moda-frontend/components/seo/json-ld.tsx Service serviceType"
|
|
193554
|
+
]
|
|
193555
|
+
},
|
|
193556
|
+
{
|
|
193557
|
+
id: "directory_categories",
|
|
193558
|
+
source: "derived",
|
|
193559
|
+
text: "AI agent monitoring; LLM evaluation",
|
|
193560
|
+
match: "exact",
|
|
193561
|
+
surfaces: [
|
|
193562
|
+
"G2, Product Hunt, There's An AI For That and other directory category fields: primary first, secondary second"
|
|
193563
|
+
]
|
|
193564
|
+
},
|
|
193565
|
+
{
|
|
193566
|
+
id: "pillar_1",
|
|
193567
|
+
source: "derived",
|
|
193568
|
+
title: "Monitor every trace",
|
|
193569
|
+
text: "Moda reads every production trace end to end and detects the failures that never throw an error: frustrated users, failing tools, lazy answers, and hallucinations. Add your own checks in plain language and get alerts in Slack, Linear, or email.",
|
|
193570
|
+
match: "exact",
|
|
193571
|
+
surfaces: [
|
|
193572
|
+
"apps/moda-frontend/components/landing/features.tsx pillar 1",
|
|
193573
|
+
"sales one-pager"
|
|
193574
|
+
]
|
|
193575
|
+
},
|
|
193576
|
+
{
|
|
193577
|
+
id: "pillar_2",
|
|
193578
|
+
source: "derived",
|
|
193579
|
+
title: "Find the mistakes they keep repeating",
|
|
193580
|
+
text: "Failures are grouped into problems ranked by how many users they affect. Each problem shows the traces behind it, the turn where it went wrong, and related problems that share the cause.",
|
|
193581
|
+
match: "exact",
|
|
193582
|
+
surfaces: [
|
|
193583
|
+
"apps/moda-frontend/components/landing/features.tsx pillar 2",
|
|
193584
|
+
"sales one-pager"
|
|
193585
|
+
]
|
|
193586
|
+
},
|
|
193587
|
+
{
|
|
193588
|
+
id: "pillar_3",
|
|
193589
|
+
source: "derived",
|
|
193590
|
+
title: "Test every change before it ships",
|
|
193591
|
+
text: "Replay a prompt, model, or tool change against the exact traces that failed and compare pass rate, latency, and tokens. Your team reviews the result and decides what ships.",
|
|
193592
|
+
match: "exact",
|
|
193593
|
+
surfaces: [
|
|
193594
|
+
"apps/moda-frontend/components/landing/features.tsx pillar 3",
|
|
193595
|
+
"sales one-pager"
|
|
193596
|
+
]
|
|
193597
|
+
}
|
|
193598
|
+
]
|
|
193599
|
+
},
|
|
193600
|
+
banned_phrases: {
|
|
193601
|
+
version: "1.0.2",
|
|
193602
|
+
phrases: [
|
|
193603
|
+
{
|
|
193604
|
+
id: "fixes_your_agent",
|
|
193605
|
+
pattern: "\\b(fix(es|ing)?|repair(s|ing)?) your (ai )?agents?\\b|\\b(moda|we) (fix|fixes|repair|repairs)\\b",
|
|
193606
|
+
reason: "Moda never claims to fix agents itself; engineers fix their agents",
|
|
193607
|
+
replacement: "test your fix against real traces",
|
|
193608
|
+
allowed_contexts: [
|
|
193609
|
+
"competitor_comparison"
|
|
193610
|
+
]
|
|
193611
|
+
},
|
|
193612
|
+
{
|
|
193613
|
+
id: "auto_fix",
|
|
193614
|
+
pattern: "\\bauto[- ]?fix(es|ing|ed)?\\b|\\bautonomous(ly)? fix|\\bself[- ]heal(ing|s)?\\b|\\bfixes itself\\b",
|
|
193615
|
+
reason: "Implies Moda changes agents without engineers",
|
|
193616
|
+
replacement: "test your change against real traces",
|
|
193617
|
+
allowed_contexts: [
|
|
193618
|
+
"competitor_comparison"
|
|
193619
|
+
]
|
|
193620
|
+
},
|
|
193621
|
+
{
|
|
193622
|
+
id: "moda_opens_prs",
|
|
193623
|
+
pattern: "\\b(moda|we) (can |will |then |also )?(opens?|creates?|files?|raises?|submits?|sends?|delivers?|drafts?|proposes?|suggests?|writes?) (a |an |the )?(draft |candidate |proposed |verified )?(fix(es)?|pull requests?|PRs?|code changes?|code fix(es)?|patch(es)?)\\b|\\b(moda|we) (can |will |then |also )?(drafts?|proposes?|suggests?) (a |an |the )?(candidate |proposed )?changes?\\b|\\bfix PRs?\\b|\\bdraft (pull requests?|PRs?)\\b",
|
|
193624
|
+
reason: "Moda does not open pull requests, write fix PRs or propose code fixes; engineers make the change",
|
|
193625
|
+
replacement: "engineers make the change; Moda tests it against real traces",
|
|
193626
|
+
allowed_contexts: [
|
|
193627
|
+
"competitor_comparison",
|
|
193628
|
+
"negation"
|
|
193629
|
+
]
|
|
193630
|
+
},
|
|
193631
|
+
{
|
|
193632
|
+
id: "learns",
|
|
193633
|
+
pattern: "\\blearns\\b|\\blearn(s|ing)? from (production|every|each|your)\\b|\\bagents? that learn\\b|\\bself[- ]learning\\b",
|
|
193634
|
+
reason: "Learning claims are visionary framing; Moda monitors, finds and tests. Navigation text such as 'Learn more' is allowed because it does not match",
|
|
193635
|
+
replacement: "find the mistakes your agents keep repeating",
|
|
193636
|
+
allowed_contexts: [
|
|
193637
|
+
"competitor_comparison"
|
|
193638
|
+
]
|
|
193639
|
+
},
|
|
193640
|
+
{
|
|
193641
|
+
id: "continual_learning",
|
|
193642
|
+
pattern: "\\bcontinual[- ]learning\\b|\\blearning (layer|loop)\\b",
|
|
193643
|
+
reason: "Undefined buzzword to buyers; rejected Oct 14",
|
|
193644
|
+
replacement: "production monitoring and evals for AI agents",
|
|
193645
|
+
allowed_contexts: [
|
|
193646
|
+
"competitor_comparison",
|
|
193647
|
+
"keyword_list"
|
|
193648
|
+
]
|
|
193649
|
+
},
|
|
193650
|
+
{
|
|
193651
|
+
id: "self_improving",
|
|
193652
|
+
pattern: "\\bself[- ]improv(e|es|ing|ement)\\b|\\bimprov(e|es) (itself|themselves)\\b|\\bget(s)? better (on (its|their) own|automatically|every week)\\b",
|
|
193653
|
+
reason: "Implies autonomy and roadmap capability",
|
|
193654
|
+
replacement: "test every change against real traces",
|
|
193655
|
+
allowed_contexts: [
|
|
193656
|
+
"competitor_comparison"
|
|
193657
|
+
]
|
|
193658
|
+
},
|
|
193659
|
+
{
|
|
193660
|
+
id: "roadmap_training",
|
|
193661
|
+
pattern: "\\bfine[- ]?tun(e|es|ed|ing)\\b|\\btrain(s|ing|ed)? (your|the|their) (models?|agents?)\\b|\\bmodel training\\b|\\bweight updates?\\b",
|
|
193662
|
+
reason: "Not shipped",
|
|
193663
|
+
replacement: "(none)",
|
|
193664
|
+
allowed_contexts: [
|
|
193665
|
+
"negation",
|
|
193666
|
+
"internal",
|
|
193667
|
+
"keyword_list"
|
|
193668
|
+
]
|
|
193669
|
+
},
|
|
193670
|
+
{
|
|
193671
|
+
id: "roadmap_rl",
|
|
193672
|
+
pattern: "\\breinforcement learning\\b|\\bRLHF\\b|\\bRLAIF\\b|\\bRL\\b|\\breward models?\\b|\\bprocess reward\\b|\\bPRM\\b",
|
|
193673
|
+
case_sensitive: true,
|
|
193674
|
+
reason: "Not shipped. Case-sensitive so the word 'url' does not match",
|
|
193675
|
+
replacement: "(none)",
|
|
193676
|
+
allowed_contexts: [
|
|
193677
|
+
"negation",
|
|
193678
|
+
"internal"
|
|
193679
|
+
]
|
|
193680
|
+
},
|
|
193681
|
+
{
|
|
193682
|
+
id: "roadmap_inference",
|
|
193683
|
+
pattern: "\\bhosted inference\\b|\\binference (platform|hosting|fleet)\\b|\\b(we|moda) (serve|host)s? (your )?models?\\b",
|
|
193684
|
+
reason: "Not shipped",
|
|
193685
|
+
replacement: "(none)",
|
|
193686
|
+
allowed_contexts: [
|
|
193687
|
+
"negation",
|
|
193688
|
+
"internal"
|
|
193689
|
+
]
|
|
193690
|
+
},
|
|
193691
|
+
{
|
|
193692
|
+
id: "visionary_framing",
|
|
193693
|
+
pattern: "\\blatent space\\b|\\boutside the (model )?weights\\b|\\bthe future of\\b|\\bnext[- ]gen(eration)?\\b|\\brevolutioni[sz]",
|
|
193694
|
+
reason: "Describe only what ships today",
|
|
193695
|
+
replacement: "(describe the shipped feature)",
|
|
193696
|
+
allowed_contexts: [
|
|
193697
|
+
"competitor_comparison"
|
|
193698
|
+
]
|
|
193699
|
+
},
|
|
193700
|
+
{
|
|
193701
|
+
id: "layer_category",
|
|
193702
|
+
pattern: "\\b(learning|intelligence|reliability|data) layer\\b|\\blayer for ai agents\\b",
|
|
193703
|
+
reason: "Vague infrastructure noun from retired positioning",
|
|
193704
|
+
replacement: "production monitoring and evals for AI agents",
|
|
193705
|
+
allowed_contexts: []
|
|
193706
|
+
},
|
|
193707
|
+
{
|
|
193708
|
+
id: "observability_category",
|
|
193709
|
+
pattern: "\\b(llm|ai|agent|ai agent) observability\\b|\\bobservability (platform|for ai|for agents|for llm)|\\bobservability-grade\\b",
|
|
193710
|
+
reason: "mo rejected observability as the pitch; names a data layer, not the job",
|
|
193711
|
+
replacement: "production monitoring and evals for AI agents",
|
|
193712
|
+
allowed_contexts: [
|
|
193713
|
+
"competitor_comparison",
|
|
193714
|
+
"keyword_list",
|
|
193715
|
+
"skill_trigger"
|
|
193716
|
+
]
|
|
193717
|
+
},
|
|
193718
|
+
{
|
|
193719
|
+
id: "product_analytics",
|
|
193720
|
+
pattern: "\\b(ai |llm )?product analytics\\b|\\bconversation analytics\\b|\\banalytics platform\\b|\\banalytics and observability\\b",
|
|
193721
|
+
reason: "mo rejected product analytics; signals a PM buyer",
|
|
193722
|
+
replacement: "production monitoring and evals for AI agents",
|
|
193723
|
+
allowed_contexts: [
|
|
193724
|
+
"competitor_comparison",
|
|
193725
|
+
"keyword_list",
|
|
193726
|
+
"skill_trigger"
|
|
193727
|
+
]
|
|
193728
|
+
},
|
|
193729
|
+
{
|
|
193730
|
+
id: "llm_native_software",
|
|
193731
|
+
pattern: "\\bllm-native software\\b|\\bchatbots, copilots, agents\\b",
|
|
193732
|
+
reason: "Dated audience framing",
|
|
193733
|
+
replacement: "AI agents in production",
|
|
193734
|
+
allowed_contexts: []
|
|
193735
|
+
},
|
|
193736
|
+
{
|
|
193737
|
+
id: "harness_category",
|
|
193738
|
+
pattern: "\\bharness engineering\\b|\\bautonomous harness\\b|\\bobservability for agent harnesses\\b",
|
|
193739
|
+
reason: "Retired by PR #5696. 'Agent harness' remains allowed as a technical noun in docs and product UI",
|
|
193740
|
+
replacement: "production monitoring and evals for AI agents",
|
|
193741
|
+
allowed_contexts: [
|
|
193742
|
+
"internal"
|
|
193743
|
+
]
|
|
193744
|
+
},
|
|
193745
|
+
{
|
|
193746
|
+
id: "reliability_category",
|
|
193747
|
+
pattern: "\\breliability platform\\b|\\bmonitoring (&|and) reliability\\b",
|
|
193748
|
+
reason: "Rejected category label; the approved label is fixed",
|
|
193749
|
+
replacement: "production monitoring and evals for AI agents",
|
|
193750
|
+
allowed_contexts: []
|
|
193751
|
+
},
|
|
193752
|
+
{
|
|
193753
|
+
id: "agent_improvement_category",
|
|
193754
|
+
pattern: "\\bagent improvement (platform|layer)\\b|\\bdata engine for\\b",
|
|
193755
|
+
reason: "Rejected category labels",
|
|
193756
|
+
replacement: "production monitoring and evals for AI agents",
|
|
193757
|
+
allowed_contexts: []
|
|
193758
|
+
},
|
|
193759
|
+
{
|
|
193760
|
+
id: "sentry_for_ai",
|
|
193761
|
+
pattern: "\\bsentry for ai\\b",
|
|
193762
|
+
reason: "Raindrop's tagline",
|
|
193763
|
+
replacement: "(none)",
|
|
193764
|
+
allowed_contexts: [
|
|
193765
|
+
"competitor_comparison"
|
|
193766
|
+
]
|
|
193767
|
+
},
|
|
193768
|
+
{
|
|
193769
|
+
id: "gateway",
|
|
193770
|
+
pattern: "\\bllm api gateway\\b|\\bgateway and pub-sub\\b",
|
|
193771
|
+
reason: "Product from an earlier era",
|
|
193772
|
+
replacement: "(none)",
|
|
193773
|
+
allowed_contexts: []
|
|
193774
|
+
}
|
|
193775
|
+
]
|
|
193776
|
+
},
|
|
193777
|
+
terminology: {
|
|
193778
|
+
version: "1.0.2",
|
|
193779
|
+
terms: [
|
|
193780
|
+
{
|
|
193781
|
+
use: "trace",
|
|
193782
|
+
avoid: [
|
|
193783
|
+
"conversation (as the product noun)",
|
|
193784
|
+
"session"
|
|
193785
|
+
],
|
|
193786
|
+
note: "Renamed in MODA-1793. API and tool parameter names may keep conversation_id"
|
|
193787
|
+
},
|
|
193788
|
+
{
|
|
193789
|
+
use: "AI agents",
|
|
193790
|
+
avoid: [
|
|
193791
|
+
"LLM apps",
|
|
193792
|
+
"chatbots",
|
|
193793
|
+
"copilots"
|
|
193794
|
+
],
|
|
193795
|
+
note: "Audience noun in all marketing copy"
|
|
193796
|
+
},
|
|
193797
|
+
{
|
|
193798
|
+
use: "problem",
|
|
193799
|
+
avoid: [
|
|
193800
|
+
"issue",
|
|
193801
|
+
"incident"
|
|
193802
|
+
],
|
|
193803
|
+
note: "A group of recurring failures ranked by users affected"
|
|
193804
|
+
},
|
|
193805
|
+
{
|
|
193806
|
+
use: "signal",
|
|
193807
|
+
avoid: [
|
|
193808
|
+
"metric",
|
|
193809
|
+
"classifier"
|
|
193810
|
+
],
|
|
193811
|
+
note: "A detection that runs on every trace"
|
|
193812
|
+
},
|
|
193813
|
+
{
|
|
193814
|
+
use: "custom signal",
|
|
193815
|
+
avoid: [
|
|
193816
|
+
"custom metric",
|
|
193817
|
+
"judge"
|
|
193818
|
+
],
|
|
193819
|
+
note: "A plain-language check the team writes"
|
|
193820
|
+
},
|
|
193821
|
+
{
|
|
193822
|
+
use: "use case",
|
|
193823
|
+
avoid: [
|
|
193824
|
+
"cluster (in marketing copy)"
|
|
193825
|
+
],
|
|
193826
|
+
note: "Cluster stays fine in docs and the product UI"
|
|
193827
|
+
},
|
|
193828
|
+
{
|
|
193829
|
+
use: "replay",
|
|
193830
|
+
avoid: [
|
|
193831
|
+
"simulation"
|
|
193832
|
+
],
|
|
193833
|
+
note: "Running a change against real traces"
|
|
193834
|
+
},
|
|
193835
|
+
{
|
|
193836
|
+
use: "monitor",
|
|
193837
|
+
avoid: [],
|
|
193838
|
+
note: "Product feature name and the category verb"
|
|
193839
|
+
},
|
|
193840
|
+
{
|
|
193841
|
+
use: "evals",
|
|
193842
|
+
avoid: [
|
|
193843
|
+
"evaluations (in headlines)"
|
|
193844
|
+
],
|
|
193845
|
+
note: "Category word; 'evaluation' is fine in body text"
|
|
193846
|
+
},
|
|
193847
|
+
{
|
|
193848
|
+
use: "fix (engineer as the actor)",
|
|
193849
|
+
avoid: [
|
|
193850
|
+
"Moda fixes",
|
|
193851
|
+
"auto-fix",
|
|
193852
|
+
"fix PRs",
|
|
193853
|
+
"Moda opens a PR",
|
|
193854
|
+
"Moda drafts a fix"
|
|
193855
|
+
],
|
|
193856
|
+
note: "A change engineers make. Moda tests it against real traces; it does not draft fixes or open pull requests"
|
|
193857
|
+
}
|
|
193858
|
+
]
|
|
193859
|
+
}
|
|
193860
|
+
};
|
|
193861
|
+
|
|
193862
|
+
// ../../packages/messaging/src/matchers.ts
|
|
193863
|
+
var normalizeCopy = (text) => text.replace(/\s+/g, " ").trim();
|
|
193864
|
+
function matchCanonical(text, entry) {
|
|
193865
|
+
const copy = normalizeCopy(text);
|
|
193866
|
+
const canonical = normalizeCopy(entry.text);
|
|
193867
|
+
if (entry.match === "exact" && copy === canonical)
|
|
193868
|
+
return "exact";
|
|
193869
|
+
return copy.toLowerCase().includes(canonical.toLowerCase()) ? "contains" : null;
|
|
193870
|
+
}
|
|
193871
|
+
var ALLOW_MARKER = /messaging-allow:\s*([a-z_]+)/g;
|
|
193872
|
+
var escapeRegExp = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
193873
|
+
var terminologyPattern = (avoid) => {
|
|
193874
|
+
const words = normalizeCopy(avoid.replace(/\([^)]*\)/g, " "));
|
|
193875
|
+
return words ? new RegExp(`(?<![\\w-])${escapeRegExp(words)}(?![\\w-])`, "gi") : null;
|
|
193876
|
+
};
|
|
193877
|
+
var distinct = (values) => [...new Set(values)];
|
|
193878
|
+
function createMatchers(messaging) {
|
|
193879
|
+
const banned = messaging.banned_phrases.phrases.map((phrase) => ({
|
|
193880
|
+
phrase,
|
|
193881
|
+
regex: new RegExp(phrase.pattern, phrase.case_sensitive ? "g" : "gi")
|
|
193882
|
+
}));
|
|
193883
|
+
const terms = messaging.terminology.terms.flatMap((term) => term.avoid.flatMap((avoid) => {
|
|
193884
|
+
const regex = terminologyPattern(avoid);
|
|
193885
|
+
return regex ? [{ term, avoid, regex }] : [];
|
|
193886
|
+
}));
|
|
193887
|
+
return {
|
|
193888
|
+
findBannedPhrases(text) {
|
|
193889
|
+
const markers = new Set([...text.matchAll(ALLOW_MARKER)].map((match) => match[1]));
|
|
193890
|
+
return banned.flatMap(({ phrase, regex }) => {
|
|
193891
|
+
const matches = distinct([...text.matchAll(regex)].map((match) => match[0]));
|
|
193892
|
+
if (matches.length === 0)
|
|
193893
|
+
return [];
|
|
193894
|
+
const allowedBy = phrase.allowed_contexts.find((context) => markers.has(context)) ?? null;
|
|
193895
|
+
return [{ phrase, matches, allowedBy }];
|
|
193896
|
+
});
|
|
193897
|
+
},
|
|
193898
|
+
findTerminology(text) {
|
|
193899
|
+
return terms.flatMap(({ term, avoid, regex }) => {
|
|
193900
|
+
const matches = distinct([...text.matchAll(regex)].map((match) => match[0]));
|
|
193901
|
+
return matches.length ? [{ term, avoid, matches }] : [];
|
|
193902
|
+
});
|
|
193903
|
+
},
|
|
193904
|
+
findCanonical(text) {
|
|
193905
|
+
return messaging.canonical_strings.strings.flatMap((entry) => {
|
|
193906
|
+
const relation = matchCanonical(text, entry);
|
|
193907
|
+
return relation ? [{ entry, relation }] : [];
|
|
193908
|
+
});
|
|
193909
|
+
}
|
|
193910
|
+
};
|
|
193911
|
+
}
|
|
193912
|
+
// ../../packages/messaging/messaging.schema.json
|
|
193913
|
+
var messaging_schema_default = {
|
|
193914
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
193915
|
+
$id: "https://moda.dev/schemas/messaging.schema.json",
|
|
193916
|
+
title: "Moda locked positioning",
|
|
193917
|
+
description: "packages/messaging/messaging.json: the canonical-strings, banned-phrases and terminology blocks of the locked positioning doc. Regenerate with `bun run --cwd packages/messaging sync -- <positioning.md>`.",
|
|
193918
|
+
type: "object",
|
|
193919
|
+
required: ["version", "locked_on", "approved_by", "source", "canonical_strings", "banned_phrases", "terminology"],
|
|
193920
|
+
additionalProperties: false,
|
|
193921
|
+
properties: {
|
|
193922
|
+
$schema: { type: "string" },
|
|
193923
|
+
version: { $ref: "#/$defs/version" },
|
|
193924
|
+
locked_on: { $ref: "#/$defs/date" },
|
|
193925
|
+
approved_by: { type: "string", minLength: 1 },
|
|
193926
|
+
source: { type: "string", minLength: 1 },
|
|
193927
|
+
canonical_strings: {
|
|
193928
|
+
type: "object",
|
|
193929
|
+
required: ["version", "locked_on", "approved_by", "strings"],
|
|
193930
|
+
additionalProperties: false,
|
|
193931
|
+
properties: {
|
|
193932
|
+
version: { $ref: "#/$defs/version" },
|
|
193933
|
+
locked_on: { $ref: "#/$defs/date" },
|
|
193934
|
+
approved_by: { type: "string", minLength: 1 },
|
|
193935
|
+
strings: { type: "array", items: { $ref: "#/$defs/canonicalString" } }
|
|
193936
|
+
}
|
|
193937
|
+
},
|
|
193938
|
+
banned_phrases: {
|
|
193939
|
+
type: "object",
|
|
193940
|
+
required: ["version", "phrases"],
|
|
193941
|
+
additionalProperties: false,
|
|
193942
|
+
properties: {
|
|
193943
|
+
version: { $ref: "#/$defs/version" },
|
|
193944
|
+
phrases: { type: "array", items: { $ref: "#/$defs/bannedPhrase" } }
|
|
193945
|
+
}
|
|
193946
|
+
},
|
|
193947
|
+
terminology: {
|
|
193948
|
+
type: "object",
|
|
193949
|
+
required: ["version", "terms"],
|
|
193950
|
+
additionalProperties: false,
|
|
193951
|
+
properties: {
|
|
193952
|
+
version: { $ref: "#/$defs/version" },
|
|
193953
|
+
terms: { type: "array", items: { $ref: "#/$defs/term" } }
|
|
193954
|
+
}
|
|
193955
|
+
}
|
|
193956
|
+
},
|
|
193957
|
+
$defs: {
|
|
193958
|
+
version: { type: "string", pattern: "^\\d+\\.\\d+\\.\\d+$" },
|
|
193959
|
+
date: { type: "string", pattern: "^\\d{4}-\\d{2}-\\d{2}$" },
|
|
193960
|
+
canonicalString: {
|
|
193961
|
+
type: "object",
|
|
193962
|
+
required: ["id", "source", "text", "match", "surfaces"],
|
|
193963
|
+
additionalProperties: false,
|
|
193964
|
+
properties: {
|
|
193965
|
+
id: { type: "string", pattern: "^[a-z0-9_]+$" },
|
|
193966
|
+
source: { enum: ["approved", "derived"] },
|
|
193967
|
+
title: { type: "string", minLength: 1 },
|
|
193968
|
+
text: { type: "string", minLength: 1 },
|
|
193969
|
+
match: {
|
|
193970
|
+
enum: ["exact", "contains_ci"],
|
|
193971
|
+
description: "exact: the live text equals text after trimming whitespace. contains_ci: the live text contains text, case-insensitively."
|
|
193972
|
+
},
|
|
193973
|
+
surfaces: { type: "array", items: { type: "string", minLength: 1 } },
|
|
193974
|
+
max_chars: { type: "integer", minimum: 1 }
|
|
193975
|
+
}
|
|
193976
|
+
},
|
|
193977
|
+
bannedPhrase: {
|
|
193978
|
+
type: "object",
|
|
193979
|
+
required: ["id", "pattern", "reason", "replacement", "allowed_contexts"],
|
|
193980
|
+
additionalProperties: false,
|
|
193981
|
+
properties: {
|
|
193982
|
+
id: { type: "string", pattern: "^[a-z0-9_]+$" },
|
|
193983
|
+
pattern: { type: "string", minLength: 1, description: "A JavaScript regular expression, case-insensitive unless case_sensitive is true." },
|
|
193984
|
+
case_sensitive: { type: "boolean" },
|
|
193985
|
+
reason: { type: "string", minLength: 1 },
|
|
193986
|
+
replacement: { type: "string", minLength: 1 },
|
|
193987
|
+
allowed_contexts: {
|
|
193988
|
+
type: "array",
|
|
193989
|
+
items: { enum: ["competitor_comparison", "keyword_list", "skill_trigger", "negation", "internal"] }
|
|
193990
|
+
}
|
|
193991
|
+
}
|
|
193992
|
+
},
|
|
193993
|
+
term: {
|
|
193994
|
+
type: "object",
|
|
193995
|
+
required: ["use", "avoid", "note"],
|
|
193996
|
+
additionalProperties: false,
|
|
193997
|
+
properties: {
|
|
193998
|
+
use: { type: "string", minLength: 1 },
|
|
193999
|
+
avoid: { type: "array", items: { type: "string", minLength: 1 } },
|
|
194000
|
+
note: { type: "string" }
|
|
194001
|
+
}
|
|
194002
|
+
}
|
|
194003
|
+
}
|
|
194004
|
+
};
|
|
194005
|
+
|
|
194006
|
+
// ../../packages/messaging/src/schema.ts
|
|
194007
|
+
var KNOWN_KEYWORDS = new Set([
|
|
194008
|
+
"$schema",
|
|
194009
|
+
"$id",
|
|
194010
|
+
"$defs",
|
|
194011
|
+
"$ref",
|
|
194012
|
+
"title",
|
|
194013
|
+
"description",
|
|
194014
|
+
"type",
|
|
194015
|
+
"required",
|
|
194016
|
+
"additionalProperties",
|
|
194017
|
+
"properties",
|
|
194018
|
+
"items",
|
|
194019
|
+
"enum",
|
|
194020
|
+
"pattern",
|
|
194021
|
+
"minLength",
|
|
194022
|
+
"minimum"
|
|
194023
|
+
]);
|
|
194024
|
+
var root = messaging_schema_default;
|
|
194025
|
+
var withArticle = (word) => `${/^[aeiou]/.test(word) ? "an" : "a"} ${word}`;
|
|
194026
|
+
var typeOf = (value) => value === null ? "null" : Array.isArray(value) ? "array" : Number.isInteger(value) ? "integer" : typeof value;
|
|
194027
|
+
function check(value, node, path, problems) {
|
|
194028
|
+
const unknown = Object.keys(node).filter((keyword) => !KNOWN_KEYWORDS.has(keyword));
|
|
194029
|
+
if (unknown.length) {
|
|
194030
|
+
problems.push(`messaging.schema.json uses unsupported keywords at ${path}: ${unknown.join(", ")}`);
|
|
194031
|
+
return;
|
|
194032
|
+
}
|
|
194033
|
+
if (node.$ref) {
|
|
194034
|
+
const name = node.$ref.replace(/^#\/\$defs\//, "");
|
|
194035
|
+
const target = root.$defs[name];
|
|
194036
|
+
if (!target)
|
|
194037
|
+
problems.push(`messaging.schema.json has no definition ${node.$ref}`);
|
|
194038
|
+
else
|
|
194039
|
+
check(value, target, path, problems);
|
|
194040
|
+
return;
|
|
194041
|
+
}
|
|
194042
|
+
if (node.enum && !node.enum.includes(value)) {
|
|
194043
|
+
problems.push(`${path} is ${JSON.stringify(value)}, expected one of ${node.enum.map((entry) => JSON.stringify(entry)).join(", ")}`);
|
|
194044
|
+
return;
|
|
194045
|
+
}
|
|
194046
|
+
if (node.type) {
|
|
194047
|
+
const actual = typeOf(value);
|
|
194048
|
+
if (actual !== node.type) {
|
|
194049
|
+
problems.push(`${path} is ${actual === "undefined" ? "missing" : withArticle(actual)}, expected ${withArticle(node.type)}`);
|
|
194050
|
+
return;
|
|
194051
|
+
}
|
|
194052
|
+
}
|
|
194053
|
+
if (typeof value === "string") {
|
|
194054
|
+
if (node.minLength !== undefined && value.length < node.minLength)
|
|
194055
|
+
problems.push(`${path} must not be empty`);
|
|
194056
|
+
if (node.pattern && !new RegExp(node.pattern, "u").test(value))
|
|
194057
|
+
problems.push(`${path} "${value}" does not match ${node.pattern}`);
|
|
194058
|
+
}
|
|
194059
|
+
if (typeof value === "number" && node.minimum !== undefined && value < node.minimum)
|
|
194060
|
+
problems.push(`${path} is below ${node.minimum}`);
|
|
194061
|
+
if (Array.isArray(value) && node.items) {
|
|
194062
|
+
value.forEach((entry, index) => check(entry, node.items, `${path}[${index}]`, problems));
|
|
194063
|
+
}
|
|
194064
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
194065
|
+
const record = value;
|
|
194066
|
+
for (const key of node.required ?? []) {
|
|
194067
|
+
if (!(key in record))
|
|
194068
|
+
problems.push(`${path}.${key} is missing`);
|
|
194069
|
+
}
|
|
194070
|
+
for (const [key, entry] of Object.entries(record)) {
|
|
194071
|
+
const child = node.properties?.[key];
|
|
194072
|
+
if (child)
|
|
194073
|
+
check(entry, child, `${path}.${key}`, problems);
|
|
194074
|
+
else if (node.additionalProperties === false)
|
|
194075
|
+
problems.push(`${path}.${key} is not allowed`);
|
|
194076
|
+
}
|
|
194077
|
+
}
|
|
194078
|
+
}
|
|
194079
|
+
function schemaProblems(value) {
|
|
194080
|
+
const problems = [];
|
|
194081
|
+
check(value, root, "messaging", problems);
|
|
194082
|
+
return problems;
|
|
194083
|
+
}
|
|
194084
|
+
|
|
194085
|
+
// ../../packages/messaging/src/positioning-doc.ts
|
|
194086
|
+
function validateMessaging(messaging) {
|
|
194087
|
+
const shape = schemaProblems(messaging);
|
|
194088
|
+
if (shape.length > 0)
|
|
194089
|
+
return shape;
|
|
194090
|
+
const problems = [];
|
|
194091
|
+
const { canonical_strings: canonical, banned_phrases: banned, terminology } = messaging;
|
|
194092
|
+
for (const [name, version] of [
|
|
194093
|
+
["canonical_strings", canonical.version],
|
|
194094
|
+
["banned_phrases", banned.version],
|
|
194095
|
+
["terminology", terminology.version]
|
|
194096
|
+
]) {
|
|
194097
|
+
if (version !== messaging.version)
|
|
194098
|
+
problems.push(`${name}.version is ${version}, expected ${messaging.version}`);
|
|
194099
|
+
}
|
|
194100
|
+
const ids = new Set;
|
|
194101
|
+
for (const entry of canonical.strings) {
|
|
194102
|
+
const label = `canonical string ${entry.id}`;
|
|
194103
|
+
if (ids.has(entry.id))
|
|
194104
|
+
problems.push(`${label} is listed twice`);
|
|
194105
|
+
ids.add(entry.id);
|
|
194106
|
+
if (entry.max_chars !== undefined && entry.text.length > entry.max_chars) {
|
|
194107
|
+
problems.push(`${label} is ${entry.text.length} characters, over its max_chars of ${entry.max_chars}`);
|
|
194108
|
+
}
|
|
194109
|
+
}
|
|
194110
|
+
const phraseIds = new Set;
|
|
194111
|
+
for (const phrase of banned.phrases) {
|
|
194112
|
+
const label = `banned phrase ${phrase.id}`;
|
|
194113
|
+
if (phraseIds.has(phrase.id))
|
|
194114
|
+
problems.push(`${label} is listed twice`);
|
|
194115
|
+
phraseIds.add(phrase.id);
|
|
194116
|
+
try {
|
|
194117
|
+
if (new RegExp(phrase.pattern, phrase.case_sensitive ? "" : "i").test(""))
|
|
194118
|
+
problems.push(`${label} matches empty text`);
|
|
194119
|
+
} catch (error) {
|
|
194120
|
+
problems.push(`${label} has an invalid pattern: ${error instanceof Error ? error.message : String(error)}`);
|
|
194121
|
+
}
|
|
194122
|
+
}
|
|
194123
|
+
return problems;
|
|
194124
|
+
}
|
|
194125
|
+
|
|
194126
|
+
// ../../packages/messaging/src/index.ts
|
|
194127
|
+
var problems = validateMessaging(messaging_default);
|
|
194128
|
+
if (problems.length > 0)
|
|
194129
|
+
throw new Error(`packages/messaging/messaging.json is invalid:
|
|
194130
|
+
- ${problems.join(`
|
|
194131
|
+
- `)}`);
|
|
194132
|
+
var messaging = messaging_default;
|
|
194133
|
+
var CANONICAL_STRINGS = messaging.canonical_strings.strings;
|
|
194134
|
+
var BANNED_PHRASES = messaging.banned_phrases.phrases;
|
|
194135
|
+
var TERMINOLOGY = messaging.terminology.terms;
|
|
194136
|
+
var matchers2 = createMatchers(messaging);
|
|
194137
|
+
function canonicalString(id) {
|
|
194138
|
+
const entry = CANONICAL_STRINGS.find((candidate) => candidate.id === id);
|
|
194139
|
+
if (!entry)
|
|
194140
|
+
throw new Error(`Unknown canonical string "${id}"`);
|
|
194141
|
+
return entry;
|
|
194142
|
+
}
|
|
194143
|
+
function canonicalText(id) {
|
|
194144
|
+
return canonicalString(id).text;
|
|
194145
|
+
}
|
|
194146
|
+
|
|
193387
194147
|
// src/tui.ts
|
|
193388
194148
|
var STATUS_LABELS = {
|
|
193389
194149
|
pass: "ok",
|
|
@@ -193411,8 +194171,8 @@ function renderDoctorHuman(report, options = {}) {
|
|
|
193411
194171
|
for (const [group, checks] of groupChecks(report.checks)) {
|
|
193412
194172
|
lines.push("");
|
|
193413
194173
|
lines.push(ui.section(titleCase(group)));
|
|
193414
|
-
for (const
|
|
193415
|
-
lines.push(renderCheck(ui,
|
|
194174
|
+
for (const check2 of checks) {
|
|
194175
|
+
lines.push(renderCheck(ui, check2));
|
|
193416
194176
|
}
|
|
193417
194177
|
}
|
|
193418
194178
|
if (report.nextCommands.length > 0) {
|
|
@@ -193473,7 +194233,7 @@ function renderInitBanner() {
|
|
|
193473
194233
|
const ui = createTerminalUi();
|
|
193474
194234
|
return [
|
|
193475
194235
|
ui.title("Moda init"),
|
|
193476
|
-
ui.dim("
|
|
194236
|
+
ui.dim(canonicalText("cli_description")),
|
|
193477
194237
|
"",
|
|
193478
194238
|
` ${ui.status("info")} Human-in-the-loop setup. Secrets stay untouched and file changes are shown before completion.`
|
|
193479
194239
|
].join(`
|
|
@@ -193631,27 +194391,27 @@ function renderSummary(ui, report) {
|
|
|
193631
194391
|
`skip ${report.summary.skipped}`
|
|
193632
194392
|
].join(" ");
|
|
193633
194393
|
}
|
|
193634
|
-
function renderCheck(ui,
|
|
194394
|
+
function renderCheck(ui, check2) {
|
|
193635
194395
|
const lines = [];
|
|
193636
|
-
lines.push(` ${ui.status(
|
|
193637
|
-
for (const evidence of
|
|
194396
|
+
lines.push(` ${ui.status(check2.status)} ${check2.title}`);
|
|
194397
|
+
for (const evidence of check2.evidence.slice(0, 4)) {
|
|
193638
194398
|
lines.push(ui.wrap(` ${evidence.label}: ${evidence.value}`, 6));
|
|
193639
194399
|
}
|
|
193640
|
-
if (
|
|
193641
|
-
lines.push(ui.wrap(` fix: ${
|
|
194400
|
+
if (check2.remediation) {
|
|
194401
|
+
lines.push(ui.wrap(` fix: ${check2.remediation}`, 6));
|
|
193642
194402
|
}
|
|
193643
|
-
if (
|
|
193644
|
-
lines.push(` next: ${ui.command(
|
|
194403
|
+
if (check2.nextCommand) {
|
|
194404
|
+
lines.push(` next: ${ui.command(check2.nextCommand)}`);
|
|
193645
194405
|
}
|
|
193646
194406
|
return lines.join(`
|
|
193647
194407
|
`);
|
|
193648
194408
|
}
|
|
193649
194409
|
function groupChecks(checks) {
|
|
193650
194410
|
const groups = new Map;
|
|
193651
|
-
for (const
|
|
193652
|
-
const existing = groups.get(
|
|
193653
|
-
existing.push(
|
|
193654
|
-
groups.set(
|
|
194411
|
+
for (const check2 of checks) {
|
|
194412
|
+
const existing = groups.get(check2.group) ?? [];
|
|
194413
|
+
existing.push(check2);
|
|
194414
|
+
groups.set(check2.group, existing);
|
|
193655
194415
|
}
|
|
193656
194416
|
return [...groups.entries()];
|
|
193657
194417
|
}
|
|
@@ -194017,7 +194777,7 @@ async function runHarnessCommand(context) {
|
|
|
194017
194777
|
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.");
|
|
194018
194778
|
}
|
|
194019
194779
|
if (context.flags["github-actions"] === "true") {
|
|
194020
|
-
const { runGithubActionsAnalyze } = await import("./harness-github-actions-
|
|
194780
|
+
const { runGithubActionsAnalyze } = await import("./harness-github-actions-73a08nct.js");
|
|
194021
194781
|
const result = await runGithubActionsAnalyze(rootDir, {
|
|
194022
194782
|
writeReport: (report2) => {
|
|
194023
194783
|
const normalized = normalizeHarnessReport(report2);
|
|
@@ -194624,7 +195384,7 @@ function extractHarnessReportFromText(output, rootDir, concern) {
|
|
|
194624
195384
|
}
|
|
194625
195385
|
function reportJsonCandidates(output) {
|
|
194626
195386
|
const candidates = [];
|
|
194627
|
-
const markerPattern = new RegExp(`${
|
|
195387
|
+
const markerPattern = new RegExp(`${escapeRegExp2(REPORT_JSON_BEGIN)}\\s*([\\s\\S]*?)\\s*${escapeRegExp2(REPORT_JSON_END)}`, "g");
|
|
194628
195388
|
for (const match of output.matchAll(markerPattern)) {
|
|
194629
195389
|
if (match[1])
|
|
194630
195390
|
candidates.push(match[1]);
|
|
@@ -194891,7 +195651,7 @@ function extractTextFromAgentEvent(event) {
|
|
|
194891
195651
|
return textParts.length > 0 ? textParts.join(`
|
|
194892
195652
|
`) : undefined;
|
|
194893
195653
|
}
|
|
194894
|
-
function
|
|
195654
|
+
function escapeRegExp2(value) {
|
|
194895
195655
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
194896
195656
|
}
|
|
194897
195657
|
var EVENT_CARD_MAX = 100;
|
|
@@ -196052,17 +196812,17 @@ function collectSnapshotInputs(rootDir, maxFiles, maxTextBytes) {
|
|
|
196052
196812
|
return inputs;
|
|
196053
196813
|
}
|
|
196054
196814
|
function buildSourceSnapshot(rootDir) {
|
|
196055
|
-
const
|
|
196815
|
+
const root2 = resolve14(rootDir);
|
|
196056
196816
|
const maxFiles = numericEnv("MODA_HARNESS_MAX_FILES", DEFAULT_MAX_INVENTORY_FILES);
|
|
196057
196817
|
const maxTextBytes = numericEnv("MODA_HARNESS_MAX_TEXT_BYTES", DEFAULT_MAX_INVENTORY_TEXT_BYTES);
|
|
196058
|
-
const inputs = collectSnapshotInputs(
|
|
196059
|
-
const repo = detectRepo(
|
|
196818
|
+
const inputs = collectSnapshotInputs(root2, maxFiles, maxTextBytes);
|
|
196819
|
+
const repo = detectRepo(root2, inputs.map((input) => ({
|
|
196060
196820
|
path: input.path,
|
|
196061
|
-
absPath: join10(
|
|
196062
|
-
rootDir:
|
|
196821
|
+
absPath: join10(root2, input.path),
|
|
196822
|
+
rootDir: root2,
|
|
196063
196823
|
text: input.text
|
|
196064
196824
|
})));
|
|
196065
|
-
const gitCommit = getGitCommit(
|
|
196825
|
+
const gitCommit = getGitCommit(root2);
|
|
196066
196826
|
return packSnapshot(inputs, {
|
|
196067
196827
|
repoName: repo.name,
|
|
196068
196828
|
...gitCommit ? { gitCommit } : {},
|
|
@@ -198062,4 +198822,4 @@ function hashText(text) {
|
|
|
198062
198822
|
return createHash7("sha256").update(text).digest("hex");
|
|
198063
198823
|
}
|
|
198064
198824
|
|
|
198065
|
-
export { isPlatformApiKey, setPlatformTenantOverride, apiKeyHeaders, ApiError, callDataAPI, callControlAPI, $isSeq, $parseDocument, $stringify, require_typescript, inspectCodeSelectors, inspectPythonSelectors, resolvePromptSource, backfillPromptSource, HARNESS_REPORT_PATH, HARNESS_REPORT_APPROVAL_PATH, HARNESS_ANALYZE_CONCERNS, validateHarnessReport, readHarnessReport, normalizeHarnessReport, hashHarnessReport, hashStableJson, assertFlags, assertPositionals, runUsersCommand, runUserCommand, runProblemReopenCommand, runSignalsManagementCommand, SIGNALS_MANAGEMENT_SUBCOMMANDS, unknownSignalsSubcommandError, shouldColorTerminalOutput, terminalStyles, stripAnsi2 as stripAnsi, renderMarkdownForTerminal, startRemoteAnalyze, pollRemoteAnalyzeUntilDone, isRecoverableRemoteRun, checkPromptMapping, safePromptEvidencePath, discoverHarnessPromptSources, renderDoctorHuman, renderStatusHuman, renderInitBanner, renderInitStep, renderInitNote, renderInitSetupPlan, renderInitComplete, runHarnessCommand, writeHarnessAnalyzeResult, emitWrittenArtifacts, analyzeHarnessPrompts, repairExternalAnalystReport, deriveRelationshipsFromGraph, mergeDeterministicArtifacts, describeCodingAgentEvent, analystEventProgress, isRetryableExternalAnalystFailure, sleep, summarizeInvalidAnalystReport, isDeterministicLocalAnalyst, resolveHarnessAnalyzeConcern, detectAvailableCodingAgents, codingAgentDisplayName, runCodingAgent, resolveAnalystModel, renderExternalHarnessAnalystPrompt, CONCERN_CANDIDATE_KINDS, SEED_CANDIDATE_KIND_LABELS, renderAnalystCandidateLines, renderAnalystSeedLines, truncateText, scanHarness, summarizeHarness, buildSourceSnapshot, writeHumanProgress, readHarnessSyncState, describeSyncIdentity, describeSyncTenantLabel, findFresherHarnessReports, writeHarnessArtifacts, assertHarnessGraphSyncQuality, graphForSync, inventoryFiles, numericEnv, numericEnvAllowZero, computeDeterministicFloor, stableId2 as stableId, titleFromId2 as titleFromId, promptNameFromPath };
|
|
198825
|
+
export { isPlatformApiKey, setPlatformTenantOverride, apiKeyHeaders, ApiError, callDataAPI, callControlAPI, $isSeq, $parseDocument, $stringify, require_typescript, inspectCodeSelectors, inspectPythonSelectors, resolvePromptSource, backfillPromptSource, HARNESS_REPORT_PATH, HARNESS_REPORT_APPROVAL_PATH, HARNESS_ANALYZE_CONCERNS, validateHarnessReport, readHarnessReport, normalizeHarnessReport, hashHarnessReport, hashStableJson, assertFlags, assertPositionals, runUsersCommand, runUserCommand, runProblemReopenCommand, runSignalsManagementCommand, SIGNALS_MANAGEMENT_SUBCOMMANDS, unknownSignalsSubcommandError, shouldColorTerminalOutput, terminalStyles, stripAnsi2 as stripAnsi, renderMarkdownForTerminal, startRemoteAnalyze, pollRemoteAnalyzeUntilDone, isRecoverableRemoteRun, checkPromptMapping, safePromptEvidencePath, discoverHarnessPromptSources, canonicalText, renderDoctorHuman, renderStatusHuman, renderInitBanner, renderInitStep, renderInitNote, renderInitSetupPlan, renderInitComplete, runHarnessCommand, writeHarnessAnalyzeResult, emitWrittenArtifacts, analyzeHarnessPrompts, repairExternalAnalystReport, deriveRelationshipsFromGraph, mergeDeterministicArtifacts, describeCodingAgentEvent, analystEventProgress, isRetryableExternalAnalystFailure, sleep, summarizeInvalidAnalystReport, isDeterministicLocalAnalyst, resolveHarnessAnalyzeConcern, detectAvailableCodingAgents, codingAgentDisplayName, runCodingAgent, resolveAnalystModel, renderExternalHarnessAnalystPrompt, CONCERN_CANDIDATE_KINDS, SEED_CANDIDATE_KIND_LABELS, renderAnalystCandidateLines, renderAnalystSeedLines, truncateText, scanHarness, summarizeHarness, buildSourceSnapshot, writeHumanProgress, readHarnessSyncState, describeSyncIdentity, describeSyncTenantLabel, findFresherHarnessReports, writeHarnessArtifacts, assertHarnessGraphSyncQuality, graphForSync, inventoryFiles, numericEnv, numericEnvAllowZero, computeDeterministicFloor, stableId2 as stableId, titleFromId2 as titleFromId, promptNameFromPath };
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
safePromptEvidencePath,
|
|
22
22
|
scanHarness,
|
|
23
23
|
setPlatformTenantOverride
|
|
24
|
-
} from "./cli-
|
|
24
|
+
} from "./cli-4af3thx7.js";
|
|
25
25
|
import {
|
|
26
26
|
SKILL_SOURCE_HARNESS,
|
|
27
27
|
SKILL_SOURCE_INTEGRATION_BUNDLED,
|
|
@@ -6752,7 +6752,7 @@ async function runPromptSyncExclusive(flags, profileOptions, options) {
|
|
|
6752
6752
|
const analyzedDefinitions = new Map;
|
|
6753
6753
|
if (flags["no-analyze"] !== "true") {
|
|
6754
6754
|
options.onProgress?.("Analyzing prompt sources before sync.");
|
|
6755
|
-
const { analyzeHarnessPrompts } = await import("./harness-
|
|
6755
|
+
const { analyzeHarnessPrompts } = await import("./harness-yshh2pgj.js");
|
|
6756
6756
|
const result = await analyzeHarnessPrompts({
|
|
6757
6757
|
rootDir: process.cwd(),
|
|
6758
6758
|
existing: established.flatMap((prompt) => prompt.sourceDefinition ? [prompt.sourceDefinition.source] : []),
|
|
@@ -7082,7 +7082,7 @@ async function migratePromptManifest(options = {}) {
|
|
|
7082
7082
|
let addedSources = [];
|
|
7083
7083
|
let pendingSources = [];
|
|
7084
7084
|
if (options.discover) {
|
|
7085
|
-
const { analyzeHarnessPrompts } = await import("./harness-
|
|
7085
|
+
const { analyzeHarnessPrompts } = await import("./harness-yshh2pgj.js");
|
|
7086
7086
|
const result = await analyzeHarnessPrompts({
|
|
7087
7087
|
rootDir: root,
|
|
7088
7088
|
existing: manifest.sources,
|
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-sjc132j8.js";
|
|
12
12
|
import"./cli-mm48br00.js";
|
|
13
13
|
import {
|
|
14
14
|
ApiError,
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
terminalStyles,
|
|
40
40
|
unknownSignalsSubcommandError,
|
|
41
41
|
validateHarnessReport
|
|
42
|
-
} from "./cli-
|
|
42
|
+
} from "./cli-4af3thx7.js";
|
|
43
43
|
import"./cli-ssfq84k5.js";
|
|
44
44
|
import {
|
|
45
45
|
authFetch,
|
|
@@ -8291,7 +8291,7 @@ False-positive flags (moda false-positive <kind> <target>):
|
|
|
8291
8291
|
tool <conversation_id> One failing tool call; needs --tool and --tool-use-id (or --msg-index); audit only
|
|
8292
8292
|
laziness <conversation_id> Laziness on that trace; audit only
|
|
8293
8293
|
hallucination <conversation_id> Hallucinations on that trace; audit only
|
|
8294
|
-
custom-signal <signal_id> A hit on that trace (--conversation-id); saved as does_not_fit
|
|
8294
|
+
custom-signal <signal_id> A hit on that trace (--conversation-id); saved as does_not_fit, a labelled counterexample for the signal
|
|
8295
8295
|
|
|
8296
8296
|
Problem-linear-file flags (needs Linear connected: Integrations -> Linear):
|
|
8297
8297
|
--issue=ENG-123|URL Link an existing Linear issue instead of filing a new one
|
|
@@ -10516,7 +10516,7 @@ var commandRegistry = createCommandRegistry([
|
|
|
10516
10516
|
resetApiRequestCountBeforeRun: true,
|
|
10517
10517
|
telemetry: "result",
|
|
10518
10518
|
handler: async (context) => {
|
|
10519
|
-
const { runInit } = await import("./index-
|
|
10519
|
+
const { runInit } = await import("./index-f3k9jgrt.js");
|
|
10520
10520
|
if (context.outputMode === "agent-stream") {
|
|
10521
10521
|
context.output.writeEvent({
|
|
10522
10522
|
event: "started",
|
|
@@ -11242,7 +11242,7 @@ var commandRegistry = createCommandRegistry([
|
|
|
11242
11242
|
}),
|
|
11243
11243
|
legacyCommand({
|
|
11244
11244
|
name: "step-scores",
|
|
11245
|
-
description: "
|
|
11245
|
+
description: "Step scores for a trace (per-segment curves, first bad step, rollup)",
|
|
11246
11246
|
examples: ["moda step-scores <conversation_id>"],
|
|
11247
11247
|
hidden: true,
|
|
11248
11248
|
...dataApiDefaults
|
|
@@ -3,9 +3,10 @@ import {
|
|
|
3
3
|
initPrompts,
|
|
4
4
|
runPromptSync,
|
|
5
5
|
runSkillSync
|
|
6
|
-
} from "./cli-
|
|
6
|
+
} from "./cli-sjc132j8.js";
|
|
7
7
|
import"./cli-mm48br00.js";
|
|
8
8
|
import {
|
|
9
|
+
canonicalText,
|
|
9
10
|
codingAgentDisplayName,
|
|
10
11
|
describeCodingAgentEvent,
|
|
11
12
|
describeSyncIdentity,
|
|
@@ -23,7 +24,7 @@ import {
|
|
|
23
24
|
runHarnessCommand,
|
|
24
25
|
startRemoteAnalyze,
|
|
25
26
|
stripAnsi
|
|
26
|
-
} from "./cli-
|
|
27
|
+
} from "./cli-4af3thx7.js";
|
|
27
28
|
import {
|
|
28
29
|
bundledSkillsDir,
|
|
29
30
|
installIntegrationSkill,
|
|
@@ -841,9 +842,11 @@ function renderSdkIntegrationPrompt(opts) {
|
|
|
841
842
|
""
|
|
842
843
|
] : [];
|
|
843
844
|
return [
|
|
845
|
+
canonicalText("init_prompt_line"),
|
|
846
|
+
"",
|
|
844
847
|
"You are running inside `moda init` as a one-shot SDK integration task. The user has",
|
|
845
848
|
"approved letting you install packages and edit source files in THIS repository to add",
|
|
846
|
-
"Moda
|
|
849
|
+
"the Moda SDK. Do the integration now — do not just describe it.",
|
|
847
850
|
"",
|
|
848
851
|
...SAFETY_RULES,
|
|
849
852
|
"",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moda-ai/cli",
|
|
3
|
-
"version": "1.55.
|
|
4
|
-
"description": "CLI for Moda
|
|
3
|
+
"version": "1.55.9",
|
|
4
|
+
"description": "CLI for Moda: production monitoring and evals for AI agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"cli": "./dist/cli.js",
|
|
@@ -43,11 +43,11 @@
|
|
|
43
43
|
},
|
|
44
44
|
"keywords": [
|
|
45
45
|
"moda",
|
|
46
|
+
"ai-agents",
|
|
47
|
+
"agent-monitoring",
|
|
48
|
+
"evals",
|
|
46
49
|
"llm",
|
|
47
|
-
"
|
|
48
|
-
"cli",
|
|
49
|
-
"analytics",
|
|
50
|
-
"ai-agents"
|
|
50
|
+
"cli"
|
|
51
51
|
],
|
|
52
52
|
"author": "Moda <hello@moda.dev>",
|
|
53
53
|
"license": "MIT",
|
|
@@ -69,6 +69,7 @@
|
|
|
69
69
|
"@moda/harness-bundle": "*",
|
|
70
70
|
"@moda/harness-snapshot": "*",
|
|
71
71
|
"@moda/integration-skills": "*",
|
|
72
|
+
"@moda/messaging": "*",
|
|
72
73
|
"@types/node": "^22.10.5",
|
|
73
74
|
"eslint": "^9.17.0",
|
|
74
75
|
"typescript": "^5.7.2",
|
package/skills/moda-cli/SKILL.md
CHANGED
|
@@ -1110,7 +1110,7 @@ What each flag does downstream:
|
|
|
1110
1110
|
|---|---|
|
|
1111
1111
|
| `problem` | Dismisses the problem: it leaves `moda problems` and the dashboard at once, and the reason is folded into the next reconcile. Cannot be undone from the CLI |
|
|
1112
1112
|
| `problem-detection` | Drops that evidence from the problem and teaches the problem reader (same as `detection-review --verdict=false_positive`) |
|
|
1113
|
-
| `custom-signal` | Saved as a `does_not_fit` label with the reason,
|
|
1113
|
+
| `custom-signal` | Saved as a `does_not_fit` label with the reason, a labelled counterexample for the signal, and the live match is retracted (same as `signal-label`). `--undo` removes the label |
|
|
1114
1114
|
| `quote`, `tool`, `laziness`, `hallucination` | Audit only: recorded for review, never fed back to the detectors |
|
|
1115
1115
|
|
|
1116
1116
|
Find targets with the read commands: `--family`, `--turn` and `--quote` verbatim
|
|
@@ -1122,7 +1122,7 @@ laziness traces from `moda laziness`; hallucination traces from
|
|
|
1122
1122
|
`moda problem <id> --evidence`.
|
|
1123
1123
|
|
|
1124
1124
|
**Custom signals** are tenant-defined behaviors (pass/fail criteria) judged on
|
|
1125
|
-
every trace. Read them, then label hits so
|
|
1125
|
+
every trace. Read them, then label hits so each signal has labelled examples:
|
|
1126
1126
|
|
|
1127
1127
|
```bash
|
|
1128
1128
|
moda signals # every signal: criteria, status, 7-day judged/matched
|