@moda-ai/cli 1.55.9 → 1.55.10

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.
@@ -1935,4 +1935,4 @@ function createCommandContext(input, options = {}) {
1935
1935
  };
1936
1936
  }
1937
1937
 
1938
- export { PROD_BASE_URL, DEFAULT_INGEST_URL, getModaPaths, getModaDir, isLoopbackBaseUrl, assertValidProfileName, describeBaseUrlSource, loadProfileConfig, saveProfileConfig, getActiveProfile, setActiveProfile, upsertProfile, clearStoredApiKeyCredentials, secretFilePathFromRef, resolveSecretReference, resolveApiKeyFromActiveProfile, resolveTenantIdFromActiveProfile, ensureSecretFilePermissions, writeSecretJsonFile, CliInputError, CliAccessError, CliInputRequiredError, CliAuthError, CliCancellationError, isNetworkLikeError, isApiLikeError, VERSION, MODA_BASE_URL, loadCliConfig, saveCliConfig, resolveApiKey, embeddedTenantIdFromApiKey, resolveIngestUrl2 as resolveIngestUrl, resolveTenantId, resolveApiTenantId, resolveModaBaseUrl, validateConfig, recordApiRequest, getApiRequestCount, resetApiRequestCount, MAX_SCANNED_FILE_BYTES, DEFAULT_MAX_INVENTORY_FILES, DEFAULT_MAX_INVENTORY_TEXT_BYTES, MAX_RECORDED_SKIPS, SKIPPED_DIRS, isSkippedDir, isSkippedPathPrefix, isEvalLikePath, shouldInventoryFile, isTextFile, isSecretishPath, SECRET_KEYS, redactDeep, redactString, packSnapshot, EXIT_OK, EXIT_ERROR, EXIT_DEGRADED, EXIT_AUTH_REQUIRED, EXIT_INPUT_REQUIRED, EXIT_CANCELLED, AGENT_ERROR_CODES, wasOutputCancelled, safeWriteStdout, safeWriteStderr, explicitOutputMode, resolveOutputMode, createCliOutput, agentEnvelopeFits, agentMaxOutputBytes, parseBooleanFlagValue, stringOption, createCommandContext };
1938
+ export { PROD_BASE_URL, DEFAULT_INGEST_URL, getModaPaths, getModaDir, isLoopbackBaseUrl, describeBaseUrlSource, loadProfileConfig, saveProfileConfig, getActiveProfile, setActiveProfile, upsertProfile, clearStoredApiKeyCredentials, secretFilePathFromRef, resolveSecretReference, resolveApiKeyFromActiveProfile, resolveTenantIdFromActiveProfile, ensureSecretFilePermissions, writeSecretJsonFile, CliInputError, CliAccessError, CliInputRequiredError, CliAuthError, CliCancellationError, isNetworkLikeError, isApiLikeError, VERSION, MODA_BASE_URL, loadCliConfig, saveCliConfig, resolveApiKey, embeddedTenantIdFromApiKey, resolveIngestUrl2 as resolveIngestUrl, resolveTenantId, resolveApiTenantId, resolveModaBaseUrl, validateConfig, recordApiRequest, getApiRequestCount, resetApiRequestCount, MAX_SCANNED_FILE_BYTES, DEFAULT_MAX_INVENTORY_FILES, DEFAULT_MAX_INVENTORY_TEXT_BYTES, MAX_RECORDED_SKIPS, SKIPPED_DIRS, isSkippedDir, isSkippedPathPrefix, isEvalLikePath, shouldInventoryFile, isTextFile, isSecretishPath, SECRET_KEYS, redactDeep, redactString, packSnapshot, EXIT_OK, EXIT_ERROR, EXIT_DEGRADED, EXIT_AUTH_REQUIRED, EXIT_INPUT_REQUIRED, EXIT_CANCELLED, AGENT_ERROR_CODES, wasOutputCancelled, safeWriteStdout, safeWriteStderr, explicitOutputMode, resolveOutputMode, createCliOutput, agentEnvelopeFits, agentMaxOutputBytes, parseBooleanFlagValue, stringOption, createCommandContext };
@@ -8,7 +8,7 @@ import {
8
8
  saveProfileConfig,
9
9
  secretFilePathFromRef,
10
10
  writeSecretJsonFile
11
- } from "./cli-mx9r1689.js";
11
+ } from "./cli-0qnghzg4.js";
12
12
  import {
13
13
  __require
14
14
  } from "./cli-0v6na3yp.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  authFetch,
3
3
  getCachedLoginContext
4
- } from "./cli-tw8jj190.js";
4
+ } from "./cli-4f0p8erk.js";
5
5
  import {
6
6
  CliAccessError,
7
7
  CliInputError,
@@ -16,7 +16,7 @@ import {
16
16
  resolveTenantIdFromActiveProfile,
17
17
  saveCliConfig,
18
18
  writeSecretJsonFile
19
- } from "./cli-mx9r1689.js";
19
+ } from "./cli-0qnghzg4.js";
20
20
 
21
21
  // src/init/tenant.ts
22
22
  import { randomUUID } from "node:crypto";
@@ -21,7 +21,7 @@ import {
21
21
  safePromptEvidencePath,
22
22
  scanHarness,
23
23
  setPlatformTenantOverride
24
- } from "./cli-4af3thx7.js";
24
+ } from "./cli-v27q5dvh.js";
25
25
  import {
26
26
  SKILL_SOURCE_HARNESS,
27
27
  SKILL_SOURCE_INTEGRATION_BUNDLED,
@@ -34,7 +34,7 @@ import {
34
34
  import {
35
35
  isAuthSessionValid,
36
36
  loadAuthSession
37
- } from "./cli-tw8jj190.js";
37
+ } from "./cli-4f0p8erk.js";
38
38
  import {
39
39
  CliInputError,
40
40
  EXIT_ERROR,
@@ -54,7 +54,7 @@ import {
54
54
  resolveTenantId,
55
55
  secretFilePathFromRef,
56
56
  validateConfig
57
- } from "./cli-mx9r1689.js";
57
+ } from "./cli-0qnghzg4.js";
58
58
  import {
59
59
  __commonJS,
60
60
  __require,
@@ -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-yshh2pgj.js");
6755
+ const { analyzeHarnessPrompts } = await import("./harness-0tnqw849.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-yshh2pgj.js");
7085
+ const { analyzeHarnessPrompts } = await import("./harness-0tnqw849.js");
7086
7086
  const result = await analyzeHarnessPrompts({
7087
7087
  rootDir: root,
7088
7088
  existing: manifest.sources,
@@ -8444,7 +8444,7 @@ async function runSkillRegistryCommand(sub, positionals, flags, context) {
8444
8444
 
8445
8445
  // src/doctor.ts
8446
8446
  import { createHash as createHash3 } from "node:crypto";
8447
- import { existsSync as existsSync5, readFileSync as readFileSync4, statSync as statSync2 } from "node:fs";
8447
+ import { existsSync as existsSync5, readFileSync as readFileSync4 } from "node:fs";
8448
8448
  import { join as join4 } from "node:path";
8449
8449
  async function runDoctorCommand(context) {
8450
8450
  const report = await buildDoctorReport(context, {
@@ -8483,7 +8483,7 @@ async function runStatusCommand(context) {
8483
8483
  harness: checkStatus(report.checks, "harness_manifest_current"),
8484
8484
  harnessSync: checkStatus(report.checks, "harness_sync_state_present"),
8485
8485
  harnessReport: "skipped",
8486
- shadowSpark: checkStatus(report.checks, "shadow_spark_workspace_health"),
8486
+ shadowSpark: "skipped",
8487
8487
  prompts: checkStatus(report.checks, "prompts_discovered"),
8488
8488
  skills: checkStatus(report.checks, "skills_discovered"),
8489
8489
  topBrokenCheck: topBroken ? {
@@ -9102,7 +9102,7 @@ function recentDataFlowCheck(overview) {
9102
9102
  { label: "last_event_at", value: lastEventAt ?? "none" }
9103
9103
  ],
9104
9104
  remediation: hasData ? undefined : "No recent Moda data was visible in the overview window.",
9105
- nextCommand: hasData ? undefined : "moda hooks install --agent=all"
9105
+ nextCommand: hasData ? undefined : "moda init"
9106
9106
  };
9107
9107
  }
9108
9108
  function numberAt(value, path) {
@@ -27,7 +27,7 @@ import {
27
27
  resolveTenantId,
28
28
  shouldInventoryFile,
29
29
  stringOption
30
- } from "./cli-mx9r1689.js";
30
+ } from "./cli-0qnghzg4.js";
31
31
  import {
32
32
  __commonJS,
33
33
  __require,
@@ -193387,12 +193387,12 @@ function assertHarnessGraphSyncSize(graph) {
193387
193387
  // ../../packages/messaging/messaging.json
193388
193388
  var messaging_default = {
193389
193389
  $schema: "./messaging.schema.json",
193390
- version: "1.0.2",
193390
+ version: "1.0.3",
193391
193391
  locked_on: "2026-10-14",
193392
193392
  approved_by: "mo",
193393
- source: "Branding project docs/positioning.md v1.0.2",
193393
+ source: "Branding project docs/positioning.md v1.0.3",
193394
193394
  canonical_strings: {
193395
- version: "1.0.2",
193395
+ version: "1.0.3",
193396
193396
  locked_on: "2026-10-14",
193397
193397
  approved_by: "mo",
193398
193398
  strings: [
@@ -193419,7 +193419,7 @@ var messaging_default = {
193419
193419
  text: "Production monitoring and evals for AI agents.",
193420
193420
  match: "contains_ci",
193421
193421
  surfaces: [
193422
- "apps/moda-frontend/components/landing/hero.tsx (eyebrow above the H1)",
193422
+ "apps/moda-frontend/app/llms.txt/route.ts (after the tagline)",
193423
193423
  "every bio, package description and directory listing below"
193424
193424
  ]
193425
193425
  },
@@ -193598,7 +193598,7 @@ var messaging_default = {
193598
193598
  ]
193599
193599
  },
193600
193600
  banned_phrases: {
193601
- version: "1.0.2",
193601
+ version: "1.0.3",
193602
193602
  phrases: [
193603
193603
  {
193604
193604
  id: "fixes_your_agent",
@@ -193775,7 +193775,7 @@ var messaging_default = {
193775
193775
  ]
193776
193776
  },
193777
193777
  terminology: {
193778
- version: "1.0.2",
193778
+ version: "1.0.3",
193779
193779
  terms: [
193780
193780
  {
193781
193781
  use: "trace",
@@ -194777,7 +194777,7 @@ async function runHarnessCommand(context) {
194777
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.");
194778
194778
  }
194779
194779
  if (context.flags["github-actions"] === "true") {
194780
- const { runGithubActionsAnalyze } = await import("./harness-github-actions-73a08nct.js");
194780
+ const { runGithubActionsAnalyze } = await import("./harness-github-actions-wpkr7jjr.js");
194781
194781
  const result = await runGithubActionsAnalyze(rootDir, {
194782
194782
  writeReport: (report2) => {
194783
194783
  const normalized = normalizeHarnessReport(report2);
package/dist/cli.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  runPromptsCommand,
9
9
  runSkillsCommand,
10
10
  runStatusCommand
11
- } from "./cli-sjc132j8.js";
11
+ } from "./cli-d3c95kks.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-4af3thx7.js";
42
+ } from "./cli-v27q5dvh.js";
43
43
  import"./cli-ssfq84k5.js";
44
44
  import {
45
45
  authFetch,
@@ -48,7 +48,7 @@ import {
48
48
  loadAuthSession,
49
49
  login,
50
50
  revokeCliSessionToken
51
- } from "./cli-tw8jj190.js";
51
+ } from "./cli-4f0p8erk.js";
52
52
  import {
53
53
  AGENT_ERROR_CODES,
54
54
  CliAccessError,
@@ -68,7 +68,6 @@ import {
68
68
  VERSION,
69
69
  agentEnvelopeFits,
70
70
  agentMaxOutputBytes,
71
- assertValidProfileName,
72
71
  clearStoredApiKeyCredentials,
73
72
  createCliOutput,
74
73
  createCommandContext,
@@ -101,9 +100,8 @@ import {
101
100
  setActiveProfile,
102
101
  upsertProfile,
103
102
  validateConfig,
104
- wasOutputCancelled,
105
- writeSecretJsonFile
106
- } from "./cli-mx9r1689.js";
103
+ wasOutputCancelled
104
+ } from "./cli-0qnghzg4.js";
107
105
  import {
108
106
  __require
109
107
  } from "./cli-0v6na3yp.js";
@@ -4946,124 +4944,6 @@ async function probeApiKey(key, options = {}) {
4946
4944
  return { outcome: "live" };
4947
4945
  }
4948
4946
 
4949
- // src/keys.ts
4950
- import { createHash as createHash2 } from "node:crypto";
4951
- import { existsSync as existsSync3, readFileSync as readFileSync4 } from "node:fs";
4952
- import { join as join3 } from "node:path";
4953
- function keySecretRef(profile, keyId) {
4954
- assertValidProfileName(profile);
4955
- assertSafeKeyId(keyId);
4956
- return `file:secrets/api-keys/${profile}/${keyId}.json`;
4957
- }
4958
- function createLocalKeyDescriptor(input) {
4959
- assertValidProfileName(input.profile);
4960
- const now = input.now ?? new Date;
4961
- const id = stableKeyId(input.profile, input.name, now);
4962
- return {
4963
- id,
4964
- profile: input.profile,
4965
- name: input.name,
4966
- purpose: input.purpose ?? "data_api",
4967
- environment: input.environment,
4968
- tenant_id: input.tenant_id,
4969
- workspace_id: input.workspace_id,
4970
- secret_ref: input.secret_ref ?? keySecretRef(input.profile, id),
4971
- status: "active",
4972
- created_at: now.toISOString()
4973
- };
4974
- }
4975
- function validateKeyDescriptor(descriptor) {
4976
- assertValidProfileName(descriptor.profile);
4977
- assertSafeKeyId(descriptor.id);
4978
- if (!descriptor.name.trim()) {
4979
- throw new Error("Key name is required.");
4980
- }
4981
- if (descriptor.status !== "active" && descriptor.status !== "rotating" && descriptor.status !== "revoked") {
4982
- throw new Error(`Invalid key status '${descriptor.status}'.`);
4983
- }
4984
- if (descriptor.purpose !== "data_api" && descriptor.purpose !== "ingest" && descriptor.purpose !== "automation") {
4985
- throw new Error(`Invalid key purpose '${descriptor.purpose}'.`);
4986
- }
4987
- if (descriptor.environment !== "local" && descriptor.environment !== "dev" && descriptor.environment !== "staging" && descriptor.environment !== "prod") {
4988
- throw new Error(`Invalid key environment '${descriptor.environment}'.`);
4989
- }
4990
- if (!descriptor.secret_ref.startsWith("file:")) {
4991
- throw new Error("Local key descriptors must point to a file: secret ref.");
4992
- }
4993
- }
4994
- function writeLocalApiKeySecret(descriptor, apiKey, options = {}) {
4995
- validateKeyDescriptor(descriptor);
4996
- if (!apiKey.trim()) {
4997
- throw new Error("API key value is required.");
4998
- }
4999
- const path = secretFilePathFromRef(descriptor.secret_ref, options);
5000
- if (!path) {
5001
- throw new Error(`Unsupported key secret reference: ${descriptor.secret_ref}`);
5002
- }
5003
- writeSecretJsonFile(path, {
5004
- value: apiKey,
5005
- key_id: descriptor.id,
5006
- profile: descriptor.profile,
5007
- purpose: descriptor.purpose,
5008
- created_at: descriptor.created_at
5009
- });
5010
- return path;
5011
- }
5012
- function keyDescriptorStorePath(options = {}) {
5013
- return join3(getModaPaths(options).dir, "keys.json");
5014
- }
5015
- function loadLocalKeyDescriptors(options = {}) {
5016
- const path = keyDescriptorStorePath(options);
5017
- try {
5018
- if (!existsSync3(path))
5019
- return [];
5020
- const parsed = JSON.parse(readFileSync4(path, "utf8"));
5021
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
5022
- return [];
5023
- }
5024
- const keys = parsed.keys;
5025
- if (!Array.isArray(keys))
5026
- return [];
5027
- return keys.filter((key) => {
5028
- try {
5029
- validateKeyDescriptor(key);
5030
- return true;
5031
- } catch {
5032
- return false;
5033
- }
5034
- });
5035
- } catch {
5036
- return [];
5037
- }
5038
- }
5039
- function saveLocalKeyDescriptors(keys, options = {}) {
5040
- for (const key of keys)
5041
- validateKeyDescriptor(key);
5042
- writeSecretJsonFile(keyDescriptorStorePath(options), {
5043
- version: 1,
5044
- keys
5045
- });
5046
- }
5047
- function upsertLocalKeyDescriptor(descriptor, options = {}) {
5048
- validateKeyDescriptor(descriptor);
5049
- const keys = loadLocalKeyDescriptors(options);
5050
- const next = [
5051
- ...keys.filter((key) => key.id !== descriptor.id),
5052
- descriptor
5053
- ].sort((a, b) => a.created_at.localeCompare(b.created_at));
5054
- saveLocalKeyDescriptors(next, options);
5055
- return next;
5056
- }
5057
- function stableKeyId(profile, name, now) {
5058
- const hash = createHash2("sha256").update(`${profile}\x00${name}\x00${now.toISOString()}`).digest("hex").slice(0, 12);
5059
- return `key_${hash}`;
5060
- }
5061
- function assertSafeKeyId(keyId) {
5062
- if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(keyId)) {
5063
- throw new Error(`Invalid key id '${keyId}'. Use letters, numbers, dots, dashes, or underscores.`);
5064
- }
5065
- }
5066
-
5067
4947
  // src/profile-commands.ts
5068
4948
  var ONLINE_PROBE_TIMEOUT_MS = 5000;
5069
4949
  function subcommand(context) {
@@ -5459,62 +5339,14 @@ async function runConfigCommand(context) {
5459
5339
  });
5460
5340
  return { exitCode: 0 };
5461
5341
  }
5462
- var KEYS_LOCAL_ONLY_NOTE = "moda keys manages local key descriptors in ~/.moda only; it does not list or change your tenant's server-side API keys (see Settings → Ingestion keys in the dashboard).";
5463
- async function runKeysCommand(context) {
5464
- switch (subcommand(context)) {
5465
- case "list": {
5466
- const profile = context.profile ?? (context.env.MODA_PROFILE?.trim() || undefined) ?? loadProfileConfig({ env: context.env }).active_profile;
5467
- const keys = loadLocalKeyDescriptors({ env: context.env }).filter((key) => !profile || key.profile === profile);
5468
- context.output.writeData({
5469
- scope: "local_descriptors",
5470
- profile,
5471
- keys
5472
- }, {
5473
- warnings: [KEYS_LOCAL_ONLY_NOTE]
5474
- });
5475
- return { exitCode: 0 };
5476
- }
5477
- case "create": {
5478
- const active = getActiveProfile({ profile: context.profile, env: context.env });
5479
- const name = flag(context, "name") ?? `${active.name}-${Date.now()}`;
5480
- const descriptor = createLocalKeyDescriptor({
5481
- profile: active.name,
5482
- environment: active.environment,
5483
- name,
5484
- purpose: "data_api",
5485
- tenant_id: active.tenant_id,
5486
- workspace_id: active.workspace_id
5487
- });
5488
- const value = flag(context, "value");
5489
- const secretPath = value ? writeLocalApiKeySecret(descriptor, value, { env: context.env }) : undefined;
5490
- upsertLocalKeyDescriptor(descriptor, { env: context.env });
5491
- context.output.writeData({
5492
- key: descriptor,
5493
- secret_path: secretPath,
5494
- scope: "local_descriptors"
5495
- }, {
5496
- warnings: [KEYS_LOCAL_ONLY_NOTE]
5497
- });
5498
- return { exitCode: 0 };
5499
- }
5500
- case "rotate":
5501
- case "revoke": {
5502
- const action = subcommand(context);
5503
- const keyId = requirePositional(context, 1, `Usage: moda keys ${action} <key_id>`);
5504
- throw new CliInputError(`moda keys ${action} is not supported: the CLI cannot ${action} server-side API keys (${keyId} was not changed).`, "Manage API keys in the dashboard at Settings → Ingestion keys.");
5505
- }
5506
- default:
5507
- throw unknownSubcommandError("keys", subcommand(context), ["list", "create", "rotate", "revoke"]);
5508
- }
5509
- }
5510
5342
 
5511
5343
  // src/agent.ts
5512
- import { existsSync as existsSync4, readFileSync as readFileSync5, statSync as statSync2 } from "node:fs";
5513
- import { join as join4, relative as relative2, resolve as resolve3 } from "node:path";
5344
+ import { existsSync as existsSync3, readFileSync as readFileSync4, statSync as statSync2 } from "node:fs";
5345
+ import { join as join3, relative as relative2, resolve as resolve3 } from "node:path";
5514
5346
  var MODA_DIR = ".moda";
5515
- var HARNESS_PATH = join4(MODA_DIR, "harness.json");
5516
- var HARNESS_REPORT_MARKDOWN_PATH = join4(MODA_DIR, "HARNESS_REPORT.md");
5517
- var HARNESS_SUMMARY_PATH = join4(MODA_DIR, "HARNESS.md");
5347
+ var HARNESS_PATH = join3(MODA_DIR, "harness.json");
5348
+ var HARNESS_REPORT_MARKDOWN_PATH = join3(MODA_DIR, "HARNESS_REPORT.md");
5349
+ var HARNESS_SUMMARY_PATH = join3(MODA_DIR, "HARNESS.md");
5518
5350
  async function runAgentCommand(context) {
5519
5351
  const subcommand2 = context.positionals[0] ?? "context";
5520
5352
  switch (subcommand2) {
@@ -5558,22 +5390,6 @@ async function runAgentCommand(context) {
5558
5390
  });
5559
5391
  return { exitCode: 0 };
5560
5392
  }
5561
- case "ask": {
5562
- const loaded = await buildAgentContext(context);
5563
- const question = context.positionals.slice(1).join(" ").trim() || context.flags.question;
5564
- context.output.writeData({
5565
- schemaVersion: "agent_ask.v0.1",
5566
- generatedAt: loaded.payload.generatedAt,
5567
- question: question || null,
5568
- answer: "Moda CLI can provide local harness context today. Cloud intelligence for free-form production questions belongs to the future Moda Ask layer.",
5569
- recommendedActions: loaded.payload.recommendedActions,
5570
- nextCommands: loaded.payload.nextCommands,
5571
- evidenceRefs: loaded.payload.evidenceRefs
5572
- }, agentWriteOptions(loaded, {
5573
- summary: "Returned local Moda context and next commands for the requested agent question."
5574
- }));
5575
- return { exitCode: 0 };
5576
- }
5577
5393
  default:
5578
5394
  throw new CliInputError(`Unknown agent subcommand '${subcommand2}'`, "Usage: moda agent context|next-action|evidence (for production issues use moda investigate)");
5579
5395
  }
@@ -5618,7 +5434,7 @@ async function buildAgentContext(context) {
5618
5434
  },
5619
5435
  report: reportState.state,
5620
5436
  sync: syncState ? {
5621
- path: join4(MODA_DIR, "sync-state.json"),
5437
+ path: join3(MODA_DIR, "sync-state.json"),
5622
5438
  exists: true,
5623
5439
  source: syncState.source,
5624
5440
  updatedAt: syncState.updatedAt,
@@ -5626,7 +5442,7 @@ async function buildAgentContext(context) {
5626
5442
  remoteHarnessId: syncState.remote.harnessId,
5627
5443
  remoteVersionId: syncState.remote.versionId
5628
5444
  } : {
5629
- path: join4(MODA_DIR, "sync-state.json"),
5445
+ path: join3(MODA_DIR, "sync-state.json"),
5630
5446
  exists: false
5631
5447
  }
5632
5448
  },
@@ -5676,18 +5492,18 @@ function summarizeAgentContext(payload, noun) {
5676
5492
  return `Local Moda ${noun} is healthy with ${agents} runtime agent(s).`;
5677
5493
  }
5678
5494
  function readHarnessGraphIfPresent(cwd) {
5679
- const path = join4(cwd, HARNESS_PATH);
5680
- if (!existsSync4(path))
5495
+ const path = join3(cwd, HARNESS_PATH);
5496
+ if (!existsSync3(path))
5681
5497
  return;
5682
5498
  try {
5683
- return JSON.parse(readFileSync5(path, "utf8"));
5499
+ return JSON.parse(readFileSync4(path, "utf8"));
5684
5500
  } catch {
5685
5501
  return;
5686
5502
  }
5687
5503
  }
5688
5504
  function readHarnessReportState(cwd) {
5689
- const path = join4(cwd, HARNESS_REPORT_PATH);
5690
- if (!existsSync4(path)) {
5505
+ const path = join3(cwd, HARNESS_REPORT_PATH);
5506
+ if (!existsSync3(path)) {
5691
5507
  return {
5692
5508
  state: {
5693
5509
  path: HARNESS_REPORT_PATH,
@@ -5731,11 +5547,11 @@ function readHarnessReportState(cwd) {
5731
5547
  }
5732
5548
  }
5733
5549
  function readApproval(cwd) {
5734
- const path = join4(cwd, HARNESS_REPORT_APPROVAL_PATH);
5735
- if (!existsSync4(path))
5550
+ const path = join3(cwd, HARNESS_REPORT_APPROVAL_PATH);
5551
+ if (!existsSync3(path))
5736
5552
  return;
5737
5553
  try {
5738
- return JSON.parse(readFileSync5(path, "utf8"));
5554
+ return JSON.parse(readFileSync4(path, "utf8"));
5739
5555
  } catch {
5740
5556
  return;
5741
5557
  }
@@ -5811,9 +5627,9 @@ function existingArtifacts(cwd) {
5811
5627
  [HARNESS_REPORT_PATH, "harness_report", "Cited harness analyst report."],
5812
5628
  [HARNESS_REPORT_MARKDOWN_PATH, "harness_report_markdown", "Human-readable harness analyst report."],
5813
5629
  [HARNESS_SUMMARY_PATH, "harness_summary", "Human-readable harness graph summary."],
5814
- [join4(MODA_DIR, "sync-state.json"), "sync_state", "Last local harness sync state."],
5815
- [join4(MODA_DIR, "prompts.yml"), "prompt_manifest", "Local prompt discovery manifest."]
5816
- ].flatMap(([path, kind, description]) => existsSync4(join4(cwd, path)) ? [{ path, kind, description }] : []);
5630
+ [join3(MODA_DIR, "sync-state.json"), "sync_state", "Last local harness sync state."],
5631
+ [join3(MODA_DIR, "prompts.yml"), "prompt_manifest", "Local prompt discovery manifest."]
5632
+ ].flatMap(([path, kind, description]) => existsSync3(join3(cwd, path)) ? [{ path, kind, description }] : []);
5817
5633
  }
5818
5634
  function expandEvidenceRef(ref, loaded, cwd) {
5819
5635
  if (ref.startsWith("doctor:")) {
@@ -5894,9 +5710,9 @@ function readCitationExcerpt(cwd, citation) {
5894
5710
  if (!citation.path || citation.type !== "file" && citation.type !== "generated_doc")
5895
5711
  return citation.excerpt;
5896
5712
  const absolute = safeResolve(cwd, citation.path);
5897
- if (!absolute || !existsSync4(absolute))
5713
+ if (!absolute || !existsSync3(absolute))
5898
5714
  return citation.excerpt;
5899
- const text = readFileSync5(absolute, "utf8");
5715
+ const text = readFileSync4(absolute, "utf8");
5900
5716
  if (citation.line && citation.line > 0) {
5901
5717
  return text.split(/\r?\n/)[citation.line - 1] ?? citation.excerpt;
5902
5718
  }
@@ -5907,13 +5723,13 @@ function readModaArtifact(cwd, artifactPath) {
5907
5723
  throw new CliInputError(`Artifact '${artifactPath}' is outside .moda and cannot be expanded directly.`, "Use a citation evidence ref for source-file evidence.");
5908
5724
  }
5909
5725
  const absolute = safeResolve(cwd, artifactPath);
5910
- if (!absolute || !existsSync4(absolute))
5726
+ if (!absolute || !existsSync3(absolute))
5911
5727
  throw missingEvidence(`artifact:${artifactPath}`);
5912
5728
  const size = statSync2(absolute).size;
5913
5729
  return {
5914
5730
  path: artifactPath,
5915
5731
  bytes: size,
5916
- text: readFileSync5(absolute, "utf8")
5732
+ text: readFileSync4(absolute, "utf8")
5917
5733
  };
5918
5734
  }
5919
5735
  function safeResolve(cwd, path) {
@@ -5951,8 +5767,8 @@ function purposeForCommand(command) {
5951
5767
  }
5952
5768
 
5953
5769
  // src/production-intelligence.ts
5954
- import { existsSync as existsSync5, readFileSync as readFileSync6 } from "node:fs";
5955
- import { join as join5 } from "node:path";
5770
+ import { existsSync as existsSync4, readFileSync as readFileSync5 } from "node:fs";
5771
+ import { join as join4 } from "node:path";
5956
5772
 
5957
5773
  // src/ask-stream.ts
5958
5774
  class AskStreamError extends Error {
@@ -7465,12 +7281,12 @@ function loadHarnessHints(cwd) {
7465
7281
  skillPaths: new Map,
7466
7282
  entrypointPaths: []
7467
7283
  };
7468
- const harnessPath = join5(cwd, ".moda", "harness.json");
7469
- if (!existsSync5(harnessPath))
7284
+ const harnessPath = join4(cwd, ".moda", "harness.json");
7285
+ if (!existsSync4(harnessPath))
7470
7286
  return hints;
7471
7287
  hints.reportPath = ".moda/harness.json";
7472
7288
  try {
7473
- const parsed = JSON.parse(readFileSync6(harnessPath, "utf8"));
7289
+ const parsed = JSON.parse(readFileSync5(harnessPath, "utf8"));
7474
7290
  const graph = asRecord(parsed);
7475
7291
  const artifacts = Array.isArray(graph?.artifacts) ? graph.artifacts : [];
7476
7292
  for (const item of artifacts) {
@@ -7498,11 +7314,11 @@ function loadHarnessHints(cwd) {
7498
7314
  return hints;
7499
7315
  }
7500
7316
  function localHarnessSummary(cwd) {
7501
- const path = join5(cwd, ".moda", "harness.json");
7502
- if (!existsSync5(path))
7317
+ const path = join4(cwd, ".moda", "harness.json");
7318
+ if (!existsSync4(path))
7503
7319
  return null;
7504
7320
  try {
7505
- const parsed = JSON.parse(readFileSync6(path, "utf8"));
7321
+ const parsed = JSON.parse(readFileSync5(path, "utf8"));
7506
7322
  return {
7507
7323
  harnessId: parsed.harnessId,
7508
7324
  graphHash: parsed.graphHash,
@@ -7513,16 +7329,16 @@ function localHarnessSummary(cwd) {
7513
7329
  }
7514
7330
  }
7515
7331
  function localSyncBrief(cwd, relativePath, label) {
7516
- const path = join5(cwd, relativePath);
7517
- if (!existsSync5(path)) {
7332
+ const path = join4(cwd, relativePath);
7333
+ if (!existsSync4(path)) {
7518
7334
  return { status: "missing", summary: `${label} state not found`, path: relativePath };
7519
7335
  }
7520
7336
  return { status: "present", summary: `${label} state exists locally`, path: relativePath };
7521
7337
  }
7522
7338
  function localSkillBrief(cwd) {
7523
- const claudeSkill = join5(cwd, ".claude", "skills");
7524
- const cursorRules = join5(cwd, ".cursor", "rules");
7525
- if (existsSync5(claudeSkill) || existsSync5(cursorRules)) {
7339
+ const claudeSkill = join4(cwd, ".claude", "skills");
7340
+ const cursorRules = join4(cwd, ".cursor", "rules");
7341
+ if (existsSync4(claudeSkill) || existsSync4(cursorRules)) {
7526
7342
  return { status: "present", summary: "Local agent skill/rule directory exists" };
7527
7343
  }
7528
7344
  return { status: "missing", summary: "No local agent skill/rule directory found" };
@@ -7960,7 +7776,6 @@ var RAW_BOOLEAN_FLAGS = new Set([
7960
7776
  "no-clustering",
7961
7777
  "no-analyze",
7962
7778
  "improve-candidates",
7963
- "hook-stdin",
7964
7779
  "auto-generate",
7965
7780
  "allow-no-agents",
7966
7781
  "allow-any-model",
@@ -8099,8 +7914,6 @@ Commands:
8099
7914
  profiles use <name> Switch active Moda profile
8100
7915
  profiles create <name> Create or update a local Moda profile
8101
7916
  profiles doctor [name] Validate a local Moda profile
8102
- keys list List local key descriptors (not server-side API keys)
8103
- keys create Create a local key descriptor
8104
7917
  config show Show resolved Moda config
8105
7918
  harness analyze Produce a cited structured harness report
8106
7919
  harness pull Fetch a server-side analyze run (status, or result when done)
@@ -9245,7 +9058,7 @@ function normalizeBooleanFlags(target) {
9245
9058
  }
9246
9059
  return error;
9247
9060
  }
9248
- var PROFILE_MANAGING_COMMANDS = new Set(["profiles", "auth", "init", "provision", "status", "config", "keys", "manifest", "agent", "doctor"]);
9061
+ var PROFILE_MANAGING_COMMANDS = new Set(["profiles", "auth", "init", "provision", "status", "config", "manifest", "agent", "doctor"]);
9249
9062
  async function runProblemsRemainder(flags, context) {
9250
9063
  const params = parseCommandFlags(ProblemsRemainderSchema, flagsToArgs(flags), "problems remainder");
9251
9064
  const query2 = new URLSearchParams;
@@ -10492,8 +10305,6 @@ function initArtifactKind(file) {
10492
10305
  return "prompt_manifest";
10493
10306
  if (file.includes("workflow"))
10494
10307
  return "ci_workflow";
10495
- if (file.startsWith("~/"))
10496
- return "agent_hook_config";
10497
10308
  return "init_artifact";
10498
10309
  }
10499
10310
  var dataApiDefaults = {
@@ -10516,7 +10327,7 @@ var commandRegistry = createCommandRegistry([
10516
10327
  resetApiRequestCountBeforeRun: true,
10517
10328
  telemetry: "result",
10518
10329
  handler: async (context) => {
10519
- const { runInit } = await import("./index-f3k9jgrt.js");
10330
+ const { runInit } = await import("./index-jqexf7kn.js");
10520
10331
  if (context.outputMode === "agent-stream") {
10521
10332
  context.output.writeEvent({
10522
10333
  event: "started",
@@ -10557,7 +10368,7 @@ var commandRegistry = createCommandRegistry([
10557
10368
  resetApiRequestCountBeforeRun: true,
10558
10369
  telemetry: "result-and-error",
10559
10370
  handler: async (context) => {
10560
- const { runProvision } = await import("./provision-parsn3xg.js");
10371
+ const { runProvision } = await import("./provision-5pkn25hh.js");
10561
10372
  return runProvision(context, {
10562
10373
  resumeCommand: buildResumeCommand("provision", context.rawFlags)
10563
10374
  });
@@ -10731,18 +10542,6 @@ var commandRegistry = createCommandRegistry([
10731
10542
  telemetry: "none",
10732
10543
  handler: runConfigCommand
10733
10544
  },
10734
- {
10735
- name: "keys",
10736
- description: "Local key descriptors in ~/.moda only (not your server-side API keys; manage those in the dashboard)",
10737
- examples: ["moda keys list", "moda keys create --name=local-dev"],
10738
- auth: "none",
10739
- outputModes: ["human", "json", "agent"],
10740
- mutability: "write",
10741
- validateConfigBeforeRun: false,
10742
- resetApiRequestCountBeforeRun: false,
10743
- telemetry: "none",
10744
- handler: runKeysCommand
10745
- },
10746
10545
  {
10747
10546
  name: "harness",
10748
10547
  description: "Analyze, validate, approve, sync, delete, and explain the local multi-agent harness graph; register it for Replay Environments",
@@ -42,8 +42,8 @@ import {
42
42
  writeHarnessAnalyzeResult,
43
43
  writeHarnessArtifacts,
44
44
  writeHumanProgress
45
- } from "./cli-4af3thx7.js";
46
- import"./cli-mx9r1689.js";
45
+ } from "./cli-v27q5dvh.js";
46
+ import"./cli-0qnghzg4.js";
47
47
  import"./cli-0v6na3yp.js";
48
48
  export {
49
49
  writeHumanProgress,
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  buildSourceSnapshot
3
- } from "./cli-4af3thx7.js";
3
+ } from "./cli-v27q5dvh.js";
4
4
  import {
5
5
  recordApiRequest
6
- } from "./cli-mx9r1689.js";
6
+ } from "./cli-0qnghzg4.js";
7
7
  import"./cli-0v6na3yp.js";
8
8
 
9
9
  // src/harness-github-actions.ts
@@ -3,7 +3,7 @@ import {
3
3
  initPrompts,
4
4
  runPromptSync,
5
5
  runSkillSync
6
- } from "./cli-sjc132j8.js";
6
+ } from "./cli-d3c95kks.js";
7
7
  import"./cli-mm48br00.js";
8
8
  import {
9
9
  canonicalText,
@@ -24,7 +24,7 @@ import {
24
24
  runHarnessCommand,
25
25
  startRemoteAnalyze,
26
26
  stripAnsi
27
- } from "./cli-4af3thx7.js";
27
+ } from "./cli-v27q5dvh.js";
28
28
  import {
29
29
  bundledSkillsDir,
30
30
  installIntegrationSkill,
@@ -36,14 +36,14 @@ import {
36
36
  } from "./cli-ssfq84k5.js";
37
37
  import {
38
38
  selectTenantAndCreateKey
39
- } from "./cli-fhfdnvh4.js";
39
+ } from "./cli-7s48d6ty.js";
40
40
  import {
41
41
  ConnectCodeError,
42
42
  connectWithCode,
43
43
  loadAuthSession,
44
44
  loadToken,
45
45
  login
46
- } from "./cli-tw8jj190.js";
46
+ } from "./cli-4f0p8erk.js";
47
47
  import {
48
48
  CliAuthError,
49
49
  CliInputError,
@@ -52,7 +52,7 @@ import {
52
52
  recordApiRequest,
53
53
  resolveIngestUrl,
54
54
  resolveModaBaseUrl
55
- } from "./cli-mx9r1689.js";
55
+ } from "./cli-0qnghzg4.js";
56
56
  import"./cli-0v6na3yp.js";
57
57
 
58
58
  // src/init/index.ts
@@ -1751,7 +1751,6 @@ async function runInit(flags, options = {}) {
1751
1751
  let setupPlan = [];
1752
1752
  const renderPlan = () => {
1753
1753
  setupPlan = buildSetupPlan({
1754
- installHooks: false,
1755
1754
  integrateSdk,
1756
1755
  configureCiCd,
1757
1756
  configureAutosync,
@@ -1861,7 +1860,7 @@ async function runInit(flags, options = {}) {
1861
1860
  board ??= new InitProgressBoard;
1862
1861
  return board;
1863
1862
  };
1864
- const validationFailure = () => new CliInputError("Moda Analyst produced a harness report that did not pass validation.", "Review .moda/harness-report-validation.json, then rerun `moda init --local --analyst=claude|cursor|codex` or `moda harness analyze --analyst=local-scan --summary`.");
1863
+ const validationFailure = () => new CliInputError("Moda Analyst produced a harness report that did not pass validation.", "Review .moda/harness-report-validation.json, then rerun `moda init --local --analyst=claude|cursor|codex` or `moda harness analyze --analyst=local-scan --summary --experimental`.");
1865
1864
  let harnessPhase = { id: "harness", title: "Harness discovery", status: "completed" };
1866
1865
  let harnessDeferred = false;
1867
1866
  let harnessSkipped = false;
@@ -1891,7 +1890,7 @@ async function runInit(flags, options = {}) {
1891
1890
  } : undefined;
1892
1891
  if (signals && harnessLooksIncomplete(signals)) {
1893
1892
  const names = [...signals.frameworks, ...signals.providers].join(", ");
1894
- const retryCommand = remote ? "moda harness analyze --remote --summary --experimental" : "moda harness analyze --analyst=claude|cursor|codex --summary";
1893
+ const retryCommand = remote ? "moda harness analyze --remote --summary --experimental" : "moda harness analyze --analyst=claude|cursor|codex --summary --experimental";
1895
1894
  warn(renderInitNote(`Harness discovery found 0 runtime agents, but this repo has LLM framework signals (${names}). ` + "Discovery likely failed, so the result was NOT approved or synced.", "warning"));
1896
1895
  warn(` Retry with \`${retryCommand}\`, then \`moda harness approve --yes && moda harness sync --from-report\`.`);
1897
1896
  emit("harness", "Harness discovery found 0 agents despite LLM framework signals; sync withheld.", "warning");
@@ -2012,7 +2011,6 @@ Harness analysis keeps running on Moda. Resume anytime with \`${HARNESS_PULL_REC
2012
2011
  }
2013
2012
  emit("apply", "Applying approved setup changes.");
2014
2013
  const laneBoard = startBoard();
2015
- const ingestCodingAgentTraces = false;
2016
2014
  const agents = detectAgents();
2017
2015
  laneBoard?.startLane("agent-skills", "Agent skills");
2018
2016
  if (agents.length > 0) {
@@ -2093,7 +2091,6 @@ Harness analysis keeps running on Moda. Resume anytime with \`${HARNESS_PULL_REC
2093
2091
  } else {
2094
2092
  markApplied(setupPlan, "sdk", "User skipped SDK integration.");
2095
2093
  }
2096
- markApplied(setupPlan, "hooks", ingestCodingAgentTraces ? undefined : "Coding-agent trace capture is temporarily unavailable.");
2097
2094
  markApplied(setupPlan, "prompts");
2098
2095
  markApplied(setupPlan, "skills");
2099
2096
  if (remote && pollPromise && remoteRunId) {
@@ -2214,16 +2211,7 @@ function buildSetupPlan(options) {
2214
2211
  ".moda/harness.json",
2215
2212
  ".moda/HARNESS.md"
2216
2213
  ],
2217
- command: options.remote ? "moda harness analyze --remote --summary && moda harness approve --yes && moda harness sync --from-report" : "moda harness analyze --analyst=auto --summary && moda harness approve --yes && moda harness sync --from-report"
2218
- },
2219
- {
2220
- category: "hooks",
2221
- title: "Install coding-agent trace hooks",
2222
- status: options.installHooks ? "planned" : "skipped",
2223
- approved: options.installHooks,
2224
- files: ["~/.claude/settings.json", "~/.codex/hooks.json", "~/.cursor/hooks.json"],
2225
- command: "moda hooks install --agent=all",
2226
- reason: options.installHooks ? undefined : "Coding-agent trace capture is temporarily unavailable."
2214
+ command: options.remote ? "moda harness analyze --remote --summary --experimental && moda harness approve --yes && moda harness sync --from-report" : "moda harness analyze --analyst=auto --summary --experimental && moda harness approve --yes && moda harness sync --from-report"
2227
2215
  },
2228
2216
  {
2229
2217
  category: "prompts",
@@ -2274,7 +2262,7 @@ function buildSetupPlan(options) {
2274
2262
  status: options.configureHarnessRescan ? "planned" : "manual",
2275
2263
  approved: options.configureHarnessRescan,
2276
2264
  files: [".github/workflows/moda-harness-rescan.yml"],
2277
- command: "moda harness analyze --remote --yes && moda harness approve --yes && moda harness sync --from-report",
2265
+ command: "moda harness analyze --remote --yes --experimental && moda harness approve --yes && moda harness sync --from-report",
2278
2266
  reason: options.configureHarnessRescan ? undefined : "No harness rescan workflow is written until it is explicitly approved (--harness-rescan)."
2279
2267
  },
2280
2268
  {
@@ -5,8 +5,8 @@ import {
5
5
  inspectCodeSelectors,
6
6
  inspectPythonSelectors,
7
7
  safePromptEvidencePath
8
- } from "./cli-4af3thx7.js";
9
- import"./cli-mx9r1689.js";
8
+ } from "./cli-v27q5dvh.js";
9
+ import"./cli-0qnghzg4.js";
10
10
  import {
11
11
  __commonJS,
12
12
  __toESM
@@ -9258,7 +9258,7 @@ class StdioServerTransport {
9258
9258
  }
9259
9259
 
9260
9260
  // src/prompt-analyst-tools.ts
9261
- import { relative, resolve } from "node:path";
9261
+ import { resolve } from "node:path";
9262
9262
  function safeRoot(rootDir) {
9263
9263
  const root = resolve(rootDir);
9264
9264
  return root;
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  selectTenantAndCreateKey
3
- } from "./cli-fhfdnvh4.js";
3
+ } from "./cli-7s48d6ty.js";
4
4
  import {
5
5
  loadAuthSession
6
- } from "./cli-tw8jj190.js";
6
+ } from "./cli-4f0p8erk.js";
7
7
  import {
8
8
  CliAuthError,
9
9
  resolveIngestUrl,
10
10
  resolveModaBaseUrl,
11
11
  stringOption
12
- } from "./cli-mx9r1689.js";
12
+ } from "./cli-0qnghzg4.js";
13
13
  import"./cli-0v6na3yp.js";
14
14
 
15
15
  // src/provision.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moda-ai/cli",
3
- "version": "1.55.9",
3
+ "version": "1.55.10",
4
4
  "description": "CLI for Moda: production monitoring and evals for AI agents.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,7 +19,6 @@
19
19
  "dist/**/*.js",
20
20
  "dist/**/*.d.ts",
21
21
  "!dist/__tests__",
22
- "hooks/**",
23
22
  "skills/**",
24
23
  "README.md"
25
24
  ],
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schema_version": "moda.skill_index.v1",
3
- "bundled_at": "2026-10-15T02:17:23.557Z",
4
- "cli_version": "1.55.9",
3
+ "bundled_at": "2026-10-15T04:43:16.280Z",
4
+ "cli_version": "1.55.10",
5
5
  "skills": [
6
6
  {
7
7
  "id": "integration-cloudflare-think",
@@ -1291,8 +1291,8 @@ moda feedback "trace is a refund request, not this problem" \
1291
1291
  you saw.
1292
1292
  - Feedback does not change the problem itself. To act on a misroute directly,
1293
1293
  use `moda problem-feedback <problem_id> --action=flag_attribution
1294
- --attribution-id=<uuid> --reason=TEXT`, `moda false-positive <kind> <target>
1295
- --reason=TEXT`, or `moda fix dismiss <fix_id> --reason=TEXT`.
1294
+ --attribution-id=<uuid> --reason=TEXT` or `moda false-positive <kind> <target>
1295
+ --reason=TEXT`.
1296
1296
  - Never include secrets or full transcripts in the note.
1297
1297
 
1298
1298
  ## Validation — how to know it worked
@@ -1,41 +0,0 @@
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