@ycodium-ai/agent-claude 0.2.3265 → 0.2.3306

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 +120 -45
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -22955,19 +22955,21 @@ function claudeSdkPermission(rules, mode) {
22955
22955
  }
22956
22956
 
22957
22957
  // src/adapter/permissionMode.ts
22958
+ var permissionControlError = (method, cause) => new Error(`${method} failed: ${toMessage(cause, String(cause))}`, { cause });
22958
22959
  var sameRules = (a, b3) => a.join("\n") === b3.join("\n");
22959
22960
  var permissionAllowInSync = (context) => sameRules(
22960
22961
  claudeSdkPermission(context.permissionRules, context.currentPermissionMode ?? "default").allow,
22961
22962
  context.currentPermissionAllow
22962
22963
  );
22963
- async function applyClaudePermissionMode(context, mode, failAs) {
22964
+ async function applyClaudePermissionMode(context, mode, control) {
22964
22965
  const sdk = claudeSdkPermission(context.permissionRules, mode);
22965
22966
  try {
22966
22967
  await context.query.setPermissionMode(sdk.mode);
22967
22968
  } catch (cause) {
22968
- throw toRequestError(failAs.threadId, failAs.method, cause);
22969
+ throw permissionControlError(control.method, cause);
22969
22970
  }
22970
22971
  context.currentPermissionMode = mode;
22972
+ control.onModeApplied?.();
22971
22973
  const allow = sdk.allow;
22972
22974
  if (sameRules(allow, context.currentPermissionAllow)) return;
22973
22975
  try {
@@ -22975,7 +22977,7 @@ async function applyClaudePermissionMode(context, mode, failAs) {
22975
22977
  permissions: allow.length > 0 ? { allow: [...allow] } : null
22976
22978
  });
22977
22979
  } catch (cause) {
22978
- throw toRequestError(failAs.threadId, "session/applyFlagSettings", cause);
22980
+ throw permissionControlError("session/applyFlagSettings", cause);
22979
22981
  }
22980
22982
  context.currentPermissionAllow = allow;
22981
22983
  }
@@ -23037,16 +23039,22 @@ var makeSendTurn = (deps) => {
23037
23039
  );
23038
23040
  context.currentEffort = getEffectiveClaudeAgentEffort(turnEffort ?? null) ?? void 0;
23039
23041
  }
23040
- if (input.interactionMode === "plan") {
23041
- await applyClaudePermissionMode(context, "plan", {
23042
- threadId: input.threadId,
23043
- method: "turn/setPermissionMode"
23044
- });
23045
- } else if (input.interactionMode === "default") {
23046
- await applyClaudePermissionMode(context, context.basePermissionMode ?? "default", {
23047
- threadId: input.threadId,
23048
- method: "turn/setPermissionMode"
23049
- });
23042
+ try {
23043
+ if (input.interactionMode === "plan") {
23044
+ await applyClaudePermissionMode(context, "plan", {
23045
+ method: "turn/setPermissionMode"
23046
+ });
23047
+ } else if (input.interactionMode === "default") {
23048
+ await applyClaudePermissionMode(context, context.basePermissionMode ?? "default", {
23049
+ method: "turn/setPermissionMode"
23050
+ });
23051
+ }
23052
+ } catch (cause) {
23053
+ const rejected = Object.assign(
23054
+ cause instanceof Error ? cause : new Error(String(cause)),
23055
+ { code: "provider-rejected" }
23056
+ );
23057
+ throw rejected;
23050
23058
  }
23051
23059
  const turnCapsForPrompt = claudeModelCapabilities(
23052
23060
  modelSelection?.model,
@@ -23155,6 +23163,16 @@ function claudeTotalProcessedTokens(value) {
23155
23163
  return total > 0 ? total : void 0;
23156
23164
  }
23157
23165
  var CLAUDE_COMPACTION_SUMMARY_MAX_CHARS = 8e3;
23166
+ function beginClaudeCompaction(context, randomUUIDv4) {
23167
+ if (!context.compactionInProgress) {
23168
+ context.compaction = {
23169
+ compactionId: randomUUIDv4(),
23170
+ trigger: context.pendingManualCompaction ? "manual" : "automatic"
23171
+ };
23172
+ context.compactionInProgress = true;
23173
+ context.pendingManualCompaction = false;
23174
+ }
23175
+ }
23158
23176
  function mergeClaudeCompactionSnapshot(snapshot, metadata) {
23159
23177
  const preTokens = finiteNonNegativeInteger(metadata?.pre_tokens);
23160
23178
  const postTokens = finiteNonNegativeInteger(metadata?.post_tokens);
@@ -23241,11 +23259,50 @@ function compactBoundaryTokenUsageSnapshot(message, contextWindow, totalProcesse
23241
23259
  }
23242
23260
 
23243
23261
  // src/adapter/sessionCallbacks.ts
23262
+ var CONTEXT_AFTER_COMPACTION_TIMEOUT_MS = 5e3;
23244
23263
  var makeSessionCallbacks = (deps) => {
23245
23264
  const { emitter, ensureSyntheticTurn, emitProposedPlanCompleted } = deps;
23246
23265
  const { randomUUIDv4, makeEventStamp, eventHeader, offerRuntimeEvent } = emitter;
23247
23266
  const forSession = (session) => {
23248
23267
  const { waitSessionContext, pendingApprovals, pendingUserInputs } = session;
23268
+ let sessionContext;
23269
+ const handlePreCompact = async () => {
23270
+ const context = await waitSessionContext();
23271
+ if (context) {
23272
+ sessionContext = context;
23273
+ beginClaudeCompaction(context, randomUUIDv4);
23274
+ }
23275
+ return {};
23276
+ };
23277
+ const handleSessionStart = async (hookInput) => {
23278
+ if (hookInput.source !== "compact" || session.contextAfterCompaction === void 0) return {};
23279
+ sessionContext ??= await waitSessionContext();
23280
+ const compactionId = sessionContext?.compaction?.compactionId;
23281
+ if (compactionId === void 0) return {};
23282
+ const signal = AbortSignal.timeout(CONTEXT_AFTER_COMPACTION_TIMEOUT_MS);
23283
+ const aborted = Promise.withResolvers();
23284
+ const onAbort = () => aborted.reject(signal.reason);
23285
+ signal.addEventListener("abort", onAbort, { once: true });
23286
+ try {
23287
+ signal.throwIfAborted();
23288
+ const context = await Promise.race([
23289
+ aborted.promise,
23290
+ session.contextAfterCompaction({ compactionId, signal })
23291
+ ]);
23292
+ signal.throwIfAborted();
23293
+ return typeof context === "string" && context.length > 0 ? {
23294
+ hookSpecificOutput: {
23295
+ hookEventName: "SessionStart",
23296
+ additionalContext: context
23297
+ }
23298
+ } : {};
23299
+ } catch {
23300
+ session.log.warn("claude.compaction.contextUnavailable");
23301
+ return {};
23302
+ } finally {
23303
+ signal.removeEventListener("abort", onAbort);
23304
+ }
23305
+ };
23249
23306
  const handleAskUserQuestion = async (context, toolInput, callbackOptions) => {
23250
23307
  const requestId = randomUUIDv4();
23251
23308
  const rawQuestions = Array.isArray(toolInput.questions) ? toolInput.questions : [];
@@ -23514,7 +23571,7 @@ var makeSessionCallbacks = (deps) => {
23514
23571
  });
23515
23572
  };
23516
23573
  const onUserDialog = (request, callbackOptions) => handleResumeDialog(request, callbackOptions);
23517
- return { canUseTool, onUserDialog, handlePostCompact };
23574
+ return { canUseTool, onUserDialog, handlePostCompact, handlePreCompact, handleSessionStart };
23518
23575
  };
23519
23576
  return { forSession };
23520
23577
  };
@@ -23591,18 +23648,22 @@ var makeSessionControls = (deps) => {
23591
23648
  return;
23592
23649
  }
23593
23650
  const permissionMode = claudePermissionModeFor(runtimeMode);
23594
- context.basePermissionMode = permissionMode;
23595
- context.session = {
23596
- ...context.session,
23597
- runtimeMode,
23598
- nativeModeId: permissionMode,
23599
- updatedAt: nowIso()
23651
+ const commitMode = () => {
23652
+ context.basePermissionMode = permissionMode;
23653
+ context.session = {
23654
+ ...context.session,
23655
+ runtimeMode,
23656
+ nativeModeId: permissionMode,
23657
+ updatedAt: nowIso()
23658
+ };
23600
23659
  };
23601
23660
  if (context.currentPermissionMode !== "plan") {
23602
23661
  await applyClaudePermissionMode(context, permissionMode, {
23603
- threadId,
23604
- method: "session/setPermissionMode"
23662
+ method: "session/setPermissionMode",
23663
+ onModeApplied: commitMode
23605
23664
  });
23665
+ } else {
23666
+ commitMode();
23606
23667
  }
23607
23668
  if (permissionMode !== "bypassPermissions") {
23608
23669
  return;
@@ -23616,17 +23677,21 @@ var makeSessionControls = (deps) => {
23616
23677
  const context = requireSession(threadId);
23617
23678
  if (!isClaudeNativeModeId(nativeModeId)) return;
23618
23679
  if (context.currentPermissionMode === nativeModeId && permissionAllowInSync(context)) return;
23619
- context.basePermissionMode = nativeModeId;
23620
- context.session = {
23621
- ...context.session,
23622
- nativeModeId,
23623
- updatedAt: nowIso()
23680
+ const commitMode = () => {
23681
+ context.basePermissionMode = nativeModeId;
23682
+ context.session = {
23683
+ ...context.session,
23684
+ nativeModeId,
23685
+ updatedAt: nowIso()
23686
+ };
23624
23687
  };
23625
23688
  if (context.currentPermissionMode !== "plan" || nativeModeId === "plan") {
23626
23689
  await applyClaudePermissionMode(context, nativeModeId, {
23627
- threadId,
23628
- method: "session/setPermissionMode"
23690
+ method: "session/setPermissionMode",
23691
+ onModeApplied: commitMode
23629
23692
  });
23693
+ } else {
23694
+ commitMode();
23630
23695
  }
23631
23696
  if (nativeModeId !== "bypassPermissions") {
23632
23697
  return;
@@ -24174,21 +24239,26 @@ var makeStartSession = (deps) => {
24174
24239
  const liveTaskIds = /* @__PURE__ */ new Set();
24175
24240
  const contextDeferred = Promise.withResolvers();
24176
24241
  const waitSessionContext = async () => {
24242
+ let timer;
24177
24243
  try {
24178
24244
  return await Promise.race([
24179
24245
  contextDeferred.promise,
24180
- new Promise(
24181
- (resolve4) => setTimeout(() => resolve4(void 0), CLAUDE_SESSION_CONTEXT_WAIT_MS)
24182
- )
24246
+ new Promise((resolve4) => {
24247
+ timer = setTimeout(() => resolve4(void 0), CLAUDE_SESSION_CONTEXT_WAIT_MS);
24248
+ })
24183
24249
  ]);
24184
24250
  } catch {
24185
24251
  return void 0;
24252
+ } finally {
24253
+ if (timer !== void 0) clearTimeout(timer);
24186
24254
  }
24187
24255
  };
24188
- const { canUseTool, onUserDialog, handlePostCompact } = sessionCallbacks.forSession({
24256
+ const { canUseTool, onUserDialog, handlePostCompact, handlePreCompact, handleSessionStart } = sessionCallbacks.forSession({
24189
24257
  waitSessionContext,
24190
24258
  pendingApprovals,
24191
- pendingUserInputs
24259
+ pendingUserInputs,
24260
+ contextAfterCompaction: input.contextAfterCompaction,
24261
+ log
24192
24262
  });
24193
24263
  const additionalDirectories = input.cwd ? [input.cwd] : [];
24194
24264
  const mcpServers = toClaudeMcpServers(input.mcpServers);
@@ -24230,7 +24300,8 @@ var makeStartSession = (deps) => {
24230
24300
  effort: effectiveEffort
24231
24301
  } : {},
24232
24302
  permissionMode: sdkPermission.mode,
24233
- ...permissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {},
24303
+ // SDK 要在启动时允许未来切入 Bypass;当前权限仍由 permissionMode 决定。
24304
+ allowDangerouslySkipPermissions: true,
24234
24305
  ...Object.keys(querySettings).length > 0 ? { settings: querySettings } : {},
24235
24306
  ...existingResumeSessionId ? { resume: existingResumeSessionId } : {},
24236
24307
  ...newSessionId ? { sessionId: newSessionId } : {},
@@ -24238,6 +24309,16 @@ var makeStartSession = (deps) => {
24238
24309
  canUseTool,
24239
24310
  onUserDialog,
24240
24311
  hooks: {
24312
+ ...input.contextAfterCompaction === void 0 ? {} : {
24313
+ PreCompact: [{ hooks: [async () => handlePreCompact()] }],
24314
+ SessionStart: [
24315
+ {
24316
+ hooks: [
24317
+ async (hookInput) => hookInput.hook_event_name === "SessionStart" ? handleSessionStart(hookInput) : {}
24318
+ ]
24319
+ }
24320
+ ]
24321
+ },
24241
24322
  PostCompact: [
24242
24323
  {
24243
24324
  hooks: [
@@ -24902,7 +24983,8 @@ var makeSystemMessageHandler = (deps) => {
24902
24983
  ...base,
24903
24984
  type: "session.state.changed",
24904
24985
  payload: {
24905
- state: compacting ? "compacting" : "running",
24986
+ // 空闲时切权限也会收到 status:null;它不能凭空启动一轮、堵住下一条排队消息。
24987
+ state: compacting ? "compacting" : context.turnState ? "running" : "ready",
24906
24988
  reason: `status:${message.status ?? "active"}`,
24907
24989
  detail: message
24908
24990
  }
@@ -24911,14 +24993,7 @@ var makeSystemMessageHandler = (deps) => {
24911
24993
  context.compactionInProgress = false;
24912
24994
  return;
24913
24995
  }
24914
- if (!context.compactionInProgress) {
24915
- context.compaction = {
24916
- compactionId: randomUUIDv4(),
24917
- trigger: context.pendingManualCompaction ? "manual" : "automatic"
24918
- };
24919
- context.compactionInProgress = true;
24920
- context.pendingManualCompaction = false;
24921
- }
24996
+ beginClaudeCompaction(context, randomUUIDv4);
24922
24997
  offerRuntimeEvent(context, {
24923
24998
  ...base,
24924
24999
  ...eventHeader(context, await makeEventStamp()),
@@ -28388,7 +28463,7 @@ var executors = [
28388
28463
  ];
28389
28464
  var index_default = definePlugin({
28390
28465
  id: "agent-claude",
28391
- apiVersion: 31,
28466
+ apiVersion: 34,
28392
28467
  executors,
28393
28468
  activate(ctx) {
28394
28469
  capturedAttachments = ctx.attachments;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycodium-ai/agent-claude",
3
- "version": "0.2.3265",
3
+ "version": "0.2.3306",
4
4
  "description": "Claude executor: Claude Code CLI via @anthropic-ai/claude-agent-sdk.",
5
5
  "keywords": [
6
6
  "ycodium",
@@ -24,10 +24,10 @@
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.3265",
27
+ "@ycodium-ai/plugin-api": "0.2.3306",
28
28
  "ycodium-composer-tokens": "0.0.0",
29
- "ycodium-executor-testing": "0.0.0",
30
- "ycodium-jsonl-stream": "0.0.0"
29
+ "ycodium-jsonl-stream": "0.0.0",
30
+ "ycodium-executor-testing": "0.0.0"
31
31
  },
32
32
  "ycodium": {
33
33
  "plugin": "./dist/index.js",