@moda-ai/cli 1.55.94 → 1.55.95

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/README.md +23 -0
  2. package/dist/{agent-pncdccck.js → agent-wa8tx02f.js} +6 -5
  3. package/dist/{change-impact-2hqk7kj0.js → change-impact-3n23nhd8.js} +3 -3
  4. package/dist/{cli-5c37h7n5.js → cli-1sdz17sn.js} +40 -16
  5. package/dist/{cli-dk08ywkn.js → cli-764m5azg.js} +2 -1031
  6. package/dist/cli-92zfpz9f.js +1037 -0
  7. package/dist/{cli-gdm94hh4.js → cli-abfcqf4p.js} +2 -2
  8. package/dist/{index-61yya1cm.js → cli-f1sx9dsa.js} +3 -21
  9. package/dist/cli-gcqpbes6.js +1660 -0
  10. package/dist/cli.js +31 -17
  11. package/dist/{doctor-kxk2j3j2.js → doctor-ec2cqgnv.js} +5 -4
  12. package/dist/{harness-github-actions-75z9c68t.js → harness-github-actions-h9b973z0.js} +3 -3
  13. package/dist/{harness-wnye9acm.js → harness-jka07f99.js} +3 -3
  14. package/dist/{index-09t1rsf2.js → index-0na4ydkc.js} +3 -3
  15. package/dist/{index-e0b4bd74.js → index-w2hs49tb.js} +12 -11
  16. package/dist/index-zp7y6mft.js +31 -0
  17. package/dist/{production-intelligence-1y884f69.js → production-intelligence-3fdpsxce.js} +2 -2
  18. package/dist/{prompt-attribution-6zeqqqfy.js → prompt-attribution-armk5gqt.js} +3 -3
  19. package/dist/prompt-source-mcp.js +3 -3
  20. package/dist/{prompts-9ngt4wyh.js → prompts-x3vdeax6.js} +4 -3
  21. package/dist/{skills-hf8fa7w7.js → skills-1pv2mp9v.js} +3 -3
  22. package/dist/{sync-zsyy15p9.js → sync-4zeyb408.js} +8 -7
  23. package/package.json +1 -1
  24. package/skills/integration/index.json +2 -2
  25. package/dist/{cli-wm0p9kn2.js → cli-9kxz65fe.js} +3 -3
  26. package/dist/{cli-t8vmcbe0.js → cli-f0z97a7t.js} +3 -3
package/README.md CHANGED
@@ -77,6 +77,29 @@ moda harness candidates --path=. --promote=all --out=harness-components.json --y
77
77
 
78
78
  Every enumerated component includes a source citation and `reachable` or `defined_only` status. Production trace evidence can later promote it to `in_prod`. Dynamic MCP allow-all servers are one group; extraction does not connect to those servers. The repository-bound `createAgentScopeResolver(result, ctx)` callback maps `CallSite.enclosing` to emitted agent IDs, including inherited hooks and shared helpers; ambiguous or unknown scopes return `[]`.
79
79
 
80
+ ### Component skeleton and diff
81
+
82
+ ```bash
83
+ moda harness skeleton --path=. --out=/tmp/skeleton.json --json
84
+ moda harness skeleton-diff /tmp/before.json /tmp/after.json --json
85
+ moda harness skeleton-diff --from=/tmp/before.json --to=/tmp/after.json --json
86
+ ```
87
+
88
+ `skeleton` produces `harness-skeleton/v1`, a component map of the harness: a `HarnessGraph` (agents, artifacts and relationships in the usual places, so sync and Ask read it unchanged) plus `skeleton.callSites`, counts, commit, content hash, coverage and a control-flow slot. It runs locally without an LLM or network calls and holds locations and owners, never bodies.
89
+
90
+ - Prompts: a named builder, template or prompt file a model call reaches is one unit, shared by every call that reaches it. Text assembled in the calling function is a `call` unit for that function, with the pieces as `members`. Constants inside a builder are not listed separately.
91
+ - Ids are stable across commits: they hold no line numbers, except the extractor's anonymous `path#L<line>` scopes. Repeated keys get `~2`, `~3` in source order.
92
+ - `liveKey` is the key traces and the traced registry match on, normalised like the backend's trace status: agent class name, model-facing tool name, model id, skill name. Prompts and call sites have none.
93
+ - Map edges live in `skeleton.edges`, a compact table; decode them with `decodeSkeletonEdges(graph.skeleton.edges)` into `{ id: "<type>:<from>-><to>", type, from, to, source, evidence }`. Types: `triggers` (entry point to agent), `invokes_subagent` and `hands_off_to` (agent to agent), `uses_artifact` (agent to prompt, tool or model), `implemented_by` (tool to `code:<path>#<handler>`), `has_control_flow` and `guards` (agent to control-flow item to call site), and `covered_by_eval` (agent or tool to eval suite). `source` is `code` for every extracted edge; consumers merge edges seen in traces as `trace`. `relationships` keeps only the agent-to-agent edges in the usual graph form, so sync and Ask read them unchanged.
94
+ - `skeleton.coverage` says per component type whether detection is `complete` or `partial`, with `skeleton.knownGaps`. Claim completeness only for `complete` types.
95
+ - Entry points: workflows and crons, exported route handlers of route agents (`trigger: "http_route"`) and Durable Object bindings (`trigger: "do_binding"`) of agent classes or of classes that construct one. Each lists the agents it starts in their `entrypointIds` (`triggers` edges); a workflow starts the function agents and sub-agent calls its code reaches.
96
+ - Tools are attributed to agents whose own model calls receive tools. A call that picks its model from a table at runtime has `modelSource: "factory (computed)"` and the table in `modelCandidates`; those candidates are not the call's or the agent's models, and each agent lists such calls in `modelChoices` (call site, location and candidates). A Workers eval suite that drives the deployed Worker covers the agents bound in its default Wrangler config.
97
+ - `covered_by_eval` is a static association (what the suite's own files import, through re-export barrels, and its own model calls), not execution or assertion coverage.
98
+
99
+ The JSON envelope's `data` is the skeleton; `--out` writes the bare skeleton. Incomplete scans return exit code 3 with warnings. `skeleton-diff` accepts either form, lists added, removed, moved and changed components and edges, ignores line-only shifts, and pairs unique same-name components across file renames as `moved`. Its `identical` flag compares content hashes. `harness extract` output is unchanged.
100
+
101
+ Library exports (`src/harness-extract/skeleton/index.ts`): `buildHarnessSkeleton(rootDir, options?)`, `skeletonFromExtract(result, ctx)`, `diffHarnessSkeletons(before, after)` and `registerControlFlowDetector(detector)`. A detector receives `{result, ctx, callSites, agents, callSiteIdOf}` and returns control-flow items; items naming unknown call sites or agents are dropped, a throwing detector leaves `controlFlowStatus: "failed"` with a warning, and without a detector the status is `not_run`.
102
+
80
103
  ## Usage
81
104
 
82
105
  Find things by meaning, then drill in:
@@ -1,9 +1,10 @@
1
1
  import {
2
2
  buildDoctorReport
3
- } from "./cli-gdm94hh4.js";
3
+ } from "./cli-abfcqf4p.js";
4
4
  import"./cli-qwnkv4jy.js";
5
- import"./cli-dk08ywkn.js";
5
+ import"./cli-92zfpz9f.js";
6
6
  import"./cli-mm48br00.js";
7
+ import"./cli-764m5azg.js";
7
8
  import {
8
9
  readHarnessSyncState
9
10
  } from "./cli-k0vxtzxb.js";
@@ -15,10 +16,10 @@ import {
15
16
  readHarnessReport,
16
17
  validateHarnessReport
17
18
  } from "./cli-krm4w2v9.js";
18
- import"./cli-6ga6kmdp.js";
19
- import"./cli-dxajrq9h.js";
20
19
  import"./cli-13zdcv4w.js";
20
+ import"./cli-6ga6kmdp.js";
21
21
  import"./cli-e0kbye4s.js";
22
+ import"./cli-dxajrq9h.js";
22
23
  import {
23
24
  resolveApiKey,
24
25
  resolveIngestUrl,
@@ -95,7 +96,7 @@ async function buildAgentContext(context) {
95
96
  const graph = readHarnessGraphIfPresent(context.cwd);
96
97
  const reportState = readHarnessReportState(context.cwd);
97
98
  const syncState = readHarnessSyncState(context.cwd);
98
- const harness = graph ? await import("./harness-wnye9acm.js") : undefined;
99
+ const harness = graph ? await import("./harness-jka07f99.js") : undefined;
99
100
  const topFindings = doctor.checks.filter((check) => check.status === "fail" || check.status === "warning").slice(0, 12).map(checkToFinding);
100
101
  const evidenceRefs = [
101
102
  ...doctor.checks.map(checkToEvidenceRef),
@@ -11,16 +11,16 @@ import {
11
11
  resolvedSymbol,
12
12
  returnExpressions,
13
13
  valueDeclaration
14
- } from "./cli-5c37h7n5.js";
14
+ } from "./cli-1sdz17sn.js";
15
15
  import"./cli-k0vxtzxb.js";
16
16
  import"./cli-97fnztpy.js";
17
17
  import {
18
18
  detectBoundRuntimeClasses
19
19
  } from "./cli-krm4w2v9.js";
20
- import"./cli-6ga6kmdp.js";
21
- import"./cli-dxajrq9h.js";
22
20
  import"./cli-13zdcv4w.js";
21
+ import"./cli-6ga6kmdp.js";
23
22
  import"./cli-e0kbye4s.js";
23
+ import"./cli-dxajrq9h.js";
24
24
  import"./cli-1nd4339b.js";
25
25
  import"./cli-k4tqwah4.js";
26
26
  import {
@@ -36,6 +36,10 @@ import {
36
36
  validateHarnessReport,
37
37
  writeHarnessReportArtifacts
38
38
  } from "./cli-krm4w2v9.js";
39
+ import {
40
+ createCommandContext,
41
+ stringOption
42
+ } from "./cli-13zdcv4w.js";
39
43
  import {
40
44
  assertFlags,
41
45
  assertPositionals,
@@ -45,10 +49,6 @@ import {
45
49
  ApiError,
46
50
  callControlAPI
47
51
  } from "./cli-dxajrq9h.js";
48
- import {
49
- createCommandContext,
50
- stringOption
51
- } from "./cli-13zdcv4w.js";
52
52
  import {
53
53
  EXIT_DEGRADED,
54
54
  embeddedTenantIdFromApiKey,
@@ -19420,8 +19420,19 @@ class PromptResolver {
19420
19420
  this.maxParamLevels = options.maxParamLevels ?? DEFAULT_MAX_PARAM_LEVELS;
19421
19421
  this.keepAll = options.keepAll === true;
19422
19422
  this.views = Object.entries(options.views ?? {}).map(([name, admits]) => ({ name, admits, refs: new Map }));
19423
+ if (options.viewOf) {
19424
+ const byName = new Map(this.views.map((view) => [view.name, view]));
19425
+ const viewOf = options.viewOf;
19426
+ this.viewFor = (site) => {
19427
+ const view = byName.get(viewOf(site) ?? "");
19428
+ return view && view.admits(site) ? [view] : [];
19429
+ };
19430
+ }
19423
19431
  }
19432
+ viewFor;
19424
19433
  refMaps(walk) {
19434
+ if (this.viewFor)
19435
+ return [this.refs, ...this.viewFor(walk.site).map((view) => view.refs)];
19425
19436
  return this.views.length ? [this.refs, ...this.views.filter((view) => view.admits(walk.site)).map((view) => view.refs)] : [this.refs];
19426
19437
  }
19427
19438
  resolveArgument(site, role, node, project = []) {
@@ -20522,7 +20533,16 @@ class PromptResolver {
20522
20533
  }
20523
20534
  return;
20524
20535
  }
20536
+ declarationsByNode = new WeakMap;
20525
20537
  declarationsOf(node) {
20538
+ const cached = this.declarationsByNode.get(node);
20539
+ if (cached)
20540
+ return cached;
20541
+ const declarations = this.lookupDeclarations(node);
20542
+ this.declarationsByNode.set(node, declarations);
20543
+ return declarations;
20544
+ }
20545
+ lookupDeclarations(node) {
20526
20546
  const path = this.relative(node.getSourceFile().fileName);
20527
20547
  const checker = this.context.checkerFor(path);
20528
20548
  if (!checker)
@@ -20989,6 +21009,10 @@ async function runHarnessCommand(context) {
20989
21009
  if (context.dryRun && !HARNESS_DRY_RUN_SUBCOMMANDS.has(subcommand)) {
20990
21010
  throw new CliInputError(`'moda harness ${subcommand}' has no dry-run mode, so nothing was sent.`, `Remove --dry-run to run it for real. Harness commands with a real dry-run: ${[...HARNESS_DRY_RUN_SUBCOMMANDS].join(", ")}.`);
20991
21011
  }
21012
+ if (subcommand === "skeleton" || subcommand === "skeleton-diff") {
21013
+ const { runSkeletonCommand } = await import("./cli-gcqpbes6.js");
21014
+ return runSkeletonCommand(context);
21015
+ }
20992
21016
  if (subcommand === "register")
20993
21017
  return runHarnessRegister(context);
20994
21018
  if (subcommand === "registration")
@@ -20998,7 +21022,7 @@ async function runHarnessCommand(context) {
20998
21022
  assertPositionals("harness impact", context.positionals, 1, "moda harness impact --from=<commit> --to=<commit>");
20999
21023
  if (!context.flags.from)
21000
21024
  throw new CliInputError("harness impact requires --from=<old-commit>.");
21001
- const { localChangeImpact, readRecordedImpactCalls } = await import("./change-impact-2hqk7kj0.js");
21025
+ const { localChangeImpact, readRecordedImpactCalls } = await import("./change-impact-3n23nhd8.js");
21002
21026
  const result = localChangeImpact({
21003
21027
  checkout: resolve10(context.cwd, context.flags.path ?? "."),
21004
21028
  from: context.flags.from,
@@ -21270,7 +21294,7 @@ async function runHarnessCommand(context) {
21270
21294
  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.");
21271
21295
  }
21272
21296
  if (context.flags["github-actions"] === "true") {
21273
- const { runGithubActionsAnalyze } = await import("./harness-github-actions-75z9c68t.js");
21297
+ const { runGithubActionsAnalyze } = await import("./harness-github-actions-h9b973z0.js");
21274
21298
  const result = await runGithubActionsAnalyze(rootDir, {
21275
21299
  writeReport: (report2) => {
21276
21300
  const normalized = normalizeHarnessReport(report2);
@@ -21421,8 +21445,8 @@ async function runHarnessCommand(context) {
21421
21445
  }
21422
21446
  const { artifacts, unknowns, canonicalAgentIdentities } = deterministicGraphItems(rootDir, promote === "all" ? undefined : promote);
21423
21447
  tagComponentStatus({ runtimeAgents: [], artifacts }, rootDir);
21424
- const { extractHarnessWithContext: extractHarnessWithContext2 } = await import("./index-09t1rsf2.js");
21425
- const { enumerateHarnessComponents, mergeEnumeratedComponents } = await import("./index-61yya1cm.js");
21448
+ const { extractHarnessWithContext: extractHarnessWithContext2 } = await import("./index-0na4ydkc.js");
21449
+ const { enumerateHarnessComponents, mergeEnumeratedComponents } = await import("./index-zp7y6mft.js");
21426
21450
  let components = { runtimeAgents: [], artifacts: [], warnings: [] };
21427
21451
  if (promote === "all" || promote === "topology" || promote === "tools") {
21428
21452
  const { result, ctx } = extractHarnessWithContext2(rootDir);
@@ -21494,8 +21518,8 @@ async function runHarnessCommand(context) {
21494
21518
  }
21495
21519
  case "extract": {
21496
21520
  writeHumanProgress(context, "Harness extract: tracing model call sites (no LLM, no network)...");
21497
- const { extractHarnessWithContext: extractHarnessWithContext2, serializeExtractResult } = await import("./index-09t1rsf2.js");
21498
- const { enumerateHarnessComponents, mergeEnumeratedComponents } = await import("./index-61yya1cm.js");
21521
+ const { extractHarnessWithContext: extractHarnessWithContext2, serializeExtractResult } = await import("./index-0na4ydkc.js");
21522
+ const { enumerateHarnessComponents, mergeEnumeratedComponents } = await import("./index-zp7y6mft.js");
21499
21523
  const { result, ctx } = extractHarnessWithContext2(rootDir, { fresh: true });
21500
21524
  const items = deterministicGraphItems(rootDir);
21501
21525
  const artifacts = items.artifacts;
@@ -21629,7 +21653,7 @@ async function runHarnessCommand(context) {
21629
21653
  return { exitCode: 0 };
21630
21654
  }
21631
21655
  default:
21632
- throw new CliInputError(`Unknown harness command '${subcommand}'.`, "Usage: moda harness analyze|pull|validate-report|approve|scan|candidates|extract|sync|delete|list|show|versions|diff|agents|graph|explain|write-summary|status|register|registration");
21656
+ throw new CliInputError(`Unknown harness command '${subcommand}'.`, "Usage: moda harness analyze|pull|validate-report|approve|scan|candidates|extract|skeleton|skeleton-diff|sync|delete|list|show|versions|diff|agents|graph|explain|write-summary|status|register|registration");
21633
21657
  }
21634
21658
  }
21635
21659
  function writeHarnessAnalyzeResult(context, payload) {
@@ -22402,8 +22426,8 @@ var CONCERN_PROMOTED_ARTIFACT_TYPES = {
22402
22426
  evals: new Set(["model_config", "eval"])
22403
22427
  };
22404
22428
  async function deterministicFloorGraph(rootDir, options = {}) {
22405
- const { extractHarnessWithContext: extractHarnessWithContext2 } = await import("./index-09t1rsf2.js");
22406
- const { enumerateHarnessComponents, mergeEnumeratedComponents } = await import("./index-61yya1cm.js");
22429
+ const { extractHarnessWithContext: extractHarnessWithContext2 } = await import("./index-0na4ydkc.js");
22430
+ const { enumerateHarnessComponents, mergeEnumeratedComponents } = await import("./index-zp7y6mft.js");
22407
22431
  const { result, ctx } = extractHarnessWithContext2(rootDir);
22408
22432
  const items = deterministicGraphItems(rootDir);
22409
22433
  const components = mergeEnumeratedComponents(items.artifacts, enumerateHarnessComponents(result, ctx));
@@ -28831,7 +28855,7 @@ function normalizedModels(ctx, roles = []) {
28831
28855
  }
28832
28856
  return { rewritten: out, outputs: served, spans };
28833
28857
  }
28834
- function collectModels(result, ctx) {
28858
+ function collectModels(result, ctx, options = {}) {
28835
28859
  const byId = new Map;
28836
28860
  const add = (id, resolution, at, site) => {
28837
28861
  let entry = byId.get(id);
@@ -28955,7 +28979,7 @@ function collectModels(result, ctx) {
28955
28979
  resolution: entry.resolution,
28956
28980
  definition: definitions[0],
28957
28981
  ...definitions.length > 1 ? { otherDefinitions: definitions.slice(1, 8) } : {},
28958
- calledFrom: sites.slice(0, MAX_CALLED_FROM).map((site) => ({
28982
+ calledFrom: sites.slice(0, options.maxCalledFrom ?? MAX_CALLED_FROM).map((site) => ({
28959
28983
  callSite: site.id,
28960
28984
  path: site.path,
28961
28985
  line: site.line,
@@ -30991,4 +31015,4 @@ function assignAgentIds(result, agentForScope) {
30991
31015
  }
30992
31016
  }
30993
31017
 
30994
- export { relPath, unwrap, calleeChain, enclosingClass, returnExpressions, importOrigin, resolvedSymbol, valueDeclaration, isTestPath, isEvalPath, EXTRACT_SCHEMA_VERSION, valueChildren, selectKey, allValues, renderings, receiverClasses, frameworkBaseOf, createFrameworkMemo, CALL_SINKS, registerCallSink, registerClassSink, checkPromptMapping, safePromptEvidencePath, discoverHarnessPromptSources, isModelId, collectModels, modelArtifacts, modelUnknowns, collectModelLiterals, TEST_PATH2 as TEST_PATH, EVAL_PATH2 as EVAL_PATH, enumerationRepository, nameOf, visit, componentId, artifact, emptyResult, stableResult, toolNamesOf, surfaceOf, emitToolsCached, workspacePackages, toolArtifacts, clearExtractCache, extractHarness, extractHarnessWithContext, extractFingerprint, scopeOf, serializeExtractResult, assignAgentIds, createAgentScopeResolver, enumerateAgents, startRemoteAnalyze, pollRemoteAnalyzeUntilDone, isRecoverableRemoteRun, resolvePromptArguments, runHarnessCommand, writeHarnessAnalyzeResult, emitWrittenArtifacts, analyzeHarnessPrompts, isToolGroupPlaceholder, deterministicOnlyArtifactTypes, repairExternalAnalystReport, deriveRelationshipsFromGraph, deterministicFloorGraph, deterministicArtifacts, deterministicGraphItems, mergeDeterministicArtifacts, analystRefutations, describeCodingAgentEvent, analystEventProgress, isRetryableExternalAnalystFailure, sleep, summarizeInvalidAnalystReport, isDeterministicLocalAnalyst, resolveHarnessAnalyzeConcern, resolveExternalHarnessAnalystInvocation, detectAvailableCodingAgents, codingAgentDisplayName, runCodingAgent, readOnlyClaudeExtraArgs, resolveAnalystModel, renderExternalHarnessAnalystPrompt, CONCERN_CANDIDATE_KINDS, SEED_CANDIDATE_KIND_LABELS, renderAnalystCandidateLines, renderAnalystSeedLines, truncateText, scanHarness, summarizeHarness, buildSourceSnapshot, writeHumanProgress, describeSyncIdentity, describeSyncTenantLabel, findFresherHarnessReports, writeHarnessArtifacts, assertHarnessGraphSyncQuality, graphForSync, inventoryFiles, numericEnv, numericEnvAllowZero, computeDeterministicFloor, stableId, titleFromId, promptNameFromPath };
31018
+ export { svelteVirtualName, relPath, lineOf, unwrap, propertyNameText, calleeChain, isFunctionLike, enclosingFunction, functionName, enclosingClass, returnExpressions, importOrigin, resolvedSymbol, valueDeclaration, isTestPath, isEvalPath, EXTRACT_SCHEMA_VERSION, valueChildren, selectKey, allValues, renderings, receiverClasses, frameworkBaseOf, createFrameworkMemo, CALL_SINKS, registerCallSink, registerClassSink, evalFileSignal, evalSuiteKey, checkPromptMapping, safePromptEvidencePath, discoverHarnessPromptSources, isModelId, collectModels, modelArtifacts, modelUnknowns, collectModelLiterals, parse, TEST_PATH2 as TEST_PATH, EVAL_PATH2 as EVAL_PATH, enumerationRepository, nameOf, visit, componentId, artifact, emptyResult, stableResult, toolNamesOf, surfaceOf, emitToolsCached, workspacePackages, toolArtifacts, clearExtractCache, extractHarness, extractHarnessWithContext, extractFingerprint, scopeOf, serializeExtractResult, assignAgentIds, createAgentScopeResolver, enumerateAgents, startRemoteAnalyze, pollRemoteAnalyzeUntilDone, isRecoverableRemoteRun, resolvePromptArguments, runHarnessCommand, writeHarnessAnalyzeResult, emitWrittenArtifacts, analyzeHarnessPrompts, isToolGroupPlaceholder, deterministicOnlyArtifactTypes, repairExternalAnalystReport, deriveRelationshipsFromGraph, deterministicFloorGraph, deterministicArtifacts, deterministicGraphItems, mergeDeterministicArtifacts, analystRefutations, describeCodingAgentEvent, analystEventProgress, isRetryableExternalAnalystFailure, sleep, summarizeInvalidAnalystReport, isDeterministicLocalAnalyst, resolveHarnessAnalyzeConcern, resolveExternalHarnessAnalystInvocation, detectAvailableCodingAgents, codingAgentDisplayName, runCodingAgent, readOnlyClaudeExtraArgs, resolveAnalystModel, renderExternalHarnessAnalystPrompt, CONCERN_CANDIDATE_KINDS, SEED_CANDIDATE_KIND_LABELS, renderAnalystCandidateLines, renderAnalystSeedLines, truncateText, scanHarness, summarizeHarness, buildSourceSnapshot, writeHumanProgress, describeSyncIdentity, describeSyncTenantLabel, findFresherHarnessReports, writeHarnessArtifacts, assertHarnessGraphSyncQuality, graphForSync, inventoryFiles, numericEnv, numericEnvAllowZero, computeDeterministicFloor, stableId, titleFromId, promptNameFromPath };