@clawos-dev/clawd 0.2.26 → 0.2.27

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/cli.cjs +115 -9
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -4398,10 +4398,17 @@ var init_methods = __esm({
4398
4398
  });
4399
4399
 
4400
4400
  // ../protocol/src/events.ts
4401
- var HISTORY_USER_META_VALUES, ASK_USER_QUESTION_TOOL_NAME;
4401
+ var SESSION_STATUS_VALUES, HISTORY_USER_META_VALUES, ASK_USER_QUESTION_TOOL_NAME;
4402
4402
  var init_events = __esm({
4403
4403
  "../protocol/src/events.ts"() {
4404
4404
  "use strict";
4405
+ SESSION_STATUS_VALUES = [
4406
+ "idle",
4407
+ "running",
4408
+ "stopped",
4409
+ "error",
4410
+ "observing"
4411
+ ];
4405
4412
  HISTORY_USER_META_VALUES = [
4406
4413
  "task-notification",
4407
4414
  "slash-command",
@@ -8566,12 +8573,13 @@ var init_zod = __esm({
8566
8573
  });
8567
8574
 
8568
8575
  // ../protocol/src/schemas.ts
8569
- var UsageSchema, ContextUsageSchema, sessionMetaShape, SessionMetaSchema, ModelInfoSchema, ModeInfoSchema, ConfigFieldSchemaSchema, CapabilitiesGetArgs, CapabilitiesResponseSchema, AllowRuleSchema, SessionFileSchema, ParsedEventBase, HistoryUserMetaSchema, SubagentToolStatsSchema, StructuredPatchHunkSchema, ToolResultExtraSchema, MemoryEntrySchema, AskQuestionOptionSchema, AskQuestionItemSchema, ParsedEventSchema, SessionCreateArgs, SessionIdArgs, SessionUpdateArgs, SessionSendArgs, SessionRewindArgs, SessionRewindResponseSchema, SessionRewindDiffArgs, RewindDiffHunkSchema, RewindDiffFileSchema, SessionRewindDiffResponseSchema, SessionRewindableMessageIdsArgs, SessionRewindableMessageIdsResponseSchema, SessionResumeArgs, SessionForkArgs, SessionForkResponseSchema, SessionObserveArgs, SessionEventsArgs, PermissionRespondArgs, HistoryListArgs, HistoryReadArgs, HistorySubagentsArgs, HistorySubagentReadArgs, WorkspaceListArgs, WorkspaceReadArgs, SkillsListArgs, SessionSubscribeArgs, SessionPinArgs, SessionReorderPinsArgs, GitRootArgs, GitRootResponseSchema, GitBranchArgs, GitBranchResponseSchema, GitBranchesArgs, GitBranchesResponseSchema, GitWorktreePrefixArgs, GitWorktreePrefixResponseSchema, GitWorktreeCreateArgs, GitWorktreeCreateResponseSchema, GitWorktreeRemoveArgs, GitWorktreeRemoveResponseSchema, HistoryRecentDirsArgs, RecentDirEntrySchema, HistoryRecentDirsResponseSchema, SessionQuestionFrameSchema, AnswerQuestionArgs, AnswerQuestionResponseSchema, AuthRequestFrameSchema, AuthOkFrameSchema, TunnelExitedEventSchema;
8576
+ var SessionStatusSchema, UsageSchema, ContextUsageSchema, sessionMetaShape, SessionMetaSchema, ModelInfoSchema, ModeInfoSchema, ConfigFieldSchemaSchema, CapabilitiesGetArgs, CapabilitiesResponseSchema, AllowRuleSchema, SessionFileSchema, ParsedEventBase, HistoryUserMetaSchema, SubagentToolStatsSchema, StructuredPatchHunkSchema, ToolResultExtraSchema, MemoryEntrySchema, AskQuestionOptionSchema, AskQuestionItemSchema, ParsedEventSchema, SessionCreateArgs, SessionIdArgs, SessionUpdateArgs, SessionSendArgs, SessionRewindArgs, SessionRewindResponseSchema, SessionRewindDiffArgs, RewindDiffHunkSchema, RewindDiffFileSchema, SessionRewindDiffResponseSchema, SessionRewindableMessageIdsArgs, SessionRewindableMessageIdsResponseSchema, SessionResumeArgs, SessionForkArgs, SessionForkResponseSchema, SessionObserveArgs, SessionEventsArgs, PermissionRespondArgs, HistoryListArgs, HistoryReadArgs, HistorySubagentsArgs, HistorySubagentReadArgs, WorkspaceListArgs, WorkspaceReadArgs, SkillsListArgs, SessionSubscribeArgs, SessionPinArgs, SessionReorderPinsArgs, GitRootArgs, GitRootResponseSchema, GitBranchArgs, GitBranchResponseSchema, GitBranchesArgs, GitBranchesResponseSchema, GitWorktreePrefixArgs, GitWorktreePrefixResponseSchema, GitWorktreeCreateArgs, GitWorktreeCreateResponseSchema, GitWorktreeRemoveArgs, GitWorktreeRemoveResponseSchema, HistoryRecentDirsArgs, RecentDirEntrySchema, HistoryRecentDirsResponseSchema, SessionQuestionFrameSchema, SessionQuestionClearedFrameSchema, AnswerQuestionArgs, AnswerQuestionResponseSchema, AuthRequestFrameSchema, AuthOkFrameSchema, TunnelExitedEventSchema, InfoRunningSessionSchema, InfoResponseSchema;
8570
8577
  var init_schemas = __esm({
8571
8578
  "../protocol/src/schemas.ts"() {
8572
8579
  "use strict";
8573
8580
  init_zod();
8574
8581
  init_events();
8582
+ SessionStatusSchema = external_exports.enum(SESSION_STATUS_VALUES);
8575
8583
  UsageSchema = external_exports.object({
8576
8584
  input_tokens: external_exports.number().int().nonnegative().optional(),
8577
8585
  cache_read_input_tokens: external_exports.number().int().nonnegative().optional(),
@@ -9034,6 +9042,13 @@ var init_schemas = __esm({
9034
9042
  // UI 单卡承载多 question;空数组语义无效,schema 必拒
9035
9043
  questions: external_exports.array(AskQuestionItemSchema).min(1)
9036
9044
  });
9045
+ SessionQuestionClearedFrameSchema = external_exports.object({
9046
+ type: external_exports.literal("session:question:cleared"),
9047
+ sessionId: external_exports.string().min(1),
9048
+ toolUseId: external_exports.string().min(1),
9049
+ // record<string,string>:与 AnswerQuestionArgs.answers 同形状(question text → label)
9050
+ answers: external_exports.record(external_exports.string(), external_exports.string()).optional()
9051
+ });
9037
9052
  AnswerQuestionArgs = external_exports.object({
9038
9053
  sessionId: external_exports.string().min(1),
9039
9054
  toolUseId: external_exports.string().min(1),
@@ -9056,6 +9071,22 @@ var init_schemas = __esm({
9056
9071
  subdomain: external_exports.string().nullable(),
9057
9072
  url: external_exports.string().nullable()
9058
9073
  });
9074
+ InfoRunningSessionSchema = external_exports.object({
9075
+ sessionId: external_exports.string().min(1),
9076
+ status: SessionStatusSchema,
9077
+ freshSpawn: external_exports.boolean(),
9078
+ pendingPermissionsCount: external_exports.number().int().nonnegative(),
9079
+ pendingQuestionsCount: external_exports.number().int().nonnegative()
9080
+ });
9081
+ InfoResponseSchema = external_exports.object({
9082
+ type: external_exports.literal("info"),
9083
+ version: external_exports.string(),
9084
+ protocolVersion: external_exports.number(),
9085
+ hostname: external_exports.string(),
9086
+ os: external_exports.string(),
9087
+ tools: external_exports.array(external_exports.object({ id: external_exports.string(), available: external_exports.boolean() })),
9088
+ runningSessions: external_exports.array(InfoRunningSessionSchema)
9089
+ });
9059
9090
  }
9060
9091
  });
9061
9092
 
@@ -15689,6 +15720,16 @@ function applyCommand(state, command, deps) {
15689
15720
  return { state: nextState, effects };
15690
15721
  }
15691
15722
  case "stop": {
15723
+ for (const toolUseId of Object.keys(state.pendingQuestions ?? {})) {
15724
+ effects.push({
15725
+ kind: "emit-frame",
15726
+ frame: {
15727
+ type: "session:question:cleared",
15728
+ sessionId,
15729
+ toolUseId
15730
+ }
15731
+ });
15732
+ }
15692
15733
  next.pendingPermissions = {};
15693
15734
  next.pendingQuestions = {};
15694
15735
  if (next.procAlive) {
@@ -15716,6 +15757,16 @@ function applyCommand(state, command, deps) {
15716
15757
  return { state: next, effects };
15717
15758
  }
15718
15759
  case "delete": {
15760
+ for (const toolUseId of Object.keys(state.pendingQuestions ?? {})) {
15761
+ effects.push({
15762
+ kind: "emit-frame",
15763
+ frame: {
15764
+ type: "session:question:cleared",
15765
+ sessionId,
15766
+ toolUseId
15767
+ }
15768
+ });
15769
+ }
15719
15770
  next.pendingPermissions = {};
15720
15771
  next.pendingQuestions = {};
15721
15772
  if (next.procAlive) {
@@ -15827,6 +15878,17 @@ function reduceSession(state, input, deps) {
15827
15878
  const next = cloneState(state);
15828
15879
  next.procAlive = false;
15829
15880
  next.status = "stopped";
15881
+ const sessionId = next.file.sessionId;
15882
+ const clearedEffects = Object.keys(state.pendingQuestions ?? {}).map(
15883
+ (toolUseId) => ({
15884
+ kind: "emit-frame",
15885
+ frame: {
15886
+ type: "session:question:cleared",
15887
+ sessionId,
15888
+ toolUseId
15889
+ }
15890
+ })
15891
+ );
15830
15892
  next.pendingQuestions = {};
15831
15893
  return {
15832
15894
  state: next,
@@ -15835,11 +15897,12 @@ function reduceSession(state, input, deps) {
15835
15897
  kind: "emit-frame",
15836
15898
  frame: {
15837
15899
  type: "session:status",
15838
- sessionId: next.file.sessionId,
15900
+ sessionId,
15839
15901
  status: next.status,
15840
15902
  exitCode: input.code
15841
15903
  }
15842
- }
15904
+ },
15905
+ ...clearedEffects
15843
15906
  ]
15844
15907
  };
15845
15908
  }
@@ -15913,6 +15976,7 @@ function reduceSession(state, input, deps) {
15913
15976
  ...baseInput,
15914
15977
  answers: input.answers
15915
15978
  };
15979
+ const sessionId = next.file.sessionId;
15916
15980
  return {
15917
15981
  state: next,
15918
15982
  effects: [
@@ -15920,6 +15984,17 @@ function reduceSession(state, input, deps) {
15920
15984
  kind: "send-control-response-allow-with-input",
15921
15985
  requestId: pending.requestId,
15922
15986
  updatedInput
15987
+ },
15988
+ // cleared(with answers) broadcast:UI dispatch session:question:submitted,
15989
+ // pendingQuestions[toolUseId] 转 submitted 只读态。target 缺省=broadcast。
15990
+ {
15991
+ kind: "emit-frame",
15992
+ frame: {
15993
+ type: "session:question:cleared",
15994
+ sessionId,
15995
+ toolUseId: input.toolUseId,
15996
+ answers: input.answers
15997
+ }
15923
15998
  }
15924
15999
  ]
15925
16000
  };
@@ -16795,7 +16870,10 @@ var SessionManager = class {
16795
16870
  running.push({
16796
16871
  sessionId: sid,
16797
16872
  status: compressStatus(st.status),
16798
- freshSpawn: st.freshSpawn
16873
+ freshSpawn: st.freshSpawn,
16874
+ // sidebar awaiting-user baseline:UI 端据此填 anonymous slot 直到 push 帧带真实 toolUseId
16875
+ pendingPermissionsCount: Object.keys(st.pendingPermissions).length,
16876
+ pendingQuestionsCount: Object.keys(st.pendingQuestions).length
16799
16877
  });
16800
16878
  }
16801
16879
  return { runningSessions: running };
@@ -17525,9 +17603,15 @@ var LocalWsServer = class {
17525
17603
  return;
17526
17604
  }
17527
17605
  if (frame.type === "session:subscribe" && typeof frame.sessionId === "string") {
17528
- addSubscription(client, frame.sessionId);
17606
+ const sessionId = frame.sessionId;
17607
+ addSubscription(client, sessionId);
17529
17608
  if (typeof frame.requestId === "string") {
17530
- this.safeSend(this.clients.get(client.id).ws, { type: "subscribed", requestId: frame.requestId, sessionId: frame.sessionId });
17609
+ this.safeSend(this.clients.get(client.id).ws, { type: "subscribed", requestId: frame.requestId, sessionId });
17610
+ }
17611
+ try {
17612
+ this.opts.onSubscribe?.(client, sessionId);
17613
+ } catch (err) {
17614
+ this.logger?.warn("onSubscribe hook threw", { err: err.message });
17531
17615
  }
17532
17616
  return;
17533
17617
  }
@@ -19040,7 +19124,28 @@ async function startDaemon(config) {
19040
19124
  logger,
19041
19125
  readyFrameBuilder: () => buildReadyFrame({ manager, getAdapter }),
19042
19126
  protocolVersion: PROTOCOL_VERSION,
19043
- authGate: authGate ?? void 0
19127
+ authGate: authGate ?? void 0,
19128
+ // 订阅成功后给该 client 重放 in-flight pendingQuestions(plan: clawd-question-server-truth)。
19129
+ // daemon 是 pendingQuestions 的唯一 source of truth;新 client 接入 / 刷新页面时
19130
+ // 把当前所有未决 question 以 session:question 帧定向回放,让 UI 不再误显示 Ended。
19131
+ // 形状与 reducer permission_request 分支构造的 session:question 帧一致;UI 不区分
19132
+ // 首播 vs 重放(last-write-wins,详见 protocol/events.ts JSDoc)。
19133
+ onSubscribe: (client, sessionId) => {
19134
+ const runner = manager.getActive(sessionId);
19135
+ if (!runner) return;
19136
+ const pendingQuestions = runner.getState().pendingQuestions ?? {};
19137
+ for (const [toolUseId, entry] of Object.entries(pendingQuestions)) {
19138
+ const rawInput = entry.input;
19139
+ const questions = rawInput && typeof rawInput === "object" && "questions" in rawInput ? rawInput.questions : void 0;
19140
+ client.send({
19141
+ type: "session:question",
19142
+ sessionId,
19143
+ toolUseId,
19144
+ requestId: entry.requestId,
19145
+ questions: Array.isArray(questions) ? questions : []
19146
+ });
19147
+ }
19148
+ }
19044
19149
  });
19045
19150
  transport = wsServer;
19046
19151
  const wss = wsServer;
@@ -19159,7 +19264,8 @@ ${bar}
19159
19264
  stop: shutdown,
19160
19265
  url,
19161
19266
  tunnelUrl: stateSnapshot.tunnelUrl ?? null,
19162
- authToken: resolvedAuthToken
19267
+ authToken: resolvedAuthToken,
19268
+ manager
19163
19269
  };
19164
19270
  }
19165
19271
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawos-dev/clawd",
3
- "version": "0.2.26",
3
+ "version": "0.2.27",
4
4
  "description": "Standalone clawd daemon — Claude Code (and future Codex) session server over WebSocket",
5
5
  "type": "module",
6
6
  "license": "MIT",