@jentrix/cli 0.5.21 → 0.5.23

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/dist/main.js CHANGED
@@ -20966,7 +20966,7 @@ function refreshAccessToken(input) {
20966
20966
 
20967
20967
  // src/client.ts
20968
20968
  var CLI_NAME = "stacks-cli";
20969
- var CLI_VERSION = "0.5.21";
20969
+ var CLI_VERSION = "0.5.23";
20970
20970
  var DEAD_TOKEN_MESSAGE = "authentication failed (HTTP 401): the token is dead or expired \u2014 mint a new PAT at /account/tokens on your Jentrix server and update STACKS_TOKEN (or --token / the config file).";
20971
20971
  var RELOGIN_MESSAGE = "OAuth session expired and could not be refreshed \u2014 run `jentrix login` to sign in again.";
20972
20972
  function originOf2(url2) {
@@ -21386,7 +21386,10 @@ function buildAlignDisclosures(catalog) {
21386
21386
  catalog.liveHostPid !== null ? `keep the live session host (pid ${catalog.liveHostPid}) running` : "start a detached session host (heartbeats + provider usage receipts)"
21387
21387
  );
21388
21388
  disclosures.push(
21389
- catalog.captureMode === "on" ? "TRACE capture: ON \u2014 the full transcript will be recorded" : "TRACE capture: OFF (MVP default) \u2014 typed artifacts only, no transcript"
21389
+ catalog.captureMode === "on" ? "TRACE capture: ON \u2014 the full transcript will be recorded" : catalog.captureMode === "off" ? "TRACE capture: OFF \u2014 typed artifacts only, no transcript" : "TRACE capture: your account default (Account \u2192 Capture; the built-in is OFF \u2014 typed artifacts only). The confirmed value is printed after the align; --capture/--no-capture decides it here instead"
21390
+ );
21391
+ disclosures.push(
21392
+ catalog.skeletonMode === "on" ? "activity skeleton: ON \u2014 content-free counts/timing (turns, tool names, files-touched), independent of capture; --no-skeleton opts out" : catalog.skeletonMode === "off" ? "activity skeleton: OFF \u2014 no counts, no timing, no files-touched; the session's Session activity section will read as not observed" : "activity skeleton: your account default (Account \u2192 Capture; the built-in is ON \u2014 content-free counts/timing). The confirmed value is printed after the align; --skeleton/--no-skeleton decides it here instead"
21390
21393
  );
21391
21394
  disclosures.push("write the local alignment marker for this checkout");
21392
21395
  const mcp = catalog.mcpConfig;
@@ -22004,6 +22007,10 @@ function upsertAlignmentMarker(file, providerSessionId, marker) {
22004
22007
  sessions[providerSessionId] = marker;
22005
22008
  return { version: 2, sessions, latest: providerSessionId };
22006
22009
  }
22010
+ function findAlignmentMarkerForSession(file, sessionId) {
22011
+ if (!file) return null;
22012
+ return Object.values(file.sessions).find((m) => m.sessionId === sessionId) ?? null;
22013
+ }
22007
22014
  function removeAlignmentMarkerEntry(file, sessionId) {
22008
22015
  if (!file) return null;
22009
22016
  const sessions = Object.fromEntries(
@@ -22450,20 +22457,39 @@ function readLiveHostMarker(deps2, sessionId) {
22450
22457
  return null;
22451
22458
  }
22452
22459
  }
22453
- async function waitForHostExit(deps2, sessionId, pid, timeoutMs) {
22460
+ async function waitForHostEnd(deps2, sessionId, pid, timeoutMs) {
22454
22461
  const sleep = deps2.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
22455
- const path = join2(deps2.spoolRoot, sessionId, "host.json");
22462
+ const dir = join2(deps2.spoolRoot, sessionId);
22463
+ const path = join2(dir, "host.json");
22456
22464
  const deadline = Date.now() + timeoutMs;
22457
22465
  while (Date.now() < deadline) {
22458
22466
  await sleep(500);
22467
+ const refusal = readEndRefusal(deps2, sessionId);
22468
+ if (refusal) return { kind: "refused", message: refusal };
22459
22469
  try {
22460
22470
  const marker = JSON.parse(readFileSync2(path, "utf8"));
22461
- if (marker.exitedAt) return true;
22471
+ if (marker.exitedAt) return { kind: "exited" };
22462
22472
  } catch {
22463
22473
  }
22464
- if (!(deps2.isPidAlive ?? defaultIsPidAlive)(pid)) return false;
22474
+ if (!(deps2.isPidAlive ?? defaultIsPidAlive)(pid)) return { kind: "gone" };
22475
+ }
22476
+ return { kind: "gone" };
22477
+ }
22478
+ function readEndRefusal(deps2, sessionId) {
22479
+ try {
22480
+ const marker = JSON.parse(
22481
+ readFileSync2(join2(deps2.spoolRoot, sessionId, "end-refusal.json"), "utf8")
22482
+ );
22483
+ return typeof marker.message === "string" && marker.message.trim() ? marker.message : null;
22484
+ } catch {
22485
+ return null;
22486
+ }
22487
+ }
22488
+ function clearEndRefusal(deps2, sessionId) {
22489
+ try {
22490
+ unlinkSync(join2(deps2.spoolRoot, sessionId, "end-refusal.json"));
22491
+ } catch {
22465
22492
  }
22466
- return false;
22467
22493
  }
22468
22494
  function localCaptureLines(deps2, sessionId, serverStatus) {
22469
22495
  const dir = join2(deps2.spoolRoot, sessionId);
@@ -23013,6 +23039,13 @@ async function runSessionStatus(sessionId, flags, deps2) {
23013
23039
  const deadLocal = open && boundHere && !hasLocalCaptureFootprint(deps2, sessionId);
23014
23040
  const captureOff = session.alignment?.capture === "off";
23015
23041
  const capture = captureOff ? "off (MVP alignment \u2014 typed artifacts only)" : session.captureComplete ? "complete" : deadLocal ? "bound server-side; local capture NOT RUNNING" : open ? "recording (finalizes when the session ends)" : `INCOMPLETE${session.captureError ? ` \u2014 ${String(session.captureError)}` : ""}`;
23042
+ const inspection = await inspectRepository(deps2.cwd(), deps2.git);
23043
+ const alignMarker = inspection ? findAlignmentMarkerForSession(
23044
+ readAlignmentMarkerFile(deps2.configPath, inspection.root),
23045
+ sessionId
23046
+ ) : null;
23047
+ const captureProvenance = alignMarker?.captureSource ? ` \xB7 resolved from ${alignMarker.captureSource}` : "";
23048
+ const skeletonProvenance = alignMarker?.skeletonSource ? ` \xB7 resolved from ${alignMarker.skeletonSource}` : "";
23016
23049
  const local = deadLocal ? [
23017
23050
  "Local capture: NOT RUNNING \u2014 this machine bound the session but no capture host ever started here (no host marker, no spool parts).",
23018
23051
  ` Fix: \`jentrix session end ${sessionId}\` closes it honestly (the capture gap is recorded), or reattach with a transcript path to start capture.`
@@ -23028,9 +23061,9 @@ async function runSessionStatus(sessionId, flags, deps2) {
23028
23061
  `Session ${String(session.id)} \xB7 ${String(session.provider)} \xB7 ${String(session.status)}`,
23029
23062
  `Project: ${String(session.projectName)} (${String(session.projectId)})`,
23030
23063
  `Repository: ${String(session.repoOwnerName)}`,
23031
- `Capture: ${capture}`,
23064
+ `Capture: ${capture}${captureProvenance}`,
23032
23065
  // Evidence floor (D3): the skeleton mode the alignment declared.
23033
- `Skeleton: ${session.alignment?.skeleton === "off" ? "off (--no-skeleton at align)" : "on (content-free activity counts/timing)"}`,
23066
+ `Skeleton: ${session.alignment?.skeleton === "off" ? "off (no activity counts, no timing, no files-touched)" : "on (content-free activity counts/timing)"}${skeletonProvenance}`,
23034
23067
  ...local,
23035
23068
  telemetry.line,
23036
23069
  `Summary artifact: ${session.summaryArtifactId ? String(session.summaryArtifactId) : "\u2014"}`
@@ -23163,14 +23196,12 @@ async function buildAttestedDiffBody(git, root, startHead, endHead, dirty) {
23163
23196
  }
23164
23197
  body = notice + kept;
23165
23198
  }
23199
+ let uncommitted = null;
23166
23200
  if (dirty) {
23167
23201
  const delta = await git(["diff", "--stat", "HEAD"], root);
23168
- body += `
23169
-
23170
- Uncommitted delta at end (stat only \u2014 not part of the attested range):
23171
- ${delta.code === 0 && delta.stdout.trim() ? delta.stdout : "(unreadable or empty)"}`;
23202
+ uncommitted = delta.code === 0 && delta.stdout.trim() ? delta.stdout.trim() : null;
23172
23203
  }
23173
- return { body: header + body, commitCount };
23204
+ return { body: header + body, commitCount, uncommitted };
23174
23205
  }
23175
23206
  async function postAttestedArtifact(deps2, sessionId, input) {
23176
23207
  const credentials = deps2.resolveTarget();
@@ -23298,6 +23329,12 @@ async function runSessionEnd(sessionIdFlag, flags, deps2) {
23298
23329
  deps2.writeOut(
23299
23330
  `Attested diff pushed \u2192 artifact ${pushed.artifactId ?? "(unknown)"} (${built.commitCount} commit(s), source: cli)`
23300
23331
  );
23332
+ if (built.uncommitted) {
23333
+ deps2.writeOut(
23334
+ `note: uncommitted delta at end (stat only \u2014 not part of the attested range):
23335
+ ${built.uncommitted}`
23336
+ );
23337
+ }
23301
23338
  } else {
23302
23339
  deps2.writeErr(
23303
23340
  `note: attested diff push failed (${pushed.detail}) \u2014 the E1 delivery check will refuse the close; retry \`jentrix session end\`, or acknowledge with --acknowledge-evidence-gaps.`
@@ -23320,21 +23357,32 @@ async function runSessionEnd(sessionIdFlag, flags, deps2) {
23320
23357
  };
23321
23358
  const live = readLiveHostMarker(deps2, sessionId);
23322
23359
  if (live) {
23360
+ clearEndRefusal(deps2, sessionId);
23323
23361
  writeFileSync2(
23324
23362
  join2(deps2.spoolRoot, sessionId, "end-request.json"),
23325
- JSON.stringify({ requestedAt: (/* @__PURE__ */ new Date()).toISOString() }),
23363
+ JSON.stringify({
23364
+ requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
23365
+ // JEN-167: the host closes the session, so the operator's
23366
+ // acknowledgement has to travel with the request — otherwise the
23367
+ // floor refuses a close they explicitly asked to force. The
23368
+ // CLI-counted commits ride along for the same reason: only the
23369
+ // CLI can count them, and the host's close is the one that lands.
23370
+ ...flags.acknowledgeEvidenceGaps ? { acknowledgeEvidenceGaps: true } : {},
23371
+ ...commitCount !== null ? { commitCount } : {}
23372
+ }),
23326
23373
  { mode: 384 }
23327
23374
  );
23328
23375
  deps2.writeOut(
23329
23376
  `Local capture host (pid ${live.pid}) is finalizing capture\u2026`
23330
23377
  );
23331
- const finished = await waitForHostExit(
23332
- deps2,
23333
- sessionId,
23334
- live.pid,
23335
- 9e4
23336
- );
23337
- if (finished) {
23378
+ const outcome = await waitForHostEnd(deps2, sessionId, live.pid, 9e4);
23379
+ if (outcome.kind === "refused") {
23380
+ deps2.writeErr(
23381
+ `local capture host (pid ${live.pid}) is still running \u2014 the skeleton, heartbeats and telemetry keep accumulating through the comply work; re-run \`jentrix session end ${sessionId}\` once the evidence is pushed`
23382
+ );
23383
+ throw new Error(outcome.message);
23384
+ }
23385
+ if (outcome.kind === "exited") {
23338
23386
  const final = await call(caller, "get_agent_session", { sessionId });
23339
23387
  const stillOpen = final.status === "STARTING" || final.status === "ACTIVE";
23340
23388
  if (!stillOpen) {
@@ -24184,7 +24232,11 @@ async function buildCatalog(caller, flags, detection) {
24184
24232
  // Host/capture disclosure inputs are filled by runAlign (they need the
24185
24233
  // checkout root); defaults here are the no-live-host reading.
24186
24234
  liveHostPid: null,
24187
- captureMode: decideCaptureMode(flags.capture, false),
24235
+ captureMode: captureSubmission(flags.capture, false, false) ?? "default",
24236
+ // JEN-169 + capture settings §5: the disclosure states the same tri-state
24237
+ // the submission carries, so "your account default" is never quietly
24238
+ // disclosed as a posture the wizard guessed.
24239
+ skeletonMode: skeletonSubmission(flags.skeleton) ?? "default",
24188
24240
  producer: producerFromFlags(flags),
24189
24241
  tokenBudget: budgetFromFlags(flags),
24190
24242
  preconditionNotices: [],
@@ -24298,6 +24350,18 @@ function decideCaptureMode(requested, liveCapturing) {
24298
24350
  if (requested === false) return "off";
24299
24351
  return liveCapturing ? "on" : "off";
24300
24352
  }
24353
+ function captureSubmission(requested, liveHost, liveCapturing) {
24354
+ if (requested === void 0 && !liveHost) return void 0;
24355
+ return decideCaptureMode(requested, liveCapturing);
24356
+ }
24357
+ function skeletonSubmission(requested) {
24358
+ if (requested === void 0) return void 0;
24359
+ return requested ? "on" : "off";
24360
+ }
24361
+ function captureSourceLabel(requested, liveHost, serverLabel) {
24362
+ if (requested === void 0 && liveHost) return "(live host)";
24363
+ return serverLabel;
24364
+ }
24301
24365
  function keepCurrentAlignment(currentAlignment, projectId, workItem, ownerUserId) {
24302
24366
  if (workItem !== null || !projectId) return null;
24303
24367
  const current = currentAlignment;
@@ -24362,7 +24426,9 @@ ${JSON.stringify(session.alignment, null, 2)}`
24362
24426
  sessionId,
24363
24427
  alignment: session.alignment,
24364
24428
  realigned: false,
24365
- captureMode: (session.alignment.capture ?? "off") === "on" ? "on" : "off"
24429
+ captureMode: (session.alignment.capture ?? "off") === "on" ? "on" : "off",
24430
+ // No align ran, so nothing resolved anything — claim no provenance.
24431
+ captureSources: null
24366
24432
  };
24367
24433
  }
24368
24434
  }
@@ -24413,7 +24479,12 @@ ${JSON.stringify(session.alignment, null, 2)}`
24413
24479
  `cannot turn TRACE capture off: the live session host (pid ${liveHost.pid}) is actively capturing \u2014 end the session (\`jentrix session end\`) to stop it`
24414
24480
  );
24415
24481
  }
24416
- const captureMode = decideCaptureMode(flags.capture, liveCapturing);
24482
+ const captureSubmitted = captureSubmission(
24483
+ flags.capture,
24484
+ liveHost !== null,
24485
+ liveCapturing
24486
+ );
24487
+ const skeletonSubmitted = skeletonSubmission(flags.skeleton);
24417
24488
  if (liveHost && session.taskId && session.taskId !== (taskId ?? null)) {
24418
24489
  const acked = await requestUsageFlush(deps2, sessionId);
24419
24490
  deps2.writeOut(
@@ -24431,14 +24502,22 @@ ${JSON.stringify(session.alignment, null, 2)}`
24431
24502
  ...producer.emoji ? { agentEmoji: producer.emoji } : {}
24432
24503
  } : {},
24433
24504
  ...budget !== null ? { tokenBudget: budget } : {},
24434
- capture: captureMode,
24435
- // Evidence floor (D3): only an explicit --no-skeleton is sent; absent
24436
- // lets the server keep the stored mode (default "on").
24437
- ...flags.skeleton === false ? { skeleton: "off" } : {},
24505
+ ...captureSubmitted !== void 0 ? { capture: captureSubmitted } : {},
24506
+ ...skeletonSubmitted !== void 0 ? { skeleton: skeletonSubmitted } : {},
24438
24507
  expectedUpdatedAt: session.updatedAt
24439
24508
  });
24440
24509
  const alignment = aligned.alignment;
24441
24510
  const skeletonMode = alignment.skeleton === "off" ? "off" : "on";
24511
+ const captureMode = alignment.capture === "on" ? "on" : "off";
24512
+ const serverSources = aligned.captureSources ?? null;
24513
+ const captureSources = serverSources ? {
24514
+ capture: captureSourceLabel(
24515
+ flags.capture,
24516
+ liveHost !== null,
24517
+ serverSources.capture
24518
+ ),
24519
+ skeleton: serverSources.skeleton
24520
+ } : null;
24442
24521
  writeAlignmentMarker(
24443
24522
  deps2.configPath,
24444
24523
  inspection.root,
@@ -24448,6 +24527,12 @@ ${JSON.stringify(session.alignment, null, 2)}`
24448
24527
  projectId: choices.projectId,
24449
24528
  taskId,
24450
24529
  capture: captureMode,
24530
+ // Capture settings D6/S4: `session status` reads the provenance back
24531
+ // from here — the snapshot deliberately stores values only, so the
24532
+ // align that resolved them is the only place the source exists.
24533
+ ...captureSources?.capture ? { captureSource: captureSources.capture } : {},
24534
+ ...captureSources?.skeleton ? { skeletonSource: captureSources.skeleton } : {},
24535
+ skeleton: skeletonMode,
24451
24536
  alignedAt: (/* @__PURE__ */ new Date()).toISOString()
24452
24537
  },
24453
24538
  detected.providerSessionId
@@ -24474,7 +24559,8 @@ ${JSON.stringify(session.alignment, null, 2)}`
24474
24559
  sessionId,
24475
24560
  alignment,
24476
24561
  realigned: Boolean(aligned.realigned),
24477
- captureMode
24562
+ captureMode,
24563
+ captureSources
24478
24564
  };
24479
24565
  }
24480
24566
  if (!liveHost && (detected.provider === "claude" && detected.transcriptPath || detected.provider === "codex" && detected.hookDir)) {
@@ -24518,7 +24604,8 @@ ${JSON.stringify(session.alignment, null, 2)}`
24518
24604
  sessionId,
24519
24605
  alignment,
24520
24606
  realigned: Boolean(aligned.realigned),
24521
- captureMode
24607
+ captureMode,
24608
+ captureSources
24522
24609
  };
24523
24610
  }
24524
24611
  async function requestUsageFlush(deps2, sessionId, timeoutMs = 6e3) {
@@ -24569,10 +24656,11 @@ async function runAlign(flags, deps2) {
24569
24656
  );
24570
24657
  const markerHost = marker ? readLiveHostMarker(deps2, marker.sessionId) : null;
24571
24658
  catalog.liveHostPid = markerHost?.pid ?? null;
24572
- catalog.captureMode = decideCaptureMode(
24659
+ catalog.captureMode = captureSubmission(
24573
24660
  flags.capture,
24661
+ markerHost !== null,
24574
24662
  marker !== null && markerHost !== null && isHostCapturing(deps2, marker.sessionId, markerHost)
24575
- );
24663
+ ) ?? "default";
24576
24664
  const newest = newestAlignmentMarker(deps2.configPath, inspection.root);
24577
24665
  catalog.lastAlignedWorkspaceId = newest?.workspaceId ?? null;
24578
24666
  catalog.binding = {
@@ -24961,6 +25049,7 @@ async function runAlign(flags, deps2) {
24961
25049
  deps2.writeOut(JSON.stringify(result));
24962
25050
  } else {
24963
25051
  const a = result.alignment;
25052
+ const sources = result.captureSources;
24964
25053
  deps2.writeOut(
24965
25054
  [
24966
25055
  `${result.realigned ? "Re-aligned" : "Aligned"} session ${result.sessionId}:`,
@@ -24970,8 +25059,12 @@ async function runAlign(flags, deps2) {
24970
25059
  ` Owner: ${a.owner?.name ?? a.owner?.email ?? "\u2014"}`,
24971
25060
  ` Agent: ${a.agent?.provider ?? "\u2014"}`,
24972
25061
  ` Repo: ${a.repo?.ownerName ?? "\u2014"}@${a.repo?.branch ?? "detached"}`,
24973
- ` Capture: ${a.capture ?? "off"}`,
24974
- ` Skeleton: ${a.skeleton ?? "on"} (content-free activity counts/timing; --no-skeleton opts out)`,
25062
+ // Capture settings D6: each resolved knob names WHERE it came
25063
+ // from, in the server's own words "(flag)", "(this session)",
25064
+ // "(your default)", "(built-in)". A server older than this round
25065
+ // sends none, and then nothing is claimed.
25066
+ ` Capture: ${a.capture ?? "off"}${sources?.capture ? ` ${sources.capture}` : ""}`,
25067
+ ` Skeleton: ${a.skeleton ?? "on"}${sources?.skeleton ? ` ${sources.skeleton}` : ""} \u2014 content-free activity counts/timing; --skeleton/--no-skeleton decides one session, Account \u2192 Capture sets your default`,
24975
25068
  `Alignment snapshot (server-confirmed): ${JSON.stringify(result.alignment)}`
24976
25069
  ].join("\n")
24977
25070
  );
@@ -25032,13 +25125,16 @@ function registerAlignCommand(program3, deps2, onExit2) {
25032
25125
  "token budget for this session \u2014 a breach is recorded and badged, never enforced"
25033
25126
  ).option(
25034
25127
  "--capture",
25035
- "turn TRACE capture ON for this session (MVP default: off; applies from a fresh attach)"
25128
+ "turn TRACE capture ON for this session (overrides your account default; applies from a fresh attach)"
25036
25129
  ).option(
25037
25130
  "--no-capture",
25038
- "keep TRACE capture OFF explicitly \u2014 also corrects a wrongly-on record on re-align"
25131
+ "keep TRACE capture OFF explicitly \u2014 overrides your account default, and corrects a wrongly-on record on re-align"
25132
+ ).option(
25133
+ "--skeleton",
25134
+ "record the content-free activity skeleton for this session explicitly (overrides your account default)"
25039
25135
  ).option(
25040
25136
  "--no-skeleton",
25041
- "opt out of the content-free activity skeleton (event/tool counts, files-touched, timing buckets) for this session \u2014 default on, independent of capture"
25137
+ "opt out of the content-free activity skeleton (event/tool counts, files-touched, timing buckets) for this session \u2014 independent of capture"
25042
25138
  ).addOption(
25043
25139
  new Option(
25044
25140
  "--provider <provider>",
@@ -26574,6 +26670,10 @@ function parseArgsJson(raw, source) {
26574
26670
  }
26575
26671
  return { ok: true, value: parsed };
26576
26672
  }
26673
+ function workspaceIdShapeError(value) {
26674
+ if (/^[a-z0-9]{20,}$/.test(value)) return null;
26675
+ return `workspaceId "${value}" is not a workspace id (ids look like "cmt2cuhyo000004l38ddsim1y"). Find yours with \`jentrix workspace list\`, set it once as \`defaults.workspace\` in the config file, or use \`jentrix align --workspace <id-or-slug>\` \u2014 align is the command that accepts a slug.`;
26676
+ }
26577
26677
  async function runToolCommand(name, flags, deps2) {
26578
26678
  const maxWaitSeconds = Number(flags.maxWait);
26579
26679
  if (!Number.isFinite(maxWaitSeconds) || maxWaitSeconds < 0) {
@@ -26610,6 +26710,14 @@ async function runToolCommand(name, flags, deps2) {
26610
26710
  deps2.writeErr(`error: ${parsed.error}`);
26611
26711
  return EXIT_CODES.INVALID_INPUT;
26612
26712
  }
26713
+ const workspaceId = parsed.value.workspaceId;
26714
+ if (typeof workspaceId === "string") {
26715
+ const shapeError = workspaceIdShapeError(workspaceId);
26716
+ if (shapeError) {
26717
+ deps2.writeErr(`error: ${shapeError}`);
26718
+ return EXIT_CODES.INVALID_INPUT;
26719
+ }
26720
+ }
26613
26721
  let config2;
26614
26722
  try {
26615
26723
  config2 = resolveConfig({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jentrix/cli",
3
- "version": "0.5.21",
3
+ "version": "0.5.23",
4
4
  "description": "Command-line client for the Jentrix MCP surface (jentrix tool <name>, generated noun-verb commands).",
5
5
  "keywords": [
6
6
  "jentrix",
package/surface.json CHANGED
@@ -441,7 +441,7 @@
441
441
  "description": "Optional producer label for this session (\"triage-bot\"). Null = the operator themself; absent leaves it unchanged."
442
442
  },
443
443
  "capture": {
444
- "description": "TRACE capture mode the CLI declared for this session MVP default off.",
444
+ "description": "TRACE capture mode for this session. OMIT to let the server resolve it: this session's previous value, then the operator's account default (Account → Capture), then the built-in off.",
445
445
  "enum": [
446
446
  "off",
447
447
  "on"
@@ -464,7 +464,7 @@
464
464
  "type": "string"
465
465
  },
466
466
  "skeleton": {
467
- "description": "Activity-skeleton mode the CLI declared for this session (--no-skeleton). Default on, independent of capture.",
467
+ "description": "Activity-skeleton mode for this session, independent of capture. OMIT to let the server resolve it: this session's previous value, then the operator's account default, then the built-in on.",
468
468
  "enum": [
469
469
  "on",
470
470
  "off"