@ycodium-ai/agent-claude 0.2.3405 → 0.2.3425

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 (3) hide show
  1. package/README.md +6 -0
  2. package/dist/index.js +54 -23
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -15,6 +15,12 @@ Facts:
15
15
  - Isolation is `CLAUDE_CONFIG_DIR` and, when set, `CLAUDE_SECURESTORAGE_CONFIG_DIR`.
16
16
  `HOME` is never overridden (macOS keychain lookup lives under `$HOME`).
17
17
  - Manifest permission is `{ kind: "executor" }`.
18
+ - `SessionStart` reports `session_id` and `transcript_path` through
19
+ `thread.metadata.updated.payload.nativeHistory`. The host persists this location on the
20
+ owning session binding and supplies `parentTranscriptPath` to `sessions.openHistory`.
21
+ The reader derives the subagent path from that transcript and checks its native session
22
+ and workspace metadata. Bindings without a saved location use the configured projects
23
+ directory. History inspection never starts a CLI or changes `CLAUDE_CONFIG_DIR`.
18
24
  - Card capabilities: `sessionModelSwitch: "in-session"`, `runtimeModeSwitch: "in-session"`,
19
25
  `contextCompaction: "native"`, `turnSteering: true`.
20
26
  - `modelConnectivity` describes how Claude Code reaches a model: it speaks
package/dist/index.js CHANGED
@@ -1854,15 +1854,12 @@ var openClaudeHistory = (input) => {
1854
1854
  for (const id2 of [input.nativeSessionId, input.parentNativeSessionId])
1855
1855
  if (!/^[A-Za-z0-9_-]+$/u.test(id2)) throw new Error("Invalid native session identifier.");
1856
1856
  const name = input.nativeSessionId.startsWith("agent-") ? input.nativeSessionId : `agent-${input.nativeSessionId}`;
1857
- const path = NodePath4.join(
1858
- input.transcriptDir,
1859
- encodeClaudeProjectDirName(input.cwd),
1860
- input.parentNativeSessionId,
1861
- "subagents",
1862
- `${name}.jsonl`
1863
- );
1857
+ if (input.parentTranscriptPath !== void 0 && (!NodePath4.isAbsolute(input.parentTranscriptPath) || NodePath4.basename(input.parentTranscriptPath) !== `${input.parentNativeSessionId}.jsonl`))
1858
+ throw new Error("Native transcript path does not match the recorded session.");
1859
+ const projectDir = input.parentTranscriptPath === void 0 ? NodePath4.join(input.transcriptDir, encodeClaudeProjectDirName(input.cwd)) : NodePath4.dirname(input.parentTranscriptPath);
1860
+ const path = NodePath4.join(projectDir, input.parentNativeSessionId, "subagents", `${name}.jsonl`);
1864
1861
  return waitForJsonlHistory({
1865
- root: input.transcriptDir,
1862
+ root: input.parentTranscriptPath === void 0 ? input.transcriptDir : projectDir,
1866
1863
  accepts: (changed) => changed === path || path.startsWith(changed + NodePath4.sep),
1867
1864
  open: (signal) => openJsonlHistory(path, claudeHistoryLayout(input), signal),
1868
1865
  ...input.signal === void 0 ? {} : { signal: input.signal }
@@ -22870,6 +22867,10 @@ function terminalResultError(reason) {
22870
22867
  function isOverloadedResult(result) {
22871
22868
  return result.subtype === "success" && result.api_error_status === 529;
22872
22869
  }
22870
+ function isEmptyNotificationResult(result) {
22871
+ return result.subtype === "success" && result.origin?.kind === "task-notification" && result.num_turns === 0 && result.duration_api_ms === 0 && result.result === "" && // 是否成功收口只有 resultOutcome 一份规则(is_error、失败终止原因、529 过载等)。
22872
+ resultOutcome(result).status === "completed";
22873
+ }
22873
22874
  function isInterruptedResult(result) {
22874
22875
  if (result.terminal_reason === "aborted_tools" || result.terminal_reason === "aborted_streaming") {
22875
22876
  return true;
@@ -24966,8 +24967,27 @@ var makeSessionCallbacks = (deps) => {
24966
24967
  return {};
24967
24968
  };
24968
24969
  const handleSessionStart = async (hookInput) => {
24969
- if (hookInput.source !== "compact" || session.contextAfterCompaction === void 0) return {};
24970
24970
  sessionContext ??= await waitSessionContext();
24971
+ const context = sessionContext;
24972
+ if (!context || context.stopped || context.stopping) return {};
24973
+ if (hookInput.session_id === context.resumeSessionId && typeof hookInput.transcript_path === "string" && hookInput.transcript_path.length > 0 && hookInput.transcript_path !== context.reportedTranscriptPath) {
24974
+ context.reportedTranscriptPath = hookInput.transcript_path;
24975
+ const stamp = await makeEventStamp();
24976
+ if (context.stopped || context.stopping) return {};
24977
+ offerRuntimeEvent(context, {
24978
+ type: "thread.metadata.updated",
24979
+ ...eventHeader(context, stamp),
24980
+ payload: {
24981
+ nativeHistory: {
24982
+ nativeSessionId: hookInput.session_id,
24983
+ transcriptPath: hookInput.transcript_path
24984
+ }
24985
+ },
24986
+ providerRefs: {}
24987
+ });
24988
+ }
24989
+ if (hookInput.source !== "compact" || session.contextAfterCompaction === void 0) return {};
24990
+ sessionContext ??= context;
24971
24991
  const compactionId = sessionContext?.compaction?.compactionId;
24972
24992
  if (compactionId === void 0) return {};
24973
24993
  const signal = AbortSignal.timeout(CONTEXT_AFTER_COMPACTION_TIMEOUT_MS);
@@ -24976,15 +24996,15 @@ var makeSessionCallbacks = (deps) => {
24976
24996
  signal.addEventListener("abort", onAbort, { once: true });
24977
24997
  try {
24978
24998
  signal.throwIfAborted();
24979
- const context = await Promise.race([
24999
+ const context2 = await Promise.race([
24980
25000
  aborted.promise,
24981
25001
  session.contextAfterCompaction({ compactionId, signal })
24982
25002
  ]);
24983
25003
  signal.throwIfAborted();
24984
- return typeof context === "string" && context.length > 0 ? {
25004
+ return typeof context2 === "string" && context2.length > 0 ? {
24985
25005
  hookSpecificOutput: {
24986
25006
  hookEventName: "SessionStart",
24987
- additionalContext: context
25007
+ additionalContext: context2
24988
25008
  }
24989
25009
  } : {};
24990
25010
  } catch {
@@ -26001,15 +26021,15 @@ var makeStartSession = (deps) => {
26001
26021
  onUserDialog,
26002
26022
  hooks: {
26003
26023
  ...input.contextAfterCompaction === void 0 ? {} : {
26004
- PreCompact: [{ hooks: [async () => handlePreCompact()] }],
26005
- SessionStart: [
26006
- {
26007
- hooks: [
26008
- async (hookInput) => hookInput.hook_event_name === "SessionStart" ? handleSessionStart(hookInput) : {}
26009
- ]
26010
- }
26011
- ]
26024
+ PreCompact: [{ hooks: [async () => handlePreCompact()] }]
26012
26025
  },
26026
+ SessionStart: [
26027
+ {
26028
+ hooks: [
26029
+ async (hookInput) => hookInput.hook_event_name === "SessionStart" ? handleSessionStart(hookInput) : {}
26030
+ ]
26031
+ }
26032
+ ],
26013
26033
  PostCompact: [
26014
26034
  {
26015
26035
  hooks: [
@@ -27281,6 +27301,7 @@ import * as NodePath13 from "node:path";
27281
27301
  var makeTurnMessageHandlers = (deps) => {
27282
27302
  const {
27283
27303
  emitter,
27304
+ log,
27284
27305
  now,
27285
27306
  buildLaunchEnvironment,
27286
27307
  emitRuntimeError,
@@ -27527,6 +27548,15 @@ var makeTurnMessageHandlers = (deps) => {
27527
27548
  if (message.type !== "result") {
27528
27549
  return;
27529
27550
  }
27551
+ const openTurn = context.turnState;
27552
+ if (openTurn !== void 0 && openTurn.synthetic !== true && openTurn.assistantTextBlockOrder.length === 0 && openTurn.latestAssistantUsage === void 0 && isEmptyNotificationResult(message)) {
27553
+ delete openTurn.resultClaim;
27554
+ log.info("claude.turn.empty-result-ignored", {
27555
+ threadId: context.session.threadId,
27556
+ turnId: openTurn.turnId
27557
+ });
27558
+ return;
27559
+ }
27530
27560
  context.compactionInProgress = false;
27531
27561
  const outcome = resultOutcome(
27532
27562
  message,
@@ -28975,9 +29005,9 @@ var createClaudeUsage = (input) => {
28975
29005
  // src/openCommands.ts
28976
29006
  import { sameArgv } from "@ycodium-ai/plugin-api/executor";
28977
29007
  var quote = (command) => "'" + command.replaceAll("'", `'"'"'`) + "'";
28978
- var basename2 = (path) => path.split(/[\\/]/).at(-1)?.toLowerCase() ?? "";
29008
+ var basename3 = (path) => path.split(/[\\/]/).at(-1)?.toLowerCase() ?? "";
28979
29009
  function claudeCommandMatches(command, argv) {
28980
- if (argv.length !== 3 || !["bash.exe", "bash"].includes(basename2(argv[0] ?? "")) || argv[1] !== "-c")
29010
+ if (argv.length !== 3 || !["bash.exe", "bash"].includes(basename3(argv[0] ?? "")) || argv[1] !== "-c")
28981
29011
  return false;
28982
29012
  const script = argv[2] ?? "";
28983
29013
  const source = /^source \S+\/shell-snapshots\/snapshot-bash-\d+-[a-zA-Z0-9]+\.sh /;
@@ -29013,7 +29043,7 @@ function openCommandsOf(context) {
29013
29043
  const normalize2 = (value) => platform4 === "win32" ? value.replaceAll("\\", "/").toLowerCase() : value;
29014
29044
  const expected = normalize2(current.command);
29015
29045
  const actual = normalize2(argv[0] ?? "");
29016
- const sameProgram = expected.includes("/") ? actual === expected : platform4 === "win32" ? basename2(actual).replace(/\.exe$/, "") === expected.replace(/\.exe$/, "") : actual.split("/").at(-1) === expected;
29046
+ const sameProgram = expected.includes("/") ? actual === expected : platform4 === "win32" ? basename3(actual).replace(/\.exe$/, "") === expected.replace(/\.exe$/, "") : actual.split("/").at(-1) === expected;
29017
29047
  return sameProgram && sameArgv(argv.slice(1), current.args);
29018
29048
  },
29019
29049
  commands
@@ -29087,6 +29117,7 @@ function createClaudeAdapter(recipe, host, options) {
29087
29117
  });
29088
29118
  const { handleUserMessage, handleAssistantMessage, handleResultMessage } = makeTurnMessageHandlers({
29089
29119
  emitter,
29120
+ log: options?.log ?? host.log,
29090
29121
  now,
29091
29122
  buildLaunchEnvironment,
29092
29123
  attachments: options?.attachments,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycodium-ai/agent-claude",
3
- "version": "0.2.3405",
3
+ "version": "0.2.3425",
4
4
  "description": "Claude executor: Claude Code CLI via @anthropic-ai/claude-agent-sdk.",
5
5
  "keywords": [
6
6
  "ycodium",
@@ -24,8 +24,8 @@
24
24
  "@types/node": "24.12.4",
25
25
  "esbuild": "0.28.1",
26
26
  "vite-plus": "0.2.2",
27
- "@ycodium-ai/plugin-api": "0.2.3405",
28
27
  "ycodium-composer-tokens": "0.0.0",
28
+ "@ycodium-ai/plugin-api": "0.2.3425",
29
29
  "ycodium-executor-testing": "0.0.0",
30
30
  "ycodium-jsonl-stream": "0.0.0"
31
31
  },