@clawos-dev/clawd 0.2.108-beta.205.1e8d4c5 → 0.2.108-beta.206.f2600cc
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/dist/cli.cjs +595 -546
- package/dist/persona-defaults/persona-app-builder/CLAUDE.md +145 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/README.md +96 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/config.env +20 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/contract/bootstrap +22 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/contract/s.yaml.tmpl +54 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/.env.example +3 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/.fcignore +7 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/nest-cli.json +8 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/package-lock.json +4531 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/package.json +26 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/app.module.ts +14 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/main.ts +14 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/messages/messages.controller.ts +27 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/messages/messages.module.ts +9 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/messages/messages.service.ts +38 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/polyfill.ts +8 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/tsconfig.json +14 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/web/index.html +12 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/web/package-lock.json +1680 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/web/package.json +18 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/web/src/App.jsx +161 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/web/src/main.jsx +5 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/web/vite.config.js +31 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/scripts/new-extension.sh +49 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/scripts/publish.sh +78 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/scripts/remove-extension.sh +57 -0
- package/dist/persona-defaults/persona-app-builder/extension-kit/scripts/verify.sh +20 -0
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -181,12 +181,16 @@ var init_methods = __esm({
|
|
|
181
181
|
// 无 subscription 持久化:guest 端身份完全来自文件系统 + reconciled publishedExtensions.
|
|
182
182
|
"extension.install-from-channel",
|
|
183
183
|
"extension.update-from-channel",
|
|
184
|
-
// ----
|
|
185
|
-
//
|
|
186
|
-
//
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
184
|
+
// ---- app-builder Project picker (spec 2026-06-01-app-builder-project-picker-design) ----
|
|
185
|
+
// persona-app-builder 多 project 管理;schemas: ProjectMetadataSchema + 4 个 args/result 对。
|
|
186
|
+
// listProjects: readdir projects/,按目录读 .clawd-project.json
|
|
187
|
+
// createProject: 校验名 + 从 6173-6182 段分配端口 + 写元数据 + 创建空目录
|
|
188
|
+
// deleteProject: 停 dev server + rm -rf 目录 + 连带删该 project 名下所有 session
|
|
189
|
+
// updateProjectPort: 校验新端口段内 + 未被别的 project 占 + 重启 dev server
|
|
190
|
+
"appBuilder:listProjects",
|
|
191
|
+
"appBuilder:createProject",
|
|
192
|
+
"appBuilder:deleteProject",
|
|
193
|
+
"appBuilder:updateProjectPort"
|
|
190
194
|
];
|
|
191
195
|
}
|
|
192
196
|
});
|
|
@@ -248,11 +252,7 @@ var init_errors = __esm({
|
|
|
248
252
|
INTERNAL: "INTERNAL",
|
|
249
253
|
UNAUTHORIZED: "UNAUTHORIZED",
|
|
250
254
|
FORBIDDEN: "FORBIDDEN",
|
|
251
|
-
INVALID_PARAM: "INVALID_PARAM"
|
|
252
|
-
// 飞书统一身份(spec 2026-06-01 决策 #9):People/远程体系强制飞书登录。
|
|
253
|
-
// daemon 进程身份未激活为飞书 unionId 时,FEISHU_GATED_METHODS 内的 RPC 一律返回此错误;
|
|
254
|
-
// UI 据此显示登录引导(区别于 UNAUTHORIZED 的越权语义)。
|
|
255
|
-
FEISHU_LOGIN_REQUIRED: "FEISHU_LOGIN_REQUIRED"
|
|
255
|
+
INVALID_PARAM: "INVALID_PARAM"
|
|
256
256
|
};
|
|
257
257
|
ClawdError = class extends Error {
|
|
258
258
|
constructor(code, message) {
|
|
@@ -682,8 +682,8 @@ var init_parseUtil = __esm({
|
|
|
682
682
|
init_errors2();
|
|
683
683
|
init_en();
|
|
684
684
|
makeIssue = (params) => {
|
|
685
|
-
const { data, path:
|
|
686
|
-
const fullPath = [...
|
|
685
|
+
const { data, path: path59, errorMaps, issueData } = params;
|
|
686
|
+
const fullPath = [...path59, ...issueData.path || []];
|
|
687
687
|
const fullIssue = {
|
|
688
688
|
...issueData,
|
|
689
689
|
path: fullPath
|
|
@@ -994,11 +994,11 @@ var init_types = __esm({
|
|
|
994
994
|
init_parseUtil();
|
|
995
995
|
init_util();
|
|
996
996
|
ParseInputLazyPath = class {
|
|
997
|
-
constructor(parent, value,
|
|
997
|
+
constructor(parent, value, path59, key) {
|
|
998
998
|
this._cachedPath = [];
|
|
999
999
|
this.parent = parent;
|
|
1000
1000
|
this.data = value;
|
|
1001
|
-
this._path =
|
|
1001
|
+
this._path = path59;
|
|
1002
1002
|
this._key = key;
|
|
1003
1003
|
}
|
|
1004
1004
|
get path() {
|
|
@@ -4532,7 +4532,7 @@ var init_persona_schemas = __esm({
|
|
|
4532
4532
|
});
|
|
4533
4533
|
|
|
4534
4534
|
// ../protocol/src/schemas.ts
|
|
4535
|
-
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, SkillEntrySchema, AgentEntrySchema, AgentsListArgs, AgentsListResponseSchema, SessionSubscribeArgs, SessionPinArgs, PeerSessionUpsertArgs, PeerSessionUpsertResponseSchema, PeerSessionRemoveArgs, PeerSessionRemoveResponseSchema, SessionReorderPinsArgs, GitRootArgs, GitRootResponseSchema, GitBranchArgs, GitBranchResponseSchema, GitBranchesArgs, GitBranchesResponseSchema, HistoryRecentDirsArgs, RecentDirEntrySchema, HistoryRecentDirsResponseSchema, SessionQuestionFrameSchema, SessionQuestionClearedFrameSchema, AnswerQuestionArgs, AnswerQuestionResponseSchema, CancelQuestionArgs, CancelQuestionResponseSchema, AuthRequestFrameSchema, AuthOkFrameSchema, TunnelExitedEventSchema, TunnelUnavailableEventSchema, InfoRunningSessionSchema, InfoResponseSchema;
|
|
4535
|
+
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, SkillEntrySchema, AgentEntrySchema, AgentsListArgs, AgentsListResponseSchema, SessionSubscribeArgs, SessionPinArgs, PeerSessionUpsertArgs, PeerSessionUpsertResponseSchema, PeerSessionRemoveArgs, PeerSessionRemoveResponseSchema, SessionReorderPinsArgs, GitRootArgs, GitRootResponseSchema, GitBranchArgs, GitBranchResponseSchema, GitBranchesArgs, GitBranchesResponseSchema, HistoryRecentDirsArgs, RecentDirEntrySchema, HistoryRecentDirsResponseSchema, SessionQuestionFrameSchema, SessionQuestionClearedFrameSchema, AnswerQuestionArgs, AnswerQuestionResponseSchema, CancelQuestionArgs, CancelQuestionResponseSchema, AuthRequestFrameSchema, AuthOkFrameSchema, TunnelReadyEventSchema, TunnelExitedEventSchema, TunnelUnavailableEventSchema, InfoRunningSessionSchema, InfoResponseSchema, PROJECT_PORT_MIN, PROJECT_PORT_MAX, projectNameRegex, ProjectMetadataSchema, ProjectWithStatusSchema, ListProjectsArgsSchema, ListProjectsResultSchema, CreateProjectArgsSchema, CreateProjectResultSchema, DeleteProjectArgsSchema, DeleteProjectResultSchema, UpdateProjectPortArgsSchema, UpdateProjectPortResultSchema;
|
|
4536
4536
|
var init_schemas = __esm({
|
|
4537
4537
|
"../protocol/src/schemas.ts"() {
|
|
4538
4538
|
"use strict";
|
|
@@ -4629,6 +4629,10 @@ var init_schemas = __esm({
|
|
|
4629
4629
|
// owner-mode persona session 身份标识;UI 用它在 SessionList 过滤 + jump,
|
|
4630
4630
|
// daemon 用它做 idempotent dedupe + spawn 时派生 ctx.personaMode='owner'
|
|
4631
4631
|
ownerPersonaId: external_exports.string().min(1).optional(),
|
|
4632
|
+
// app-builder Project 反向索引(spec: superpowers/specs/2026-06-01-app-builder-project-picker-design.md)。
|
|
4633
|
+
// 当此 session 绑定到某个 build 中的 project 时填写;name 与 projects/<name>/ 子目录同名,
|
|
4634
|
+
// 受 projectNameSchema regex 约束。daemon session:resume 时校验该目录存在,不存在则拒。
|
|
4635
|
+
appBuilderProject: external_exports.string().regex(/^[a-z][a-z0-9-]{0,39}$/).optional(),
|
|
4632
4636
|
// listener-mode sub-session 的原始 chatId(owner-mode 不写;listener-scope 强制写入)。
|
|
4633
4637
|
// 派生 sessionId 是单向 hash `${personaId}-${tokenHash12}-${chatHash8}`,必须保留原始 chatId
|
|
4634
4638
|
// 才能让 alice 重连同一 sub-session(持久化在 alice localStorage 之外,由 daemon push 同步)。
|
|
@@ -4901,7 +4905,12 @@ var init_schemas = __esm({
|
|
|
4901
4905
|
forkedFromSessionId: external_exports.string().min(1).optional(),
|
|
4902
4906
|
// owner-mode persona session:传此字段时 daemon 自行派生 cwd 和启动参数,
|
|
4903
4907
|
// 且按 ownerPersonaId 做 idempotent dedupe(每 persona 永远只有一个 owner session)
|
|
4904
|
-
ownerPersonaId: external_exports.string().min(1).optional()
|
|
4908
|
+
ownerPersonaId: external_exports.string().min(1).optional(),
|
|
4909
|
+
// app-builder Project 绑定(spec 2026-06-01-app-builder-project-picker-design)。
|
|
4910
|
+
// UI picker 上点 idle project / 新建 project 时传入;daemon 透传写入 SessionFile.appBuilderProject。
|
|
4911
|
+
// 跟 ownerPersonaId 同层但不互斥(典型场景两者都传:ownerPersonaId='persona-app-builder' +
|
|
4912
|
+
// appBuilderProject='<project-name>')。
|
|
4913
|
+
appBuilderProject: external_exports.string().regex(/^[a-z][a-z0-9-]{0,39}$/).optional()
|
|
4905
4914
|
}).refine((args) => args.cwd != null || args.ownerPersonaId != null, {
|
|
4906
4915
|
message: "cwd \u4E0E ownerPersonaId \u81F3\u5C11\u4F20\u4E00\u4E2A"
|
|
4907
4916
|
});
|
|
@@ -5112,12 +5121,6 @@ var init_schemas = __esm({
|
|
|
5112
5121
|
* 后调 capabilityManager.recordPeerHello(capId, ownerPrincipalId, displayName)
|
|
5113
5122
|
* 把 cap.peerOwnerId / firstUsedByPeerAt 字段回写,让 owner 端 UI 在 People
|
|
5114
5123
|
* tab 顶层 PeerOwner 视图 + Personas tab 二级分组拿到对端身份。
|
|
5115
|
-
*
|
|
5116
|
-
* 飞书统一身份 Phase 1 (2026-06-01):取值升级为飞书 union_id(owner 已飞书登录时;
|
|
5117
|
-
* 来自 whoami.owner.id → daemon ownerPrincipalId → owner-identity.json unionId)。
|
|
5118
|
-
* 未登录 daemon 仍为 auth.json 的 owner-<uuid>。daemon 端不验证该身份真实性
|
|
5119
|
-
* (Phase 1 信任模型,见 spec §9)。Phase 2 将以 connect token 替代(introspect
|
|
5120
|
-
* 返回身份,删除自报字段,见 spec §10)。
|
|
5121
5124
|
*/
|
|
5122
5125
|
selfPrincipalId: external_exports.string().min(1).optional(),
|
|
5123
5126
|
/**
|
|
@@ -5132,6 +5135,11 @@ var init_schemas = __esm({
|
|
|
5132
5135
|
version: external_exports.string().min(1).optional(),
|
|
5133
5136
|
protocolVersion: external_exports.number().int().nonnegative().optional()
|
|
5134
5137
|
});
|
|
5138
|
+
TunnelReadyEventSchema = external_exports.object({
|
|
5139
|
+
type: external_exports.literal("tunnel:ready"),
|
|
5140
|
+
url: external_exports.string().min(1),
|
|
5141
|
+
subdomain: external_exports.string().min(1)
|
|
5142
|
+
});
|
|
5135
5143
|
TunnelExitedEventSchema = external_exports.object({
|
|
5136
5144
|
type: external_exports.literal("tunnel:exited"),
|
|
5137
5145
|
code: external_exports.number().int().nullable(),
|
|
@@ -5173,6 +5181,41 @@ var init_schemas = __esm({
|
|
|
5173
5181
|
/** file-sharing HTTP 路由的 Authorization: Bearer token;与 WS token 解耦,HTTP 401 仅触发 ReAuth 不强踢 WS(spec §11 第 4 条) */
|
|
5174
5182
|
httpToken: external_exports.string().optional()
|
|
5175
5183
|
});
|
|
5184
|
+
PROJECT_PORT_MIN = 6173;
|
|
5185
|
+
PROJECT_PORT_MAX = 6182;
|
|
5186
|
+
projectNameRegex = /^[a-z][a-z0-9-]{0,39}$/;
|
|
5187
|
+
ProjectMetadataSchema = external_exports.object({
|
|
5188
|
+
name: external_exports.string().regex(projectNameRegex, {
|
|
5189
|
+
message: "kebab-case, \u5C0F\u5199\u5B57\u6BCD\u5F00\u5934\uFF0C\u53EA\u5141\u8BB8\u5C0F\u5199\u5B57\u6BCD / \u6570\u5B57 / -\uFF0C\u6700\u957F 40 \u5B57\u7B26"
|
|
5190
|
+
}),
|
|
5191
|
+
port: external_exports.number().int().min(PROJECT_PORT_MIN).max(PROJECT_PORT_MAX),
|
|
5192
|
+
createdAt: external_exports.string().datetime()
|
|
5193
|
+
});
|
|
5194
|
+
ProjectWithStatusSchema = ProjectMetadataSchema.extend({
|
|
5195
|
+
isRunning: external_exports.boolean(),
|
|
5196
|
+
boundSessionId: external_exports.string().nullable()
|
|
5197
|
+
});
|
|
5198
|
+
ListProjectsArgsSchema = external_exports.object({}).strict();
|
|
5199
|
+
ListProjectsResultSchema = external_exports.object({
|
|
5200
|
+
projects: external_exports.array(ProjectWithStatusSchema)
|
|
5201
|
+
}).strict();
|
|
5202
|
+
CreateProjectArgsSchema = external_exports.object({
|
|
5203
|
+
name: external_exports.string()
|
|
5204
|
+
}).strict();
|
|
5205
|
+
CreateProjectResultSchema = external_exports.object({
|
|
5206
|
+
project: ProjectMetadataSchema
|
|
5207
|
+
}).strict();
|
|
5208
|
+
DeleteProjectArgsSchema = external_exports.object({
|
|
5209
|
+
name: external_exports.string()
|
|
5210
|
+
}).strict();
|
|
5211
|
+
DeleteProjectResultSchema = external_exports.object({}).strict();
|
|
5212
|
+
UpdateProjectPortArgsSchema = external_exports.object({
|
|
5213
|
+
name: external_exports.string(),
|
|
5214
|
+
newPort: external_exports.number().int()
|
|
5215
|
+
}).strict();
|
|
5216
|
+
UpdateProjectPortResultSchema = external_exports.object({
|
|
5217
|
+
project: ProjectMetadataSchema
|
|
5218
|
+
}).strict();
|
|
5176
5219
|
}
|
|
5177
5220
|
});
|
|
5178
5221
|
|
|
@@ -5581,64 +5624,6 @@ var init_extension = __esm({
|
|
|
5581
5624
|
}
|
|
5582
5625
|
});
|
|
5583
5626
|
|
|
5584
|
-
// ../protocol/src/feishu-auth.ts
|
|
5585
|
-
var FEISHU_GATED_METHODS, FeishuIdentitySchema, AuthLoginStartResponseSchema, AuthGetIdentityResponseSchema, AuthLogoutResponseSchema, AuthLoginDoneEventSchema, AuthLoginFailedEventSchema;
|
|
5586
|
-
var init_feishu_auth = __esm({
|
|
5587
|
-
"../protocol/src/feishu-auth.ts"() {
|
|
5588
|
-
"use strict";
|
|
5589
|
-
init_zod();
|
|
5590
|
-
FEISHU_GATED_METHODS = [
|
|
5591
|
-
// capability / 邀请码(生成添加码 = 把自己的身份分享出去)
|
|
5592
|
-
"capability:list",
|
|
5593
|
-
"capability:delete",
|
|
5594
|
-
"personal-cap:get",
|
|
5595
|
-
// 联系人(添加朋友 / 联系人列表 / 自动重连)
|
|
5596
|
-
"received-capability:list",
|
|
5597
|
-
"received-capability:add",
|
|
5598
|
-
"received-capability:remove",
|
|
5599
|
-
"received-capability:autoAttach",
|
|
5600
|
-
// DM / 跨用户通知
|
|
5601
|
-
"inbox:list",
|
|
5602
|
-
"inbox:markRead",
|
|
5603
|
-
"inbox:postMessage",
|
|
5604
|
-
// mirror peer sessions(远端会话镜像)
|
|
5605
|
-
"peerSession:upsert",
|
|
5606
|
-
"peerSession:remove"
|
|
5607
|
-
];
|
|
5608
|
-
FeishuIdentitySchema = external_exports.object({
|
|
5609
|
-
/** 飞书 union_id(租户维度,跨应用稳定)。TTC user_info 接口 data.union_id */
|
|
5610
|
-
unionId: external_exports.string().min(1),
|
|
5611
|
-
/** 飞书姓名。TTC user_info 接口 data.name */
|
|
5612
|
-
displayName: external_exports.string().min(1),
|
|
5613
|
-
/** TTC user_info 接口 data.avatar_url,可缺省 */
|
|
5614
|
-
avatarUrl: external_exports.string().optional()
|
|
5615
|
-
});
|
|
5616
|
-
AuthLoginStartResponseSchema = external_exports.object({
|
|
5617
|
-
type: external_exports.literal("auth:login:start:ok"),
|
|
5618
|
-
/** 完整 TTC 授权页 URL(含 callback_url + state + auto=1),UI 直接 window.open */
|
|
5619
|
-
authUrl: external_exports.string().min(1),
|
|
5620
|
-
/** 防 CSRF 的一次性 nonce;回调时 daemon 校验 */
|
|
5621
|
-
state: external_exports.string().min(1)
|
|
5622
|
-
});
|
|
5623
|
-
AuthGetIdentityResponseSchema = external_exports.object({
|
|
5624
|
-
type: external_exports.literal("auth:getIdentity:ok"),
|
|
5625
|
-
/** null = 未登录 */
|
|
5626
|
-
identity: FeishuIdentitySchema.nullable()
|
|
5627
|
-
});
|
|
5628
|
-
AuthLogoutResponseSchema = external_exports.object({
|
|
5629
|
-
type: external_exports.literal("auth:logout:ok")
|
|
5630
|
-
});
|
|
5631
|
-
AuthLoginDoneEventSchema = external_exports.object({
|
|
5632
|
-
type: external_exports.literal("auth:login:done"),
|
|
5633
|
-
identity: FeishuIdentitySchema
|
|
5634
|
-
});
|
|
5635
|
-
AuthLoginFailedEventSchema = external_exports.object({
|
|
5636
|
-
type: external_exports.literal("auth:login:failed"),
|
|
5637
|
-
reason: external_exports.string()
|
|
5638
|
-
});
|
|
5639
|
-
}
|
|
5640
|
-
});
|
|
5641
|
-
|
|
5642
5627
|
// ../protocol/src/runtime.ts
|
|
5643
5628
|
var init_runtime = __esm({
|
|
5644
5629
|
"../protocol/src/runtime.ts"() {
|
|
@@ -5656,7 +5641,6 @@ var init_runtime = __esm({
|
|
|
5656
5641
|
init_inbox();
|
|
5657
5642
|
init_received_capability();
|
|
5658
5643
|
init_extension();
|
|
5659
|
-
init_feishu_auth();
|
|
5660
5644
|
}
|
|
5661
5645
|
});
|
|
5662
5646
|
|
|
@@ -5931,8 +5915,8 @@ var require_req = __commonJS({
|
|
|
5931
5915
|
if (req.originalUrl) {
|
|
5932
5916
|
_req.url = req.originalUrl;
|
|
5933
5917
|
} else {
|
|
5934
|
-
const
|
|
5935
|
-
_req.url = typeof
|
|
5918
|
+
const path59 = req.path;
|
|
5919
|
+
_req.url = typeof path59 === "string" ? path59 : req.url ? req.url.path || req.url : void 0;
|
|
5936
5920
|
}
|
|
5937
5921
|
if (req.query) {
|
|
5938
5922
|
_req.query = req.query;
|
|
@@ -6097,14 +6081,14 @@ var require_redact = __commonJS({
|
|
|
6097
6081
|
}
|
|
6098
6082
|
return obj;
|
|
6099
6083
|
}
|
|
6100
|
-
function parsePath(
|
|
6084
|
+
function parsePath(path59) {
|
|
6101
6085
|
const parts = [];
|
|
6102
6086
|
let current = "";
|
|
6103
6087
|
let inBrackets = false;
|
|
6104
6088
|
let inQuotes = false;
|
|
6105
6089
|
let quoteChar = "";
|
|
6106
|
-
for (let i = 0; i <
|
|
6107
|
-
const char =
|
|
6090
|
+
for (let i = 0; i < path59.length; i++) {
|
|
6091
|
+
const char = path59[i];
|
|
6108
6092
|
if (!inBrackets && char === ".") {
|
|
6109
6093
|
if (current) {
|
|
6110
6094
|
parts.push(current);
|
|
@@ -6235,10 +6219,10 @@ var require_redact = __commonJS({
|
|
|
6235
6219
|
return current;
|
|
6236
6220
|
}
|
|
6237
6221
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
6238
|
-
for (const
|
|
6239
|
-
const parts = parsePath(
|
|
6222
|
+
for (const path59 of paths) {
|
|
6223
|
+
const parts = parsePath(path59);
|
|
6240
6224
|
if (parts.includes("*")) {
|
|
6241
|
-
redactWildcardPath(obj, parts, censor,
|
|
6225
|
+
redactWildcardPath(obj, parts, censor, path59, remove);
|
|
6242
6226
|
} else {
|
|
6243
6227
|
if (remove) {
|
|
6244
6228
|
removeKey(obj, parts);
|
|
@@ -6323,8 +6307,8 @@ var require_redact = __commonJS({
|
|
|
6323
6307
|
}
|
|
6324
6308
|
} else {
|
|
6325
6309
|
if (afterWildcard.includes("*")) {
|
|
6326
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6327
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
6310
|
+
const wrappedCensor = typeof censor === "function" ? (value, path59) => {
|
|
6311
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path59];
|
|
6328
6312
|
return censor(value, fullPath);
|
|
6329
6313
|
} : censor;
|
|
6330
6314
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -6359,8 +6343,8 @@ var require_redact = __commonJS({
|
|
|
6359
6343
|
return null;
|
|
6360
6344
|
}
|
|
6361
6345
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
6362
|
-
for (const
|
|
6363
|
-
const parts = parsePath(
|
|
6346
|
+
for (const path59 of pathsToClone) {
|
|
6347
|
+
const parts = parsePath(path59);
|
|
6364
6348
|
let current = pathStructure;
|
|
6365
6349
|
for (let i = 0; i < parts.length; i++) {
|
|
6366
6350
|
const part = parts[i];
|
|
@@ -6412,24 +6396,24 @@ var require_redact = __commonJS({
|
|
|
6412
6396
|
}
|
|
6413
6397
|
return cloneSelectively(obj, pathStructure);
|
|
6414
6398
|
}
|
|
6415
|
-
function validatePath(
|
|
6416
|
-
if (typeof
|
|
6399
|
+
function validatePath(path59) {
|
|
6400
|
+
if (typeof path59 !== "string") {
|
|
6417
6401
|
throw new Error("Paths must be (non-empty) strings");
|
|
6418
6402
|
}
|
|
6419
|
-
if (
|
|
6403
|
+
if (path59 === "") {
|
|
6420
6404
|
throw new Error("Invalid redaction path ()");
|
|
6421
6405
|
}
|
|
6422
|
-
if (
|
|
6423
|
-
throw new Error(`Invalid redaction path (${
|
|
6406
|
+
if (path59.includes("..")) {
|
|
6407
|
+
throw new Error(`Invalid redaction path (${path59})`);
|
|
6424
6408
|
}
|
|
6425
|
-
if (
|
|
6426
|
-
throw new Error(`Invalid redaction path (${
|
|
6409
|
+
if (path59.includes(",")) {
|
|
6410
|
+
throw new Error(`Invalid redaction path (${path59})`);
|
|
6427
6411
|
}
|
|
6428
6412
|
let bracketCount = 0;
|
|
6429
6413
|
let inQuotes = false;
|
|
6430
6414
|
let quoteChar = "";
|
|
6431
|
-
for (let i = 0; i <
|
|
6432
|
-
const char =
|
|
6415
|
+
for (let i = 0; i < path59.length; i++) {
|
|
6416
|
+
const char = path59[i];
|
|
6433
6417
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
6434
6418
|
if (!inQuotes) {
|
|
6435
6419
|
inQuotes = true;
|
|
@@ -6443,20 +6427,20 @@ var require_redact = __commonJS({
|
|
|
6443
6427
|
} else if (char === "]" && !inQuotes) {
|
|
6444
6428
|
bracketCount--;
|
|
6445
6429
|
if (bracketCount < 0) {
|
|
6446
|
-
throw new Error(`Invalid redaction path (${
|
|
6430
|
+
throw new Error(`Invalid redaction path (${path59})`);
|
|
6447
6431
|
}
|
|
6448
6432
|
}
|
|
6449
6433
|
}
|
|
6450
6434
|
if (bracketCount !== 0) {
|
|
6451
|
-
throw new Error(`Invalid redaction path (${
|
|
6435
|
+
throw new Error(`Invalid redaction path (${path59})`);
|
|
6452
6436
|
}
|
|
6453
6437
|
}
|
|
6454
6438
|
function validatePaths(paths) {
|
|
6455
6439
|
if (!Array.isArray(paths)) {
|
|
6456
6440
|
throw new TypeError("paths must be an array");
|
|
6457
6441
|
}
|
|
6458
|
-
for (const
|
|
6459
|
-
validatePath(
|
|
6442
|
+
for (const path59 of paths) {
|
|
6443
|
+
validatePath(path59);
|
|
6460
6444
|
}
|
|
6461
6445
|
}
|
|
6462
6446
|
function slowRedact(options = {}) {
|
|
@@ -6624,8 +6608,8 @@ var require_redaction = __commonJS({
|
|
|
6624
6608
|
if (shape[k2] === null) {
|
|
6625
6609
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
6626
6610
|
} else {
|
|
6627
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6628
|
-
return censor(value, [k2, ...
|
|
6611
|
+
const wrappedCensor = typeof censor === "function" ? (value, path59) => {
|
|
6612
|
+
return censor(value, [k2, ...path59]);
|
|
6629
6613
|
} : censor;
|
|
6630
6614
|
o[k2] = Redact({
|
|
6631
6615
|
paths: shape[k2],
|
|
@@ -6844,9 +6828,9 @@ var require_sonic_boom = __commonJS({
|
|
|
6844
6828
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
6845
6829
|
"use strict";
|
|
6846
6830
|
var fs48 = require("fs");
|
|
6847
|
-
var
|
|
6831
|
+
var EventEmitter3 = require("events");
|
|
6848
6832
|
var inherits = require("util").inherits;
|
|
6849
|
-
var
|
|
6833
|
+
var path59 = require("path");
|
|
6850
6834
|
var sleep = require_atomic_sleep();
|
|
6851
6835
|
var assert = require("assert");
|
|
6852
6836
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -6900,7 +6884,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6900
6884
|
const mode = sonic.mode;
|
|
6901
6885
|
if (sonic.sync) {
|
|
6902
6886
|
try {
|
|
6903
|
-
if (sonic.mkdir) fs48.mkdirSync(
|
|
6887
|
+
if (sonic.mkdir) fs48.mkdirSync(path59.dirname(file), { recursive: true });
|
|
6904
6888
|
const fd = fs48.openSync(file, flags, mode);
|
|
6905
6889
|
fileOpened(null, fd);
|
|
6906
6890
|
} catch (err) {
|
|
@@ -6908,7 +6892,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6908
6892
|
throw err;
|
|
6909
6893
|
}
|
|
6910
6894
|
} else if (sonic.mkdir) {
|
|
6911
|
-
fs48.mkdir(
|
|
6895
|
+
fs48.mkdir(path59.dirname(file), { recursive: true }, (err) => {
|
|
6912
6896
|
if (err) return fileOpened(err);
|
|
6913
6897
|
fs48.open(file, flags, mode, fileOpened);
|
|
6914
6898
|
});
|
|
@@ -7081,7 +7065,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7081
7065
|
sonic._asyncDrainScheduled = false;
|
|
7082
7066
|
sonic.emit("drain");
|
|
7083
7067
|
}
|
|
7084
|
-
inherits(SonicBoom,
|
|
7068
|
+
inherits(SonicBoom, EventEmitter3);
|
|
7085
7069
|
function mergeBuf(bufs, len) {
|
|
7086
7070
|
if (bufs.length === 0) {
|
|
7087
7071
|
return kEmptyBuffer;
|
|
@@ -7659,9 +7643,9 @@ var require_thread_stream = __commonJS({
|
|
|
7659
7643
|
"../node_modules/.pnpm/thread-stream@3.1.0/node_modules/thread-stream/index.js"(exports2, module2) {
|
|
7660
7644
|
"use strict";
|
|
7661
7645
|
var { version: version2 } = require_package();
|
|
7662
|
-
var { EventEmitter:
|
|
7646
|
+
var { EventEmitter: EventEmitter3 } = require("events");
|
|
7663
7647
|
var { Worker } = require("worker_threads");
|
|
7664
|
-
var { join:
|
|
7648
|
+
var { join: join12 } = require("path");
|
|
7665
7649
|
var { pathToFileURL } = require("url");
|
|
7666
7650
|
var { wait } = require_wait();
|
|
7667
7651
|
var {
|
|
@@ -7697,7 +7681,7 @@ var require_thread_stream = __commonJS({
|
|
|
7697
7681
|
function createWorker(stream, opts) {
|
|
7698
7682
|
const { filename, workerData } = opts;
|
|
7699
7683
|
const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
|
|
7700
|
-
const toExecute = bundlerOverrides["thread-stream-worker"] ||
|
|
7684
|
+
const toExecute = bundlerOverrides["thread-stream-worker"] || join12(__dirname, "lib", "worker.js");
|
|
7701
7685
|
const worker = new Worker(toExecute, {
|
|
7702
7686
|
...opts.workerOpts,
|
|
7703
7687
|
trackUnmanagedFds: false,
|
|
@@ -7815,7 +7799,7 @@ var require_thread_stream = __commonJS({
|
|
|
7815
7799
|
stream.worker.off("exit", onWorkerExit);
|
|
7816
7800
|
destroy(stream, code !== 0 ? new Error("the worker thread exited") : null);
|
|
7817
7801
|
}
|
|
7818
|
-
var ThreadStream = class extends
|
|
7802
|
+
var ThreadStream = class extends EventEmitter3 {
|
|
7819
7803
|
constructor(opts = {}) {
|
|
7820
7804
|
super();
|
|
7821
7805
|
if (opts.bufferSize < 4) {
|
|
@@ -8083,7 +8067,7 @@ var require_transport = __commonJS({
|
|
|
8083
8067
|
"use strict";
|
|
8084
8068
|
var { createRequire } = require("module");
|
|
8085
8069
|
var getCallers = require_caller();
|
|
8086
|
-
var { join:
|
|
8070
|
+
var { join: join12, isAbsolute: isAbsolute2, sep: sep3 } = require("path");
|
|
8087
8071
|
var sleep = require_atomic_sleep();
|
|
8088
8072
|
var onExit = require_on_exit_leak_free();
|
|
8089
8073
|
var ThreadStream = require_thread_stream();
|
|
@@ -8146,7 +8130,7 @@ var require_transport = __commonJS({
|
|
|
8146
8130
|
throw new Error("only one of target or targets can be specified");
|
|
8147
8131
|
}
|
|
8148
8132
|
if (targets) {
|
|
8149
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
8133
|
+
target = bundlerOverrides["pino-worker"] || join12(__dirname, "worker.js");
|
|
8150
8134
|
options.targets = targets.filter((dest) => dest.target).map((dest) => {
|
|
8151
8135
|
return {
|
|
8152
8136
|
...dest,
|
|
@@ -8164,7 +8148,7 @@ var require_transport = __commonJS({
|
|
|
8164
8148
|
});
|
|
8165
8149
|
});
|
|
8166
8150
|
} else if (pipeline3) {
|
|
8167
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
8151
|
+
target = bundlerOverrides["pino-worker"] || join12(__dirname, "worker.js");
|
|
8168
8152
|
options.pipelines = [pipeline3.map((dest) => {
|
|
8169
8153
|
return {
|
|
8170
8154
|
...dest,
|
|
@@ -8186,7 +8170,7 @@ var require_transport = __commonJS({
|
|
|
8186
8170
|
return origin;
|
|
8187
8171
|
}
|
|
8188
8172
|
if (origin === "pino/file") {
|
|
8189
|
-
return
|
|
8173
|
+
return join12(__dirname, "..", "file.js");
|
|
8190
8174
|
}
|
|
8191
8175
|
let fixTarget2;
|
|
8192
8176
|
for (const filePath of callers) {
|
|
@@ -8773,7 +8757,7 @@ var require_meta = __commonJS({
|
|
|
8773
8757
|
var require_proto = __commonJS({
|
|
8774
8758
|
"../node_modules/.pnpm/pino@9.14.0/node_modules/pino/lib/proto.js"(exports2, module2) {
|
|
8775
8759
|
"use strict";
|
|
8776
|
-
var { EventEmitter:
|
|
8760
|
+
var { EventEmitter: EventEmitter3 } = require("events");
|
|
8777
8761
|
var {
|
|
8778
8762
|
lsCacheSym,
|
|
8779
8763
|
levelValSym,
|
|
@@ -8855,7 +8839,7 @@ var require_proto = __commonJS({
|
|
|
8855
8839
|
[getLevelSym]: getLevel,
|
|
8856
8840
|
[setLevelSym]: setLevel
|
|
8857
8841
|
};
|
|
8858
|
-
Object.setPrototypeOf(prototype,
|
|
8842
|
+
Object.setPrototypeOf(prototype, EventEmitter3.prototype);
|
|
8859
8843
|
module2.exports = function() {
|
|
8860
8844
|
return Object.create(prototype);
|
|
8861
8845
|
};
|
|
@@ -9176,7 +9160,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
9176
9160
|
return circularValue;
|
|
9177
9161
|
}
|
|
9178
9162
|
let res = "";
|
|
9179
|
-
let
|
|
9163
|
+
let join12 = ",";
|
|
9180
9164
|
const originalIndentation = indentation;
|
|
9181
9165
|
if (Array.isArray(value)) {
|
|
9182
9166
|
if (value.length === 0) {
|
|
@@ -9190,7 +9174,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
9190
9174
|
indentation += spacer;
|
|
9191
9175
|
res += `
|
|
9192
9176
|
${indentation}`;
|
|
9193
|
-
|
|
9177
|
+
join12 = `,
|
|
9194
9178
|
${indentation}`;
|
|
9195
9179
|
}
|
|
9196
9180
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -9198,13 +9182,13 @@ ${indentation}`;
|
|
|
9198
9182
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
9199
9183
|
const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
9200
9184
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
9201
|
-
res +=
|
|
9185
|
+
res += join12;
|
|
9202
9186
|
}
|
|
9203
9187
|
const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
9204
9188
|
res += tmp !== void 0 ? tmp : "null";
|
|
9205
9189
|
if (value.length - 1 > maximumBreadth) {
|
|
9206
9190
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
9207
|
-
res += `${
|
|
9191
|
+
res += `${join12}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
9208
9192
|
}
|
|
9209
9193
|
if (spacer !== "") {
|
|
9210
9194
|
res += `
|
|
@@ -9225,7 +9209,7 @@ ${originalIndentation}`;
|
|
|
9225
9209
|
let separator = "";
|
|
9226
9210
|
if (spacer !== "") {
|
|
9227
9211
|
indentation += spacer;
|
|
9228
|
-
|
|
9212
|
+
join12 = `,
|
|
9229
9213
|
${indentation}`;
|
|
9230
9214
|
whitespace = " ";
|
|
9231
9215
|
}
|
|
@@ -9239,13 +9223,13 @@ ${indentation}`;
|
|
|
9239
9223
|
const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
|
|
9240
9224
|
if (tmp !== void 0) {
|
|
9241
9225
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
9242
|
-
separator =
|
|
9226
|
+
separator = join12;
|
|
9243
9227
|
}
|
|
9244
9228
|
}
|
|
9245
9229
|
if (keyLength > maximumBreadth) {
|
|
9246
9230
|
const removedKeys = keyLength - maximumBreadth;
|
|
9247
9231
|
res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
|
|
9248
|
-
separator =
|
|
9232
|
+
separator = join12;
|
|
9249
9233
|
}
|
|
9250
9234
|
if (spacer !== "" && separator.length > 1) {
|
|
9251
9235
|
res = `
|
|
@@ -9286,7 +9270,7 @@ ${originalIndentation}`;
|
|
|
9286
9270
|
}
|
|
9287
9271
|
const originalIndentation = indentation;
|
|
9288
9272
|
let res = "";
|
|
9289
|
-
let
|
|
9273
|
+
let join12 = ",";
|
|
9290
9274
|
if (Array.isArray(value)) {
|
|
9291
9275
|
if (value.length === 0) {
|
|
9292
9276
|
return "[]";
|
|
@@ -9299,7 +9283,7 @@ ${originalIndentation}`;
|
|
|
9299
9283
|
indentation += spacer;
|
|
9300
9284
|
res += `
|
|
9301
9285
|
${indentation}`;
|
|
9302
|
-
|
|
9286
|
+
join12 = `,
|
|
9303
9287
|
${indentation}`;
|
|
9304
9288
|
}
|
|
9305
9289
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -9307,13 +9291,13 @@ ${indentation}`;
|
|
|
9307
9291
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
9308
9292
|
const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
9309
9293
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
9310
|
-
res +=
|
|
9294
|
+
res += join12;
|
|
9311
9295
|
}
|
|
9312
9296
|
const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
9313
9297
|
res += tmp !== void 0 ? tmp : "null";
|
|
9314
9298
|
if (value.length - 1 > maximumBreadth) {
|
|
9315
9299
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
9316
|
-
res += `${
|
|
9300
|
+
res += `${join12}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
9317
9301
|
}
|
|
9318
9302
|
if (spacer !== "") {
|
|
9319
9303
|
res += `
|
|
@@ -9326,7 +9310,7 @@ ${originalIndentation}`;
|
|
|
9326
9310
|
let whitespace = "";
|
|
9327
9311
|
if (spacer !== "") {
|
|
9328
9312
|
indentation += spacer;
|
|
9329
|
-
|
|
9313
|
+
join12 = `,
|
|
9330
9314
|
${indentation}`;
|
|
9331
9315
|
whitespace = " ";
|
|
9332
9316
|
}
|
|
@@ -9335,7 +9319,7 @@ ${indentation}`;
|
|
|
9335
9319
|
const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
|
|
9336
9320
|
if (tmp !== void 0) {
|
|
9337
9321
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
9338
|
-
separator =
|
|
9322
|
+
separator = join12;
|
|
9339
9323
|
}
|
|
9340
9324
|
}
|
|
9341
9325
|
if (spacer !== "" && separator.length > 1) {
|
|
@@ -9393,20 +9377,20 @@ ${originalIndentation}`;
|
|
|
9393
9377
|
indentation += spacer;
|
|
9394
9378
|
let res2 = `
|
|
9395
9379
|
${indentation}`;
|
|
9396
|
-
const
|
|
9380
|
+
const join13 = `,
|
|
9397
9381
|
${indentation}`;
|
|
9398
9382
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
9399
9383
|
let i = 0;
|
|
9400
9384
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
9401
9385
|
const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
9402
9386
|
res2 += tmp2 !== void 0 ? tmp2 : "null";
|
|
9403
|
-
res2 +=
|
|
9387
|
+
res2 += join13;
|
|
9404
9388
|
}
|
|
9405
9389
|
const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
9406
9390
|
res2 += tmp !== void 0 ? tmp : "null";
|
|
9407
9391
|
if (value.length - 1 > maximumBreadth) {
|
|
9408
9392
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
9409
|
-
res2 += `${
|
|
9393
|
+
res2 += `${join13}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
9410
9394
|
}
|
|
9411
9395
|
res2 += `
|
|
9412
9396
|
${originalIndentation}`;
|
|
@@ -9422,16 +9406,16 @@ ${originalIndentation}`;
|
|
|
9422
9406
|
return '"[Object]"';
|
|
9423
9407
|
}
|
|
9424
9408
|
indentation += spacer;
|
|
9425
|
-
const
|
|
9409
|
+
const join12 = `,
|
|
9426
9410
|
${indentation}`;
|
|
9427
9411
|
let res = "";
|
|
9428
9412
|
let separator = "";
|
|
9429
9413
|
let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
|
|
9430
9414
|
if (isTypedArrayWithEntries(value)) {
|
|
9431
|
-
res += stringifyTypedArray(value,
|
|
9415
|
+
res += stringifyTypedArray(value, join12, maximumBreadth);
|
|
9432
9416
|
keys = keys.slice(value.length);
|
|
9433
9417
|
maximumPropertiesToStringify -= value.length;
|
|
9434
|
-
separator =
|
|
9418
|
+
separator = join12;
|
|
9435
9419
|
}
|
|
9436
9420
|
if (deterministic) {
|
|
9437
9421
|
keys = sort(keys, comparator);
|
|
@@ -9442,13 +9426,13 @@ ${indentation}`;
|
|
|
9442
9426
|
const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
|
|
9443
9427
|
if (tmp !== void 0) {
|
|
9444
9428
|
res += `${separator}${strEscape(key2)}: ${tmp}`;
|
|
9445
|
-
separator =
|
|
9429
|
+
separator = join12;
|
|
9446
9430
|
}
|
|
9447
9431
|
}
|
|
9448
9432
|
if (keyLength > maximumBreadth) {
|
|
9449
9433
|
const removedKeys = keyLength - maximumBreadth;
|
|
9450
9434
|
res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
|
|
9451
|
-
separator =
|
|
9435
|
+
separator = join12;
|
|
9452
9436
|
}
|
|
9453
9437
|
if (separator !== "") {
|
|
9454
9438
|
res = `
|
|
@@ -10539,11 +10523,11 @@ var init_lib = __esm({
|
|
|
10539
10523
|
}
|
|
10540
10524
|
}
|
|
10541
10525
|
},
|
|
10542
|
-
addToPath: function addToPath(
|
|
10543
|
-
var last =
|
|
10526
|
+
addToPath: function addToPath(path59, added, removed, oldPosInc, options) {
|
|
10527
|
+
var last = path59.lastComponent;
|
|
10544
10528
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
10545
10529
|
return {
|
|
10546
|
-
oldPos:
|
|
10530
|
+
oldPos: path59.oldPos + oldPosInc,
|
|
10547
10531
|
lastComponent: {
|
|
10548
10532
|
count: last.count + 1,
|
|
10549
10533
|
added,
|
|
@@ -10553,7 +10537,7 @@ var init_lib = __esm({
|
|
|
10553
10537
|
};
|
|
10554
10538
|
} else {
|
|
10555
10539
|
return {
|
|
10556
|
-
oldPos:
|
|
10540
|
+
oldPos: path59.oldPos + oldPosInc,
|
|
10557
10541
|
lastComponent: {
|
|
10558
10542
|
count: 1,
|
|
10559
10543
|
added,
|
|
@@ -10999,10 +10983,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
10999
10983
|
const memories = raw.map((m2) => {
|
|
11000
10984
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11001
10985
|
const rec = m2;
|
|
11002
|
-
const
|
|
10986
|
+
const path59 = typeof rec.path === "string" ? rec.path : null;
|
|
11003
10987
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
11004
|
-
if (!
|
|
11005
|
-
const entry = { path:
|
|
10988
|
+
if (!path59 || content == null) return null;
|
|
10989
|
+
const entry = { path: path59, content };
|
|
11006
10990
|
if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
|
|
11007
10991
|
return entry;
|
|
11008
10992
|
}).filter((m2) => m2 !== null);
|
|
@@ -11833,10 +11817,10 @@ function parseAttachment(obj) {
|
|
|
11833
11817
|
const memories = raw.map((m2) => {
|
|
11834
11818
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11835
11819
|
const rec = m2;
|
|
11836
|
-
const
|
|
11820
|
+
const path59 = typeof rec.path === "string" ? rec.path : null;
|
|
11837
11821
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
11838
|
-
if (!
|
|
11839
|
-
const out = { path:
|
|
11822
|
+
if (!path59 || content == null) return null;
|
|
11823
|
+
const out = { path: path59, content };
|
|
11840
11824
|
if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
|
|
11841
11825
|
return out;
|
|
11842
11826
|
}).filter((m2) => m2 !== null);
|
|
@@ -19330,10 +19314,10 @@ var require_extension = __commonJS({
|
|
|
19330
19314
|
var require_websocket = __commonJS({
|
|
19331
19315
|
"../node_modules/.pnpm/ws@8.20.0/node_modules/ws/lib/websocket.js"(exports2, module2) {
|
|
19332
19316
|
"use strict";
|
|
19333
|
-
var
|
|
19317
|
+
var EventEmitter3 = require("events");
|
|
19334
19318
|
var https = require("https");
|
|
19335
|
-
var
|
|
19336
|
-
var
|
|
19319
|
+
var http3 = require("http");
|
|
19320
|
+
var net3 = require("net");
|
|
19337
19321
|
var tls = require("tls");
|
|
19338
19322
|
var { randomBytes, createHash: createHash2 } = require("crypto");
|
|
19339
19323
|
var { Duplex, Readable: Readable3 } = require("stream");
|
|
@@ -19362,7 +19346,7 @@ var require_websocket = __commonJS({
|
|
|
19362
19346
|
var protocolVersions = [8, 13];
|
|
19363
19347
|
var readyStates = ["CONNECTING", "OPEN", "CLOSING", "CLOSED"];
|
|
19364
19348
|
var subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/;
|
|
19365
|
-
var WebSocket2 = class _WebSocket extends
|
|
19349
|
+
var WebSocket2 = class _WebSocket extends EventEmitter3 {
|
|
19366
19350
|
/**
|
|
19367
19351
|
* Create a new `WebSocket`.
|
|
19368
19352
|
*
|
|
@@ -19866,7 +19850,7 @@ var require_websocket = __commonJS({
|
|
|
19866
19850
|
}
|
|
19867
19851
|
const defaultPort = isSecure ? 443 : 80;
|
|
19868
19852
|
const key = randomBytes(16).toString("base64");
|
|
19869
|
-
const request = isSecure ? https.request :
|
|
19853
|
+
const request = isSecure ? https.request : http3.request;
|
|
19870
19854
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
19871
19855
|
let perMessageDeflate;
|
|
19872
19856
|
opts.createConnection = opts.createConnection || (isSecure ? tlsConnect : netConnect);
|
|
@@ -20067,12 +20051,12 @@ var require_websocket = __commonJS({
|
|
|
20067
20051
|
}
|
|
20068
20052
|
function netConnect(options) {
|
|
20069
20053
|
options.path = options.socketPath;
|
|
20070
|
-
return
|
|
20054
|
+
return net3.connect(options);
|
|
20071
20055
|
}
|
|
20072
20056
|
function tlsConnect(options) {
|
|
20073
20057
|
options.path = void 0;
|
|
20074
20058
|
if (!options.servername && options.servername !== "") {
|
|
20075
|
-
options.servername =
|
|
20059
|
+
options.servername = net3.isIP(options.host) ? "" : options.host;
|
|
20076
20060
|
}
|
|
20077
20061
|
return tls.connect(options);
|
|
20078
20062
|
}
|
|
@@ -20359,8 +20343,8 @@ var require_subprotocol = __commonJS({
|
|
|
20359
20343
|
var require_websocket_server = __commonJS({
|
|
20360
20344
|
"../node_modules/.pnpm/ws@8.20.0/node_modules/ws/lib/websocket-server.js"(exports2, module2) {
|
|
20361
20345
|
"use strict";
|
|
20362
|
-
var
|
|
20363
|
-
var
|
|
20346
|
+
var EventEmitter3 = require("events");
|
|
20347
|
+
var http3 = require("http");
|
|
20364
20348
|
var { Duplex } = require("stream");
|
|
20365
20349
|
var { createHash: createHash2 } = require("crypto");
|
|
20366
20350
|
var extension2 = require_extension();
|
|
@@ -20372,7 +20356,7 @@ var require_websocket_server = __commonJS({
|
|
|
20372
20356
|
var RUNNING = 0;
|
|
20373
20357
|
var CLOSING = 1;
|
|
20374
20358
|
var CLOSED = 2;
|
|
20375
|
-
var WebSocketServer2 = class extends
|
|
20359
|
+
var WebSocketServer2 = class extends EventEmitter3 {
|
|
20376
20360
|
/**
|
|
20377
20361
|
* Create a `WebSocketServer` instance.
|
|
20378
20362
|
*
|
|
@@ -20435,8 +20419,8 @@ var require_websocket_server = __commonJS({
|
|
|
20435
20419
|
);
|
|
20436
20420
|
}
|
|
20437
20421
|
if (options.port != null) {
|
|
20438
|
-
this._server =
|
|
20439
|
-
const body =
|
|
20422
|
+
this._server = http3.createServer((req, res) => {
|
|
20423
|
+
const body = http3.STATUS_CODES[426];
|
|
20440
20424
|
res.writeHead(426, {
|
|
20441
20425
|
"Content-Length": body.length,
|
|
20442
20426
|
"Content-Type": "text/plain"
|
|
@@ -20723,7 +20707,7 @@ var require_websocket_server = __commonJS({
|
|
|
20723
20707
|
this.destroy();
|
|
20724
20708
|
}
|
|
20725
20709
|
function abortHandshake(socket, code, message, headers) {
|
|
20726
|
-
message = message ||
|
|
20710
|
+
message = message || http3.STATUS_CODES[code];
|
|
20727
20711
|
headers = {
|
|
20728
20712
|
Connection: "close",
|
|
20729
20713
|
"Content-Type": "text/html",
|
|
@@ -20732,7 +20716,7 @@ var require_websocket_server = __commonJS({
|
|
|
20732
20716
|
};
|
|
20733
20717
|
socket.once("finish", socket.destroy);
|
|
20734
20718
|
socket.end(
|
|
20735
|
-
`HTTP/1.1 ${code} ${
|
|
20719
|
+
`HTTP/1.1 ${code} ${http3.STATUS_CODES[code]}\r
|
|
20736
20720
|
` + Object.keys(headers).map((h) => `${h}: ${headers[h]}`).join("\r\n") + "\r\n\r\n" + message
|
|
20737
20721
|
);
|
|
20738
20722
|
}
|
|
@@ -21035,7 +21019,7 @@ var require_BufferList = __commonJS({
|
|
|
21035
21019
|
this.head = this.tail = null;
|
|
21036
21020
|
this.length = 0;
|
|
21037
21021
|
};
|
|
21038
|
-
BufferList.prototype.join = function
|
|
21022
|
+
BufferList.prototype.join = function join12(s) {
|
|
21039
21023
|
if (this.length === 0) return "";
|
|
21040
21024
|
var p2 = this.head;
|
|
21041
21025
|
var ret = "" + p2.data;
|
|
@@ -23625,8 +23609,8 @@ var require_utils = __commonJS({
|
|
|
23625
23609
|
var result = transform[inputType][outputType](input);
|
|
23626
23610
|
return result;
|
|
23627
23611
|
};
|
|
23628
|
-
exports2.resolve = function(
|
|
23629
|
-
var parts =
|
|
23612
|
+
exports2.resolve = function(path59) {
|
|
23613
|
+
var parts = path59.split("/");
|
|
23630
23614
|
var result = [];
|
|
23631
23615
|
for (var index = 0; index < parts.length; index++) {
|
|
23632
23616
|
var part = parts[index];
|
|
@@ -29479,18 +29463,18 @@ var require_object = __commonJS({
|
|
|
29479
29463
|
var object = new ZipObject(name, zipObjectContent, o);
|
|
29480
29464
|
this.files[name] = object;
|
|
29481
29465
|
};
|
|
29482
|
-
var parentFolder = function(
|
|
29483
|
-
if (
|
|
29484
|
-
|
|
29466
|
+
var parentFolder = function(path59) {
|
|
29467
|
+
if (path59.slice(-1) === "/") {
|
|
29468
|
+
path59 = path59.substring(0, path59.length - 1);
|
|
29485
29469
|
}
|
|
29486
|
-
var lastSlash =
|
|
29487
|
-
return lastSlash > 0 ?
|
|
29470
|
+
var lastSlash = path59.lastIndexOf("/");
|
|
29471
|
+
return lastSlash > 0 ? path59.substring(0, lastSlash) : "";
|
|
29488
29472
|
};
|
|
29489
|
-
var forceTrailingSlash = function(
|
|
29490
|
-
if (
|
|
29491
|
-
|
|
29473
|
+
var forceTrailingSlash = function(path59) {
|
|
29474
|
+
if (path59.slice(-1) !== "/") {
|
|
29475
|
+
path59 += "/";
|
|
29492
29476
|
}
|
|
29493
|
-
return
|
|
29477
|
+
return path59;
|
|
29494
29478
|
};
|
|
29495
29479
|
var folderAdd = function(name, createFolders) {
|
|
29496
29480
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
|
|
@@ -30945,6 +30929,8 @@ function resolveConfig(opts) {
|
|
|
30945
30929
|
const frpcBinary = env.CLAWD_FRPC_BIN ?? null;
|
|
30946
30930
|
const rawMode = env.CLAWD_CC_MODE;
|
|
30947
30931
|
const mode = DAEMON_MODE_VALUES.includes(rawMode ?? "") ? rawMode : "sdk";
|
|
30932
|
+
const filePreviewPorts = Array.isArray(fileCfg.previewPorts) ? fileCfg.previewPorts.map((n) => Number(n)).filter((n) => Number.isInteger(n) && n > 0) : null;
|
|
30933
|
+
const previewPorts = env.CLAWD_PREVIEW_PORTS ? env.CLAWD_PREVIEW_PORTS.split(",").map((s) => Number(s.trim())).filter((n) => Number.isInteger(n) && n > 0) : filePreviewPorts && filePreviewPorts.length > 0 ? filePreviewPorts : null;
|
|
30948
30934
|
return {
|
|
30949
30935
|
port,
|
|
30950
30936
|
host,
|
|
@@ -30956,7 +30942,8 @@ function resolveConfig(opts) {
|
|
|
30956
30942
|
authToken,
|
|
30957
30943
|
noTunnelPersist,
|
|
30958
30944
|
frpcBinary,
|
|
30959
|
-
mode
|
|
30945
|
+
mode,
|
|
30946
|
+
previewPorts
|
|
30960
30947
|
};
|
|
30961
30948
|
}
|
|
30962
30949
|
var HELP_TEXT = `clawd [options]
|
|
@@ -32995,6 +32982,7 @@ var SessionManager = class {
|
|
|
32995
32982
|
iconKey: args.iconKey,
|
|
32996
32983
|
forkedFromSessionId: args.forkedFromSessionId,
|
|
32997
32984
|
ownerPersonaId: args.ownerPersonaId,
|
|
32985
|
+
appBuilderProject: args.appBuilderProject,
|
|
32998
32986
|
creatorPrincipalId,
|
|
32999
32987
|
...creatorOwnerPrincipalId ? { creatorOwnerPrincipalId } : {},
|
|
33000
32988
|
createdAt: iso,
|
|
@@ -34631,6 +34619,15 @@ var DEFAULT_PERSONAS = [
|
|
|
34631
34619
|
model: "opus",
|
|
34632
34620
|
iconKey: "assist",
|
|
34633
34621
|
public: false
|
|
34622
|
+
},
|
|
34623
|
+
{
|
|
34624
|
+
// app-builder:全栈应用搭建师,绑 extension-kit 模板 + multi-project picker
|
|
34625
|
+
// spec: superpowers/specs/2026-06-01-app-builder-project-picker-design.md
|
|
34626
|
+
personaId: "persona-app-builder",
|
|
34627
|
+
label: "App Builder",
|
|
34628
|
+
model: "opus",
|
|
34629
|
+
iconKey: "assist",
|
|
34630
|
+
public: false
|
|
34634
34631
|
}
|
|
34635
34632
|
];
|
|
34636
34633
|
function findDefaultsRoot() {
|
|
@@ -36327,13 +36324,63 @@ var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
|
36327
36324
|
var wrapper_default = import_websocket.default;
|
|
36328
36325
|
|
|
36329
36326
|
// src/transport/local-ws-server.ts
|
|
36327
|
+
var import_node_http2 = __toESM(require("http"), 1);
|
|
36328
|
+
|
|
36329
|
+
// src/transport/preview-proxy.ts
|
|
36330
36330
|
var import_node_http = __toESM(require("http"), 1);
|
|
36331
|
+
var import_node_net = __toESM(require("net"), 1);
|
|
36332
|
+
var PREVIEW_RE = /^\/preview\/(\d+)(?:\/.*)?$/;
|
|
36333
|
+
function matchPreviewPort(pathname) {
|
|
36334
|
+
const m2 = pathname.match(PREVIEW_RE);
|
|
36335
|
+
return m2 ? Number(m2[1]) : null;
|
|
36336
|
+
}
|
|
36337
|
+
function isPreviewPortAllowed(port, cfg) {
|
|
36338
|
+
return cfg.allowedPorts.includes(port);
|
|
36339
|
+
}
|
|
36340
|
+
function proxyPreviewHttp(req, res, port) {
|
|
36341
|
+
return new Promise((resolve6) => {
|
|
36342
|
+
const upstream = import_node_http.default.request(
|
|
36343
|
+
{ host: "localhost", port, method: req.method, path: req.url, headers: req.headers },
|
|
36344
|
+
(upRes) => {
|
|
36345
|
+
res.writeHead(upRes.statusCode || 502, upRes.headers);
|
|
36346
|
+
upRes.pipe(res);
|
|
36347
|
+
upRes.on("end", () => resolve6());
|
|
36348
|
+
}
|
|
36349
|
+
);
|
|
36350
|
+
upstream.on("error", (e) => {
|
|
36351
|
+
if (!res.headersSent) {
|
|
36352
|
+
res.writeHead(502, { "content-type": "text/plain; charset=utf-8" });
|
|
36353
|
+
}
|
|
36354
|
+
res.end(`preview upstream error: ${e.message}`);
|
|
36355
|
+
resolve6();
|
|
36356
|
+
});
|
|
36357
|
+
req.pipe(upstream);
|
|
36358
|
+
});
|
|
36359
|
+
}
|
|
36360
|
+
function proxyPreviewUpgrade(req, socket, head, port) {
|
|
36361
|
+
const upstream = import_node_net.default.connect(port, "localhost", () => {
|
|
36362
|
+
let raw = `${req.method} ${req.url} HTTP/1.1\r
|
|
36363
|
+
`;
|
|
36364
|
+
for (let i = 0; i < req.rawHeaders.length; i += 2) {
|
|
36365
|
+
raw += `${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}\r
|
|
36366
|
+
`;
|
|
36367
|
+
}
|
|
36368
|
+
raw += "\r\n";
|
|
36369
|
+
upstream.write(raw);
|
|
36370
|
+
if (head && head.length) upstream.write(head);
|
|
36371
|
+
upstream.pipe(socket);
|
|
36372
|
+
socket.pipe(upstream);
|
|
36373
|
+
});
|
|
36374
|
+
upstream.on("error", () => socket.destroy());
|
|
36375
|
+
socket.on("error", () => upstream.destroy());
|
|
36376
|
+
}
|
|
36377
|
+
|
|
36378
|
+
// src/transport/local-ws-server.ts
|
|
36331
36379
|
var LocalWsServer = class {
|
|
36332
36380
|
constructor(opts) {
|
|
36333
36381
|
this.opts = opts;
|
|
36334
36382
|
this.logger = opts.logger;
|
|
36335
36383
|
this.pingIntervalMs = opts.pingIntervalMs ?? 3e4;
|
|
36336
|
-
this.currentOwnerPrincipalId = opts.ownerPrincipalId;
|
|
36337
36384
|
}
|
|
36338
36385
|
opts;
|
|
36339
36386
|
wss = null;
|
|
@@ -36345,19 +36392,28 @@ var LocalWsServer = class {
|
|
|
36345
36392
|
capabilityIdToClients = /* @__PURE__ */ new Map();
|
|
36346
36393
|
logger;
|
|
36347
36394
|
pingIntervalMs;
|
|
36348
|
-
// 飞书热切换(spec 决策 #9,2026-06-01 拍板):登录后实时更新,broadcastToPrincipal
|
|
36349
|
-
// 路由用最新身份;初始值来自 opts.ownerPrincipalId
|
|
36350
|
-
currentOwnerPrincipalId;
|
|
36351
|
-
/** 飞书热切换:登录回调成功后由 daemon wiring 调用,更新 DM 路由身份 */
|
|
36352
|
-
setOwnerPrincipalId(id) {
|
|
36353
|
-
this.currentOwnerPrincipalId = id;
|
|
36354
|
-
}
|
|
36355
36395
|
async start() {
|
|
36356
36396
|
const host = this.opts.host ?? "127.0.0.1";
|
|
36357
36397
|
await new Promise((resolve6, reject) => {
|
|
36358
|
-
const httpServer =
|
|
36398
|
+
const httpServer = import_node_http2.default.createServer((req, res) => this.handleHttpRequest(req, res));
|
|
36359
36399
|
const wss = new import_websocket_server.default({ noServer: true, clientTracking: true });
|
|
36360
36400
|
httpServer.on("upgrade", (req, socket, head) => {
|
|
36401
|
+
if (req.url?.startsWith("/preview/")) {
|
|
36402
|
+
const pathname = (() => {
|
|
36403
|
+
try {
|
|
36404
|
+
return new URL(req.url, "http://localhost").pathname;
|
|
36405
|
+
} catch {
|
|
36406
|
+
return "/";
|
|
36407
|
+
}
|
|
36408
|
+
})();
|
|
36409
|
+
const port = matchPreviewPort(pathname);
|
|
36410
|
+
if (port != null && (this.opts.previewPorts ?? []).includes(port)) {
|
|
36411
|
+
proxyPreviewUpgrade(req, socket, head, port);
|
|
36412
|
+
} else {
|
|
36413
|
+
socket.destroy();
|
|
36414
|
+
}
|
|
36415
|
+
return;
|
|
36416
|
+
}
|
|
36361
36417
|
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
36362
36418
|
this.routeConnection(ws, req);
|
|
36363
36419
|
});
|
|
@@ -36471,7 +36527,7 @@ var LocalWsServer = class {
|
|
|
36471
36527
|
// principalId === 'cap_xxx' → 该 capability 的所有 guest ws (多端 / 多 tab)
|
|
36472
36528
|
// 用于 DM inbox:event 路由: from + to 两侧各播一次, 让双方 UI 实时看到 thread 更新.
|
|
36473
36529
|
broadcastToPrincipal(principalId, frame) {
|
|
36474
|
-
if (principalId === "owner" || principalId === this.
|
|
36530
|
+
if (principalId === "owner" || principalId === this.opts.ownerPrincipalId) {
|
|
36475
36531
|
this.broadcastToOwners(frame);
|
|
36476
36532
|
return;
|
|
36477
36533
|
}
|
|
@@ -36523,21 +36579,6 @@ var LocalWsServer = class {
|
|
|
36523
36579
|
getClientContext(clientId) {
|
|
36524
36580
|
return this.clients.get(clientId)?.ctx ?? null;
|
|
36525
36581
|
}
|
|
36526
|
-
// 飞书热切换(spec 决策 #9):身份切换后踢掉所有连接强制重连——在线连接的 ctx
|
|
36527
|
-
// (attachClientContext 时绑定)持有旧身份,重连后用新身份重建。
|
|
36528
|
-
// close code 4408(非 4401!4401 = token 撤销,客户端会停止重连):
|
|
36529
|
-
// 客户端按普通断连处理 → 自动重连 → 新身份 ctx。
|
|
36530
|
-
closeAllClients(code = 4408, reason = "IDENTITY_SWITCHED") {
|
|
36531
|
-
const ids = [...this.clients.keys()];
|
|
36532
|
-
for (const id of ids) {
|
|
36533
|
-
const c = this.clients.get(id);
|
|
36534
|
-
if (!c) continue;
|
|
36535
|
-
try {
|
|
36536
|
-
c.ws.close(code, reason);
|
|
36537
|
-
} catch {
|
|
36538
|
-
}
|
|
36539
|
-
}
|
|
36540
|
-
}
|
|
36541
36582
|
// Task 1.10 撤销级联:关闭某 capability 的所有活跃 ws 连接。close code 4401
|
|
36542
36583
|
// 让客户端识别 'capability revoked' 而非普通断连。
|
|
36543
36584
|
closeConnectionsByCapability(capabilityId, code = 4401, reason = "TOKEN_REVOKED") {
|
|
@@ -38020,23 +38061,13 @@ function createHttpRouter(deps) {
|
|
|
38020
38061
|
});
|
|
38021
38062
|
return true;
|
|
38022
38063
|
}
|
|
38023
|
-
if (url.pathname
|
|
38024
|
-
|
|
38025
|
-
|
|
38064
|
+
if (url.pathname.startsWith("/preview/")) {
|
|
38065
|
+
const port = matchPreviewPort(url.pathname);
|
|
38066
|
+
if (port != null && isPreviewPortAllowed(port, { allowedPorts: deps.previewPorts ?? [] })) {
|
|
38067
|
+
await proxyPreviewHttp(req, res, port);
|
|
38026
38068
|
return true;
|
|
38027
38069
|
}
|
|
38028
|
-
|
|
38029
|
-
sendJson(res, 501, { code: "NOT_IMPLEMENTED", message: "feishu login not wired" });
|
|
38030
|
-
return true;
|
|
38031
|
-
}
|
|
38032
|
-
const result = await deps.feishuLogin.handleLoginCallback({
|
|
38033
|
-
token: url.searchParams.get("token") ?? "",
|
|
38034
|
-
state: url.searchParams.get("state") ?? "",
|
|
38035
|
-
expiresAt: url.searchParams.get("expires_at")
|
|
38036
|
-
});
|
|
38037
|
-
const html = result.ok ? `<!doctype html><meta charset="utf-8"><title>clawd</title><style>body{font-family:-apple-system,sans-serif;padding:48px;color:#222}</style><h2>\u767B\u5F55\u6210\u529F\uFF0C\u53EF\u5173\u95ED\u6B64\u9875\u3002</h2><p>\u8EAB\u4EFD\uFF1A${escapeHtml(result.identity.displayName)}</p><script>setTimeout(()=>window.close(),1500)</script>` : `<!doctype html><meta charset="utf-8"><title>clawd</title><style>body{font-family:-apple-system,sans-serif;padding:48px;color:#922}</style><h2>\u767B\u5F55\u5931\u8D25</h2><p>${escapeHtml(result.reason)}</p>`;
|
|
38038
|
-
res.writeHead(result.ok ? 200 : 400, { "Content-Type": "text/html; charset=utf-8" });
|
|
38039
|
-
res.end(html);
|
|
38070
|
+
sendJson(res, 403, { code: "PREVIEW_PORT_FORBIDDEN", message: "preview port not allowed" });
|
|
38040
38071
|
return true;
|
|
38041
38072
|
}
|
|
38042
38073
|
if (!url.pathname.startsWith("/session/") && !url.pathname.startsWith("/files/") && url.pathname !== "/attachments/upload" && url.pathname !== "/extensions/import") {
|
|
@@ -38274,9 +38305,6 @@ function parseUrl(rawUrl) {
|
|
|
38274
38305
|
return null;
|
|
38275
38306
|
}
|
|
38276
38307
|
}
|
|
38277
|
-
function escapeHtml(s) {
|
|
38278
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
38279
|
-
}
|
|
38280
38308
|
function sendJson(res, status, body, extraHeaders) {
|
|
38281
38309
|
res.writeHead(status, {
|
|
38282
38310
|
"Content-Type": "application/json; charset=utf-8",
|
|
@@ -39299,160 +39327,6 @@ function loadOwnerDisplayName(dataDir) {
|
|
|
39299
39327
|
return displayName;
|
|
39300
39328
|
}
|
|
39301
39329
|
|
|
39302
|
-
// src/feishu-auth/owner-identity-store.ts
|
|
39303
|
-
var import_node_fs27 = __toESM(require("fs"), 1);
|
|
39304
|
-
var import_node_path31 = __toESM(require("path"), 1);
|
|
39305
|
-
var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
|
|
39306
|
-
var OwnerIdentityStore = class {
|
|
39307
|
-
file;
|
|
39308
|
-
constructor(dataDir) {
|
|
39309
|
-
this.file = import_node_path31.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
|
|
39310
|
-
}
|
|
39311
|
-
read() {
|
|
39312
|
-
let raw;
|
|
39313
|
-
try {
|
|
39314
|
-
raw = import_node_fs27.default.readFileSync(this.file, "utf8");
|
|
39315
|
-
} catch {
|
|
39316
|
-
return null;
|
|
39317
|
-
}
|
|
39318
|
-
let parsed;
|
|
39319
|
-
try {
|
|
39320
|
-
parsed = JSON.parse(raw);
|
|
39321
|
-
} catch {
|
|
39322
|
-
return null;
|
|
39323
|
-
}
|
|
39324
|
-
const r = parsed;
|
|
39325
|
-
if (!r.identity || typeof r.identity.unionId !== "string" || r.identity.unionId.length === 0 || typeof r.identity.displayName !== "string" || r.identity.displayName.length === 0 || typeof r.ttcToken !== "string" || r.ttcToken.length === 0) {
|
|
39326
|
-
return null;
|
|
39327
|
-
}
|
|
39328
|
-
return {
|
|
39329
|
-
identity: {
|
|
39330
|
-
unionId: r.identity.unionId,
|
|
39331
|
-
displayName: r.identity.displayName,
|
|
39332
|
-
...typeof r.identity.avatarUrl === "string" ? { avatarUrl: r.identity.avatarUrl } : {}
|
|
39333
|
-
},
|
|
39334
|
-
ttcToken: r.ttcToken,
|
|
39335
|
-
ttcTokenExpiresAt: typeof r.ttcTokenExpiresAt === "number" ? r.ttcTokenExpiresAt : null,
|
|
39336
|
-
loginAt: typeof r.loginAt === "string" ? r.loginAt : (/* @__PURE__ */ new Date(0)).toISOString()
|
|
39337
|
-
};
|
|
39338
|
-
}
|
|
39339
|
-
write(record) {
|
|
39340
|
-
import_node_fs27.default.mkdirSync(import_node_path31.default.dirname(this.file), { recursive: true });
|
|
39341
|
-
import_node_fs27.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
|
|
39342
|
-
try {
|
|
39343
|
-
import_node_fs27.default.chmodSync(this.file, 384);
|
|
39344
|
-
} catch {
|
|
39345
|
-
}
|
|
39346
|
-
}
|
|
39347
|
-
clear() {
|
|
39348
|
-
try {
|
|
39349
|
-
import_node_fs27.default.unlinkSync(this.file);
|
|
39350
|
-
} catch (err) {
|
|
39351
|
-
const code = err?.code;
|
|
39352
|
-
if (code !== "ENOENT") throw err;
|
|
39353
|
-
}
|
|
39354
|
-
}
|
|
39355
|
-
};
|
|
39356
|
-
|
|
39357
|
-
// src/feishu-auth/login-flow.ts
|
|
39358
|
-
var import_node_crypto11 = __toESM(require("crypto"), 1);
|
|
39359
|
-
var STATE_TTL_MS = 5 * 60 * 1e3;
|
|
39360
|
-
var LoginFlow = class {
|
|
39361
|
-
constructor(deps) {
|
|
39362
|
-
this.deps = deps;
|
|
39363
|
-
}
|
|
39364
|
-
deps;
|
|
39365
|
-
pendingStates = /* @__PURE__ */ new Map();
|
|
39366
|
-
start() {
|
|
39367
|
-
const state = import_node_crypto11.default.randomBytes(16).toString("base64url");
|
|
39368
|
-
const now = (this.deps.now ?? Date.now)();
|
|
39369
|
-
this.pendingStates.set(state, now);
|
|
39370
|
-
this.gcExpired(now);
|
|
39371
|
-
const url = new URL("/auth/authorize", this.deps.ttcAuthBase);
|
|
39372
|
-
url.searchParams.set("callback_url", this.deps.getCallbackUrl());
|
|
39373
|
-
url.searchParams.set("state", state);
|
|
39374
|
-
url.searchParams.set("auto", "1");
|
|
39375
|
-
return { authUrl: url.toString(), state };
|
|
39376
|
-
}
|
|
39377
|
-
async handleCallback(params) {
|
|
39378
|
-
const now = (this.deps.now ?? Date.now)();
|
|
39379
|
-
const issuedAt = this.pendingStates.get(params.state);
|
|
39380
|
-
if (issuedAt === void 0) {
|
|
39381
|
-
return { ok: false, reason: "state mismatch" };
|
|
39382
|
-
}
|
|
39383
|
-
this.pendingStates.delete(params.state);
|
|
39384
|
-
if (now - issuedAt > STATE_TTL_MS) {
|
|
39385
|
-
return { ok: false, reason: "state expired" };
|
|
39386
|
-
}
|
|
39387
|
-
if (!params.token) {
|
|
39388
|
-
return { ok: false, reason: "missing token" };
|
|
39389
|
-
}
|
|
39390
|
-
let identity;
|
|
39391
|
-
try {
|
|
39392
|
-
identity = await this.deps.fetchUserInfo(params.token);
|
|
39393
|
-
} catch (err) {
|
|
39394
|
-
return { ok: false, reason: `user_info failed: ${err.message}` };
|
|
39395
|
-
}
|
|
39396
|
-
const expiresAtNum = params.expiresAt ? Number.parseInt(params.expiresAt, 10) : NaN;
|
|
39397
|
-
this.deps.store.write({
|
|
39398
|
-
identity,
|
|
39399
|
-
ttcToken: params.token,
|
|
39400
|
-
ttcTokenExpiresAt: Number.isFinite(expiresAtNum) ? expiresAtNum : null,
|
|
39401
|
-
loginAt: new Date(now).toISOString()
|
|
39402
|
-
});
|
|
39403
|
-
return { ok: true, identity };
|
|
39404
|
-
}
|
|
39405
|
-
gcExpired(now) {
|
|
39406
|
-
for (const [state, issuedAt] of this.pendingStates) {
|
|
39407
|
-
if (now - issuedAt > STATE_TTL_MS) this.pendingStates.delete(state);
|
|
39408
|
-
}
|
|
39409
|
-
}
|
|
39410
|
-
};
|
|
39411
|
-
|
|
39412
|
-
// src/feishu-auth/ttc-client.ts
|
|
39413
|
-
var TTC_HOSTS = {
|
|
39414
|
-
auth: "https://app.ttcadvisory.com",
|
|
39415
|
-
api: "https://api.ttcadvisory.com"
|
|
39416
|
-
};
|
|
39417
|
-
var TtcUserInfoError = class extends Error {
|
|
39418
|
-
constructor(code, message) {
|
|
39419
|
-
super(message);
|
|
39420
|
-
this.code = code;
|
|
39421
|
-
this.name = "TtcUserInfoError";
|
|
39422
|
-
}
|
|
39423
|
-
code;
|
|
39424
|
-
};
|
|
39425
|
-
async function fetchTtcUserInfo(opts) {
|
|
39426
|
-
const doFetch = opts.fetchImpl ?? fetch;
|
|
39427
|
-
let res;
|
|
39428
|
-
try {
|
|
39429
|
-
res = await doFetch(`${opts.apiBase}/api/user_service/v1/login/user`, {
|
|
39430
|
-
headers: { Authorization: `Bearer ${opts.token}` }
|
|
39431
|
-
});
|
|
39432
|
-
} catch (err) {
|
|
39433
|
-
throw new TtcUserInfoError("NETWORK", `TTC user_info request failed: ${err.message}`);
|
|
39434
|
-
}
|
|
39435
|
-
if (!res.ok) {
|
|
39436
|
-
if (res.status === 401) {
|
|
39437
|
-
throw new TtcUserInfoError("UNAUTHORIZED", "TTC token invalid or expired");
|
|
39438
|
-
}
|
|
39439
|
-
throw new TtcUserInfoError("API_ERROR", `TTC user_info HTTP ${res.status}`);
|
|
39440
|
-
}
|
|
39441
|
-
const body = await res.json();
|
|
39442
|
-
if (body.code !== 0) {
|
|
39443
|
-
throw new TtcUserInfoError("API_ERROR", `TTC user_info code=${body.code}: ${body.message ?? ""}`);
|
|
39444
|
-
}
|
|
39445
|
-
const d = body.data;
|
|
39446
|
-
if (!d || typeof d.union_id !== "string" || d.union_id.length === 0 || typeof d.name !== "string" || d.name.length === 0) {
|
|
39447
|
-
throw new TtcUserInfoError("BAD_RESPONSE", "TTC user_info missing union_id or name");
|
|
39448
|
-
}
|
|
39449
|
-
return {
|
|
39450
|
-
unionId: d.union_id,
|
|
39451
|
-
displayName: d.name,
|
|
39452
|
-
...typeof d.avatar_url === "string" && d.avatar_url.length > 0 ? { avatarUrl: d.avatar_url } : {}
|
|
39453
|
-
};
|
|
39454
|
-
}
|
|
39455
|
-
|
|
39456
39330
|
// src/index.ts
|
|
39457
39331
|
init_protocol();
|
|
39458
39332
|
|
|
@@ -39460,12 +39334,12 @@ init_protocol();
|
|
|
39460
39334
|
init_protocol();
|
|
39461
39335
|
|
|
39462
39336
|
// src/session/fork.ts
|
|
39463
|
-
var
|
|
39337
|
+
var import_node_fs27 = __toESM(require("fs"), 1);
|
|
39464
39338
|
var import_node_os14 = __toESM(require("os"), 1);
|
|
39465
|
-
var
|
|
39339
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
39466
39340
|
init_claude_history();
|
|
39467
39341
|
function readJsonlEntries(file) {
|
|
39468
|
-
const raw =
|
|
39342
|
+
const raw = import_node_fs27.default.readFileSync(file, "utf8");
|
|
39469
39343
|
const out = [];
|
|
39470
39344
|
for (const line of raw.split("\n")) {
|
|
39471
39345
|
const t = line.trim();
|
|
@@ -39478,10 +39352,10 @@ function readJsonlEntries(file) {
|
|
|
39478
39352
|
return out;
|
|
39479
39353
|
}
|
|
39480
39354
|
function forkSession(input) {
|
|
39481
|
-
const baseDir = input.baseDir ??
|
|
39482
|
-
const projectDir =
|
|
39483
|
-
const sourceFile =
|
|
39484
|
-
if (!
|
|
39355
|
+
const baseDir = input.baseDir ?? import_node_path31.default.join(import_node_os14.default.homedir(), ".claude");
|
|
39356
|
+
const projectDir = import_node_path31.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
39357
|
+
const sourceFile = import_node_path31.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
39358
|
+
if (!import_node_fs27.default.existsSync(sourceFile)) {
|
|
39485
39359
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
39486
39360
|
}
|
|
39487
39361
|
const entries = readJsonlEntries(sourceFile);
|
|
@@ -39511,9 +39385,9 @@ function forkSession(input) {
|
|
|
39511
39385
|
}
|
|
39512
39386
|
forkedLines.push(JSON.stringify(forked));
|
|
39513
39387
|
}
|
|
39514
|
-
const forkedFilePath =
|
|
39515
|
-
|
|
39516
|
-
|
|
39388
|
+
const forkedFilePath = import_node_path31.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
39389
|
+
import_node_fs27.default.mkdirSync(projectDir, { recursive: true });
|
|
39390
|
+
import_node_fs27.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
39517
39391
|
return { forkedToolSessionId, forkedFilePath };
|
|
39518
39392
|
}
|
|
39519
39393
|
|
|
@@ -39865,7 +39739,7 @@ function buildPermissionHandlers(deps) {
|
|
|
39865
39739
|
}
|
|
39866
39740
|
|
|
39867
39741
|
// src/handlers/history.ts
|
|
39868
|
-
var
|
|
39742
|
+
var path41 = __toESM(require("path"), 1);
|
|
39869
39743
|
init_protocol();
|
|
39870
39744
|
|
|
39871
39745
|
// src/session/recent-dirs.ts
|
|
@@ -39883,7 +39757,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
39883
39757
|
}
|
|
39884
39758
|
|
|
39885
39759
|
// src/permission/persona-paths.ts
|
|
39886
|
-
var
|
|
39760
|
+
var path40 = __toESM(require("path"), 1);
|
|
39887
39761
|
function getAllowedPersonaIds(grants, action) {
|
|
39888
39762
|
const ids = /* @__PURE__ */ new Set();
|
|
39889
39763
|
for (const g2 of grants) {
|
|
@@ -39896,26 +39770,26 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
39896
39770
|
return ids;
|
|
39897
39771
|
}
|
|
39898
39772
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read") {
|
|
39899
|
-
const root =
|
|
39900
|
-
const target =
|
|
39901
|
-
const sep3 = root.endsWith(
|
|
39773
|
+
const root = path40.resolve(personaRoot);
|
|
39774
|
+
const target = path40.resolve(absPath);
|
|
39775
|
+
const sep3 = root.endsWith(path40.sep) ? "" : path40.sep;
|
|
39902
39776
|
if (!target.startsWith(root + sep3)) return false;
|
|
39903
|
-
const rel =
|
|
39777
|
+
const rel = path40.relative(root, target);
|
|
39904
39778
|
if (!rel || rel.startsWith("..")) return false;
|
|
39905
|
-
const personaId = rel.split(
|
|
39779
|
+
const personaId = rel.split(path40.sep)[0];
|
|
39906
39780
|
if (!personaId) return false;
|
|
39907
39781
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
39908
39782
|
if (allowed === "*") return true;
|
|
39909
39783
|
return allowed.has(personaId);
|
|
39910
39784
|
}
|
|
39911
39785
|
function personaIdFromPath(absPath, personaRoot) {
|
|
39912
|
-
const root =
|
|
39913
|
-
const target =
|
|
39914
|
-
const sep3 = root.endsWith(
|
|
39786
|
+
const root = path40.resolve(personaRoot);
|
|
39787
|
+
const target = path40.resolve(absPath);
|
|
39788
|
+
const sep3 = root.endsWith(path40.sep) ? "" : path40.sep;
|
|
39915
39789
|
if (!target.startsWith(root + sep3)) return null;
|
|
39916
|
-
const rel =
|
|
39790
|
+
const rel = path40.relative(root, target);
|
|
39917
39791
|
if (!rel || rel.startsWith("..")) return null;
|
|
39918
|
-
const id = rel.split(
|
|
39792
|
+
const id = rel.split(path40.sep)[0];
|
|
39919
39793
|
return id || null;
|
|
39920
39794
|
}
|
|
39921
39795
|
|
|
@@ -39940,7 +39814,7 @@ function buildHistoryHandlers(deps) {
|
|
|
39940
39814
|
if (!pid) return false;
|
|
39941
39815
|
return isGuestPathAllowed(
|
|
39942
39816
|
ctx.grants,
|
|
39943
|
-
|
|
39817
|
+
path41.join(personaRoot, pid),
|
|
39944
39818
|
personaRoot,
|
|
39945
39819
|
"read"
|
|
39946
39820
|
);
|
|
@@ -39951,7 +39825,7 @@ function buildHistoryHandlers(deps) {
|
|
|
39951
39825
|
};
|
|
39952
39826
|
const list = async (frame, _client, ctx) => {
|
|
39953
39827
|
const args = HistoryListArgs.parse(frame);
|
|
39954
|
-
assertGuestPath(ctx,
|
|
39828
|
+
assertGuestPath(ctx, path41.resolve(args.projectPath), personaRoot, "history:list");
|
|
39955
39829
|
const sessions = await history.listSessions(args);
|
|
39956
39830
|
return { response: { type: "history:list", sessions } };
|
|
39957
39831
|
};
|
|
@@ -39983,13 +39857,13 @@ function buildHistoryHandlers(deps) {
|
|
|
39983
39857
|
};
|
|
39984
39858
|
const subagents = async (frame, _client, ctx) => {
|
|
39985
39859
|
const args = HistorySubagentsArgs.parse(frame);
|
|
39986
|
-
assertGuestPath(ctx,
|
|
39860
|
+
assertGuestPath(ctx, path41.resolve(args.cwd), personaRoot, "history:subagents");
|
|
39987
39861
|
const subs = await history.listSubagents(args);
|
|
39988
39862
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
39989
39863
|
};
|
|
39990
39864
|
const subagentRead = async (frame, _client, ctx) => {
|
|
39991
39865
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
39992
|
-
assertGuestPath(ctx,
|
|
39866
|
+
assertGuestPath(ctx, path41.resolve(args.cwd), personaRoot, "history:subagent-read");
|
|
39993
39867
|
const res = await history.readSubagent(args);
|
|
39994
39868
|
return { response: { type: "history:subagent-read", ...res } };
|
|
39995
39869
|
};
|
|
@@ -39997,7 +39871,7 @@ function buildHistoryHandlers(deps) {
|
|
|
39997
39871
|
const dirs = listRecentDirs(store);
|
|
39998
39872
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
39999
39873
|
const filtered = dirs.filter(
|
|
40000
|
-
(d) => isGuestPathAllowed(ctx.grants,
|
|
39874
|
+
(d) => isGuestPathAllowed(ctx.grants, path41.resolve(d.cwd), personaRoot, "read")
|
|
40001
39875
|
);
|
|
40002
39876
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
40003
39877
|
}
|
|
@@ -40014,7 +39888,7 @@ function buildHistoryHandlers(deps) {
|
|
|
40014
39888
|
}
|
|
40015
39889
|
|
|
40016
39890
|
// src/handlers/workspace.ts
|
|
40017
|
-
var
|
|
39891
|
+
var path42 = __toESM(require("path"), 1);
|
|
40018
39892
|
var os15 = __toESM(require("os"), 1);
|
|
40019
39893
|
init_protocol();
|
|
40020
39894
|
init_protocol();
|
|
@@ -40055,22 +39929,22 @@ function buildWorkspaceHandlers(deps) {
|
|
|
40055
39929
|
const args = WorkspaceListArgs.parse(frame);
|
|
40056
39930
|
const isGuest = ctx?.principal.kind === "guest";
|
|
40057
39931
|
const fallbackCwd = isGuest && personaRoot ? personaRoot : os15.homedir();
|
|
40058
|
-
const resolvedCwd =
|
|
40059
|
-
const target = args.path ?
|
|
39932
|
+
const resolvedCwd = path42.resolve(args.cwd ?? fallbackCwd);
|
|
39933
|
+
const target = args.path ? path42.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
40060
39934
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list");
|
|
40061
39935
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
40062
39936
|
return { response: { type: "workspace:list", ...res } };
|
|
40063
39937
|
};
|
|
40064
39938
|
const read = async (frame, _client, ctx) => {
|
|
40065
39939
|
const args = WorkspaceReadArgs.parse(frame);
|
|
40066
|
-
const target =
|
|
39940
|
+
const target = path42.isAbsolute(args.path) ? path42.resolve(args.path) : path42.resolve(args.cwd, args.path);
|
|
40067
39941
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read");
|
|
40068
39942
|
const res = workspace.read(args);
|
|
40069
39943
|
return { response: { type: "workspace:read", ...res } };
|
|
40070
39944
|
};
|
|
40071
39945
|
const skillsList = async (frame, _client, ctx) => {
|
|
40072
39946
|
const args = SkillsListArgs.parse(frame);
|
|
40073
|
-
const cwdAbs =
|
|
39947
|
+
const cwdAbs = path42.resolve(args.cwd);
|
|
40074
39948
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list");
|
|
40075
39949
|
const list2 = skills.list(args);
|
|
40076
39950
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -40082,7 +39956,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
40082
39956
|
};
|
|
40083
39957
|
const agentsList = async (frame, _client, ctx) => {
|
|
40084
39958
|
const args = AgentsListArgs.parse(frame);
|
|
40085
|
-
const cwdAbs =
|
|
39959
|
+
const cwdAbs = path42.resolve(args.cwd);
|
|
40086
39960
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list");
|
|
40087
39961
|
const list2 = agents.list(args);
|
|
40088
39962
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -40101,20 +39975,20 @@ function buildWorkspaceHandlers(deps) {
|
|
|
40101
39975
|
}
|
|
40102
39976
|
|
|
40103
39977
|
// src/handlers/git.ts
|
|
40104
|
-
var
|
|
39978
|
+
var path44 = __toESM(require("path"), 1);
|
|
40105
39979
|
init_protocol();
|
|
40106
39980
|
init_protocol();
|
|
40107
39981
|
|
|
40108
39982
|
// src/workspace/git.ts
|
|
40109
39983
|
var import_node_child_process6 = require("child_process");
|
|
40110
|
-
var
|
|
40111
|
-
var
|
|
39984
|
+
var import_node_fs28 = __toESM(require("fs"), 1);
|
|
39985
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
40112
39986
|
var import_node_util = require("util");
|
|
40113
39987
|
var pexec = (0, import_node_util.promisify)(import_node_child_process6.execFile);
|
|
40114
39988
|
function normalizePath(p2) {
|
|
40115
|
-
const resolved =
|
|
39989
|
+
const resolved = import_node_path32.default.resolve(p2);
|
|
40116
39990
|
try {
|
|
40117
|
-
return
|
|
39991
|
+
return import_node_fs28.default.realpathSync(resolved);
|
|
40118
39992
|
} catch {
|
|
40119
39993
|
return resolved;
|
|
40120
39994
|
}
|
|
@@ -40187,7 +40061,7 @@ async function listGitBranches(cwd) {
|
|
|
40187
40061
|
// src/handlers/git.ts
|
|
40188
40062
|
function assertGuestCwd(ctx, cwd, personaRoot, method) {
|
|
40189
40063
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
40190
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
40064
|
+
if (!isGuestPathAllowed(ctx.grants, path44.resolve(cwd), personaRoot, "read")) {
|
|
40191
40065
|
throw new ClawdError(
|
|
40192
40066
|
ERROR_CODES.UNAUTHORIZED,
|
|
40193
40067
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -40549,36 +40423,6 @@ function buildWhoamiHandler(deps) {
|
|
|
40549
40423
|
};
|
|
40550
40424
|
}
|
|
40551
40425
|
|
|
40552
|
-
// src/handlers/feishu-auth.ts
|
|
40553
|
-
function buildFeishuAuthHandlers(deps) {
|
|
40554
|
-
const loginStart = async () => {
|
|
40555
|
-
const { authUrl, state } = deps.loginFlow.start();
|
|
40556
|
-
return {
|
|
40557
|
-
response: { type: "auth:login:start:ok", authUrl, state }
|
|
40558
|
-
};
|
|
40559
|
-
};
|
|
40560
|
-
const getIdentity = async () => {
|
|
40561
|
-
const record = deps.ownerIdentityStore.read();
|
|
40562
|
-
return {
|
|
40563
|
-
response: {
|
|
40564
|
-
type: "auth:getIdentity:ok",
|
|
40565
|
-
identity: record ? record.identity : null
|
|
40566
|
-
}
|
|
40567
|
-
};
|
|
40568
|
-
};
|
|
40569
|
-
const logout = async () => {
|
|
40570
|
-
deps.ownerIdentityStore.clear();
|
|
40571
|
-
return {
|
|
40572
|
-
response: { type: "auth:logout:ok" }
|
|
40573
|
-
};
|
|
40574
|
-
};
|
|
40575
|
-
return {
|
|
40576
|
-
"auth:login:start": loginStart,
|
|
40577
|
-
"auth:getIdentity": getIdentity,
|
|
40578
|
-
"auth:logout": logout
|
|
40579
|
-
};
|
|
40580
|
-
}
|
|
40581
|
-
|
|
40582
40426
|
// src/handlers/meta.ts
|
|
40583
40427
|
var import_node_os15 = __toESM(require("os"), 1);
|
|
40584
40428
|
init_protocol();
|
|
@@ -40706,7 +40550,7 @@ function buildPersonaHandlers(deps) {
|
|
|
40706
40550
|
}
|
|
40707
40551
|
|
|
40708
40552
|
// src/handlers/attachment.ts
|
|
40709
|
-
var
|
|
40553
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
40710
40554
|
init_protocol();
|
|
40711
40555
|
init_protocol();
|
|
40712
40556
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -40760,12 +40604,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
40760
40604
|
`session ${args.sessionId} scope unresolved`
|
|
40761
40605
|
);
|
|
40762
40606
|
}
|
|
40763
|
-
const cwdAbs =
|
|
40764
|
-
const candidateAbs =
|
|
40607
|
+
const cwdAbs = import_node_path33.default.resolve(sessionFile.cwd);
|
|
40608
|
+
const candidateAbs = import_node_path33.default.isAbsolute(args.relPath) ? import_node_path33.default.resolve(args.relPath) : import_node_path33.default.resolve(cwdAbs, args.relPath);
|
|
40765
40609
|
assertGuestAttachmentPath(ctx, candidateAbs, deps.personaRoot, "attachment.signUrl");
|
|
40766
40610
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
40767
40611
|
const entry = entries.find((e) => {
|
|
40768
|
-
const storedAbs =
|
|
40612
|
+
const storedAbs = import_node_path33.default.isAbsolute(e.relPath) ? import_node_path33.default.resolve(e.relPath) : import_node_path33.default.resolve(cwdAbs, e.relPath);
|
|
40769
40613
|
return storedAbs === candidateAbs && !e.stale;
|
|
40770
40614
|
});
|
|
40771
40615
|
if (!entry) {
|
|
@@ -40789,7 +40633,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
40789
40633
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
40790
40634
|
const f = deps.sessionStore.read(sessionId);
|
|
40791
40635
|
if (!f) return;
|
|
40792
|
-
assertGuestAttachmentPath(ctx,
|
|
40636
|
+
assertGuestAttachmentPath(ctx, import_node_path33.default.resolve(f.cwd), deps.personaRoot, method);
|
|
40793
40637
|
}
|
|
40794
40638
|
const groupAdd = async (frame, _client, ctx) => {
|
|
40795
40639
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -40861,19 +40705,19 @@ function buildAttachmentHandlers(deps) {
|
|
|
40861
40705
|
|
|
40862
40706
|
// src/handlers/extension.ts
|
|
40863
40707
|
var import_promises7 = __toESM(require("fs/promises"), 1);
|
|
40864
|
-
var
|
|
40708
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
40865
40709
|
init_protocol();
|
|
40866
40710
|
|
|
40867
40711
|
// src/extension/bundle-zip.ts
|
|
40868
40712
|
var import_promises4 = __toESM(require("fs/promises"), 1);
|
|
40869
|
-
var
|
|
40870
|
-
var
|
|
40713
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
40714
|
+
var import_node_crypto11 = __toESM(require("crypto"), 1);
|
|
40871
40715
|
var import_jszip2 = __toESM(require_lib3(), 1);
|
|
40872
40716
|
async function bundleExtensionDir(dir) {
|
|
40873
40717
|
const entries = await listFilesSorted(dir);
|
|
40874
40718
|
const zip = new import_jszip2.default();
|
|
40875
40719
|
for (const rel of entries) {
|
|
40876
|
-
const abs =
|
|
40720
|
+
const abs = import_node_path34.default.join(dir, rel);
|
|
40877
40721
|
const content = await import_promises4.default.readFile(abs);
|
|
40878
40722
|
zip.file(rel, content, { date: FIXED_DATE });
|
|
40879
40723
|
}
|
|
@@ -40882,7 +40726,7 @@ async function bundleExtensionDir(dir) {
|
|
|
40882
40726
|
compression: "DEFLATE",
|
|
40883
40727
|
compressionOptions: { level: 6 }
|
|
40884
40728
|
});
|
|
40885
|
-
const sha256 =
|
|
40729
|
+
const sha256 = import_node_crypto11.default.createHash("sha256").update(buffer).digest("hex");
|
|
40886
40730
|
return { buffer, sha256 };
|
|
40887
40731
|
}
|
|
40888
40732
|
var FIXED_DATE = /* @__PURE__ */ new Date("2020-01-01T00:00:00.000Z");
|
|
@@ -40894,7 +40738,7 @@ async function listFilesSorted(rootDir) {
|
|
|
40894
40738
|
return out;
|
|
40895
40739
|
}
|
|
40896
40740
|
async function walk(absRoot, relPrefix, out) {
|
|
40897
|
-
const dirAbs =
|
|
40741
|
+
const dirAbs = import_node_path34.default.join(absRoot, relPrefix);
|
|
40898
40742
|
const entries = await import_promises4.default.readdir(dirAbs, { withFileTypes: true });
|
|
40899
40743
|
for (const e of entries) {
|
|
40900
40744
|
if (IGNORE_BASENAMES.has(e.name)) continue;
|
|
@@ -40948,25 +40792,25 @@ function computePublishCheck(args) {
|
|
|
40948
40792
|
|
|
40949
40793
|
// src/extension/install-flow.ts
|
|
40950
40794
|
var import_promises5 = __toESM(require("fs/promises"), 1);
|
|
40951
|
-
var
|
|
40795
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
40952
40796
|
var import_node_os17 = __toESM(require("os"), 1);
|
|
40953
|
-
var
|
|
40797
|
+
var import_node_crypto12 = __toESM(require("crypto"), 1);
|
|
40954
40798
|
var import_jszip3 = __toESM(require_lib3(), 1);
|
|
40955
40799
|
|
|
40956
40800
|
// src/extension/paths.ts
|
|
40957
40801
|
var import_node_os16 = __toESM(require("os"), 1);
|
|
40958
|
-
var
|
|
40802
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
40959
40803
|
function clawdHomeRoot(override) {
|
|
40960
|
-
return override ?? process.env.CLAWD_HOME ??
|
|
40804
|
+
return override ?? process.env.CLAWD_HOME ?? import_node_path35.default.join(import_node_os16.default.homedir(), ".clawd");
|
|
40961
40805
|
}
|
|
40962
40806
|
function extensionsRoot(override) {
|
|
40963
|
-
return
|
|
40807
|
+
return import_node_path35.default.join(clawdHomeRoot(override), "extensions");
|
|
40964
40808
|
}
|
|
40965
40809
|
function publishedChannelsFile(override) {
|
|
40966
|
-
return
|
|
40810
|
+
return import_node_path35.default.join(clawdHomeRoot(override), "extensions-published.json");
|
|
40967
40811
|
}
|
|
40968
40812
|
function bundleCacheRoot(override) {
|
|
40969
|
-
return
|
|
40813
|
+
return import_node_path35.default.join(clawdHomeRoot(override), "extension-bundles");
|
|
40970
40814
|
}
|
|
40971
40815
|
|
|
40972
40816
|
// src/extension/install-flow.ts
|
|
@@ -40979,7 +40823,7 @@ var InstallError = class extends Error {
|
|
|
40979
40823
|
};
|
|
40980
40824
|
async function installFromChannel(args, deps) {
|
|
40981
40825
|
const { channelRef, snapshotHash, bundleZip } = args;
|
|
40982
|
-
const computed =
|
|
40826
|
+
const computed = import_node_crypto12.default.createHash("sha256").update(bundleZip).digest("hex");
|
|
40983
40827
|
if (computed !== snapshotHash) {
|
|
40984
40828
|
throw new InstallError(
|
|
40985
40829
|
"HASH_MISMATCH",
|
|
@@ -40993,7 +40837,7 @@ async function installFromChannel(args, deps) {
|
|
|
40993
40837
|
throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
40994
40838
|
}
|
|
40995
40839
|
for (const name of Object.keys(zip.files)) {
|
|
40996
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
40840
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path36.default.isAbsolute(name)) {
|
|
40997
40841
|
throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
40998
40842
|
}
|
|
40999
40843
|
}
|
|
@@ -41025,7 +40869,7 @@ async function installFromChannel(args, deps) {
|
|
|
41025
40869
|
);
|
|
41026
40870
|
}
|
|
41027
40871
|
const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
|
|
41028
|
-
const destDir =
|
|
40872
|
+
const destDir = import_node_path36.default.join(deps.extensionsRoot, localExtId);
|
|
41029
40873
|
let destExists = false;
|
|
41030
40874
|
try {
|
|
41031
40875
|
await import_promises5.default.access(destDir);
|
|
@@ -41039,16 +40883,16 @@ async function installFromChannel(args, deps) {
|
|
|
41039
40883
|
);
|
|
41040
40884
|
}
|
|
41041
40885
|
const stage = await import_promises5.default.mkdtemp(
|
|
41042
|
-
|
|
40886
|
+
import_node_path36.default.join(import_node_os17.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
|
|
41043
40887
|
);
|
|
41044
40888
|
try {
|
|
41045
40889
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
41046
|
-
const dest =
|
|
40890
|
+
const dest = import_node_path36.default.join(stage, name);
|
|
41047
40891
|
if (entry.dir) {
|
|
41048
40892
|
await import_promises5.default.mkdir(dest, { recursive: true });
|
|
41049
40893
|
continue;
|
|
41050
40894
|
}
|
|
41051
|
-
await import_promises5.default.mkdir(
|
|
40895
|
+
await import_promises5.default.mkdir(import_node_path36.default.dirname(dest), { recursive: true });
|
|
41052
40896
|
if (name === "manifest.json") {
|
|
41053
40897
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
41054
40898
|
await import_promises5.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -41069,9 +40913,9 @@ async function installFromChannel(args, deps) {
|
|
|
41069
40913
|
|
|
41070
40914
|
// src/extension/update-flow.ts
|
|
41071
40915
|
var import_promises6 = __toESM(require("fs/promises"), 1);
|
|
41072
|
-
var
|
|
40916
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
41073
40917
|
var import_node_os18 = __toESM(require("os"), 1);
|
|
41074
|
-
var
|
|
40918
|
+
var import_node_crypto13 = __toESM(require("crypto"), 1);
|
|
41075
40919
|
var import_jszip4 = __toESM(require_lib3(), 1);
|
|
41076
40920
|
var UpdateError = class extends Error {
|
|
41077
40921
|
constructor(code, message) {
|
|
@@ -41086,11 +40930,11 @@ async function updateFromChannel(args, deps) {
|
|
|
41086
40930
|
channelRef.extId,
|
|
41087
40931
|
channelRef.ownerPrincipalId
|
|
41088
40932
|
);
|
|
41089
|
-
const liveDir =
|
|
40933
|
+
const liveDir = import_node_path37.default.join(deps.extensionsRoot, localExtId);
|
|
41090
40934
|
const prevDir = `${liveDir}.prev`;
|
|
41091
40935
|
let existingVersion;
|
|
41092
40936
|
try {
|
|
41093
|
-
const raw = await import_promises6.default.readFile(
|
|
40937
|
+
const raw = await import_promises6.default.readFile(import_node_path37.default.join(liveDir, "manifest.json"), "utf8");
|
|
41094
40938
|
const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
|
|
41095
40939
|
if (!parsed2.success) {
|
|
41096
40940
|
throw new UpdateError(
|
|
@@ -41109,7 +40953,7 @@ async function updateFromChannel(args, deps) {
|
|
|
41109
40953
|
if (e instanceof UpdateError) throw e;
|
|
41110
40954
|
throw e;
|
|
41111
40955
|
}
|
|
41112
|
-
const computed =
|
|
40956
|
+
const computed = import_node_crypto13.default.createHash("sha256").update(bundleZip).digest("hex");
|
|
41113
40957
|
if (computed !== snapshotHash) {
|
|
41114
40958
|
throw new UpdateError(
|
|
41115
40959
|
"HASH_MISMATCH",
|
|
@@ -41123,7 +40967,7 @@ async function updateFromChannel(args, deps) {
|
|
|
41123
40967
|
throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
41124
40968
|
}
|
|
41125
40969
|
for (const name of Object.keys(zip.files)) {
|
|
41126
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
40970
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path37.default.isAbsolute(name)) {
|
|
41127
40971
|
throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
41128
40972
|
}
|
|
41129
40973
|
}
|
|
@@ -41158,16 +41002,16 @@ async function updateFromChannel(args, deps) {
|
|
|
41158
41002
|
await import_promises6.default.rm(prevDir, { recursive: true, force: true });
|
|
41159
41003
|
await import_promises6.default.rename(liveDir, prevDir);
|
|
41160
41004
|
const stage = await import_promises6.default.mkdtemp(
|
|
41161
|
-
|
|
41005
|
+
import_node_path37.default.join(import_node_os18.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
|
|
41162
41006
|
);
|
|
41163
41007
|
try {
|
|
41164
41008
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
41165
|
-
const dest =
|
|
41009
|
+
const dest = import_node_path37.default.join(stage, name);
|
|
41166
41010
|
if (entry.dir) {
|
|
41167
41011
|
await import_promises6.default.mkdir(dest, { recursive: true });
|
|
41168
41012
|
continue;
|
|
41169
41013
|
}
|
|
41170
|
-
await import_promises6.default.mkdir(
|
|
41014
|
+
await import_promises6.default.mkdir(import_node_path37.default.dirname(dest), { recursive: true });
|
|
41171
41015
|
if (name === "manifest.json") {
|
|
41172
41016
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
41173
41017
|
await import_promises6.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -41260,7 +41104,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
41260
41104
|
);
|
|
41261
41105
|
}
|
|
41262
41106
|
}
|
|
41263
|
-
const manifestPath =
|
|
41107
|
+
const manifestPath = import_node_path38.default.join(root, extId, "manifest.json");
|
|
41264
41108
|
const manifest = await readManifest(root, extId);
|
|
41265
41109
|
const next = { ...manifest, version: newVersion };
|
|
41266
41110
|
const tmp = `${manifestPath}.tmp`;
|
|
@@ -41268,7 +41112,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
41268
41112
|
await import_promises7.default.rename(tmp, manifestPath);
|
|
41269
41113
|
}
|
|
41270
41114
|
async function readManifest(root, extId) {
|
|
41271
|
-
const file =
|
|
41115
|
+
const file = import_node_path38.default.join(root, extId, "manifest.json");
|
|
41272
41116
|
let raw;
|
|
41273
41117
|
try {
|
|
41274
41118
|
raw = await import_promises7.default.readFile(file, "utf8");
|
|
@@ -41359,7 +41203,7 @@ function buildExtensionHandlers(deps) {
|
|
|
41359
41203
|
};
|
|
41360
41204
|
async function buildSnapshotMeta(extId) {
|
|
41361
41205
|
const manifest = await readManifest(deps.root, extId);
|
|
41362
|
-
const { sha256, buffer } = await bundleExtensionDir(
|
|
41206
|
+
const { sha256, buffer } = await bundleExtensionDir(import_node_path38.default.join(deps.root, extId));
|
|
41363
41207
|
return { manifest, contentHash: sha256, buffer };
|
|
41364
41208
|
}
|
|
41365
41209
|
const publish = async (frame, _client, ctx) => {
|
|
@@ -41539,9 +41383,64 @@ function buildExtensionHandlers(deps) {
|
|
|
41539
41383
|
};
|
|
41540
41384
|
}
|
|
41541
41385
|
|
|
41386
|
+
// src/handlers/app-builder.ts
|
|
41387
|
+
function buildAppBuilderHandlers(deps) {
|
|
41388
|
+
const { store, deleteSessionsByProject, devServerLifecycle } = deps;
|
|
41389
|
+
const listProjects = async () => {
|
|
41390
|
+
const projects = await store.list();
|
|
41391
|
+
return {
|
|
41392
|
+
response: {
|
|
41393
|
+
projects: projects.map((p2) => ({
|
|
41394
|
+
...p2,
|
|
41395
|
+
isRunning: devServerLifecycle.isRunning(p2.name),
|
|
41396
|
+
boundSessionId: devServerLifecycle.boundSessionId(p2.name)
|
|
41397
|
+
}))
|
|
41398
|
+
}
|
|
41399
|
+
};
|
|
41400
|
+
};
|
|
41401
|
+
const createProject = async (frame) => {
|
|
41402
|
+
const name = frame.name;
|
|
41403
|
+
if (typeof name !== "string") throw new Error("createProject: name must be string");
|
|
41404
|
+
const project = await store.create(name);
|
|
41405
|
+
return { response: { project } };
|
|
41406
|
+
};
|
|
41407
|
+
const deleteProject = async (frame) => {
|
|
41408
|
+
const name = frame.name;
|
|
41409
|
+
if (typeof name !== "string") throw new Error("deleteProject: name must be string");
|
|
41410
|
+
await devServerLifecycle.stopForProject(name);
|
|
41411
|
+
await deleteSessionsByProject(name);
|
|
41412
|
+
await store.delete(name);
|
|
41413
|
+
return { response: {} };
|
|
41414
|
+
};
|
|
41415
|
+
const updateProjectPort = async (frame) => {
|
|
41416
|
+
const f = frame;
|
|
41417
|
+
if (typeof f.name !== "string") throw new Error("updateProjectPort: name must be string");
|
|
41418
|
+
if (typeof f.newPort !== "number") throw new Error("updateProjectPort: newPort must be number");
|
|
41419
|
+
const entry = devServerLifecycle.boundEntry(f.name);
|
|
41420
|
+
await devServerLifecycle.stopForProject(f.name);
|
|
41421
|
+
const project = await store.updatePort(f.name, f.newPort);
|
|
41422
|
+
if (entry) {
|
|
41423
|
+
await devServerLifecycle.restartForProjectAt({
|
|
41424
|
+
projectName: f.name,
|
|
41425
|
+
newPort: f.newPort,
|
|
41426
|
+
sessionId: entry.sessionId,
|
|
41427
|
+
cwd: entry.cwd,
|
|
41428
|
+
tunnelHost: entry.tunnelHost
|
|
41429
|
+
});
|
|
41430
|
+
}
|
|
41431
|
+
return { response: { project } };
|
|
41432
|
+
};
|
|
41433
|
+
return {
|
|
41434
|
+
"appBuilder:listProjects": listProjects,
|
|
41435
|
+
"appBuilder:createProject": createProject,
|
|
41436
|
+
"appBuilder:deleteProject": deleteProject,
|
|
41437
|
+
"appBuilder:updateProjectPort": updateProjectPort
|
|
41438
|
+
};
|
|
41439
|
+
}
|
|
41440
|
+
|
|
41542
41441
|
// src/extension/registry.ts
|
|
41543
41442
|
var import_promises8 = __toESM(require("fs/promises"), 1);
|
|
41544
|
-
var
|
|
41443
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
41545
41444
|
async function loadAll(root) {
|
|
41546
41445
|
let entries;
|
|
41547
41446
|
try {
|
|
@@ -41554,13 +41453,13 @@ async function loadAll(root) {
|
|
|
41554
41453
|
for (const ent of entries) {
|
|
41555
41454
|
if (!ent.isDirectory()) continue;
|
|
41556
41455
|
if (ent.name.startsWith(".")) continue;
|
|
41557
|
-
records.push(await loadOne(
|
|
41456
|
+
records.push(await loadOne(import_node_path39.default.join(root, ent.name), ent.name));
|
|
41558
41457
|
}
|
|
41559
41458
|
records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
|
|
41560
41459
|
return records;
|
|
41561
41460
|
}
|
|
41562
41461
|
async function loadOne(dir, dirName) {
|
|
41563
|
-
const manifestPath =
|
|
41462
|
+
const manifestPath = import_node_path39.default.join(dir, "manifest.json");
|
|
41564
41463
|
let raw;
|
|
41565
41464
|
try {
|
|
41566
41465
|
raw = await import_promises8.default.readFile(manifestPath, "utf8");
|
|
@@ -41605,7 +41504,7 @@ async function loadOne(dir, dirName) {
|
|
|
41605
41504
|
|
|
41606
41505
|
// src/extension/uninstall.ts
|
|
41607
41506
|
var import_promises9 = __toESM(require("fs/promises"), 1);
|
|
41608
|
-
var
|
|
41507
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
41609
41508
|
var UninstallError = class extends Error {
|
|
41610
41509
|
constructor(code, message) {
|
|
41611
41510
|
super(message);
|
|
@@ -41614,7 +41513,7 @@ var UninstallError = class extends Error {
|
|
|
41614
41513
|
code;
|
|
41615
41514
|
};
|
|
41616
41515
|
async function uninstall(deps) {
|
|
41617
|
-
const dir =
|
|
41516
|
+
const dir = import_node_path40.default.join(deps.root, deps.extId);
|
|
41618
41517
|
try {
|
|
41619
41518
|
await import_promises9.default.access(dir);
|
|
41620
41519
|
} catch {
|
|
@@ -41660,7 +41559,6 @@ function buildMethodHandlers(deps) {
|
|
|
41660
41559
|
personaStore: deps.personaStore,
|
|
41661
41560
|
capabilityManager: deps.capabilityManager
|
|
41662
41561
|
}),
|
|
41663
|
-
...buildFeishuAuthHandlers(deps.feishuAuth),
|
|
41664
41562
|
...deps.attachment ? buildAttachmentHandlers(deps.attachment) : {},
|
|
41665
41563
|
...buildExtensionHandlers({
|
|
41666
41564
|
loadAll,
|
|
@@ -41669,10 +41567,186 @@ function buildMethodHandlers(deps) {
|
|
|
41669
41567
|
root: extensionsRoot(),
|
|
41670
41568
|
publishedChannelStore: deps.publishedChannelStore,
|
|
41671
41569
|
bundleCache: deps.bundleCache
|
|
41570
|
+
}),
|
|
41571
|
+
...buildAppBuilderHandlers({
|
|
41572
|
+
store: deps.appBuilderStore,
|
|
41573
|
+
deleteSessionsByProject: deps.deleteSessionsByProject,
|
|
41574
|
+
devServerLifecycle: deps.devServerLifecycle
|
|
41672
41575
|
})
|
|
41673
41576
|
};
|
|
41674
41577
|
}
|
|
41675
41578
|
|
|
41579
|
+
// src/app-builder/project-store.ts
|
|
41580
|
+
var import_node_fs29 = require("fs");
|
|
41581
|
+
var import_node_path41 = require("path");
|
|
41582
|
+
init_protocol();
|
|
41583
|
+
var PROJECTS_DIR = "projects";
|
|
41584
|
+
var META_FILE = ".clawd-project.json";
|
|
41585
|
+
var ProjectStore = class {
|
|
41586
|
+
/** @param personaRoot persona 目录,例如 `~/.clawd/personas/persona-app-builder/` */
|
|
41587
|
+
constructor(personaRoot) {
|
|
41588
|
+
this.personaRoot = personaRoot;
|
|
41589
|
+
}
|
|
41590
|
+
personaRoot;
|
|
41591
|
+
/** projects/<name>/.clawd-project.json 路径 */
|
|
41592
|
+
metaPath(name) {
|
|
41593
|
+
return (0, import_node_path41.join)(this.projectsRoot(), name, META_FILE);
|
|
41594
|
+
}
|
|
41595
|
+
/** projects/<name>/ 目录路径(cwd 用) */
|
|
41596
|
+
projectDir(name) {
|
|
41597
|
+
return (0, import_node_path41.join)(this.projectsRoot(), name);
|
|
41598
|
+
}
|
|
41599
|
+
projectsRoot() {
|
|
41600
|
+
return (0, import_node_path41.join)(this.personaRoot, PROJECTS_DIR);
|
|
41601
|
+
}
|
|
41602
|
+
async list() {
|
|
41603
|
+
let entries;
|
|
41604
|
+
try {
|
|
41605
|
+
entries = await import_node_fs29.promises.readdir(this.projectsRoot());
|
|
41606
|
+
} catch (err) {
|
|
41607
|
+
if (err.code === "ENOENT") return [];
|
|
41608
|
+
throw err;
|
|
41609
|
+
}
|
|
41610
|
+
const out = [];
|
|
41611
|
+
for (const name of entries) {
|
|
41612
|
+
try {
|
|
41613
|
+
const raw = await import_node_fs29.promises.readFile(this.metaPath(name), "utf8");
|
|
41614
|
+
const parsed = ProjectMetadataSchema.safeParse(JSON.parse(raw));
|
|
41615
|
+
if (parsed.success) out.push(parsed.data);
|
|
41616
|
+
} catch {
|
|
41617
|
+
}
|
|
41618
|
+
}
|
|
41619
|
+
return out.sort((a, b2) => a.name.localeCompare(b2.name));
|
|
41620
|
+
}
|
|
41621
|
+
async create(name) {
|
|
41622
|
+
const existing = await this.list();
|
|
41623
|
+
if (existing.some((p2) => p2.name === name)) {
|
|
41624
|
+
throw new Error(`project "${name}" already exists / \u5DF2\u5B58\u5728`);
|
|
41625
|
+
}
|
|
41626
|
+
const usedPorts = new Set(existing.map((p2) => p2.port));
|
|
41627
|
+
let port = -1;
|
|
41628
|
+
for (let p2 = PROJECT_PORT_MIN; p2 <= PROJECT_PORT_MAX; p2++) {
|
|
41629
|
+
if (!usedPorts.has(p2)) {
|
|
41630
|
+
port = p2;
|
|
41631
|
+
break;
|
|
41632
|
+
}
|
|
41633
|
+
}
|
|
41634
|
+
if (port < 0) {
|
|
41635
|
+
throw new Error(
|
|
41636
|
+
`port pool exhausted / \u7AEF\u53E3\u6C60\u5DF2\u6EE1\uFF08${PROJECT_PORT_MIN}-${PROJECT_PORT_MAX}\uFF09\uFF0C\u5148\u5220\u4E00\u4E2A project \u91CA\u653E\u7AEF\u53E3`
|
|
41637
|
+
);
|
|
41638
|
+
}
|
|
41639
|
+
const meta = {
|
|
41640
|
+
name,
|
|
41641
|
+
port,
|
|
41642
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
41643
|
+
};
|
|
41644
|
+
const validated = ProjectMetadataSchema.safeParse(meta);
|
|
41645
|
+
if (!validated.success) {
|
|
41646
|
+
throw new Error(`invalid name "${name}": ${validated.error.message}`);
|
|
41647
|
+
}
|
|
41648
|
+
const dir = this.projectDir(name);
|
|
41649
|
+
await import_node_fs29.promises.mkdir(dir, { recursive: true });
|
|
41650
|
+
await import_node_fs29.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
|
|
41651
|
+
return meta;
|
|
41652
|
+
}
|
|
41653
|
+
async delete(name) {
|
|
41654
|
+
const dir = this.projectDir(name);
|
|
41655
|
+
await import_node_fs29.promises.rm(dir, { recursive: true, force: true });
|
|
41656
|
+
}
|
|
41657
|
+
async updatePort(name, newPort) {
|
|
41658
|
+
if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
|
|
41659
|
+
throw new Error(
|
|
41660
|
+
`port range invalid: must be ${PROJECT_PORT_MIN}-${PROJECT_PORT_MAX}, got ${newPort}`
|
|
41661
|
+
);
|
|
41662
|
+
}
|
|
41663
|
+
const list = await this.list();
|
|
41664
|
+
const target = list.find((p2) => p2.name === name);
|
|
41665
|
+
if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
|
|
41666
|
+
const conflict = list.find((p2) => p2.name !== name && p2.port === newPort);
|
|
41667
|
+
if (conflict) {
|
|
41668
|
+
throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
|
|
41669
|
+
}
|
|
41670
|
+
const updated = { ...target, port: newPort };
|
|
41671
|
+
await import_node_fs29.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
|
|
41672
|
+
return updated;
|
|
41673
|
+
}
|
|
41674
|
+
};
|
|
41675
|
+
|
|
41676
|
+
// src/app-builder/dev-server-supervisor.ts
|
|
41677
|
+
var import_node_child_process7 = require("child_process");
|
|
41678
|
+
var import_node_events2 = require("events");
|
|
41679
|
+
var DevServerSupervisor = class extends import_node_events2.EventEmitter {
|
|
41680
|
+
running = /* @__PURE__ */ new Map();
|
|
41681
|
+
// key: sessionId
|
|
41682
|
+
startForSession(args) {
|
|
41683
|
+
if (this.running.has(args.sessionId)) return;
|
|
41684
|
+
const env = {
|
|
41685
|
+
...process.env,
|
|
41686
|
+
CLAWD_TUNNEL_HOST: args.tunnelHost ?? "",
|
|
41687
|
+
CLAWD_PREVIEW_PORT: String(args.port)
|
|
41688
|
+
};
|
|
41689
|
+
const child = (0, import_node_child_process7.spawn)("pnpm", ["dev"], { cwd: args.cwd, env, stdio: "pipe" });
|
|
41690
|
+
const entry = { ...args, process: child };
|
|
41691
|
+
this.running.set(args.sessionId, entry);
|
|
41692
|
+
child.on("exit", (code) => {
|
|
41693
|
+
this.running.delete(args.sessionId);
|
|
41694
|
+
if (code !== 0 && code !== null) {
|
|
41695
|
+
const ev = {
|
|
41696
|
+
sessionId: args.sessionId,
|
|
41697
|
+
projectName: args.projectName,
|
|
41698
|
+
port: args.port,
|
|
41699
|
+
exitCode: code
|
|
41700
|
+
};
|
|
41701
|
+
this.emit("devServer:failed", ev);
|
|
41702
|
+
}
|
|
41703
|
+
});
|
|
41704
|
+
}
|
|
41705
|
+
stopForSession(sessionId) {
|
|
41706
|
+
const entry = this.running.get(sessionId);
|
|
41707
|
+
if (!entry) return Promise.resolve();
|
|
41708
|
+
return new Promise((resolve6) => {
|
|
41709
|
+
entry.process.once("exit", () => {
|
|
41710
|
+
this.running.delete(sessionId);
|
|
41711
|
+
resolve6();
|
|
41712
|
+
});
|
|
41713
|
+
entry.process.kill("SIGTERM");
|
|
41714
|
+
});
|
|
41715
|
+
}
|
|
41716
|
+
async stopForProject(projectName) {
|
|
41717
|
+
const entry = [...this.running.values()].find((e) => e.projectName === projectName);
|
|
41718
|
+
if (!entry) return;
|
|
41719
|
+
await this.stopForSession(entry.sessionId);
|
|
41720
|
+
}
|
|
41721
|
+
async restartForProjectAt(args) {
|
|
41722
|
+
await this.stopForSession(args.sessionId);
|
|
41723
|
+
this.startForSession({
|
|
41724
|
+
sessionId: args.sessionId,
|
|
41725
|
+
projectName: args.projectName,
|
|
41726
|
+
port: args.newPort,
|
|
41727
|
+
cwd: args.cwd,
|
|
41728
|
+
tunnelHost: args.tunnelHost
|
|
41729
|
+
});
|
|
41730
|
+
}
|
|
41731
|
+
isRunning(projectName) {
|
|
41732
|
+
return [...this.running.values()].some((e) => e.projectName === projectName);
|
|
41733
|
+
}
|
|
41734
|
+
boundSessionId(projectName) {
|
|
41735
|
+
const entry = [...this.running.values()].find((e) => e.projectName === projectName);
|
|
41736
|
+
return entry?.sessionId ?? null;
|
|
41737
|
+
}
|
|
41738
|
+
boundEntry(projectName) {
|
|
41739
|
+
const entry = [...this.running.values()].find((e) => e.projectName === projectName);
|
|
41740
|
+
if (!entry) return null;
|
|
41741
|
+
return {
|
|
41742
|
+
sessionId: entry.sessionId,
|
|
41743
|
+
cwd: entry.cwd,
|
|
41744
|
+
port: entry.port,
|
|
41745
|
+
tunnelHost: entry.tunnelHost
|
|
41746
|
+
};
|
|
41747
|
+
}
|
|
41748
|
+
};
|
|
41749
|
+
|
|
41676
41750
|
// src/handlers/method-grants.ts
|
|
41677
41751
|
var ADMIN_ANY = {
|
|
41678
41752
|
kind: "fixed",
|
|
@@ -41803,11 +41877,14 @@ var METHOD_GRANT_MAP = {
|
|
|
41803
41877
|
// guest-self:guest 在自己 daemon 上触发安装与更新(无持久化 subscription 概念)
|
|
41804
41878
|
"extension.install-from-channel": ADMIN_ANY,
|
|
41805
41879
|
"extension.update-from-channel": ADMIN_ANY,
|
|
41806
|
-
// ----
|
|
41807
|
-
//
|
|
41808
|
-
|
|
41809
|
-
|
|
41810
|
-
"
|
|
41880
|
+
// ---- app-builder Project picker(spec 2026-06-01-app-builder-project-picker-design) ----
|
|
41881
|
+
// owner-only:picker UI 给 owner 管理本机 build 中的 project(fs + 端口分配)。
|
|
41882
|
+
// 即使 persona-app-builder 是 PreinstalledPersona,project 管理也属本机 owner 行为,
|
|
41883
|
+
// 不暴露给 guest(远端接入者)。
|
|
41884
|
+
"appBuilder:listProjects": ADMIN_ANY,
|
|
41885
|
+
"appBuilder:createProject": ADMIN_ANY,
|
|
41886
|
+
"appBuilder:deleteProject": ADMIN_ANY,
|
|
41887
|
+
"appBuilder:updateProjectPort": ADMIN_ANY
|
|
41811
41888
|
};
|
|
41812
41889
|
function computeGrantForFrame(method, frame) {
|
|
41813
41890
|
const rule = METHOD_GRANT_MAP[method];
|
|
@@ -41823,12 +41900,12 @@ function computeGrantForFrame(method, frame) {
|
|
|
41823
41900
|
}
|
|
41824
41901
|
|
|
41825
41902
|
// src/extension/runtime.ts
|
|
41826
|
-
var
|
|
41903
|
+
var import_node_child_process8 = require("child_process");
|
|
41827
41904
|
var import_node_path42 = __toESM(require("path"), 1);
|
|
41828
41905
|
var import_promises10 = require("timers/promises");
|
|
41829
41906
|
|
|
41830
41907
|
// src/extension/port-allocator.ts
|
|
41831
|
-
var
|
|
41908
|
+
var import_node_net2 = __toESM(require("net"), 1);
|
|
41832
41909
|
var PortExhaustedError = class extends Error {
|
|
41833
41910
|
constructor(min, max) {
|
|
41834
41911
|
super(`no free port in [${min},${max}]`);
|
|
@@ -41841,7 +41918,7 @@ var PortExhaustedError = class extends Error {
|
|
|
41841
41918
|
};
|
|
41842
41919
|
function probe(port) {
|
|
41843
41920
|
return new Promise((resolve6) => {
|
|
41844
|
-
const srv =
|
|
41921
|
+
const srv = import_node_net2.default.createServer();
|
|
41845
41922
|
srv.once("error", () => resolve6(false));
|
|
41846
41923
|
srv.once("listening", () => {
|
|
41847
41924
|
srv.close(() => resolve6(true));
|
|
@@ -41931,7 +42008,7 @@ var Runtime = class {
|
|
|
41931
42008
|
CLAWOS_EXT_PORT: String(port),
|
|
41932
42009
|
CLAWOS_EXT_ID: extId
|
|
41933
42010
|
};
|
|
41934
|
-
const child = (0,
|
|
42011
|
+
const child = (0, import_node_child_process8.spawn)("sh", ["-c", cmd], {
|
|
41935
42012
|
cwd: dir,
|
|
41936
42013
|
env,
|
|
41937
42014
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -42197,11 +42274,8 @@ async function startDaemon(config) {
|
|
|
42197
42274
|
} else if (config.tunnel) {
|
|
42198
42275
|
resolvedAuthToken = authFile.token;
|
|
42199
42276
|
}
|
|
42200
|
-
const
|
|
42201
|
-
const
|
|
42202
|
-
let feishuActive = feishuIdentity !== null;
|
|
42203
|
-
let ownerPrincipalId = feishuIdentity?.identity.unionId ?? authFile.ownerPrincipalId;
|
|
42204
|
-
let ownerDisplayName = feishuIdentity?.identity.displayName ?? loadOwnerDisplayName(config.dataDir);
|
|
42277
|
+
const ownerPrincipalId = authFile.ownerPrincipalId;
|
|
42278
|
+
const ownerDisplayName = loadOwnerDisplayName(config.dataDir);
|
|
42205
42279
|
const authMode = resolvedAuthToken == null ? "none" : "first-message";
|
|
42206
42280
|
const inboxStore = new InboxStore(config.dataDir);
|
|
42207
42281
|
const inboxManager = new InboxManager(inboxStore, (_peerOwnerId, frame) => {
|
|
@@ -42243,9 +42317,7 @@ async function startDaemon(config) {
|
|
|
42243
42317
|
isOwnerToken: (x) => resolvedAuthToken != null && constantTimeEqual(x, resolvedAuthToken),
|
|
42244
42318
|
ownerPrincipalId,
|
|
42245
42319
|
ownerDisplayName,
|
|
42246
|
-
|
|
42247
|
-
// 不传 registry 让 guest token 一律 BAD_TOKEN。owner 自己连接不受影响。
|
|
42248
|
-
...feishuActive ? { capabilityRegistry } : {},
|
|
42320
|
+
capabilityRegistry,
|
|
42249
42321
|
selfPrincipalId,
|
|
42250
42322
|
selfDisplayName
|
|
42251
42323
|
});
|
|
@@ -42402,13 +42474,13 @@ async function startDaemon(config) {
|
|
|
42402
42474
|
const publishedChannelStore = new PublishedChannelStore(publishedChannelsFile());
|
|
42403
42475
|
await publishedChannelStore.load();
|
|
42404
42476
|
const bundleCache = new BundleCache(bundleCacheRoot());
|
|
42405
|
-
const
|
|
42406
|
-
|
|
42407
|
-
|
|
42408
|
-
|
|
42409
|
-
|
|
42410
|
-
}
|
|
42411
|
-
const
|
|
42477
|
+
const appBuilderStore = new ProjectStore(
|
|
42478
|
+
import_node_path45.default.join(config.dataDir, "personas/persona-app-builder")
|
|
42479
|
+
);
|
|
42480
|
+
const devServerSupervisor = new DevServerSupervisor();
|
|
42481
|
+
const deleteSessionsByProject = async (_name) => {
|
|
42482
|
+
};
|
|
42483
|
+
const handlers = buildMethodHandlers({
|
|
42412
42484
|
manager,
|
|
42413
42485
|
workspace,
|
|
42414
42486
|
skills,
|
|
@@ -42481,10 +42553,11 @@ async function startDaemon(config) {
|
|
|
42481
42553
|
// extension sharing v1 — owner-side published-channels store.
|
|
42482
42554
|
publishedChannelStore,
|
|
42483
42555
|
bundleCache,
|
|
42484
|
-
//
|
|
42485
|
-
|
|
42556
|
+
// app-builder
|
|
42557
|
+
appBuilderStore,
|
|
42558
|
+
deleteSessionsByProject,
|
|
42559
|
+
devServerLifecycle: devServerSupervisor
|
|
42486
42560
|
});
|
|
42487
|
-
let handlers = makeHandlers();
|
|
42488
42561
|
const authResolver = new AuthContextResolver({
|
|
42489
42562
|
ownerToken: resolvedAuthToken
|
|
42490
42563
|
});
|
|
@@ -42510,29 +42583,8 @@ async function startDaemon(config) {
|
|
|
42510
42583
|
},
|
|
42511
42584
|
// POST /extensions/import lands in ~/.clawd/extensions/<id>/
|
|
42512
42585
|
extensionsRoot: () => extensionsRoot(),
|
|
42513
|
-
//
|
|
42514
|
-
|
|
42515
|
-
// 2. 广播 auth:login:done 给在线 owner 连接(UI 即时反馈)
|
|
42516
|
-
// 3. 踢掉所有 ws 连接(在线连接的 ctx 是旧身份)→ UI 自动重连 → 新身份 ctx →
|
|
42517
|
-
// People 立即解锁,不需要重启 daemon
|
|
42518
|
-
// 失败则广播 auth:login:failed。
|
|
42519
|
-
feishuLogin: {
|
|
42520
|
-
handleLoginCallback: async (params) => {
|
|
42521
|
-
const result = await loginFlow.handleCallback(params);
|
|
42522
|
-
if (result.ok) {
|
|
42523
|
-
feishuActive = true;
|
|
42524
|
-
ownerPrincipalId = result.identity.unionId;
|
|
42525
|
-
ownerDisplayName = result.identity.displayName;
|
|
42526
|
-
handlers = makeHandlers();
|
|
42527
|
-
wsServer?.setOwnerPrincipalId(result.identity.unionId);
|
|
42528
|
-
wsServer?.broadcastToOwners({ type: "auth:login:done", identity: result.identity });
|
|
42529
|
-
setImmediate(() => wsServer?.closeAllClients());
|
|
42530
|
-
} else {
|
|
42531
|
-
wsServer?.broadcastToOwners({ type: "auth:login:failed", reason: result.reason });
|
|
42532
|
-
}
|
|
42533
|
-
return result;
|
|
42534
|
-
}
|
|
42535
|
-
}
|
|
42586
|
+
// app-builder build 模式:/preview/<port>/ 反代 dev server 的端口白名单(见 spec §三.2)
|
|
42587
|
+
previewPorts: config.previewPorts ?? void 0
|
|
42536
42588
|
});
|
|
42537
42589
|
wsServer = new LocalWsServer({
|
|
42538
42590
|
host: config.host,
|
|
@@ -42571,6 +42623,8 @@ async function startDaemon(config) {
|
|
|
42571
42623
|
},
|
|
42572
42624
|
// file-sharing HTTP 路由复用 daemon 同端口(spec §5 第 3 条);router 自己处理 auth + 404
|
|
42573
42625
|
httpRequestHandler: httpRouter,
|
|
42626
|
+
// app-builder build 模式:/preview/<port>/ HMR websocket upgrade 转发的端口白名单(同 http-router 配置)
|
|
42627
|
+
previewPorts: config.previewPorts ?? void 0,
|
|
42574
42628
|
// 订阅成功后给该 client 重放 in-flight pendingQuestions(plan: clawd-question-server-truth)。
|
|
42575
42629
|
// daemon 是 pendingQuestions 的唯一 source of truth;新 client 接入 / 刷新页面时
|
|
42576
42630
|
// 把当前所有未决 question 以 session:question 帧定向回放,让 UI 不再误显示 Ended。
|
|
@@ -42615,12 +42669,6 @@ async function startDaemon(config) {
|
|
|
42615
42669
|
const requestId = typeof frame.requestId === "string" ? frame.requestId : void 0;
|
|
42616
42670
|
const handler = handlers[type];
|
|
42617
42671
|
if (!handler) throw new ClawdError(ERROR_CODES.METHOD_NOT_IMPLEMENTED, `not implemented: ${type}`);
|
|
42618
|
-
if (!feishuActive && FEISHU_GATED_METHODS.includes(type)) {
|
|
42619
|
-
throw new ClawdError(
|
|
42620
|
-
ERROR_CODES.FEISHU_LOGIN_REQUIRED,
|
|
42621
|
-
`${type} requires feishu login (People/remote identity)`
|
|
42622
|
-
);
|
|
42623
|
-
}
|
|
42624
42672
|
const ctx = wsServer.getClientContext(client.id) ?? ownerContext(ownerPrincipalId, ownerDisplayName);
|
|
42625
42673
|
const verdict = computeGrantForFrame(type, frame);
|
|
42626
42674
|
if (verdict.kind === "check") {
|
|
@@ -42693,6 +42741,7 @@ async function startDaemon(config) {
|
|
|
42693
42741
|
stateSnapshot = { ...stateSnapshot, tunnelUrl: r.url, tunnelError: void 0 };
|
|
42694
42742
|
stateMgr.write(stateSnapshot);
|
|
42695
42743
|
currentTunnelUrl = r.url;
|
|
42744
|
+
wss.broadcastAll({ type: "tunnel:ready", url: r.url, subdomain: r.subdomain });
|
|
42696
42745
|
const connectUrl = resolvedAuthToken ? `${r.url}#token=${resolvedAuthToken}` : r.url;
|
|
42697
42746
|
const lines = [
|
|
42698
42747
|
`Tunnel: ${r.url}`,
|