@appchy/jarvis 0.1.36 → 0.1.37

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/dev/bin.js CHANGED
@@ -28752,7 +28752,8 @@ ${content}`;
28752
28752
  const entry = activeRuns.get(req.runId);
28753
28753
  if (entry?.sdk?.setPermissionMode) {
28754
28754
  try {
28755
- await entry.sdk.setPermissionMode(req.mode);
28755
+ const translated = toClaudeCode({ mode: req.mode });
28756
+ await entry.sdk.setPermissionMode(translated);
28756
28757
  } catch (err) {
28757
28758
  logger.sys.warn("[claude-code] setPermissionMode failed", {
28758
28759
  runId: req.runId,
@@ -29661,7 +29662,7 @@ function buildChat(req) {
29661
29662
  };
29662
29663
  }
29663
29664
  var SESSION_CACHE_NAMESPACE = "sessions";
29664
- var SESSION_CACHE_VERSION = 10;
29665
+ var SESSION_CACHE_VERSION = 11;
29665
29666
  async function readSessionCacheEntry(req) {
29666
29667
  const { value } = await readCacheEntry({
29667
29668
  namespace: SESSION_CACHE_NAMESPACE,
@@ -29781,6 +29782,36 @@ async function recordExternalId(_ctx, req) {
29781
29782
  });
29782
29783
  await writeSessionCacheEntry({ sessionId: req.chatId, entry: next });
29783
29784
  }
29785
+ async function recordTurnSettings(_ctx, req) {
29786
+ const { entry: existing } = await readSessionCacheEntry({ sessionId: req.chatId });
29787
+ const nextSkill = req.skill ?? void 0;
29788
+ const nextEnabled = req.enabledTools?.length ? req.enabledTools : void 0;
29789
+ if (existing?.lastSkill === nextSkill && arraysEqual(existing?.lastEnabledTools, nextEnabled)) {
29790
+ return;
29791
+ }
29792
+ const base = existing ?? createSessionCacheEntry({
29793
+ filePath: "",
29794
+ rollup: createEmptyRollup(),
29795
+ pendingToolUses: {},
29796
+ progress: { bytes: 0, line: 0, mtimeMs: 0 },
29797
+ controller: "jarvis"
29798
+ });
29799
+ const next = {
29800
+ ...base,
29801
+ ...nextSkill ? { lastSkill: nextSkill } : { lastSkill: void 0 },
29802
+ ...nextEnabled ? { lastEnabledTools: nextEnabled } : { lastEnabledTools: void 0 }
29803
+ };
29804
+ await writeSessionCacheEntry({ sessionId: req.chatId, entry: next });
29805
+ }
29806
+ function arraysEqual(a, b) {
29807
+ if (a === b) return true;
29808
+ if (!a || !b) return !a && !b;
29809
+ if (a.length !== b.length) return false;
29810
+ for (let i = 0; i < a.length; i++) {
29811
+ if (a[i] !== b[i]) return false;
29812
+ }
29813
+ return true;
29814
+ }
29784
29815
  var TRANSCRIPT_CACHE_NAMESPACE = "transcripts";
29785
29816
  var TRANSCRIPT_CACHE_VERSION = 10;
29786
29817
  async function readTranscriptCacheEntry(req) {
@@ -30723,8 +30754,10 @@ function getTaskProvider() {
30723
30754
 
30724
30755
  // src/resume.ts
30725
30756
  function buildResumePayload(req) {
30726
- const { output, inputId, controller, toolUseId } = req;
30757
+ const { output, inputId, controller, toolUseId, carryOver } = req;
30727
30758
  const mode = output.action === "allow" && output.mode ? output.mode : void 0;
30759
+ const skill2 = carryOver?.skill;
30760
+ const enabledTools = carryOver?.enabledTools?.length ? carryOver.enabledTools : void 0;
30728
30761
  const allowed = output.action === "allow";
30729
30762
  const rejectionContent = output.feedback && output.feedback.trim().length > 0 ? output.feedback : "User denied this tool call.";
30730
30763
  if (controller !== "claudeCode" && toolUseId) {
@@ -30734,24 +30767,36 @@ function buildResumePayload(req) {
30734
30767
  toolUseId,
30735
30768
  content: "User approved this tool call.",
30736
30769
  denied: false,
30737
- ...mode ? { mode } : {}
30770
+ ...mode ? { mode } : {},
30771
+ ...skill2 ? { skill: skill2 } : {},
30772
+ ...enabledTools ? { enabledTools } : {}
30738
30773
  };
30739
30774
  }
30740
30775
  return {
30741
30776
  kind: "tool_result",
30742
30777
  toolUseId,
30743
30778
  content: rejectionContent,
30744
- denied: true
30779
+ denied: true,
30780
+ ...skill2 ? { skill: skill2 } : {},
30781
+ ...enabledTools ? { enabledTools } : {}
30745
30782
  };
30746
30783
  }
30747
30784
  const id = `resume-${inputId}`;
30748
30785
  if (allowed) {
30749
30786
  const content = "I approve this tool call. Please continue.";
30750
- return mode ? { kind: "user_message", message: { id, content }, mode } : { kind: "user_message", message: { id, content } };
30787
+ return {
30788
+ kind: "user_message",
30789
+ message: { id, content },
30790
+ ...mode ? { mode } : {},
30791
+ ...skill2 ? { skill: skill2 } : {},
30792
+ ...enabledTools ? { enabledTools } : {}
30793
+ };
30751
30794
  }
30752
30795
  return {
30753
30796
  kind: "user_message",
30754
- message: { id, content: rejectionContent }
30797
+ message: { id, content: rejectionContent },
30798
+ ...skill2 ? { skill: skill2 } : {},
30799
+ ...enabledTools ? { enabledTools } : {}
30755
30800
  };
30756
30801
  }
30757
30802
 
@@ -32031,6 +32076,10 @@ async function resolveInteraction(ctx, req) {
32031
32076
  }
32032
32077
  const { entry } = await readSessionCacheEntry({ sessionId: req.sessionId });
32033
32078
  const controller = entry?.controller;
32079
+ const carryOver = entry ? {
32080
+ ...entry.lastSkill ? { skill: entry.lastSkill } : {},
32081
+ ...entry.lastEnabledTools?.length ? { enabledTools: entry.lastEnabledTools } : {}
32082
+ } : void 0;
32034
32083
  const resume = buildResumePayload({
32035
32084
  output: req.output,
32036
32085
  inputId: req.inputId,
@@ -32038,7 +32087,8 @@ async function resolveInteraction(ctx, req) {
32038
32087
  // `pendingInput.id === toolUseID` by construction (see
32039
32088
  // `convertGenericTool` / `fromSdkInput` in the provider), so
32040
32089
  // `req.inputId` IS the open tool_use_id for tool interactions.
32041
- toolUseId: req.inputId
32090
+ toolUseId: req.inputId,
32091
+ ...carryOver && (carryOver.skill || carryOver.enabledTools) ? { carryOver } : {}
32042
32092
  });
32043
32093
  const messages = resume.kind === "tool_result" ? [
32044
32094
  {
@@ -32059,7 +32109,9 @@ async function resolveInteraction(ctx, req) {
32059
32109
  chatId: req.sessionId,
32060
32110
  session: { resume: req.sessionId },
32061
32111
  messages,
32062
- ...resume.mode ? { mode: resume.mode } : {}
32112
+ ...resume.mode ? { mode: resume.mode } : {},
32113
+ ...resume.skill ? { skill: resume.skill } : {},
32114
+ ...resume.enabledTools?.length ? { enabledTools: resume.enabledTools } : {}
32063
32115
  });
32064
32116
  return { resumed: true };
32065
32117
  }
@@ -32114,7 +32166,11 @@ async function runTask(ctx, req) {
32114
32166
  ...extraTools.length > 0 ? { tools: extraTools } : {}
32115
32167
  };
32116
32168
  if (!normalized.code && req.chatId) {
32117
- const task = await getTaskProvider().get(ctx, { id: req.chatId });
32169
+ const { entry: sessionEntry } = await readSessionCacheEntry({
32170
+ sessionId: req.chatId
32171
+ });
32172
+ const taskLookupId = sessionEntry?.taskId ?? req.chatId;
32173
+ const task = await getTaskProvider().get(ctx, { id: taskLookupId });
32118
32174
  if (task) {
32119
32175
  const workdir = task.state?.workdir;
32120
32176
  const repo = task.config?.repo;
@@ -32124,6 +32180,13 @@ async function runTask(ctx, req) {
32124
32180
  ...repo ? { repo } : {}
32125
32181
  };
32126
32182
  }
32183
+ } else {
32184
+ logger.warn(ctx, "[runTask] task lookup miss \u2014 code.workdir unset", {
32185
+ runId,
32186
+ chatId: req.chatId,
32187
+ taskLookupId,
32188
+ sessionTaskId: sessionEntry?.taskId ?? null
32189
+ });
32127
32190
  }
32128
32191
  }
32129
32192
  if (!normalized.code?.workdir && normalized.code?.repo) {
@@ -32191,6 +32254,19 @@ async function runTask(ctx, req) {
32191
32254
  publish(ctx, "chat.status", { chatId: runId, status: "busy" });
32192
32255
  runningChats.add(runId);
32193
32256
  logger.info(ctx, "[runTask.add]", { runId, runningChatsSize: runningChats.size });
32257
+ if (req.chatId) {
32258
+ void recordTurnSettings(ctx, {
32259
+ chatId: req.chatId,
32260
+ ...normalized.skill ? { skill: normalized.skill } : {},
32261
+ ...normalized.enabledTools?.length ? { enabledTools: normalized.enabledTools } : {}
32262
+ }).catch((err) => {
32263
+ logger.warn(ctx, "[runTask] recordTurnSettings failed", {
32264
+ runId,
32265
+ chatId: req.chatId,
32266
+ error: err instanceof Error ? err.message : String(err)
32267
+ });
32268
+ });
32269
+ }
32194
32270
  try {
32195
32271
  const result = await getProvider().run(ctx, normalized, {
32196
32272
  onEvent: (event) => publish(ctx, "chat.event", { chatId: runId, event }),
@@ -32274,7 +32350,8 @@ async function runTask(ctx, req) {
32274
32350
  ...req.modelId ? { modelId: req.modelId } : {},
32275
32351
  ...req.thinking ? { thinking: req.thinking } : {},
32276
32352
  ...req.enabledTools?.length ? { enabledTools: req.enabledTools } : {},
32277
- ...req.skill ? { skill: req.skill } : {}
32353
+ ...req.skill ? { skill: req.skill } : {},
32354
+ ...req.references?.length ? { references: req.references } : {}
32278
32355
  };
32279
32356
  const feedbackEvent = {
32280
32357
  id: queued.id,
@@ -32658,6 +32735,22 @@ async function send(ctx, req) {
32658
32735
  publish(ctx, "chat.event", { chatId: req.chatId, event: userEvent });
32659
32736
  await appendCachedEvent({ sessionId: req.chatId, event: userEvent });
32660
32737
  if (isRunning(req.chatId)) {
32738
+ if (req.mode) {
32739
+ await setMode(ctx, { runId: req.chatId, mode: req.mode });
32740
+ }
32741
+ if (req.model) {
32742
+ await setModel(ctx, { runId: req.chatId, model: req.model });
32743
+ }
32744
+ if (req.thinking) {
32745
+ await setThinking(ctx, { runId: req.chatId, thinking: req.thinking });
32746
+ }
32747
+ if (req.skill || req.enabledTools?.length) {
32748
+ logger.warn(ctx, "[runner.chat.send] skill/enabledTools change ignored mid-query", {
32749
+ chatId: req.chatId,
32750
+ skill: req.skill ?? null,
32751
+ enabledToolsCount: req.enabledTools?.length ?? 0
32752
+ });
32753
+ }
32661
32754
  const queued = await enqueueMessage(ctx, {
32662
32755
  runId: req.chatId,
32663
32756
  content: req.content,
@@ -32768,6 +32861,12 @@ function parseUpdate(params) {
32768
32861
  }
32769
32862
  async function update(ctx, req) {
32770
32863
  const { chatId, patch } = req;
32864
+ const { entry: session } = await readSessionCacheEntry({ sessionId: chatId });
32865
+ if (session?.controller === "claudeCode") {
32866
+ throw new Error(
32867
+ "controller_mismatch: this chat is owned by the terminal Claude Code CLI. Send a message to take over before changing settings."
32868
+ );
32869
+ }
32771
32870
  if (patch.mode) {
32772
32871
  await setMode(ctx, { runId: chatId, mode: patch.mode });
32773
32872
  }
@@ -32817,7 +32916,11 @@ async function get(_ctx, req) {
32817
32916
  prefs: {
32818
32917
  mode: transcript.mode ?? "auto",
32819
32918
  model: session?.rollup.model ?? "",
32820
- thinking: { type: "disabled" }
32919
+ // Same source as `mode`/`model` — the rollup is populated by the
32920
+ // JSONL projector from the latest assistant turn's thinking config.
32921
+ // Cold-loaded CC-watched chats reflect the session's current
32922
+ // thinking setting in the picker without walking the event stream.
32923
+ thinking: session?.rollup.thinking ?? { type: "disabled" }
32821
32924
  },
32822
32925
  isRunning: isRunning(req.chatId),
32823
32926
  ...session?.controller ? { controller: session.controller } : {}