@jentrix/cli 0.5.16 → 0.5.18

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jentrix",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "Connect Codex tasks to Jentrix projects with trusted lifecycle hooks, alignment, checkpoints, and honest session capture.",
5
5
  "author": {
6
6
  "name": "Jentrix",
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: stacks-align
2
+ name: jentrix-align
3
3
  description: Align the current Codex task to a Jentrix workspace, project, work item, and owner with an operator-confirmed server snapshot.
4
4
  ---
5
5
  <!-- Source of truth. The cli/{claude,codex}-plugin copy is GENERATED by cli/scripts/build.mjs (rm + cp) on every build — edits made there are deleted. Edit this file. -->
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: stacks-checkpoint
2
+ name: jentrix-checkpoint
3
3
  description: Distill verified session state into a typed Jentrix checkpoint that survives compaction or handoff.
4
4
  ---
5
5
  <!-- Source of truth. The cli/{claude,codex}-plugin copy is GENERATED by cli/scripts/build.mjs (rm + cp) on every build — edits made there are deleted. Edit this file. -->
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: stacks-connect
2
+ name: jentrix-connect
3
3
  description: Connect the current Codex task to a Jentrix project using trusted lifecycle identity and start the session capture host.
4
4
  ---
5
5
  <!-- Source of truth. The cli/{claude,codex}-plugin copy is GENERATED by cli/scripts/build.mjs (rm + cp) on every build — edits made there are deleted. Edit this file. -->
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: stacks-end
2
+ name: jentrix-end
3
3
  description: End a connected Jentrix session after preserving approved outputs, parking completed work in review, and reporting capture honestly.
4
4
  ---
5
5
  <!-- Source of truth. The cli/{claude,codex}-plugin copy is GENERATED by cli/scripts/build.mjs (rm + cp) on every build — edits made there are deleted. Edit this file. -->
@@ -22,8 +22,8 @@ description: End a connected Jentrix session after preserving approved outputs,
22
22
  Declining never blocks closure.
23
23
  5. Run `jentrix session end <session-id>` and relay all output, including the exact
24
24
  telemetry line and any capture gap.
25
- 6. Explain that Codex lifecycle hooks do not report token receipts, so null token
26
- fields are expected on hook-watched sessions. Do not report estimates.
25
+ 6. Report provider-reported Codex token receipts when the hook supplied a rollout
26
+ path. If none were observed, keep token fields null; never report estimates.
27
27
  7. A final-response artifact exists only when a prior `Stop` hook observed assistant
28
28
  text before closure. The assistant text produced by this closing turn occurs after
29
29
  the command and must not be claimed as captured.
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: stacks-plan
2
+ name: jentrix-plan
3
3
  description: Turn the opening request into an operator-approved goal and small Jentrix task set, then store the prompt and goal as typed artifacts.
4
4
  ---
5
5
  <!-- Source of truth. The cli/{claude,codex}-plugin copy is GENERATED by cli/scripts/build.mjs (rm + cp) on every build — edits made there are deleted. Edit this file. -->
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: stacks-review
2
+ name: jentrix-review
3
3
  description: Review a Jentrix session's typed artifacts by category, verify the readiness contract, and post the verdict as a comment on the aligned task.
4
4
  ---
5
5
  <!-- Source of truth. The cli/{claude,codex}-plugin copy is GENERATED by cli/scripts/build.mjs (rm + cp) on every build — edits made there are deleted. Edit this file. -->
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: stacks-status
2
+ name: jentrix-status
3
3
  description: Show the connected Jentrix session, alignment, capture health, and honest telemetry availability for this Codex task.
4
4
  ---
5
5
  <!-- Source of truth. The cli/{claude,codex}-plugin copy is GENERATED by cli/scripts/build.mjs (rm + cp) on every build — edits made there are deleted. Edit this file. -->
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.16";
20969
+ var CLI_VERSION = "0.5.18";
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) {
@@ -22620,6 +22620,7 @@ function readTranscriptHead(path) {
22620
22620
  function parseHookLedger(body) {
22621
22621
  const starts = [];
22622
22622
  const endedAt = /* @__PURE__ */ new Map();
22623
+ const transcriptBySession = /* @__PURE__ */ new Map();
22623
22624
  for (const line of body.split("\n").filter(Boolean)) {
22624
22625
  let parsed;
22625
22626
  try {
@@ -22629,6 +22630,10 @@ function parseHookLedger(body) {
22629
22630
  }
22630
22631
  const sessionId = parsed.payload?.session_id;
22631
22632
  if (typeof sessionId !== "string") continue;
22633
+ const transcriptPath = parsed.payload?.transcript_path?.trim();
22634
+ if (transcriptPath) {
22635
+ transcriptBySession.set(sessionId, transcriptPath);
22636
+ }
22632
22637
  const stamped = parsed.at ? Date.parse(parsed.at) : NaN;
22633
22638
  const ms = Number.isNaN(stamped) ? 0 : stamped;
22634
22639
  if (parsed.event === "SessionEnd") {
@@ -22643,16 +22648,10 @@ function parseHookLedger(body) {
22643
22648
  });
22644
22649
  }
22645
22650
  }
22646
- return { starts, endedAt };
22651
+ return { starts, endedAt, transcriptBySession };
22647
22652
  }
22648
22653
  function transcriptForSessionIn(ledger, sessionId) {
22649
- for (let i = ledger.starts.length - 1; i >= 0; i--) {
22650
- const start = ledger.starts[i];
22651
- if (start.sessionId === sessionId && start.transcriptPath) {
22652
- return start.transcriptPath;
22653
- }
22654
- }
22655
- return null;
22654
+ return ledger.transcriptBySession.get(sessionId) ?? null;
22656
22655
  }
22657
22656
  var CLAUDE_SESSION_ENV = "CLAUDE_CODE_SESSION_ID";
22658
22657
  var CODEX_THREAD_ENV = "CODEX_THREAD_ID";
@@ -22676,9 +22675,10 @@ function readClaudeHookContext(deps2, readFile = (path) => readFileSync2(path, "
22676
22675
  } catch {
22677
22676
  }
22678
22677
  }
22679
- const { starts, endedAt } = parseHookLedger(body);
22678
+ const ledger = parseHookLedger(body);
22679
+ const { starts, endedAt } = ledger;
22680
22680
  if (own) {
22681
- const transcriptPath = transcriptForSessionIn({ starts }, own);
22681
+ const transcriptPath = transcriptForSessionIn(ledger, own);
22682
22682
  return {
22683
22683
  sessionId: own,
22684
22684
  transcriptPath,
@@ -22740,13 +22740,15 @@ function readCodexHookContext(deps2, readFile = (path) => readFileSync2(path, "u
22740
22740
  } catch {
22741
22741
  }
22742
22742
  }
22743
- const { starts, endedAt } = parseHookLedger(body);
22743
+ const ledger = parseHookLedger(body);
22744
+ const { starts, endedAt } = ledger;
22744
22745
  if (own) {
22745
22746
  const source = threadId ? CODEX_THREAD_ENV : CODEX_SESSION_ENV;
22747
+ const transcriptPath = transcriptForSessionIn(ledger, own);
22746
22748
  return {
22747
22749
  sessionId: own,
22748
- transcriptPath: null,
22749
- basis: `${source}=${own} \u2014 this Codex task's own id`,
22750
+ transcriptPath,
22751
+ basis: `${source}=${own} \u2014 this Codex task's own id${transcriptPath ? " (rollout from its hook record)" : ""}`,
22750
22752
  newerElsewhere: null
22751
22753
  };
22752
22754
  }
@@ -22769,7 +22771,7 @@ function readCodexHookContext(deps2, readFile = (path) => readFileSync2(path, "u
22769
22771
  const match = matches[0];
22770
22772
  return match ? {
22771
22773
  sessionId: match.sessionId,
22772
- transcriptPath: null,
22774
+ transcriptPath: transcriptForSessionIn(ledger, match.sessionId),
22773
22775
  basis: `unambiguous SessionStart${match.at ? ` at ${match.at}` : ""} in ${match.cwd}`,
22774
22776
  newerElsewhere: null
22775
22777
  } : null;
@@ -22851,7 +22853,12 @@ async function runSessionAttach(flags, deps2) {
22851
22853
  }
22852
22854
  } else if (!flags.providerSession && flags.provider === "codex") {
22853
22855
  const hookContext = readCodexHookContext(deps2);
22854
- if (hookContext) flags.providerSession = hookContext.sessionId;
22856
+ if (hookContext) {
22857
+ flags.providerSession = hookContext.sessionId;
22858
+ if (!flags.transcriptPath && hookContext.transcriptPath) {
22859
+ flags.transcriptPath = hookContext.transcriptPath;
22860
+ }
22861
+ }
22855
22862
  } else if (flags.provider === "claude" && flags.providerSession && !flags.transcriptPath) {
22856
22863
  flags.transcriptPath = readClaudeHookTranscript(deps2, flags.providerSession) ?? void 0;
22857
22864
  }
@@ -23076,7 +23083,7 @@ function telemetryVerdict(sessionId, usage, hostRan, provider = "claude") {
23076
23083
  if (provider === "codex" && hostRan) {
23077
23084
  return {
23078
23085
  state: "unavailable",
23079
- line: `Telemetry: token usage unavailable \u2014 Codex lifecycle hooks report no token receipts${wallPart} (coverage ${coverage})`,
23086
+ line: `Telemetry: token usage unavailable \u2014 no Codex rollout receipt was observed${wallPart} (coverage ${coverage})`,
23080
23087
  warning: null
23081
23088
  };
23082
23089
  }
@@ -23858,7 +23865,7 @@ function sessionBindingCheck(detected) {
23858
23865
  return detected.hookDir ? {
23859
23866
  name: "session",
23860
23867
  status: "ok",
23861
- detail: `${detected.providerSessionId} \xB7 ${detected.basis ?? "resolved"} \xB7 host watches trusted Codex lifecycle hooks; token usage is unavailable by provider contract`
23868
+ detail: `${detected.providerSessionId} \xB7 ${detected.basis ?? "resolved"} \xB7 host watches trusted Codex lifecycle hooks and provider-reported rollout usage`
23862
23869
  } : {
23863
23870
  name: "session",
23864
23871
  status: "warn",
@@ -23886,7 +23893,7 @@ function detectProvider(flags, deps2) {
23886
23893
  return {
23887
23894
  provider: "codex",
23888
23895
  providerSessionId: flags.providerSession ?? hook2?.sessionId ?? null,
23889
- transcriptPath: null,
23896
+ transcriptPath: flags.transcriptPath ?? hook2?.transcriptPath ?? null,
23890
23897
  basis: flags.providerSession ? `codex thread ${flags.providerSession} (explicit)` : hook2?.basis ?? null,
23891
23898
  newerElsewhere: null,
23892
23899
  transcriptGap: null,
@@ -23898,7 +23905,7 @@ function detectProvider(flags, deps2) {
23898
23905
  return {
23899
23906
  provider: "codex",
23900
23907
  providerSessionId: current.sessionId,
23901
- transcriptPath: null,
23908
+ transcriptPath: flags.transcriptPath ?? current.transcriptPath,
23902
23909
  basis: current.basis,
23903
23910
  newerElsewhere: null,
23904
23911
  transcriptGap: null,
@@ -24332,7 +24339,7 @@ ${JSON.stringify(session.alignment, null, 2)}`
24332
24339
  });
24333
24340
  if (pid !== null) {
24334
24341
  deps2.writeOut(
24335
- captureMode === "on" ? `Capture host running (pid ${pid}) \u2014 TRACE capture ON for this session.` : detected.provider === "codex" ? `Session host running (pid ${pid}) \u2014 heartbeats + Codex lifecycle hooks; token usage is unavailable and TRACE capture is OFF.` : `Session host running (pid ${pid}) \u2014 heartbeats + telemetry only; TRACE capture is OFF (MVP default; a NEW session aligned with --capture records one \u2014 it cannot start mid-session).`
24342
+ captureMode === "on" ? `Capture host running (pid ${pid}) \u2014 TRACE capture ON for this session.` : detected.provider === "codex" ? `Session host running (pid ${pid}) \u2014 heartbeats + Codex rollout telemetry; TRACE capture is OFF.` : `Session host running (pid ${pid}) \u2014 heartbeats + telemetry only; TRACE capture is OFF (MVP default; a NEW session aligned with --capture records one \u2014 it cannot start mid-session).`
24336
24343
  );
24337
24344
  }
24338
24345
  } else if (!liveHost) {
@@ -27627,7 +27634,7 @@ async function installCodexPlugin(deps2, codex, pluginDir) {
27627
27634
  }
27628
27635
  return finishInstall(
27629
27636
  deps2,
27630
- "Jentrix Codex plugin ready: $jentrix-connect, $jentrix-align, $jentrix-plan, $jentrix-checkpoint, $jentrix-status, and $jentrix-end are available in NEW Codex tasks. Open `/hooks` and trust the Jentrix hooks before use." + await removeLegacyPlugin(deps2, codex, "codex")
27637
+ "Jentrix Codex plugin ready: $jentrix-connect, $jentrix-align, $jentrix-plan, $jentrix-checkpoint, $jentrix-status, $jentrix-review, and $jentrix-end are available in NEW Codex tasks. Open `/hooks` and trust the Jentrix hooks before use." + await removeLegacyPlugin(deps2, codex, "codex")
27631
27638
  );
27632
27639
  }
27633
27640
  async function runPluginInstall(deps2, provider = "claude") {
@@ -27718,7 +27725,7 @@ ${update.stderr}`.match(
27718
27725
  );
27719
27726
  return finishInstall(
27720
27727
  deps2,
27721
- `Jentrix plugin ready: /jentrix-connect, /jentrix-align, /jentrix-plan, /jentrix-checkpoint, /jentrix-status, /jentrix-end are available in NEW Claude Code sessions (running sessions pick it up on restart).${await removeLegacyPlugin(deps2, claude, "claude")}`
27728
+ `Jentrix plugin ready: /jentrix-connect, /jentrix-align, /jentrix-plan, /jentrix-checkpoint, /jentrix-status, /jentrix-review, /jentrix-end are available in NEW Claude Code sessions (running sessions pick it up on restart).${await removeLegacyPlugin(deps2, claude, "claude")}`
27722
27729
  );
27723
27730
  }
27724
27731
  function registerPluginCommand(program3, deps2, onExit2) {
@@ -28369,7 +28376,7 @@ async function installRuntimes(deps2, pending) {
28369
28376
  }
28370
28377
  }
28371
28378
  }
28372
- async function registerCodexMcp(deps2, codex, pending) {
28379
+ async function registerCodexMcp(deps2, codex, pending, url2) {
28373
28380
  const configPath = deps2.codexConfigPath();
28374
28381
  const config2 = deps2.readTextFile(configPath);
28375
28382
  const existingKey = config2 ? /^\[mcp_servers\.jentrix\]/m.test(config2) ? "jentrix" : /^\[mcp_servers\.stacks\]/m.test(config2) ? "stacks" : null : null;
@@ -28392,7 +28399,6 @@ async function registerCodexMcp(deps2, codex, pending) {
28392
28399
  );
28393
28400
  return;
28394
28401
  }
28395
- const url2 = deps2.signedInUrl();
28396
28402
  if (!url2) {
28397
28403
  say(
28398
28404
  deps2,
@@ -28532,6 +28538,14 @@ async function runSetupCommand(flags, deps2) {
28532
28538
  );
28533
28539
  return EXIT_CODES.INVALID_INPUT;
28534
28540
  }
28541
+ if (flags.url) {
28542
+ try {
28543
+ new URL(flags.url);
28544
+ } catch {
28545
+ deps2.writeErr(`INVALID_URL: ${JSON.stringify(flags.url)}`);
28546
+ return EXIT_CODES.INVALID_INPUT;
28547
+ }
28548
+ }
28535
28549
  const toolchain = await installToolchain(deps2);
28536
28550
  if (toolchain !== EXIT_CODES.OK) return toolchain;
28537
28551
  const pending = { failedPlugins: [] };
@@ -28553,8 +28567,9 @@ async function runSetupCommand(flags, deps2) {
28553
28567
  );
28554
28568
  }
28555
28569
  }
28570
+ const targetUrl = flags.url ?? deps2.signedInUrl();
28556
28571
  const codex = await deps2.resolveCodex();
28557
- if (codex) await registerCodexMcp(deps2, codex, pending);
28572
+ if (codex) await registerCodexMcp(deps2, codex, pending, targetUrl);
28558
28573
  if (flags.git !== false && deps2.cwd() !== deps2.homeDir()) {
28559
28574
  let inWorkTree;
28560
28575
  if (deps2.isInteractive) {
@@ -28569,7 +28584,7 @@ async function runSetupCommand(flags, deps2) {
28569
28584
  }
28570
28585
  }
28571
28586
  if (inWorkTree) {
28572
- writeCheckoutMcpConfig(deps2, deps2.signedInUrl() ?? flags.url ?? null);
28587
+ writeCheckoutMcpConfig(deps2, targetUrl);
28573
28588
  }
28574
28589
  }
28575
28590
  say(deps2, "");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jentrix/cli",
3
- "version": "0.5.16",
3
+ "version": "0.5.18",
4
4
  "description": "Command-line client for the Jentrix MCP surface (jentrix tool <name>, generated noun-verb commands).",
5
5
  "keywords": [
6
6
  "jentrix",