@moda-ai/cli 1.25.0 → 1.27.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 CHANGED
@@ -34,49 +34,87 @@ Get your API key from [moda.dev/settings](https://moda.dev/settings).
34
34
 
35
35
  ## Usage
36
36
 
37
+ Find things by meaning, then drill in:
38
+
37
39
  ```bash
38
- moda overview # Dashboard overview
39
- moda overview --days-back=30 # Last 30 days
40
+ moda search "user wants a refund" --mode=semantic # Semantic/keyword/hybrid message search
41
+ moda search "stripe.charges.create" --mode=keyword # Exact identifiers, incl. tool calls
42
+ moda search "checkout" --include-tool-io # Search tool inputs/outputs too
43
+ moda context <conversation_id> --msg-index=5 # Read the exact turn
44
+ moda audit <conversation_id|trace_id> # Raw span/trace audit
45
+ ```
40
46
 
41
- moda clusters # Browse topic clusters
42
- moda clusters --parent-id=node-abc # Drill into a category
47
+ Production intelligence:
43
48
 
44
- moda cluster-conversations <node_id> # Conversations in a cluster
49
+ ```bash
50
+ moda overview --days-back=30 # Health briefing (KPIs, clusters, activity)
51
+ moda ask "what should I fix first?" # Grounded answer with evidence
52
+ moda investigate # Ranked issues worth fixing
53
+ moda problems # Cross-signal Problems by root cause
54
+ moda problem <problem_id> # One Problem: full dossier
55
+ moda problem <problem_id> --evidence # ...attribution evidence (keyset paged)
56
+ moda problem <problem_id> --reports # ...investigation reports
57
+ moda problem <problem_id> --conversations # ...affected conversations
58
+ moda problem-feedback <problem_id> --action=mark_fixed # Close the loop from the terminal
59
+ ```
45
60
 
46
- moda conversations --search="error" # Search conversations
47
- moda conversations --time-range=24h # Filter by time
48
- moda conversations --environment=production # Filter by environment
61
+ Signals:
49
62
 
50
- moda context <conversation_id> # Get conversation context
51
- moda context <conversation_id> --msg-index=5 # Center on message 5
63
+ ```bash
64
+ moda emotions --family=confusion # Multi-family emotion detections
65
+ moda hallucinations --kind=contradicted # Grounding: contradicted/verified outputs
66
+ moda frustrations --include-window --window=1 # Legacy single-family frustration view
67
+ moda tool-failures # Tool failure overview
68
+ moda tool-failure-detail <tool_name> --include-window
69
+ moda step-scores <conversation_id> # Graph-PRM per-step reward curves
70
+ ```
52
71
 
53
- moda frustrations # User frustration detections
54
- moda frustrations --days-back=14 --limit=20
55
- moda frustrations --include-window --window=1 # Attach 3-message slice per row
72
+ Conversations, clusters, memory:
56
73
 
57
- moda tool-failures # Tool failure overview
58
- moda tool-failure-detail <tool_name> # Per-tool failure detail
59
- moda tool-failure-detail <tool_name> --include-window --window=1
74
+ ```bash
75
+ moda conversations --search="error" --environment=production
76
+ moda clusters # Walk the topic hierarchy
77
+ moda clusters --search="billing disputes" # Find a cluster by meaning
78
+ moda world-state <conversation_id> # Agent memory (slots/threads/events)
79
+ moda world-state <id> --snapshot --msg-index=42 # What the agent believed at turn 42
80
+ moda world-state <id> --replay --message-count=50 # State evolution frame by frame
81
+ ```
60
82
 
61
- moda feedback "cluster label looks wrong" # Help us improve: flag wrong/missing data
62
- moda feedback "..." --category=missing_data --conversation-id=<id>
83
+ Live tail (one JSON line per new item — `tail -f` for your agent):
63
84
 
64
- # Prompt management
85
+ ```bash
86
+ moda tail # New conversations, every 15s
87
+ moda tail --signal=all --interval=30 # Conversations + emotion detections
88
+ ```
89
+
90
+ Prompt management:
91
+
92
+ ```bash
65
93
  moda prompts init # Create .moda/prompts.yml
66
94
  moda prompts status # Read-only local prompt status
67
- moda prompts diff # Read-only local prompt diff/status
68
95
  moda prompts sync # Upload changed prompt versions
69
- moda prompts sync --watch # Sync when local prompt hashes change
70
96
  moda prompts promote support.triage --label=prod --version=pver_abc123
71
97
  ```
72
98
 
73
- All commands output JSON. Pipe to `jq` for filtering:
99
+ Feedback:
74
100
 
75
101
  ```bash
76
- moda overview | jq '.frustrations'
77
- moda frustrations | jq '.frustrations[].primary_cause'
102
+ moda feedback "cluster label looks wrong" --category=bad_cluster_label
78
103
  ```
79
104
 
105
+ Output adapts to where it runs: piped/CI/agent environments get schema-versioned
106
+ JSON (`moda.agent.v1`), an interactive terminal gets human prose. Force a mode
107
+ with `--json`, `--agent`, or `--human`. In JSON modes, pipe to `jq`:
108
+
109
+ ```bash
110
+ moda overview | jq '.data.metrics'
111
+ moda frustrations | jq '.data.frustrations[].primary_cause'
112
+ ```
113
+
114
+ Every command supports `moda <command> --help` for scoped usage, and
115
+ `moda manifest --json` describes the full machine protocol (commands, exit
116
+ codes, event schema) for agents.
117
+
80
118
  ## Prompt Management
81
119
 
82
120
  Prompt management is code-first. Keep prompts in `prompts/**/*.prompt.md` or
@@ -1301,6 +1301,19 @@ function createAgentEvent(command, event, state) {
1301
1301
  };
1302
1302
  return redactDeep(stamped);
1303
1303
  }
1304
+ function formatValidationMessage(error) {
1305
+ const issues = error.issues;
1306
+ if (error.name !== "ZodError" || !Array.isArray(issues) || issues.length === 0) {
1307
+ return error.message;
1308
+ }
1309
+ const parts = issues.map((issue) => {
1310
+ const record = issue;
1311
+ const path = Array.isArray(record.path) && record.path.length > 0 ? record.path.join(".") : "input";
1312
+ const message = typeof record.message === "string" ? record.message : "is invalid";
1313
+ return `${path}: ${message}`;
1314
+ });
1315
+ return `Validation error — ${parts.join("; ")}`;
1316
+ }
1304
1317
  function errorToAgentError(error) {
1305
1318
  if (error instanceof CliInputRequiredError) {
1306
1319
  return {
@@ -1344,7 +1357,7 @@ function errorToAgentError(error) {
1344
1357
  if (error instanceof CliInputError || error.name === "ZodError") {
1345
1358
  return {
1346
1359
  code: "input_error",
1347
- message: error.message,
1360
+ message: formatValidationMessage(error),
1348
1361
  cause: "usage" in error && typeof error.usage === "string" ? error.usage : undefined,
1349
1362
  suggested_commands: "usage" in error && typeof error.usage === "string" ? extractSuggestedCommands(error.usage) : undefined,
1350
1363
  blocking: true
@@ -8,7 +8,7 @@ import {
8
8
  saveProfileConfig,
9
9
  secretFilePathFromRef,
10
10
  writeSecretJsonFile
11
- } from "./cli-vc7zddj1.js";
11
+ } from "./cli-59yacef3.js";
12
12
 
13
13
  // src/auth-storage.ts
14
14
  import { existsSync, readFileSync, rmSync } from "node:fs";
@@ -11,11 +11,11 @@ import {
11
11
  renderStatusHuman,
12
12
  scanHarness,
13
13
  validateHarnessReport
14
- } from "./cli-jntzpem2.js";
14
+ } from "./cli-g931ntph.js";
15
15
  import {
16
16
  isAuthSessionValid,
17
17
  loadAuthSession
18
- } from "./cli-8s69sg7f.js";
18
+ } from "./cli-9xw5bq1j.js";
19
19
  import {
20
20
  CliInputError,
21
21
  createCommandContext,
@@ -31,7 +31,7 @@ import {
31
31
  resolveTenantId,
32
32
  secretFilePathFromRef,
33
33
  validateConfig
34
- } from "./cli-vc7zddj1.js";
34
+ } from "./cli-59yacef3.js";
35
35
 
36
36
  // src/prompts.ts
37
37
  import { execFileSync } from "node:child_process";
@@ -1071,14 +1071,14 @@ function detectAgents() {
1071
1071
  import { execFileSync as execFileSync2 } from "node:child_process";
1072
1072
  import { createHash as createHash2 } from "node:crypto";
1073
1073
  import {
1074
- existsSync as existsSync6,
1074
+ existsSync as existsSync7,
1075
1075
  lstatSync as lstatSync2,
1076
- mkdirSync as mkdirSync4,
1076
+ mkdirSync as mkdirSync5,
1077
1077
  readdirSync as readdirSync3,
1078
- readFileSync as readFileSync4,
1079
- writeFileSync as writeFileSync5
1078
+ readFileSync as readFileSync5,
1079
+ writeFileSync as writeFileSync6
1080
1080
  } from "node:fs";
1081
- import { basename, dirname as dirname4, join as join5, relative as relative3 } from "node:path";
1081
+ import { basename, dirname as dirname5, join as join6, relative as relative3 } from "node:path";
1082
1082
 
1083
1083
  // src/skills-manifest.ts
1084
1084
  import {
@@ -1299,10 +1299,86 @@ function yamlQuote(value) {
1299
1299
  return JSON.stringify(value);
1300
1300
  }
1301
1301
 
1302
+ // src/agents-md.ts
1303
+ import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync5 } from "node:fs";
1304
+ import { dirname as dirname4, join as join5 } from "node:path";
1305
+ var AGENTS_MD_FILENAME = "AGENTS.md";
1306
+ var FIXES_BLOCK_BEGIN = "<!-- moda:fixes:begin -->";
1307
+ var FIXES_BLOCK_END = "<!-- moda:fixes:end -->";
1308
+ function renderFixesBlock() {
1309
+ return [
1310
+ FIXES_BLOCK_BEGIN,
1311
+ "## Moda Fixes (managed block — edits inside are overwritten by moda-cli)",
1312
+ "",
1313
+ "- Before editing prompt or skill files, run `moda fixes` to see the ranked",
1314
+ ' queue of Moda Fixes ("a fix with proof") already drafted for this repo,',
1315
+ " and `moda fix <fix_id> --packet` for the evidence packet.",
1316
+ "- Gate any prompt/skill change against production evidence with",
1317
+ " `moda fix verify <fix_id> [--prompt-file=<path>]`. Exit codes: 0 = holdout",
1318
+ " win vs baseline (pass), 1 = failing (per-case findings in the envelope),",
1319
+ " 3 = degraded/inconclusive — never treat exit 3 as a pass.",
1320
+ "- Fix PRs must carry the magic word `Fixes MODA-FIX-<SHORTREF>` in the PR",
1321
+ " body so the merge confirms the fix and starts production monitoring.",
1322
+ FIXES_BLOCK_END
1323
+ ].join(`
1324
+ `);
1325
+ }
1326
+ function upsertManagedBlock(existing, block) {
1327
+ if (existing === null) {
1328
+ return `${block}
1329
+ `;
1330
+ }
1331
+ const beginIdx = existing.indexOf(FIXES_BLOCK_BEGIN);
1332
+ const endIdx = existing.indexOf(FIXES_BLOCK_END);
1333
+ if (beginIdx !== -1 && endIdx !== -1 && endIdx >= beginIdx) {
1334
+ const before = existing.slice(0, beginIdx);
1335
+ const after = existing.slice(endIdx + FIXES_BLOCK_END.length);
1336
+ return `${before}${block}${after}`;
1337
+ }
1338
+ const separator = existing === "" || existing.endsWith(`
1339
+
1340
+ `) ? "" : existing.endsWith(`
1341
+ `) ? `
1342
+ ` : `
1343
+
1344
+ `;
1345
+ return `${existing}${separator}${block}
1346
+ `;
1347
+ }
1348
+ function writeFileIfChanged(filePath, content) {
1349
+ try {
1350
+ mkdirSync4(dirname4(filePath), { recursive: true });
1351
+ if (existsSync6(filePath)) {
1352
+ const current = readFileSync4(filePath, "utf8");
1353
+ if (current === content)
1354
+ return "unchanged";
1355
+ writeFileSync5(filePath, content);
1356
+ return "updated";
1357
+ }
1358
+ writeFileSync5(filePath, content);
1359
+ return "wrote";
1360
+ } catch {
1361
+ return "failed";
1362
+ }
1363
+ }
1364
+ function upsertFixesAgentsBlock(cwd) {
1365
+ const filePath = join5(cwd, AGENTS_MD_FILENAME);
1366
+ let existing = null;
1367
+ if (existsSync6(filePath)) {
1368
+ try {
1369
+ existing = readFileSync4(filePath, "utf8");
1370
+ } catch {
1371
+ return { path: AGENTS_MD_FILENAME, status: "failed" };
1372
+ }
1373
+ }
1374
+ const next = upsertManagedBlock(existing, renderFixesBlock());
1375
+ return { path: AGENTS_MD_FILENAME, status: writeFileIfChanged(filePath, next) };
1376
+ }
1377
+
1302
1378
  // src/skills.ts
1303
1379
  var SKILLS_REQUEST_TIMEOUT_MS = 15000;
1304
1380
  var VALID_STATUSES = new Set(["approved", "proposed", "all"]);
1305
- var SKILL_PROPOSALS_MANIFEST_PATH = join5(".moda", "skill-proposals.yml");
1381
+ var SKILL_PROPOSALS_MANIFEST_PATH = join6(".moda", "skill-proposals.yml");
1306
1382
  async function fetchSkills(status) {
1307
1383
  const apiKey = resolveApiKey();
1308
1384
  if (!apiKey) {
@@ -1427,15 +1503,15 @@ function formatRunStatusHuman(run, events) {
1427
1503
  }
1428
1504
  function writeIfChanged(filePath, content) {
1429
1505
  try {
1430
- mkdirSync4(dirname4(filePath), { recursive: true });
1431
- if (existsSync6(filePath)) {
1432
- const current = readFileSync4(filePath, "utf8");
1506
+ mkdirSync5(dirname5(filePath), { recursive: true });
1507
+ if (existsSync7(filePath)) {
1508
+ const current = readFileSync5(filePath, "utf8");
1433
1509
  if (current === content)
1434
1510
  return "unchanged";
1435
- writeFileSync5(filePath, content);
1511
+ writeFileSync6(filePath, content);
1436
1512
  return "updated";
1437
1513
  }
1438
- writeFileSync5(filePath, content);
1514
+ writeFileSync6(filePath, content);
1439
1515
  return "wrote";
1440
1516
  } catch {
1441
1517
  return "failed";
@@ -1472,7 +1548,7 @@ async function pullSkills(options = {}) {
1472
1548
  }
1473
1549
  }
1474
1550
  const agents = detectAgents();
1475
- const writeCursor = agents.includes("Cursor") || existsSync6(join5(cwd, ".cursor"));
1551
+ const writeCursor = agents.includes("Cursor") || existsSync7(join6(cwd, ".cursor"));
1476
1552
  const records = [];
1477
1553
  for (const skill of skills) {
1478
1554
  if (!skill.skill_id || !skill.skill_md) {
@@ -1485,7 +1561,7 @@ async function pullSkills(options = {}) {
1485
1561
  log(` skipped invalid skill_id: ${JSON.stringify(skill.skill_id).slice(0, 80)}`);
1486
1562
  continue;
1487
1563
  }
1488
- const claudePath = join5(cwd, ".claude", "skills", safeId, "SKILL.md");
1564
+ const claudePath = join6(cwd, ".claude", "skills", safeId, "SKILL.md");
1489
1565
  const claudeStatus = writeIfChanged(claudePath, skill.skill_md);
1490
1566
  const claudeRelativePath = `.claude/skills/${safeId}/SKILL.md`;
1491
1567
  recordOutcome(summary, claudeStatus, log, claudeRelativePath);
@@ -1493,7 +1569,7 @@ async function pullSkills(options = {}) {
1493
1569
  if (claudeStatus !== "failed")
1494
1570
  paths.push(claudeRelativePath);
1495
1571
  if (writeCursor) {
1496
- const cursorPath = join5(cwd, ".cursor", "rules", `${safeId}.mdc`);
1572
+ const cursorPath = join6(cwd, ".cursor", "rules", `${safeId}.mdc`);
1497
1573
  const cursorStatus = writeIfChanged(cursorPath, claudeSkillToCursorRule(skill.skill_md));
1498
1574
  const cursorRelativePath = `.cursor/rules/${safeId}.mdc`;
1499
1575
  recordOutcome(summary, cursorStatus, log, cursorRelativePath);
@@ -1531,15 +1607,16 @@ function recordOutcome(summary, status, log, relativePath) {
1531
1607
  break;
1532
1608
  }
1533
1609
  }
1534
- var SKILLS_DIR = join5(".claude", "skills");
1610
+ var SKILLS_DIR = join6(".claude", "skills");
1535
1611
  var SKILL_FILE = "SKILL.md";
1536
1612
  var MAX_SKILL_WALK_DEPTH = 4;
1537
1613
  async function runSkillSync(flags = {}, profileOptions = {}, options = {}) {
1538
1614
  const cwd = options.cwd ?? process.cwd();
1539
1615
  const dryRun = flags["dry-run"] === "true";
1616
+ const agentsMd = dryRun ? undefined : upsertFixesAgentsBlock(cwd);
1540
1617
  const skills = discoverLocalSkills(cwd);
1541
1618
  if (skills.length === 0) {
1542
- return { synced: [], dryRun };
1619
+ return { synced: [], dryRun, ...agentsMd ? { agentsMd } : {} };
1543
1620
  }
1544
1621
  const sourceCommit = getGitCommit2(cwd);
1545
1622
  const response = await callControlAPI("/skills/sync", {
@@ -1558,11 +1635,11 @@ async function runSkillSync(flags = {}, profileOptions = {}, options = {}) {
1558
1635
  dryRun
1559
1636
  })
1560
1637
  }, profileOptions);
1561
- return { synced: response.synced ?? [], dryRun };
1638
+ return { synced: response.synced ?? [], dryRun, ...agentsMd ? { agentsMd } : {} };
1562
1639
  }
1563
1640
  function discoverLocalSkills(cwd) {
1564
- const skillsRoot = join5(cwd, SKILLS_DIR);
1565
- if (!existsSync6(skillsRoot))
1641
+ const skillsRoot = join6(cwd, SKILLS_DIR);
1642
+ if (!existsSync7(skillsRoot))
1566
1643
  return [];
1567
1644
  const managed = new Set(managedSkillPaths(cwd));
1568
1645
  const skills = [];
@@ -1570,12 +1647,12 @@ function discoverLocalSkills(cwd) {
1570
1647
  const sourcePath = relative3(cwd, absPath).replace(/\\/g, "/");
1571
1648
  if (managed.has(sourcePath))
1572
1649
  continue;
1573
- const key = basename(dirname4(absPath));
1650
+ const key = basename(dirname5(absPath));
1574
1651
  if (key === "moda-cli" || !/^[A-Za-z0-9_-]+$/.test(key))
1575
1652
  continue;
1576
1653
  let content;
1577
1654
  try {
1578
- content = readFileSync4(absPath, "utf8");
1655
+ content = readFileSync5(absPath, "utf8");
1579
1656
  } catch {
1580
1657
  continue;
1581
1658
  }
@@ -1610,7 +1687,7 @@ function walkSkillFiles(dir, depth) {
1610
1687
  }
1611
1688
  const files = [];
1612
1689
  for (const entry of entries) {
1613
- const fullPath = join5(dir, entry);
1690
+ const fullPath = join6(dir, entry);
1614
1691
  let stat;
1615
1692
  try {
1616
1693
  stat = lstatSync2(fullPath);
@@ -1684,7 +1761,7 @@ async function applySkillProposal(proposalId, flags, profileOptions = {}, option
1684
1761
  }
1685
1762
  const safeId = safeSkillId(proposal.skillId);
1686
1763
  const relativePath = `.claude/skills/${safeId}/SKILL.md`;
1687
- const writeStatus = writeIfChanged(join5(cwd, relativePath), proposal.skillMd);
1764
+ const writeStatus = writeIfChanged(join6(cwd, relativePath), proposal.skillMd);
1688
1765
  if (writeStatus === "failed") {
1689
1766
  throw new Error(`Failed to write ${relativePath}`);
1690
1767
  }
@@ -1717,9 +1794,9 @@ function safeSkillId(skillId) {
1717
1794
  return safeId;
1718
1795
  }
1719
1796
  function writeSkillProposalManifest(cwd, proposal, relativePath) {
1720
- const manifestPath = join5(cwd, SKILL_PROPOSALS_MANIFEST_PATH);
1721
- mkdirSync4(dirname4(manifestPath), { recursive: true });
1722
- const existing = existsSync6(manifestPath) ? readFileSync4(manifestPath, "utf8") : `applied_proposals:
1797
+ const manifestPath = join6(cwd, SKILL_PROPOSALS_MANIFEST_PATH);
1798
+ mkdirSync5(dirname5(manifestPath), { recursive: true });
1799
+ const existing = existsSync7(manifestPath) ? readFileSync5(manifestPath, "utf8") : `applied_proposals:
1723
1800
  `;
1724
1801
  const entry = [
1725
1802
  ` - proposal_id: "${escapeYamlString(proposal.proposalId)}"`,
@@ -1738,7 +1815,7 @@ function writeSkillProposalManifest(cwd, proposal, relativePath) {
1738
1815
  const prefix = existing.endsWith(`
1739
1816
  `) ? existing : `${existing}
1740
1817
  `;
1741
- writeFileSync5(manifestPath, `${prefix}${entry}
1818
+ writeFileSync6(manifestPath, `${prefix}${entry}
1742
1819
  `);
1743
1820
  }
1744
1821
  function escapeYamlString(value) {
@@ -1843,7 +1920,11 @@ async function runSkillsCommand(input) {
1843
1920
  }
1844
1921
  if (sub === "sync") {
1845
1922
  const result = await runSkillSync(flags, { profile: context.profile, env: context.env });
1846
- context.output.writeData({ synced: result.synced, dryRun: result.dryRun });
1923
+ context.output.writeData({
1924
+ synced: result.synced,
1925
+ dryRun: result.dryRun,
1926
+ ...result.agentsMd ? { agentsMd: result.agentsMd } : {}
1927
+ });
1847
1928
  return 0;
1848
1929
  }
1849
1930
  if (sub !== "pull") {
@@ -1973,8 +2054,8 @@ function sha2562(input) {
1973
2054
 
1974
2055
  // src/doctor.ts
1975
2056
  import { createHash as createHash3 } from "node:crypto";
1976
- import { existsSync as existsSync7, readFileSync as readFileSync5, statSync } from "node:fs";
1977
- import { join as join6 } from "node:path";
2057
+ import { existsSync as existsSync8, readFileSync as readFileSync6, statSync } from "node:fs";
2058
+ import { join as join7 } from "node:path";
1978
2059
  async function runDoctorCommand(context) {
1979
2060
  const report = await buildDoctorReport(context, {
1980
2061
  offline: context.flags.offline === "true"
@@ -2097,8 +2178,8 @@ async function buildDoctorReport(context, options) {
2097
2178
  checks.push(urlCheck("base_url_valid", "config", "Base URL is valid", baseUrl));
2098
2179
  checks.push(urlCheck("ingest_url_valid", "config", "Ingest URL is valid", ingestUrl));
2099
2180
  checks.push(localBaseUrlCheck(activeProfile.environment, baseUrl));
2100
- const manifestPath = join6(context.cwd, ".moda", "harness.json");
2101
- const manifestExists = existsSync7(manifestPath);
2181
+ const manifestPath = join7(context.cwd, ".moda", "harness.json");
2182
+ const manifestExists = existsSync8(manifestPath);
2102
2183
  checks.push({
2103
2184
  id: "harness_manifest_exists",
2104
2185
  group: "harness",
@@ -2184,7 +2265,7 @@ function authTokenCheck(context, hasApiKey) {
2184
2265
  };
2185
2266
  }
2186
2267
  function configPermissionCheck(path) {
2187
- if (!existsSync7(path)) {
2268
+ if (!existsSync8(path)) {
2188
2269
  return {
2189
2270
  id: "config_file_permissions",
2190
2271
  group: "config",
@@ -2327,7 +2408,7 @@ function harnessCurrentCheck(cwd, manifestPath, manifestExists, tenantId) {
2327
2408
  tenantId,
2328
2409
  tenantSource: tenantId ? "env_or_config" : undefined
2329
2410
  });
2330
- const saved = JSON.parse(readFileSync5(manifestPath, "utf8"));
2411
+ const saved = JSON.parse(readFileSync6(manifestPath, "utf8"));
2331
2412
  const savedHash = stableGraphHash(saved);
2332
2413
  const currentHash = stableGraphHash(current);
2333
2414
  const matches = savedHash === currentHash;
@@ -2387,8 +2468,8 @@ function harnessSyncStateCheck(cwd) {
2387
2468
  };
2388
2469
  }
2389
2470
  function harnessReportStateCheck(cwd) {
2390
- const reportPath = join6(cwd, HARNESS_REPORT_PATH);
2391
- if (!existsSync7(reportPath)) {
2471
+ const reportPath = join7(cwd, HARNESS_REPORT_PATH);
2472
+ if (!existsSync8(reportPath)) {
2392
2473
  return {
2393
2474
  id: "harness_report_approved_synced",
2394
2475
  group: "harness",
@@ -2481,11 +2562,11 @@ function harnessReportStateCheck(cwd) {
2481
2562
  }
2482
2563
  }
2483
2564
  function readHarnessReportApproval(cwd) {
2484
- const approvalPath = join6(cwd, HARNESS_REPORT_APPROVAL_PATH);
2485
- if (!existsSync7(approvalPath))
2565
+ const approvalPath = join7(cwd, HARNESS_REPORT_APPROVAL_PATH);
2566
+ if (!existsSync8(approvalPath))
2486
2567
  return null;
2487
2568
  try {
2488
- return JSON.parse(readFileSync5(approvalPath, "utf8"));
2569
+ return JSON.parse(readFileSync6(approvalPath, "utf8"));
2489
2570
  } catch {
2490
2571
  return {
2491
2572
  schemaVersion: HARNESS_REPORT_APPROVAL_SCHEMA_VERSION,
@@ -2499,7 +2580,7 @@ function readHarnessReportApproval(cwd) {
2499
2580
  }
2500
2581
  }
2501
2582
  function discoveryCheck(id, group, title, cwd, relativePaths, nextCommand) {
2502
- const found = relativePaths.filter((path) => existsSync7(join6(cwd, path)));
2583
+ const found = relativePaths.filter((path) => existsSync8(join7(cwd, path)));
2503
2584
  return {
2504
2585
  id,
2505
2586
  group,
@@ -2515,8 +2596,8 @@ function sdkInitializationCheck(cwd) {
2515
2596
  const candidates = ["src", "app", "agent_harness"];
2516
2597
  let detected = false;
2517
2598
  for (const candidate of candidates) {
2518
- const path = join6(cwd, candidate);
2519
- if (!existsSync7(path))
2599
+ const path = join7(cwd, candidate);
2600
+ if (!existsSync8(path))
2520
2601
  continue;
2521
2602
  try {
2522
2603
  const stat = statSync(path);
@@ -2839,4 +2920,4 @@ function isRecord(value) {
2839
2920
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2840
2921
  }
2841
2922
 
2842
- export { runPromptsCommand, initPrompts, runPromptSync, claudeSkillToCursorRule, installRules, detectAgents, SKILL_SOURCE_INTEGRATION_BUNDLED, readSkillsManifest, upsertSkillManifestRecord, runSkillSync, runSkillsCommand, runDoctorCommand, runStatusCommand, buildDoctorReport };
2923
+ export { DEFAULT_POLL_INTERVAL_MS, DEFAULT_WAIT_TIMEOUT_MS, fetchLatestRun, runPromptsCommand, initPrompts, runPromptSync, claudeSkillToCursorRule, installRules, detectAgents, SKILL_SOURCE_INTEGRATION_BUNDLED, readSkillsManifest, upsertSkillManifestRecord, runSkillSync, runSkillsCommand, runDoctorCommand, runStatusCommand, buildDoctorReport };
@@ -23,7 +23,7 @@ import {
23
23
  resolveTenantId,
24
24
  shouldInventoryFile,
25
25
  stringOption
26
- } from "./cli-vc7zddj1.js";
26
+ } from "./cli-59yacef3.js";
27
27
 
28
28
  // src/api-client.ts
29
29
  var REQUEST_TIMEOUT_MS = 30000;
@@ -3338,7 +3338,7 @@ async function runHarnessCommand(context) {
3338
3338
  elapsed_ms: Date.now() - context.startedAt
3339
3339
  });
3340
3340
  if (context.flags["github-actions"] === "true") {
3341
- const { runGithubActionsAnalyze } = await import("./harness-github-actions-rjyc9a7z.js");
3341
+ const { runGithubActionsAnalyze } = await import("./harness-github-actions-ct8fwzdr.js");
3342
3342
  const result = await runGithubActionsAnalyze(rootDir, {
3343
3343
  writeReport: (report2) => {
3344
3344
  const normalized = normalizeHarnessReport(report2);
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  authFetch,
3
3
  getCachedLoginContext
4
- } from "./cli-8s69sg7f.js";
4
+ } from "./cli-9xw5bq1j.js";
5
5
  import {
6
6
  CliAccessError,
7
7
  CliInputError,
@@ -15,7 +15,7 @@ import {
15
15
  resolveTenantIdFromActiveProfile,
16
16
  saveCliConfig,
17
17
  writeSecretJsonFile
18
- } from "./cli-vc7zddj1.js";
18
+ } from "./cli-59yacef3.js";
19
19
 
20
20
  // src/init/tenant.ts
21
21
  import { randomUUID } from "node:crypto";