@ycodium-ai/agent-claude 0.2.2488 → 0.2.2510

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 (2) hide show
  1. package/dist/index.js +61 -54
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -21119,6 +21119,28 @@ var CLAUDE_SETTING_SOURCES = [
21119
21119
  "local"
21120
21120
  ];
21121
21121
 
21122
+ // src/readOnlyDirectories.ts
21123
+ var GLOB_METACHARACTERS = /[*?[\]{}]/;
21124
+ function toClaudeAbsolutePath(directory) {
21125
+ const trimmed = directory.trim();
21126
+ if (GLOB_METACHARACTERS.test(trimmed)) return void 0;
21127
+ const drive = /^([A-Za-z]):[\\/]+(.*)$/.exec(trimmed);
21128
+ if (drive) {
21129
+ const rest = (drive[2] ?? "").split("\\").join("/").replace(/\/+$/, "");
21130
+ return rest === "" ? void 0 : `//${(drive[1] ?? "").toLowerCase()}/${rest}`;
21131
+ }
21132
+ if (/^\/[^/]/.test(trimmed)) return `/${trimmed.replace(/\/+$/, "")}`;
21133
+ return void 0;
21134
+ }
21135
+ function claudeReadAllowRules(directories) {
21136
+ const rules = [];
21137
+ for (const directory of directories ?? []) {
21138
+ const path = toClaudeAbsolutePath(directory);
21139
+ if (path !== void 0) rules.push(`Read(${path}/**)`);
21140
+ }
21141
+ return rules;
21142
+ }
21143
+
21122
21144
  // src/sessions.ts
21123
21145
  import * as NodeFS3 from "node:fs";
21124
21146
  import * as NodeOS6 from "node:os";
@@ -21537,16 +21559,6 @@ function normalizeClaudeActiveTokenUsage(value, contextWindow, totalProcessedTok
21537
21559
  ...totalProcessedTokens !== void 0 ? { totalProcessedTokens } : {}
21538
21560
  });
21539
21561
  }
21540
- function normalizeClaudeContextUsageApiSnapshot(value, totalProcessedTokens) {
21541
- const autoCompactThreshold = finitePositiveInteger(value.autoCompactThreshold);
21542
- return makeClaudeTokenUsageSnapshot({
21543
- activeTokens: value.totalTokens,
21544
- contextWindow: value.maxTokens,
21545
- ...totalProcessedTokens !== void 0 ? { totalProcessedTokens } : {},
21546
- compactsAutomatically: value.isAutoCompactEnabled,
21547
- ...autoCompactThreshold !== void 0 ? { autoCompactThreshold } : {}
21548
- });
21549
- }
21550
21562
  function compactBoundaryTokenUsageSnapshot(message, contextWindow, totalProcessedTokens) {
21551
21563
  const metadata = message.compact_metadata;
21552
21564
  if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) {
@@ -22648,9 +22660,6 @@ function nativeProviderRefs(_context, options) {
22648
22660
  }
22649
22661
  async function buildUserMessageFromTurn(input) {
22650
22662
  const sdkContent = [];
22651
- if (input.text.length > 0) {
22652
- sdkContent.push({ type: "text", text: input.text });
22653
- }
22654
22663
  for (const attachment of input.attachments ?? []) {
22655
22664
  if (!attachment || typeof attachment !== "object" || Array.isArray(attachment)) continue;
22656
22665
  const rec = attachment;
@@ -22669,6 +22678,9 @@ async function buildUserMessageFromTurn(input) {
22669
22678
  const bytes = await input.attachmentsApi.read(id2);
22670
22679
  sdkContent.push(buildClaudeImageContentBlock({ mimeType, bytes }));
22671
22680
  }
22681
+ if (input.text.length > 0) {
22682
+ sdkContent.push({ type: "text", text: input.text });
22683
+ }
22672
22684
  return buildUserMessage({ sdkContent });
22673
22685
  }
22674
22686
  async function persistProducedImage(input) {
@@ -22782,10 +22794,7 @@ function createClaudeAdapter(recipe, host, options) {
22782
22794
  }
22783
22795
  return {
22784
22796
  threadId,
22785
- turns: context.turns.map((turn) => ({
22786
- id: turn.id,
22787
- items: [...turn.items]
22788
- }))
22797
+ turns: context.turns.map((turn) => ({ id: turn.id, items: [] }))
22789
22798
  };
22790
22799
  };
22791
22800
  const updateResumeCursor = async (context) => {
@@ -23039,27 +23048,6 @@ function createClaudeAdapter(recipe, host, options) {
23039
23048
  } : {}
23040
23049
  });
23041
23050
  };
23042
- const queryCurrentContextUsage = async (context, totalProcessedTokens) => {
23043
- if (!context.query.getContextUsage) {
23044
- return void 0;
23045
- }
23046
- let usage;
23047
- try {
23048
- usage = await Promise.race([
23049
- context.query.getContextUsage(),
23050
- new Promise((resolve2) => {
23051
- setTimeout(() => resolve2(void 0), 1e3);
23052
- })
23053
- ]);
23054
- } catch {
23055
- usage = void 0;
23056
- }
23057
- if (!usage) {
23058
- return void 0;
23059
- }
23060
- context.lastKnownContextWindow = usage.maxTokens;
23061
- return normalizeClaudeContextUsageApiSnapshot(usage, totalProcessedTokens);
23062
- };
23063
23051
  const emitProposedPlanCompleted = async (context, input) => {
23064
23052
  const turnState = context.turnState;
23065
23053
  const planMarkdown = input.planMarkdown.trim();
@@ -23132,10 +23120,11 @@ function createClaudeAdapter(recipe, host, options) {
23132
23120
  turnId,
23133
23121
  startedAt,
23134
23122
  synthetic: true,
23135
- items: [],
23136
23123
  assistantTextBlocks: /* @__PURE__ */ new Map(),
23137
23124
  assistantTextBlockOrder: [],
23138
23125
  capturedProposedPlanKeys: /* @__PURE__ */ new Set(),
23126
+ latestAssistantUsage: void 0,
23127
+ compactedSinceLatestAssistantUsage: false,
23139
23128
  retrying: false,
23140
23129
  nextSyntheticAssistantBlockIndex: -1
23141
23130
  };
@@ -23175,10 +23164,6 @@ function createClaudeAdapter(recipe, host, options) {
23175
23164
  if (accumulatedTotalProcessedTokens !== void 0) {
23176
23165
  context.lastKnownTotalProcessedTokens = accumulatedTotalProcessedTokens;
23177
23166
  }
23178
- const contextUsageSnapshot = await queryCurrentContextUsage(
23179
- context,
23180
- accumulatedTotalProcessedTokens ?? context.lastKnownTotalProcessedTokens
23181
- );
23182
23167
  const resultUsageRecord = result?.usage && typeof result.usage === "object" && !Array.isArray(result.usage) ? result.usage : void 0;
23183
23168
  const hasResultUsageIteration = resultUsageRecord !== void 0 && lastClaudeUsageIteration(resultUsageRecord) !== void 0;
23184
23169
  const resultHasActiveUsage = resultUsageRecord !== void 0 && (hasResultUsageIteration || claudeUsageInputTokens(resultUsageRecord) + claudeUsageOutputTokens(resultUsageRecord) > 0);
@@ -23188,8 +23173,14 @@ function createClaudeAdapter(recipe, host, options) {
23188
23173
  maxTokens,
23189
23174
  accumulatedTotalProcessedTokens ?? context.lastKnownTotalProcessedTokens
23190
23175
  ) : void 0;
23176
+ const latestAssistantSnapshot = normalizeClaudeActiveTokenUsage(
23177
+ context.turnState?.latestAssistantUsage,
23178
+ maxTokens,
23179
+ accumulatedTotalProcessedTokens ?? context.lastKnownTotalProcessedTokens
23180
+ );
23191
23181
  const lastGoodUsage = context.lastKnownTokenUsage;
23192
- const usageSnapshot = contextUsageSnapshot ?? (resultTotalOnly && lastGoodUsage ? {
23182
+ const usageSnapshot = latestAssistantSnapshot ?? // 压缩之后还没有新的 assistant 用量时,result 里的累计数反映的是压缩前的上下文,不能用。
23183
+ (context.turnState?.compactedSinceLatestAssistantUsage ? void 0 : resultTotalOnly && lastGoodUsage ? {
23193
23184
  ...lastGoodUsage,
23194
23185
  ...typeof maxTokens === "number" && Number.isFinite(maxTokens) && maxTokens > 0 ? { maxTokens } : {},
23195
23186
  ...typeof accumulatedTotalProcessedTokens === "number" && Number.isFinite(accumulatedTotalProcessedTokens) && accumulatedTotalProcessedTokens > lastGoodUsage.usedTokens ? {
@@ -23256,10 +23247,7 @@ function createClaudeAdapter(recipe, host, options) {
23256
23247
  rawPayload: result ?? { status }
23257
23248
  });
23258
23249
  }
23259
- context.turns.push({
23260
- id: turnState.turnId,
23261
- items: [...turnState.items]
23262
- });
23250
+ context.turns.push({ id: turnState.turnId });
23263
23251
  await emitThreadTokenUsage(context, usageSnapshot, {
23264
23252
  rawMethod: "claude/result",
23265
23253
  rawPayload: result ?? { status }
@@ -23557,9 +23545,6 @@ function createClaudeAdapter(recipe, host, options) {
23557
23545
  if (message.type !== "user") {
23558
23546
  return;
23559
23547
  }
23560
- if (context.turnState) {
23561
- context.turnState.items.push(message.message);
23562
- }
23563
23548
  for (const toolResult of toolResultBlocksFromUserMessage(message)) {
23564
23549
  const toolEntry = Array.from(context.inFlightTools.entries()).find(
23565
23550
  ([, tool2]) => tool2.itemId === toolResult.toolUseId
@@ -23778,7 +23763,14 @@ function createClaudeAdapter(recipe, host, options) {
23778
23763
  }
23779
23764
  }
23780
23765
  if (context.turnState) {
23781
- context.turnState.items.push(message.message);
23766
+ if (normalizeClaudeActiveTokenUsage(
23767
+ message.message.usage,
23768
+ context.lastKnownContextWindow,
23769
+ context.lastKnownTotalProcessedTokens
23770
+ )) {
23771
+ context.turnState.latestAssistantUsage = message.message.usage;
23772
+ context.turnState.compactedSinceLatestAssistantUsage = false;
23773
+ }
23782
23774
  await backfillAssistantTextBlocksFromSnapshot(context, message);
23783
23775
  }
23784
23776
  context.lastAssistantUuid = message.uuid;
@@ -23924,6 +23916,10 @@ function createClaudeAdapter(recipe, host, options) {
23924
23916
  return;
23925
23917
  }
23926
23918
  case "compact_boundary": {
23919
+ if (context.turnState) {
23920
+ context.turnState.latestAssistantUsage = void 0;
23921
+ context.turnState.compactedSinceLatestAssistantUsage = true;
23922
+ }
23927
23923
  await emitThreadTokenUsage(
23928
23924
  context,
23929
23925
  compactBoundaryTokenUsageSnapshot(
@@ -24189,13 +24185,19 @@ function createClaudeAdapter(recipe, host, options) {
24189
24185
  return;
24190
24186
  // 目前无 Ycodium 表面的内部协议/UX 细节 — 主动消费
24191
24187
  // deliberately so they don't masquerade as unknown-subtype warnings.
24192
- case "model_refusal_fallback":
24193
24188
  case "local_command_output":
24194
24189
  case "plugin_install":
24195
24190
  case "commands_changed":
24196
24191
  case "memory_recall":
24197
24192
  case "elicitation_complete":
24198
24193
  return;
24194
+ case "model_refusal_fallback":
24195
+ await emitRuntimeWarning(
24196
+ context,
24197
+ message.content.length > 0 ? message.content : `Claude switched from ${message.original_model} to ${message.fallback_model} after a safety refusal.`,
24198
+ message
24199
+ );
24200
+ return;
24199
24201
  case "permission_denied":
24200
24202
  offerRuntimeEvent(context, {
24201
24203
  ...base,
@@ -24902,6 +24904,10 @@ function createClaudeAdapter(recipe, host, options) {
24902
24904
  const additionalDirectories = input.cwd ? [input.cwd] : [];
24903
24905
  const mcpServers = toClaudeMcpServers(input.mcpServers);
24904
24906
  const querySettings = { ...settings };
24907
+ const readAllowRules = claudeReadAllowRules(input.readOnlyDirectories);
24908
+ if (readAllowRules.length > 0) {
24909
+ querySettings.permissions = { allow: [...readAllowRules] };
24910
+ }
24905
24911
  const stderrTail = createOutputTail(CLAUDE_STDERR_TAIL_CHARS);
24906
24912
  const queryOptions = {
24907
24913
  ...input.cwd ? { cwd: input.cwd } : {},
@@ -25141,10 +25147,11 @@ function createClaudeAdapter(recipe, host, options) {
25141
25147
  const turnState = {
25142
25148
  turnId,
25143
25149
  startedAt: nowIso(),
25144
- items: [],
25145
25150
  assistantTextBlocks: /* @__PURE__ */ new Map(),
25146
25151
  assistantTextBlockOrder: [],
25147
25152
  capturedProposedPlanKeys: /* @__PURE__ */ new Set(),
25153
+ latestAssistantUsage: void 0,
25154
+ compactedSinceLatestAssistantUsage: false,
25148
25155
  retrying: false,
25149
25156
  nextSyntheticAssistantBlockIndex: -1
25150
25157
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycodium-ai/agent-claude",
3
- "version": "0.2.2488",
3
+ "version": "0.2.2510",
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-executor-testing": "0.0.0",
28
- "@ycodium-ai/plugin-api": "0.2.2488"
27
+ "@ycodium-ai/plugin-api": "0.2.2510",
28
+ "ycodium-executor-testing": "0.0.0"
29
29
  },
30
30
  "ycodium": {
31
31
  "plugin": "./dist/index.js",