@clawos-dev/clawd 0.2.108-beta.205.1e8d4c5 → 0.2.108-beta.207.1de9acd
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 +633 -548
- 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
|
});
|
|
@@ -4915,7 +4924,11 @@ var init_schemas = __esm({
|
|
|
4915
4924
|
effort: external_exports.string().optional(),
|
|
4916
4925
|
cwd: external_exports.string().optional(),
|
|
4917
4926
|
// 用户在 Edit modal 选择的 icon 标识;UI 端做 enum 兜底
|
|
4918
|
-
iconKey: external_exports.string().optional()
|
|
4927
|
+
iconKey: external_exports.string().optional(),
|
|
4928
|
+
// app-builder picker 在当前 session 内切 project 时写入(spec 2026-06-01-app-builder-project-picker-design)。
|
|
4929
|
+
// daemon session:update handler 检测此字段变化时停旧 project dev server + 起新 project dev server。
|
|
4930
|
+
// 设为空字符串 '' 表示解绑(picker 不暴露解绑入口,但 schema 允许)。
|
|
4931
|
+
appBuilderProject: external_exports.string().regex(/^[a-z][a-z0-9-]{0,39}$/).or(external_exports.literal("")).optional()
|
|
4919
4932
|
})
|
|
4920
4933
|
});
|
|
4921
4934
|
SessionSendArgs = external_exports.object({
|
|
@@ -5112,12 +5125,6 @@ var init_schemas = __esm({
|
|
|
5112
5125
|
* 后调 capabilityManager.recordPeerHello(capId, ownerPrincipalId, displayName)
|
|
5113
5126
|
* 把 cap.peerOwnerId / firstUsedByPeerAt 字段回写,让 owner 端 UI 在 People
|
|
5114
5127
|
* 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
5128
|
*/
|
|
5122
5129
|
selfPrincipalId: external_exports.string().min(1).optional(),
|
|
5123
5130
|
/**
|
|
@@ -5132,6 +5139,11 @@ var init_schemas = __esm({
|
|
|
5132
5139
|
version: external_exports.string().min(1).optional(),
|
|
5133
5140
|
protocolVersion: external_exports.number().int().nonnegative().optional()
|
|
5134
5141
|
});
|
|
5142
|
+
TunnelReadyEventSchema = external_exports.object({
|
|
5143
|
+
type: external_exports.literal("tunnel:ready"),
|
|
5144
|
+
url: external_exports.string().min(1),
|
|
5145
|
+
subdomain: external_exports.string().min(1)
|
|
5146
|
+
});
|
|
5135
5147
|
TunnelExitedEventSchema = external_exports.object({
|
|
5136
5148
|
type: external_exports.literal("tunnel:exited"),
|
|
5137
5149
|
code: external_exports.number().int().nullable(),
|
|
@@ -5173,6 +5185,41 @@ var init_schemas = __esm({
|
|
|
5173
5185
|
/** file-sharing HTTP 路由的 Authorization: Bearer token;与 WS token 解耦,HTTP 401 仅触发 ReAuth 不强踢 WS(spec §11 第 4 条) */
|
|
5174
5186
|
httpToken: external_exports.string().optional()
|
|
5175
5187
|
});
|
|
5188
|
+
PROJECT_PORT_MIN = 6173;
|
|
5189
|
+
PROJECT_PORT_MAX = 6182;
|
|
5190
|
+
projectNameRegex = /^[a-z][a-z0-9-]{0,39}$/;
|
|
5191
|
+
ProjectMetadataSchema = external_exports.object({
|
|
5192
|
+
name: external_exports.string().regex(projectNameRegex, {
|
|
5193
|
+
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"
|
|
5194
|
+
}),
|
|
5195
|
+
port: external_exports.number().int().min(PROJECT_PORT_MIN).max(PROJECT_PORT_MAX),
|
|
5196
|
+
createdAt: external_exports.string().datetime()
|
|
5197
|
+
});
|
|
5198
|
+
ProjectWithStatusSchema = ProjectMetadataSchema.extend({
|
|
5199
|
+
isRunning: external_exports.boolean(),
|
|
5200
|
+
boundSessionId: external_exports.string().nullable()
|
|
5201
|
+
});
|
|
5202
|
+
ListProjectsArgsSchema = external_exports.object({}).strict();
|
|
5203
|
+
ListProjectsResultSchema = external_exports.object({
|
|
5204
|
+
projects: external_exports.array(ProjectWithStatusSchema)
|
|
5205
|
+
}).strict();
|
|
5206
|
+
CreateProjectArgsSchema = external_exports.object({
|
|
5207
|
+
name: external_exports.string()
|
|
5208
|
+
}).strict();
|
|
5209
|
+
CreateProjectResultSchema = external_exports.object({
|
|
5210
|
+
project: ProjectMetadataSchema
|
|
5211
|
+
}).strict();
|
|
5212
|
+
DeleteProjectArgsSchema = external_exports.object({
|
|
5213
|
+
name: external_exports.string()
|
|
5214
|
+
}).strict();
|
|
5215
|
+
DeleteProjectResultSchema = external_exports.object({}).strict();
|
|
5216
|
+
UpdateProjectPortArgsSchema = external_exports.object({
|
|
5217
|
+
name: external_exports.string(),
|
|
5218
|
+
newPort: external_exports.number().int()
|
|
5219
|
+
}).strict();
|
|
5220
|
+
UpdateProjectPortResultSchema = external_exports.object({
|
|
5221
|
+
project: ProjectMetadataSchema
|
|
5222
|
+
}).strict();
|
|
5176
5223
|
}
|
|
5177
5224
|
});
|
|
5178
5225
|
|
|
@@ -5581,64 +5628,6 @@ var init_extension = __esm({
|
|
|
5581
5628
|
}
|
|
5582
5629
|
});
|
|
5583
5630
|
|
|
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
5631
|
// ../protocol/src/runtime.ts
|
|
5643
5632
|
var init_runtime = __esm({
|
|
5644
5633
|
"../protocol/src/runtime.ts"() {
|
|
@@ -5656,7 +5645,6 @@ var init_runtime = __esm({
|
|
|
5656
5645
|
init_inbox();
|
|
5657
5646
|
init_received_capability();
|
|
5658
5647
|
init_extension();
|
|
5659
|
-
init_feishu_auth();
|
|
5660
5648
|
}
|
|
5661
5649
|
});
|
|
5662
5650
|
|
|
@@ -5931,8 +5919,8 @@ var require_req = __commonJS({
|
|
|
5931
5919
|
if (req.originalUrl) {
|
|
5932
5920
|
_req.url = req.originalUrl;
|
|
5933
5921
|
} else {
|
|
5934
|
-
const
|
|
5935
|
-
_req.url = typeof
|
|
5922
|
+
const path59 = req.path;
|
|
5923
|
+
_req.url = typeof path59 === "string" ? path59 : req.url ? req.url.path || req.url : void 0;
|
|
5936
5924
|
}
|
|
5937
5925
|
if (req.query) {
|
|
5938
5926
|
_req.query = req.query;
|
|
@@ -6097,14 +6085,14 @@ var require_redact = __commonJS({
|
|
|
6097
6085
|
}
|
|
6098
6086
|
return obj;
|
|
6099
6087
|
}
|
|
6100
|
-
function parsePath(
|
|
6088
|
+
function parsePath(path59) {
|
|
6101
6089
|
const parts = [];
|
|
6102
6090
|
let current = "";
|
|
6103
6091
|
let inBrackets = false;
|
|
6104
6092
|
let inQuotes = false;
|
|
6105
6093
|
let quoteChar = "";
|
|
6106
|
-
for (let i = 0; i <
|
|
6107
|
-
const char =
|
|
6094
|
+
for (let i = 0; i < path59.length; i++) {
|
|
6095
|
+
const char = path59[i];
|
|
6108
6096
|
if (!inBrackets && char === ".") {
|
|
6109
6097
|
if (current) {
|
|
6110
6098
|
parts.push(current);
|
|
@@ -6235,10 +6223,10 @@ var require_redact = __commonJS({
|
|
|
6235
6223
|
return current;
|
|
6236
6224
|
}
|
|
6237
6225
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
6238
|
-
for (const
|
|
6239
|
-
const parts = parsePath(
|
|
6226
|
+
for (const path59 of paths) {
|
|
6227
|
+
const parts = parsePath(path59);
|
|
6240
6228
|
if (parts.includes("*")) {
|
|
6241
|
-
redactWildcardPath(obj, parts, censor,
|
|
6229
|
+
redactWildcardPath(obj, parts, censor, path59, remove);
|
|
6242
6230
|
} else {
|
|
6243
6231
|
if (remove) {
|
|
6244
6232
|
removeKey(obj, parts);
|
|
@@ -6323,8 +6311,8 @@ var require_redact = __commonJS({
|
|
|
6323
6311
|
}
|
|
6324
6312
|
} else {
|
|
6325
6313
|
if (afterWildcard.includes("*")) {
|
|
6326
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6327
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
6314
|
+
const wrappedCensor = typeof censor === "function" ? (value, path59) => {
|
|
6315
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path59];
|
|
6328
6316
|
return censor(value, fullPath);
|
|
6329
6317
|
} : censor;
|
|
6330
6318
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -6359,8 +6347,8 @@ var require_redact = __commonJS({
|
|
|
6359
6347
|
return null;
|
|
6360
6348
|
}
|
|
6361
6349
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
6362
|
-
for (const
|
|
6363
|
-
const parts = parsePath(
|
|
6350
|
+
for (const path59 of pathsToClone) {
|
|
6351
|
+
const parts = parsePath(path59);
|
|
6364
6352
|
let current = pathStructure;
|
|
6365
6353
|
for (let i = 0; i < parts.length; i++) {
|
|
6366
6354
|
const part = parts[i];
|
|
@@ -6412,24 +6400,24 @@ var require_redact = __commonJS({
|
|
|
6412
6400
|
}
|
|
6413
6401
|
return cloneSelectively(obj, pathStructure);
|
|
6414
6402
|
}
|
|
6415
|
-
function validatePath(
|
|
6416
|
-
if (typeof
|
|
6403
|
+
function validatePath(path59) {
|
|
6404
|
+
if (typeof path59 !== "string") {
|
|
6417
6405
|
throw new Error("Paths must be (non-empty) strings");
|
|
6418
6406
|
}
|
|
6419
|
-
if (
|
|
6407
|
+
if (path59 === "") {
|
|
6420
6408
|
throw new Error("Invalid redaction path ()");
|
|
6421
6409
|
}
|
|
6422
|
-
if (
|
|
6423
|
-
throw new Error(`Invalid redaction path (${
|
|
6410
|
+
if (path59.includes("..")) {
|
|
6411
|
+
throw new Error(`Invalid redaction path (${path59})`);
|
|
6424
6412
|
}
|
|
6425
|
-
if (
|
|
6426
|
-
throw new Error(`Invalid redaction path (${
|
|
6413
|
+
if (path59.includes(",")) {
|
|
6414
|
+
throw new Error(`Invalid redaction path (${path59})`);
|
|
6427
6415
|
}
|
|
6428
6416
|
let bracketCount = 0;
|
|
6429
6417
|
let inQuotes = false;
|
|
6430
6418
|
let quoteChar = "";
|
|
6431
|
-
for (let i = 0; i <
|
|
6432
|
-
const char =
|
|
6419
|
+
for (let i = 0; i < path59.length; i++) {
|
|
6420
|
+
const char = path59[i];
|
|
6433
6421
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
6434
6422
|
if (!inQuotes) {
|
|
6435
6423
|
inQuotes = true;
|
|
@@ -6443,20 +6431,20 @@ var require_redact = __commonJS({
|
|
|
6443
6431
|
} else if (char === "]" && !inQuotes) {
|
|
6444
6432
|
bracketCount--;
|
|
6445
6433
|
if (bracketCount < 0) {
|
|
6446
|
-
throw new Error(`Invalid redaction path (${
|
|
6434
|
+
throw new Error(`Invalid redaction path (${path59})`);
|
|
6447
6435
|
}
|
|
6448
6436
|
}
|
|
6449
6437
|
}
|
|
6450
6438
|
if (bracketCount !== 0) {
|
|
6451
|
-
throw new Error(`Invalid redaction path (${
|
|
6439
|
+
throw new Error(`Invalid redaction path (${path59})`);
|
|
6452
6440
|
}
|
|
6453
6441
|
}
|
|
6454
6442
|
function validatePaths(paths) {
|
|
6455
6443
|
if (!Array.isArray(paths)) {
|
|
6456
6444
|
throw new TypeError("paths must be an array");
|
|
6457
6445
|
}
|
|
6458
|
-
for (const
|
|
6459
|
-
validatePath(
|
|
6446
|
+
for (const path59 of paths) {
|
|
6447
|
+
validatePath(path59);
|
|
6460
6448
|
}
|
|
6461
6449
|
}
|
|
6462
6450
|
function slowRedact(options = {}) {
|
|
@@ -6624,8 +6612,8 @@ var require_redaction = __commonJS({
|
|
|
6624
6612
|
if (shape[k2] === null) {
|
|
6625
6613
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
6626
6614
|
} else {
|
|
6627
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6628
|
-
return censor(value, [k2, ...
|
|
6615
|
+
const wrappedCensor = typeof censor === "function" ? (value, path59) => {
|
|
6616
|
+
return censor(value, [k2, ...path59]);
|
|
6629
6617
|
} : censor;
|
|
6630
6618
|
o[k2] = Redact({
|
|
6631
6619
|
paths: shape[k2],
|
|
@@ -6844,9 +6832,9 @@ var require_sonic_boom = __commonJS({
|
|
|
6844
6832
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
6845
6833
|
"use strict";
|
|
6846
6834
|
var fs48 = require("fs");
|
|
6847
|
-
var
|
|
6835
|
+
var EventEmitter3 = require("events");
|
|
6848
6836
|
var inherits = require("util").inherits;
|
|
6849
|
-
var
|
|
6837
|
+
var path59 = require("path");
|
|
6850
6838
|
var sleep = require_atomic_sleep();
|
|
6851
6839
|
var assert = require("assert");
|
|
6852
6840
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -6900,7 +6888,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6900
6888
|
const mode = sonic.mode;
|
|
6901
6889
|
if (sonic.sync) {
|
|
6902
6890
|
try {
|
|
6903
|
-
if (sonic.mkdir) fs48.mkdirSync(
|
|
6891
|
+
if (sonic.mkdir) fs48.mkdirSync(path59.dirname(file), { recursive: true });
|
|
6904
6892
|
const fd = fs48.openSync(file, flags, mode);
|
|
6905
6893
|
fileOpened(null, fd);
|
|
6906
6894
|
} catch (err) {
|
|
@@ -6908,7 +6896,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6908
6896
|
throw err;
|
|
6909
6897
|
}
|
|
6910
6898
|
} else if (sonic.mkdir) {
|
|
6911
|
-
fs48.mkdir(
|
|
6899
|
+
fs48.mkdir(path59.dirname(file), { recursive: true }, (err) => {
|
|
6912
6900
|
if (err) return fileOpened(err);
|
|
6913
6901
|
fs48.open(file, flags, mode, fileOpened);
|
|
6914
6902
|
});
|
|
@@ -7081,7 +7069,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7081
7069
|
sonic._asyncDrainScheduled = false;
|
|
7082
7070
|
sonic.emit("drain");
|
|
7083
7071
|
}
|
|
7084
|
-
inherits(SonicBoom,
|
|
7072
|
+
inherits(SonicBoom, EventEmitter3);
|
|
7085
7073
|
function mergeBuf(bufs, len) {
|
|
7086
7074
|
if (bufs.length === 0) {
|
|
7087
7075
|
return kEmptyBuffer;
|
|
@@ -7659,9 +7647,9 @@ var require_thread_stream = __commonJS({
|
|
|
7659
7647
|
"../node_modules/.pnpm/thread-stream@3.1.0/node_modules/thread-stream/index.js"(exports2, module2) {
|
|
7660
7648
|
"use strict";
|
|
7661
7649
|
var { version: version2 } = require_package();
|
|
7662
|
-
var { EventEmitter:
|
|
7650
|
+
var { EventEmitter: EventEmitter3 } = require("events");
|
|
7663
7651
|
var { Worker } = require("worker_threads");
|
|
7664
|
-
var { join:
|
|
7652
|
+
var { join: join12 } = require("path");
|
|
7665
7653
|
var { pathToFileURL } = require("url");
|
|
7666
7654
|
var { wait } = require_wait();
|
|
7667
7655
|
var {
|
|
@@ -7697,7 +7685,7 @@ var require_thread_stream = __commonJS({
|
|
|
7697
7685
|
function createWorker(stream, opts) {
|
|
7698
7686
|
const { filename, workerData } = opts;
|
|
7699
7687
|
const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
|
|
7700
|
-
const toExecute = bundlerOverrides["thread-stream-worker"] ||
|
|
7688
|
+
const toExecute = bundlerOverrides["thread-stream-worker"] || join12(__dirname, "lib", "worker.js");
|
|
7701
7689
|
const worker = new Worker(toExecute, {
|
|
7702
7690
|
...opts.workerOpts,
|
|
7703
7691
|
trackUnmanagedFds: false,
|
|
@@ -7815,7 +7803,7 @@ var require_thread_stream = __commonJS({
|
|
|
7815
7803
|
stream.worker.off("exit", onWorkerExit);
|
|
7816
7804
|
destroy(stream, code !== 0 ? new Error("the worker thread exited") : null);
|
|
7817
7805
|
}
|
|
7818
|
-
var ThreadStream = class extends
|
|
7806
|
+
var ThreadStream = class extends EventEmitter3 {
|
|
7819
7807
|
constructor(opts = {}) {
|
|
7820
7808
|
super();
|
|
7821
7809
|
if (opts.bufferSize < 4) {
|
|
@@ -8083,7 +8071,7 @@ var require_transport = __commonJS({
|
|
|
8083
8071
|
"use strict";
|
|
8084
8072
|
var { createRequire } = require("module");
|
|
8085
8073
|
var getCallers = require_caller();
|
|
8086
|
-
var { join:
|
|
8074
|
+
var { join: join12, isAbsolute: isAbsolute2, sep: sep3 } = require("path");
|
|
8087
8075
|
var sleep = require_atomic_sleep();
|
|
8088
8076
|
var onExit = require_on_exit_leak_free();
|
|
8089
8077
|
var ThreadStream = require_thread_stream();
|
|
@@ -8146,7 +8134,7 @@ var require_transport = __commonJS({
|
|
|
8146
8134
|
throw new Error("only one of target or targets can be specified");
|
|
8147
8135
|
}
|
|
8148
8136
|
if (targets) {
|
|
8149
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
8137
|
+
target = bundlerOverrides["pino-worker"] || join12(__dirname, "worker.js");
|
|
8150
8138
|
options.targets = targets.filter((dest) => dest.target).map((dest) => {
|
|
8151
8139
|
return {
|
|
8152
8140
|
...dest,
|
|
@@ -8164,7 +8152,7 @@ var require_transport = __commonJS({
|
|
|
8164
8152
|
});
|
|
8165
8153
|
});
|
|
8166
8154
|
} else if (pipeline3) {
|
|
8167
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
8155
|
+
target = bundlerOverrides["pino-worker"] || join12(__dirname, "worker.js");
|
|
8168
8156
|
options.pipelines = [pipeline3.map((dest) => {
|
|
8169
8157
|
return {
|
|
8170
8158
|
...dest,
|
|
@@ -8186,7 +8174,7 @@ var require_transport = __commonJS({
|
|
|
8186
8174
|
return origin;
|
|
8187
8175
|
}
|
|
8188
8176
|
if (origin === "pino/file") {
|
|
8189
|
-
return
|
|
8177
|
+
return join12(__dirname, "..", "file.js");
|
|
8190
8178
|
}
|
|
8191
8179
|
let fixTarget2;
|
|
8192
8180
|
for (const filePath of callers) {
|
|
@@ -8773,7 +8761,7 @@ var require_meta = __commonJS({
|
|
|
8773
8761
|
var require_proto = __commonJS({
|
|
8774
8762
|
"../node_modules/.pnpm/pino@9.14.0/node_modules/pino/lib/proto.js"(exports2, module2) {
|
|
8775
8763
|
"use strict";
|
|
8776
|
-
var { EventEmitter:
|
|
8764
|
+
var { EventEmitter: EventEmitter3 } = require("events");
|
|
8777
8765
|
var {
|
|
8778
8766
|
lsCacheSym,
|
|
8779
8767
|
levelValSym,
|
|
@@ -8855,7 +8843,7 @@ var require_proto = __commonJS({
|
|
|
8855
8843
|
[getLevelSym]: getLevel,
|
|
8856
8844
|
[setLevelSym]: setLevel
|
|
8857
8845
|
};
|
|
8858
|
-
Object.setPrototypeOf(prototype,
|
|
8846
|
+
Object.setPrototypeOf(prototype, EventEmitter3.prototype);
|
|
8859
8847
|
module2.exports = function() {
|
|
8860
8848
|
return Object.create(prototype);
|
|
8861
8849
|
};
|
|
@@ -9176,7 +9164,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
9176
9164
|
return circularValue;
|
|
9177
9165
|
}
|
|
9178
9166
|
let res = "";
|
|
9179
|
-
let
|
|
9167
|
+
let join12 = ",";
|
|
9180
9168
|
const originalIndentation = indentation;
|
|
9181
9169
|
if (Array.isArray(value)) {
|
|
9182
9170
|
if (value.length === 0) {
|
|
@@ -9190,7 +9178,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
9190
9178
|
indentation += spacer;
|
|
9191
9179
|
res += `
|
|
9192
9180
|
${indentation}`;
|
|
9193
|
-
|
|
9181
|
+
join12 = `,
|
|
9194
9182
|
${indentation}`;
|
|
9195
9183
|
}
|
|
9196
9184
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -9198,13 +9186,13 @@ ${indentation}`;
|
|
|
9198
9186
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
9199
9187
|
const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
9200
9188
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
9201
|
-
res +=
|
|
9189
|
+
res += join12;
|
|
9202
9190
|
}
|
|
9203
9191
|
const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
9204
9192
|
res += tmp !== void 0 ? tmp : "null";
|
|
9205
9193
|
if (value.length - 1 > maximumBreadth) {
|
|
9206
9194
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
9207
|
-
res += `${
|
|
9195
|
+
res += `${join12}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
9208
9196
|
}
|
|
9209
9197
|
if (spacer !== "") {
|
|
9210
9198
|
res += `
|
|
@@ -9225,7 +9213,7 @@ ${originalIndentation}`;
|
|
|
9225
9213
|
let separator = "";
|
|
9226
9214
|
if (spacer !== "") {
|
|
9227
9215
|
indentation += spacer;
|
|
9228
|
-
|
|
9216
|
+
join12 = `,
|
|
9229
9217
|
${indentation}`;
|
|
9230
9218
|
whitespace = " ";
|
|
9231
9219
|
}
|
|
@@ -9239,13 +9227,13 @@ ${indentation}`;
|
|
|
9239
9227
|
const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
|
|
9240
9228
|
if (tmp !== void 0) {
|
|
9241
9229
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
9242
|
-
separator =
|
|
9230
|
+
separator = join12;
|
|
9243
9231
|
}
|
|
9244
9232
|
}
|
|
9245
9233
|
if (keyLength > maximumBreadth) {
|
|
9246
9234
|
const removedKeys = keyLength - maximumBreadth;
|
|
9247
9235
|
res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
|
|
9248
|
-
separator =
|
|
9236
|
+
separator = join12;
|
|
9249
9237
|
}
|
|
9250
9238
|
if (spacer !== "" && separator.length > 1) {
|
|
9251
9239
|
res = `
|
|
@@ -9286,7 +9274,7 @@ ${originalIndentation}`;
|
|
|
9286
9274
|
}
|
|
9287
9275
|
const originalIndentation = indentation;
|
|
9288
9276
|
let res = "";
|
|
9289
|
-
let
|
|
9277
|
+
let join12 = ",";
|
|
9290
9278
|
if (Array.isArray(value)) {
|
|
9291
9279
|
if (value.length === 0) {
|
|
9292
9280
|
return "[]";
|
|
@@ -9299,7 +9287,7 @@ ${originalIndentation}`;
|
|
|
9299
9287
|
indentation += spacer;
|
|
9300
9288
|
res += `
|
|
9301
9289
|
${indentation}`;
|
|
9302
|
-
|
|
9290
|
+
join12 = `,
|
|
9303
9291
|
${indentation}`;
|
|
9304
9292
|
}
|
|
9305
9293
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -9307,13 +9295,13 @@ ${indentation}`;
|
|
|
9307
9295
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
9308
9296
|
const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
9309
9297
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
9310
|
-
res +=
|
|
9298
|
+
res += join12;
|
|
9311
9299
|
}
|
|
9312
9300
|
const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
9313
9301
|
res += tmp !== void 0 ? tmp : "null";
|
|
9314
9302
|
if (value.length - 1 > maximumBreadth) {
|
|
9315
9303
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
9316
|
-
res += `${
|
|
9304
|
+
res += `${join12}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
9317
9305
|
}
|
|
9318
9306
|
if (spacer !== "") {
|
|
9319
9307
|
res += `
|
|
@@ -9326,7 +9314,7 @@ ${originalIndentation}`;
|
|
|
9326
9314
|
let whitespace = "";
|
|
9327
9315
|
if (spacer !== "") {
|
|
9328
9316
|
indentation += spacer;
|
|
9329
|
-
|
|
9317
|
+
join12 = `,
|
|
9330
9318
|
${indentation}`;
|
|
9331
9319
|
whitespace = " ";
|
|
9332
9320
|
}
|
|
@@ -9335,7 +9323,7 @@ ${indentation}`;
|
|
|
9335
9323
|
const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
|
|
9336
9324
|
if (tmp !== void 0) {
|
|
9337
9325
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
9338
|
-
separator =
|
|
9326
|
+
separator = join12;
|
|
9339
9327
|
}
|
|
9340
9328
|
}
|
|
9341
9329
|
if (spacer !== "" && separator.length > 1) {
|
|
@@ -9393,20 +9381,20 @@ ${originalIndentation}`;
|
|
|
9393
9381
|
indentation += spacer;
|
|
9394
9382
|
let res2 = `
|
|
9395
9383
|
${indentation}`;
|
|
9396
|
-
const
|
|
9384
|
+
const join13 = `,
|
|
9397
9385
|
${indentation}`;
|
|
9398
9386
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
9399
9387
|
let i = 0;
|
|
9400
9388
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
9401
9389
|
const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
9402
9390
|
res2 += tmp2 !== void 0 ? tmp2 : "null";
|
|
9403
|
-
res2 +=
|
|
9391
|
+
res2 += join13;
|
|
9404
9392
|
}
|
|
9405
9393
|
const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
9406
9394
|
res2 += tmp !== void 0 ? tmp : "null";
|
|
9407
9395
|
if (value.length - 1 > maximumBreadth) {
|
|
9408
9396
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
9409
|
-
res2 += `${
|
|
9397
|
+
res2 += `${join13}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
9410
9398
|
}
|
|
9411
9399
|
res2 += `
|
|
9412
9400
|
${originalIndentation}`;
|
|
@@ -9422,16 +9410,16 @@ ${originalIndentation}`;
|
|
|
9422
9410
|
return '"[Object]"';
|
|
9423
9411
|
}
|
|
9424
9412
|
indentation += spacer;
|
|
9425
|
-
const
|
|
9413
|
+
const join12 = `,
|
|
9426
9414
|
${indentation}`;
|
|
9427
9415
|
let res = "";
|
|
9428
9416
|
let separator = "";
|
|
9429
9417
|
let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
|
|
9430
9418
|
if (isTypedArrayWithEntries(value)) {
|
|
9431
|
-
res += stringifyTypedArray(value,
|
|
9419
|
+
res += stringifyTypedArray(value, join12, maximumBreadth);
|
|
9432
9420
|
keys = keys.slice(value.length);
|
|
9433
9421
|
maximumPropertiesToStringify -= value.length;
|
|
9434
|
-
separator =
|
|
9422
|
+
separator = join12;
|
|
9435
9423
|
}
|
|
9436
9424
|
if (deterministic) {
|
|
9437
9425
|
keys = sort(keys, comparator);
|
|
@@ -9442,13 +9430,13 @@ ${indentation}`;
|
|
|
9442
9430
|
const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
|
|
9443
9431
|
if (tmp !== void 0) {
|
|
9444
9432
|
res += `${separator}${strEscape(key2)}: ${tmp}`;
|
|
9445
|
-
separator =
|
|
9433
|
+
separator = join12;
|
|
9446
9434
|
}
|
|
9447
9435
|
}
|
|
9448
9436
|
if (keyLength > maximumBreadth) {
|
|
9449
9437
|
const removedKeys = keyLength - maximumBreadth;
|
|
9450
9438
|
res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
|
|
9451
|
-
separator =
|
|
9439
|
+
separator = join12;
|
|
9452
9440
|
}
|
|
9453
9441
|
if (separator !== "") {
|
|
9454
9442
|
res = `
|
|
@@ -10539,11 +10527,11 @@ var init_lib = __esm({
|
|
|
10539
10527
|
}
|
|
10540
10528
|
}
|
|
10541
10529
|
},
|
|
10542
|
-
addToPath: function addToPath(
|
|
10543
|
-
var last =
|
|
10530
|
+
addToPath: function addToPath(path59, added, removed, oldPosInc, options) {
|
|
10531
|
+
var last = path59.lastComponent;
|
|
10544
10532
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
10545
10533
|
return {
|
|
10546
|
-
oldPos:
|
|
10534
|
+
oldPos: path59.oldPos + oldPosInc,
|
|
10547
10535
|
lastComponent: {
|
|
10548
10536
|
count: last.count + 1,
|
|
10549
10537
|
added,
|
|
@@ -10553,7 +10541,7 @@ var init_lib = __esm({
|
|
|
10553
10541
|
};
|
|
10554
10542
|
} else {
|
|
10555
10543
|
return {
|
|
10556
|
-
oldPos:
|
|
10544
|
+
oldPos: path59.oldPos + oldPosInc,
|
|
10557
10545
|
lastComponent: {
|
|
10558
10546
|
count: 1,
|
|
10559
10547
|
added,
|
|
@@ -10999,10 +10987,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
10999
10987
|
const memories = raw.map((m2) => {
|
|
11000
10988
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11001
10989
|
const rec = m2;
|
|
11002
|
-
const
|
|
10990
|
+
const path59 = typeof rec.path === "string" ? rec.path : null;
|
|
11003
10991
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
11004
|
-
if (!
|
|
11005
|
-
const entry = { path:
|
|
10992
|
+
if (!path59 || content == null) return null;
|
|
10993
|
+
const entry = { path: path59, content };
|
|
11006
10994
|
if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
|
|
11007
10995
|
return entry;
|
|
11008
10996
|
}).filter((m2) => m2 !== null);
|
|
@@ -11833,10 +11821,10 @@ function parseAttachment(obj) {
|
|
|
11833
11821
|
const memories = raw.map((m2) => {
|
|
11834
11822
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11835
11823
|
const rec = m2;
|
|
11836
|
-
const
|
|
11824
|
+
const path59 = typeof rec.path === "string" ? rec.path : null;
|
|
11837
11825
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
11838
|
-
if (!
|
|
11839
|
-
const out = { path:
|
|
11826
|
+
if (!path59 || content == null) return null;
|
|
11827
|
+
const out = { path: path59, content };
|
|
11840
11828
|
if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
|
|
11841
11829
|
return out;
|
|
11842
11830
|
}).filter((m2) => m2 !== null);
|
|
@@ -19330,10 +19318,10 @@ var require_extension = __commonJS({
|
|
|
19330
19318
|
var require_websocket = __commonJS({
|
|
19331
19319
|
"../node_modules/.pnpm/ws@8.20.0/node_modules/ws/lib/websocket.js"(exports2, module2) {
|
|
19332
19320
|
"use strict";
|
|
19333
|
-
var
|
|
19321
|
+
var EventEmitter3 = require("events");
|
|
19334
19322
|
var https = require("https");
|
|
19335
|
-
var
|
|
19336
|
-
var
|
|
19323
|
+
var http3 = require("http");
|
|
19324
|
+
var net3 = require("net");
|
|
19337
19325
|
var tls = require("tls");
|
|
19338
19326
|
var { randomBytes, createHash: createHash2 } = require("crypto");
|
|
19339
19327
|
var { Duplex, Readable: Readable3 } = require("stream");
|
|
@@ -19362,7 +19350,7 @@ var require_websocket = __commonJS({
|
|
|
19362
19350
|
var protocolVersions = [8, 13];
|
|
19363
19351
|
var readyStates = ["CONNECTING", "OPEN", "CLOSING", "CLOSED"];
|
|
19364
19352
|
var subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/;
|
|
19365
|
-
var WebSocket2 = class _WebSocket extends
|
|
19353
|
+
var WebSocket2 = class _WebSocket extends EventEmitter3 {
|
|
19366
19354
|
/**
|
|
19367
19355
|
* Create a new `WebSocket`.
|
|
19368
19356
|
*
|
|
@@ -19866,7 +19854,7 @@ var require_websocket = __commonJS({
|
|
|
19866
19854
|
}
|
|
19867
19855
|
const defaultPort = isSecure ? 443 : 80;
|
|
19868
19856
|
const key = randomBytes(16).toString("base64");
|
|
19869
|
-
const request = isSecure ? https.request :
|
|
19857
|
+
const request = isSecure ? https.request : http3.request;
|
|
19870
19858
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
19871
19859
|
let perMessageDeflate;
|
|
19872
19860
|
opts.createConnection = opts.createConnection || (isSecure ? tlsConnect : netConnect);
|
|
@@ -20067,12 +20055,12 @@ var require_websocket = __commonJS({
|
|
|
20067
20055
|
}
|
|
20068
20056
|
function netConnect(options) {
|
|
20069
20057
|
options.path = options.socketPath;
|
|
20070
|
-
return
|
|
20058
|
+
return net3.connect(options);
|
|
20071
20059
|
}
|
|
20072
20060
|
function tlsConnect(options) {
|
|
20073
20061
|
options.path = void 0;
|
|
20074
20062
|
if (!options.servername && options.servername !== "") {
|
|
20075
|
-
options.servername =
|
|
20063
|
+
options.servername = net3.isIP(options.host) ? "" : options.host;
|
|
20076
20064
|
}
|
|
20077
20065
|
return tls.connect(options);
|
|
20078
20066
|
}
|
|
@@ -20359,8 +20347,8 @@ var require_subprotocol = __commonJS({
|
|
|
20359
20347
|
var require_websocket_server = __commonJS({
|
|
20360
20348
|
"../node_modules/.pnpm/ws@8.20.0/node_modules/ws/lib/websocket-server.js"(exports2, module2) {
|
|
20361
20349
|
"use strict";
|
|
20362
|
-
var
|
|
20363
|
-
var
|
|
20350
|
+
var EventEmitter3 = require("events");
|
|
20351
|
+
var http3 = require("http");
|
|
20364
20352
|
var { Duplex } = require("stream");
|
|
20365
20353
|
var { createHash: createHash2 } = require("crypto");
|
|
20366
20354
|
var extension2 = require_extension();
|
|
@@ -20372,7 +20360,7 @@ var require_websocket_server = __commonJS({
|
|
|
20372
20360
|
var RUNNING = 0;
|
|
20373
20361
|
var CLOSING = 1;
|
|
20374
20362
|
var CLOSED = 2;
|
|
20375
|
-
var WebSocketServer2 = class extends
|
|
20363
|
+
var WebSocketServer2 = class extends EventEmitter3 {
|
|
20376
20364
|
/**
|
|
20377
20365
|
* Create a `WebSocketServer` instance.
|
|
20378
20366
|
*
|
|
@@ -20435,8 +20423,8 @@ var require_websocket_server = __commonJS({
|
|
|
20435
20423
|
);
|
|
20436
20424
|
}
|
|
20437
20425
|
if (options.port != null) {
|
|
20438
|
-
this._server =
|
|
20439
|
-
const body =
|
|
20426
|
+
this._server = http3.createServer((req, res) => {
|
|
20427
|
+
const body = http3.STATUS_CODES[426];
|
|
20440
20428
|
res.writeHead(426, {
|
|
20441
20429
|
"Content-Length": body.length,
|
|
20442
20430
|
"Content-Type": "text/plain"
|
|
@@ -20723,7 +20711,7 @@ var require_websocket_server = __commonJS({
|
|
|
20723
20711
|
this.destroy();
|
|
20724
20712
|
}
|
|
20725
20713
|
function abortHandshake(socket, code, message, headers) {
|
|
20726
|
-
message = message ||
|
|
20714
|
+
message = message || http3.STATUS_CODES[code];
|
|
20727
20715
|
headers = {
|
|
20728
20716
|
Connection: "close",
|
|
20729
20717
|
"Content-Type": "text/html",
|
|
@@ -20732,7 +20720,7 @@ var require_websocket_server = __commonJS({
|
|
|
20732
20720
|
};
|
|
20733
20721
|
socket.once("finish", socket.destroy);
|
|
20734
20722
|
socket.end(
|
|
20735
|
-
`HTTP/1.1 ${code} ${
|
|
20723
|
+
`HTTP/1.1 ${code} ${http3.STATUS_CODES[code]}\r
|
|
20736
20724
|
` + Object.keys(headers).map((h) => `${h}: ${headers[h]}`).join("\r\n") + "\r\n\r\n" + message
|
|
20737
20725
|
);
|
|
20738
20726
|
}
|
|
@@ -21035,7 +21023,7 @@ var require_BufferList = __commonJS({
|
|
|
21035
21023
|
this.head = this.tail = null;
|
|
21036
21024
|
this.length = 0;
|
|
21037
21025
|
};
|
|
21038
|
-
BufferList.prototype.join = function
|
|
21026
|
+
BufferList.prototype.join = function join12(s) {
|
|
21039
21027
|
if (this.length === 0) return "";
|
|
21040
21028
|
var p2 = this.head;
|
|
21041
21029
|
var ret = "" + p2.data;
|
|
@@ -23625,8 +23613,8 @@ var require_utils = __commonJS({
|
|
|
23625
23613
|
var result = transform[inputType][outputType](input);
|
|
23626
23614
|
return result;
|
|
23627
23615
|
};
|
|
23628
|
-
exports2.resolve = function(
|
|
23629
|
-
var parts =
|
|
23616
|
+
exports2.resolve = function(path59) {
|
|
23617
|
+
var parts = path59.split("/");
|
|
23630
23618
|
var result = [];
|
|
23631
23619
|
for (var index = 0; index < parts.length; index++) {
|
|
23632
23620
|
var part = parts[index];
|
|
@@ -29479,18 +29467,18 @@ var require_object = __commonJS({
|
|
|
29479
29467
|
var object = new ZipObject(name, zipObjectContent, o);
|
|
29480
29468
|
this.files[name] = object;
|
|
29481
29469
|
};
|
|
29482
|
-
var parentFolder = function(
|
|
29483
|
-
if (
|
|
29484
|
-
|
|
29470
|
+
var parentFolder = function(path59) {
|
|
29471
|
+
if (path59.slice(-1) === "/") {
|
|
29472
|
+
path59 = path59.substring(0, path59.length - 1);
|
|
29485
29473
|
}
|
|
29486
|
-
var lastSlash =
|
|
29487
|
-
return lastSlash > 0 ?
|
|
29474
|
+
var lastSlash = path59.lastIndexOf("/");
|
|
29475
|
+
return lastSlash > 0 ? path59.substring(0, lastSlash) : "";
|
|
29488
29476
|
};
|
|
29489
|
-
var forceTrailingSlash = function(
|
|
29490
|
-
if (
|
|
29491
|
-
|
|
29477
|
+
var forceTrailingSlash = function(path59) {
|
|
29478
|
+
if (path59.slice(-1) !== "/") {
|
|
29479
|
+
path59 += "/";
|
|
29492
29480
|
}
|
|
29493
|
-
return
|
|
29481
|
+
return path59;
|
|
29494
29482
|
};
|
|
29495
29483
|
var folderAdd = function(name, createFolders) {
|
|
29496
29484
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
|
|
@@ -30945,6 +30933,8 @@ function resolveConfig(opts) {
|
|
|
30945
30933
|
const frpcBinary = env.CLAWD_FRPC_BIN ?? null;
|
|
30946
30934
|
const rawMode = env.CLAWD_CC_MODE;
|
|
30947
30935
|
const mode = DAEMON_MODE_VALUES.includes(rawMode ?? "") ? rawMode : "sdk";
|
|
30936
|
+
const filePreviewPorts = Array.isArray(fileCfg.previewPorts) ? fileCfg.previewPorts.map((n) => Number(n)).filter((n) => Number.isInteger(n) && n > 0) : null;
|
|
30937
|
+
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
30938
|
return {
|
|
30949
30939
|
port,
|
|
30950
30940
|
host,
|
|
@@ -30956,7 +30946,8 @@ function resolveConfig(opts) {
|
|
|
30956
30946
|
authToken,
|
|
30957
30947
|
noTunnelPersist,
|
|
30958
30948
|
frpcBinary,
|
|
30959
|
-
mode
|
|
30949
|
+
mode,
|
|
30950
|
+
previewPorts
|
|
30960
30951
|
};
|
|
30961
30952
|
}
|
|
30962
30953
|
var HELP_TEXT = `clawd [options]
|
|
@@ -32995,6 +32986,7 @@ var SessionManager = class {
|
|
|
32995
32986
|
iconKey: args.iconKey,
|
|
32996
32987
|
forkedFromSessionId: args.forkedFromSessionId,
|
|
32997
32988
|
ownerPersonaId: args.ownerPersonaId,
|
|
32989
|
+
appBuilderProject: args.appBuilderProject,
|
|
32998
32990
|
creatorPrincipalId,
|
|
32999
32991
|
...creatorOwnerPrincipalId ? { creatorOwnerPrincipalId } : {},
|
|
33000
32992
|
createdAt: iso,
|
|
@@ -34631,6 +34623,15 @@ var DEFAULT_PERSONAS = [
|
|
|
34631
34623
|
model: "opus",
|
|
34632
34624
|
iconKey: "assist",
|
|
34633
34625
|
public: false
|
|
34626
|
+
},
|
|
34627
|
+
{
|
|
34628
|
+
// app-builder:全栈应用搭建师,绑 extension-kit 模板 + multi-project picker
|
|
34629
|
+
// spec: superpowers/specs/2026-06-01-app-builder-project-picker-design.md
|
|
34630
|
+
personaId: "persona-app-builder",
|
|
34631
|
+
label: "App Builder",
|
|
34632
|
+
model: "opus",
|
|
34633
|
+
iconKey: "assist",
|
|
34634
|
+
public: false
|
|
34634
34635
|
}
|
|
34635
34636
|
];
|
|
34636
34637
|
function findDefaultsRoot() {
|
|
@@ -36327,13 +36328,63 @@ var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
|
36327
36328
|
var wrapper_default = import_websocket.default;
|
|
36328
36329
|
|
|
36329
36330
|
// src/transport/local-ws-server.ts
|
|
36331
|
+
var import_node_http2 = __toESM(require("http"), 1);
|
|
36332
|
+
|
|
36333
|
+
// src/transport/preview-proxy.ts
|
|
36330
36334
|
var import_node_http = __toESM(require("http"), 1);
|
|
36335
|
+
var import_node_net = __toESM(require("net"), 1);
|
|
36336
|
+
var PREVIEW_RE = /^\/preview\/(\d+)(?:\/.*)?$/;
|
|
36337
|
+
function matchPreviewPort(pathname) {
|
|
36338
|
+
const m2 = pathname.match(PREVIEW_RE);
|
|
36339
|
+
return m2 ? Number(m2[1]) : null;
|
|
36340
|
+
}
|
|
36341
|
+
function isPreviewPortAllowed(port, cfg) {
|
|
36342
|
+
return cfg.allowedPorts.includes(port);
|
|
36343
|
+
}
|
|
36344
|
+
function proxyPreviewHttp(req, res, port) {
|
|
36345
|
+
return new Promise((resolve6) => {
|
|
36346
|
+
const upstream = import_node_http.default.request(
|
|
36347
|
+
{ host: "localhost", port, method: req.method, path: req.url, headers: req.headers },
|
|
36348
|
+
(upRes) => {
|
|
36349
|
+
res.writeHead(upRes.statusCode || 502, upRes.headers);
|
|
36350
|
+
upRes.pipe(res);
|
|
36351
|
+
upRes.on("end", () => resolve6());
|
|
36352
|
+
}
|
|
36353
|
+
);
|
|
36354
|
+
upstream.on("error", (e) => {
|
|
36355
|
+
if (!res.headersSent) {
|
|
36356
|
+
res.writeHead(502, { "content-type": "text/plain; charset=utf-8" });
|
|
36357
|
+
}
|
|
36358
|
+
res.end(`preview upstream error: ${e.message}`);
|
|
36359
|
+
resolve6();
|
|
36360
|
+
});
|
|
36361
|
+
req.pipe(upstream);
|
|
36362
|
+
});
|
|
36363
|
+
}
|
|
36364
|
+
function proxyPreviewUpgrade(req, socket, head, port) {
|
|
36365
|
+
const upstream = import_node_net.default.connect(port, "localhost", () => {
|
|
36366
|
+
let raw = `${req.method} ${req.url} HTTP/1.1\r
|
|
36367
|
+
`;
|
|
36368
|
+
for (let i = 0; i < req.rawHeaders.length; i += 2) {
|
|
36369
|
+
raw += `${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}\r
|
|
36370
|
+
`;
|
|
36371
|
+
}
|
|
36372
|
+
raw += "\r\n";
|
|
36373
|
+
upstream.write(raw);
|
|
36374
|
+
if (head && head.length) upstream.write(head);
|
|
36375
|
+
upstream.pipe(socket);
|
|
36376
|
+
socket.pipe(upstream);
|
|
36377
|
+
});
|
|
36378
|
+
upstream.on("error", () => socket.destroy());
|
|
36379
|
+
socket.on("error", () => upstream.destroy());
|
|
36380
|
+
}
|
|
36381
|
+
|
|
36382
|
+
// src/transport/local-ws-server.ts
|
|
36331
36383
|
var LocalWsServer = class {
|
|
36332
36384
|
constructor(opts) {
|
|
36333
36385
|
this.opts = opts;
|
|
36334
36386
|
this.logger = opts.logger;
|
|
36335
36387
|
this.pingIntervalMs = opts.pingIntervalMs ?? 3e4;
|
|
36336
|
-
this.currentOwnerPrincipalId = opts.ownerPrincipalId;
|
|
36337
36388
|
}
|
|
36338
36389
|
opts;
|
|
36339
36390
|
wss = null;
|
|
@@ -36345,19 +36396,28 @@ var LocalWsServer = class {
|
|
|
36345
36396
|
capabilityIdToClients = /* @__PURE__ */ new Map();
|
|
36346
36397
|
logger;
|
|
36347
36398
|
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
36399
|
async start() {
|
|
36356
36400
|
const host = this.opts.host ?? "127.0.0.1";
|
|
36357
36401
|
await new Promise((resolve6, reject) => {
|
|
36358
|
-
const httpServer =
|
|
36402
|
+
const httpServer = import_node_http2.default.createServer((req, res) => this.handleHttpRequest(req, res));
|
|
36359
36403
|
const wss = new import_websocket_server.default({ noServer: true, clientTracking: true });
|
|
36360
36404
|
httpServer.on("upgrade", (req, socket, head) => {
|
|
36405
|
+
if (req.url?.startsWith("/preview/")) {
|
|
36406
|
+
const pathname = (() => {
|
|
36407
|
+
try {
|
|
36408
|
+
return new URL(req.url, "http://localhost").pathname;
|
|
36409
|
+
} catch {
|
|
36410
|
+
return "/";
|
|
36411
|
+
}
|
|
36412
|
+
})();
|
|
36413
|
+
const port = matchPreviewPort(pathname);
|
|
36414
|
+
if (port != null && (this.opts.previewPorts ?? []).includes(port)) {
|
|
36415
|
+
proxyPreviewUpgrade(req, socket, head, port);
|
|
36416
|
+
} else {
|
|
36417
|
+
socket.destroy();
|
|
36418
|
+
}
|
|
36419
|
+
return;
|
|
36420
|
+
}
|
|
36361
36421
|
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
36362
36422
|
this.routeConnection(ws, req);
|
|
36363
36423
|
});
|
|
@@ -36471,7 +36531,7 @@ var LocalWsServer = class {
|
|
|
36471
36531
|
// principalId === 'cap_xxx' → 该 capability 的所有 guest ws (多端 / 多 tab)
|
|
36472
36532
|
// 用于 DM inbox:event 路由: from + to 两侧各播一次, 让双方 UI 实时看到 thread 更新.
|
|
36473
36533
|
broadcastToPrincipal(principalId, frame) {
|
|
36474
|
-
if (principalId === "owner" || principalId === this.
|
|
36534
|
+
if (principalId === "owner" || principalId === this.opts.ownerPrincipalId) {
|
|
36475
36535
|
this.broadcastToOwners(frame);
|
|
36476
36536
|
return;
|
|
36477
36537
|
}
|
|
@@ -36523,21 +36583,6 @@ var LocalWsServer = class {
|
|
|
36523
36583
|
getClientContext(clientId) {
|
|
36524
36584
|
return this.clients.get(clientId)?.ctx ?? null;
|
|
36525
36585
|
}
|
|
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
36586
|
// Task 1.10 撤销级联:关闭某 capability 的所有活跃 ws 连接。close code 4401
|
|
36542
36587
|
// 让客户端识别 'capability revoked' 而非普通断连。
|
|
36543
36588
|
closeConnectionsByCapability(capabilityId, code = 4401, reason = "TOKEN_REVOKED") {
|
|
@@ -38020,23 +38065,13 @@ function createHttpRouter(deps) {
|
|
|
38020
38065
|
});
|
|
38021
38066
|
return true;
|
|
38022
38067
|
}
|
|
38023
|
-
if (url.pathname
|
|
38024
|
-
|
|
38025
|
-
|
|
38026
|
-
|
|
38027
|
-
}
|
|
38028
|
-
if (!deps.feishuLogin) {
|
|
38029
|
-
sendJson(res, 501, { code: "NOT_IMPLEMENTED", message: "feishu login not wired" });
|
|
38068
|
+
if (url.pathname.startsWith("/preview/")) {
|
|
38069
|
+
const port = matchPreviewPort(url.pathname);
|
|
38070
|
+
if (port != null && isPreviewPortAllowed(port, { allowedPorts: deps.previewPorts ?? [] })) {
|
|
38071
|
+
await proxyPreviewHttp(req, res, port);
|
|
38030
38072
|
return true;
|
|
38031
38073
|
}
|
|
38032
|
-
|
|
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);
|
|
38074
|
+
sendJson(res, 403, { code: "PREVIEW_PORT_FORBIDDEN", message: "preview port not allowed" });
|
|
38040
38075
|
return true;
|
|
38041
38076
|
}
|
|
38042
38077
|
if (!url.pathname.startsWith("/session/") && !url.pathname.startsWith("/files/") && url.pathname !== "/attachments/upload" && url.pathname !== "/extensions/import") {
|
|
@@ -38274,9 +38309,6 @@ function parseUrl(rawUrl) {
|
|
|
38274
38309
|
return null;
|
|
38275
38310
|
}
|
|
38276
38311
|
}
|
|
38277
|
-
function escapeHtml(s) {
|
|
38278
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
38279
|
-
}
|
|
38280
38312
|
function sendJson(res, status, body, extraHeaders) {
|
|
38281
38313
|
res.writeHead(status, {
|
|
38282
38314
|
"Content-Type": "application/json; charset=utf-8",
|
|
@@ -39299,160 +39331,6 @@ function loadOwnerDisplayName(dataDir) {
|
|
|
39299
39331
|
return displayName;
|
|
39300
39332
|
}
|
|
39301
39333
|
|
|
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
39334
|
// src/index.ts
|
|
39457
39335
|
init_protocol();
|
|
39458
39336
|
|
|
@@ -39460,12 +39338,12 @@ init_protocol();
|
|
|
39460
39338
|
init_protocol();
|
|
39461
39339
|
|
|
39462
39340
|
// src/session/fork.ts
|
|
39463
|
-
var
|
|
39341
|
+
var import_node_fs27 = __toESM(require("fs"), 1);
|
|
39464
39342
|
var import_node_os14 = __toESM(require("os"), 1);
|
|
39465
|
-
var
|
|
39343
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
39466
39344
|
init_claude_history();
|
|
39467
39345
|
function readJsonlEntries(file) {
|
|
39468
|
-
const raw =
|
|
39346
|
+
const raw = import_node_fs27.default.readFileSync(file, "utf8");
|
|
39469
39347
|
const out = [];
|
|
39470
39348
|
for (const line of raw.split("\n")) {
|
|
39471
39349
|
const t = line.trim();
|
|
@@ -39478,10 +39356,10 @@ function readJsonlEntries(file) {
|
|
|
39478
39356
|
return out;
|
|
39479
39357
|
}
|
|
39480
39358
|
function forkSession(input) {
|
|
39481
|
-
const baseDir = input.baseDir ??
|
|
39482
|
-
const projectDir =
|
|
39483
|
-
const sourceFile =
|
|
39484
|
-
if (!
|
|
39359
|
+
const baseDir = input.baseDir ?? import_node_path31.default.join(import_node_os14.default.homedir(), ".claude");
|
|
39360
|
+
const projectDir = import_node_path31.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
39361
|
+
const sourceFile = import_node_path31.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
39362
|
+
if (!import_node_fs27.default.existsSync(sourceFile)) {
|
|
39485
39363
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
39486
39364
|
}
|
|
39487
39365
|
const entries = readJsonlEntries(sourceFile);
|
|
@@ -39511,9 +39389,9 @@ function forkSession(input) {
|
|
|
39511
39389
|
}
|
|
39512
39390
|
forkedLines.push(JSON.stringify(forked));
|
|
39513
39391
|
}
|
|
39514
|
-
const forkedFilePath =
|
|
39515
|
-
|
|
39516
|
-
|
|
39392
|
+
const forkedFilePath = import_node_path31.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
39393
|
+
import_node_fs27.default.mkdirSync(projectDir, { recursive: true });
|
|
39394
|
+
import_node_fs27.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
39517
39395
|
return { forkedToolSessionId, forkedFilePath };
|
|
39518
39396
|
}
|
|
39519
39397
|
|
|
@@ -39613,7 +39491,34 @@ function buildSessionHandlers(deps) {
|
|
|
39613
39491
|
const update = async (frame, _client, ctx) => {
|
|
39614
39492
|
const args = SessionUpdateArgs.parse(frame);
|
|
39615
39493
|
ensureSessionAccess(ctx, args.sessionId, "send");
|
|
39494
|
+
const prevFile = manager.findOwnedSession(args.sessionId);
|
|
39495
|
+
const prevProject = prevFile?.appBuilderProject ?? null;
|
|
39496
|
+
const nextProject = args.patch.appBuilderProject ?? prevProject;
|
|
39616
39497
|
const { response, broadcast } = manager.update(args);
|
|
39498
|
+
if (deps.devServerLifecycle && deps.appBuilderStore && args.patch.appBuilderProject !== void 0) {
|
|
39499
|
+
const lifecycle = deps.devServerLifecycle;
|
|
39500
|
+
const projectStore = deps.appBuilderStore;
|
|
39501
|
+
const tunnelUrl = deps.getTunnelUrl?.() ?? null;
|
|
39502
|
+
try {
|
|
39503
|
+
if (prevProject && prevProject !== nextProject) {
|
|
39504
|
+
await lifecycle.stopForSession(args.sessionId);
|
|
39505
|
+
}
|
|
39506
|
+
if (nextProject && nextProject !== "" && nextProject !== prevProject) {
|
|
39507
|
+
const projects = await projectStore.list();
|
|
39508
|
+
const target = projects.find((p2) => p2.name === nextProject);
|
|
39509
|
+
if (target) {
|
|
39510
|
+
lifecycle.startForSession({
|
|
39511
|
+
sessionId: args.sessionId,
|
|
39512
|
+
projectName: nextProject,
|
|
39513
|
+
cwd: projectStore.projectDir(nextProject),
|
|
39514
|
+
port: target.port,
|
|
39515
|
+
tunnelHost: tunnelUrl ? new URL(tunnelUrl.replace(/^wss?:\/\//i, "https://")).host : null
|
|
39516
|
+
});
|
|
39517
|
+
}
|
|
39518
|
+
}
|
|
39519
|
+
} catch {
|
|
39520
|
+
}
|
|
39521
|
+
}
|
|
39617
39522
|
return { response: { type: "session:info", ...response }, broadcast };
|
|
39618
39523
|
};
|
|
39619
39524
|
const del = async (frame, _client, ctx) => {
|
|
@@ -39865,7 +39770,7 @@ function buildPermissionHandlers(deps) {
|
|
|
39865
39770
|
}
|
|
39866
39771
|
|
|
39867
39772
|
// src/handlers/history.ts
|
|
39868
|
-
var
|
|
39773
|
+
var path41 = __toESM(require("path"), 1);
|
|
39869
39774
|
init_protocol();
|
|
39870
39775
|
|
|
39871
39776
|
// src/session/recent-dirs.ts
|
|
@@ -39883,7 +39788,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
39883
39788
|
}
|
|
39884
39789
|
|
|
39885
39790
|
// src/permission/persona-paths.ts
|
|
39886
|
-
var
|
|
39791
|
+
var path40 = __toESM(require("path"), 1);
|
|
39887
39792
|
function getAllowedPersonaIds(grants, action) {
|
|
39888
39793
|
const ids = /* @__PURE__ */ new Set();
|
|
39889
39794
|
for (const g2 of grants) {
|
|
@@ -39896,26 +39801,26 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
39896
39801
|
return ids;
|
|
39897
39802
|
}
|
|
39898
39803
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read") {
|
|
39899
|
-
const root =
|
|
39900
|
-
const target =
|
|
39901
|
-
const sep3 = root.endsWith(
|
|
39804
|
+
const root = path40.resolve(personaRoot);
|
|
39805
|
+
const target = path40.resolve(absPath);
|
|
39806
|
+
const sep3 = root.endsWith(path40.sep) ? "" : path40.sep;
|
|
39902
39807
|
if (!target.startsWith(root + sep3)) return false;
|
|
39903
|
-
const rel =
|
|
39808
|
+
const rel = path40.relative(root, target);
|
|
39904
39809
|
if (!rel || rel.startsWith("..")) return false;
|
|
39905
|
-
const personaId = rel.split(
|
|
39810
|
+
const personaId = rel.split(path40.sep)[0];
|
|
39906
39811
|
if (!personaId) return false;
|
|
39907
39812
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
39908
39813
|
if (allowed === "*") return true;
|
|
39909
39814
|
return allowed.has(personaId);
|
|
39910
39815
|
}
|
|
39911
39816
|
function personaIdFromPath(absPath, personaRoot) {
|
|
39912
|
-
const root =
|
|
39913
|
-
const target =
|
|
39914
|
-
const sep3 = root.endsWith(
|
|
39817
|
+
const root = path40.resolve(personaRoot);
|
|
39818
|
+
const target = path40.resolve(absPath);
|
|
39819
|
+
const sep3 = root.endsWith(path40.sep) ? "" : path40.sep;
|
|
39915
39820
|
if (!target.startsWith(root + sep3)) return null;
|
|
39916
|
-
const rel =
|
|
39821
|
+
const rel = path40.relative(root, target);
|
|
39917
39822
|
if (!rel || rel.startsWith("..")) return null;
|
|
39918
|
-
const id = rel.split(
|
|
39823
|
+
const id = rel.split(path40.sep)[0];
|
|
39919
39824
|
return id || null;
|
|
39920
39825
|
}
|
|
39921
39826
|
|
|
@@ -39940,7 +39845,7 @@ function buildHistoryHandlers(deps) {
|
|
|
39940
39845
|
if (!pid) return false;
|
|
39941
39846
|
return isGuestPathAllowed(
|
|
39942
39847
|
ctx.grants,
|
|
39943
|
-
|
|
39848
|
+
path41.join(personaRoot, pid),
|
|
39944
39849
|
personaRoot,
|
|
39945
39850
|
"read"
|
|
39946
39851
|
);
|
|
@@ -39951,7 +39856,7 @@ function buildHistoryHandlers(deps) {
|
|
|
39951
39856
|
};
|
|
39952
39857
|
const list = async (frame, _client, ctx) => {
|
|
39953
39858
|
const args = HistoryListArgs.parse(frame);
|
|
39954
|
-
assertGuestPath(ctx,
|
|
39859
|
+
assertGuestPath(ctx, path41.resolve(args.projectPath), personaRoot, "history:list");
|
|
39955
39860
|
const sessions = await history.listSessions(args);
|
|
39956
39861
|
return { response: { type: "history:list", sessions } };
|
|
39957
39862
|
};
|
|
@@ -39983,13 +39888,13 @@ function buildHistoryHandlers(deps) {
|
|
|
39983
39888
|
};
|
|
39984
39889
|
const subagents = async (frame, _client, ctx) => {
|
|
39985
39890
|
const args = HistorySubagentsArgs.parse(frame);
|
|
39986
|
-
assertGuestPath(ctx,
|
|
39891
|
+
assertGuestPath(ctx, path41.resolve(args.cwd), personaRoot, "history:subagents");
|
|
39987
39892
|
const subs = await history.listSubagents(args);
|
|
39988
39893
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
39989
39894
|
};
|
|
39990
39895
|
const subagentRead = async (frame, _client, ctx) => {
|
|
39991
39896
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
39992
|
-
assertGuestPath(ctx,
|
|
39897
|
+
assertGuestPath(ctx, path41.resolve(args.cwd), personaRoot, "history:subagent-read");
|
|
39993
39898
|
const res = await history.readSubagent(args);
|
|
39994
39899
|
return { response: { type: "history:subagent-read", ...res } };
|
|
39995
39900
|
};
|
|
@@ -39997,7 +39902,7 @@ function buildHistoryHandlers(deps) {
|
|
|
39997
39902
|
const dirs = listRecentDirs(store);
|
|
39998
39903
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
39999
39904
|
const filtered = dirs.filter(
|
|
40000
|
-
(d) => isGuestPathAllowed(ctx.grants,
|
|
39905
|
+
(d) => isGuestPathAllowed(ctx.grants, path41.resolve(d.cwd), personaRoot, "read")
|
|
40001
39906
|
);
|
|
40002
39907
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
40003
39908
|
}
|
|
@@ -40014,7 +39919,7 @@ function buildHistoryHandlers(deps) {
|
|
|
40014
39919
|
}
|
|
40015
39920
|
|
|
40016
39921
|
// src/handlers/workspace.ts
|
|
40017
|
-
var
|
|
39922
|
+
var path42 = __toESM(require("path"), 1);
|
|
40018
39923
|
var os15 = __toESM(require("os"), 1);
|
|
40019
39924
|
init_protocol();
|
|
40020
39925
|
init_protocol();
|
|
@@ -40055,22 +39960,22 @@ function buildWorkspaceHandlers(deps) {
|
|
|
40055
39960
|
const args = WorkspaceListArgs.parse(frame);
|
|
40056
39961
|
const isGuest = ctx?.principal.kind === "guest";
|
|
40057
39962
|
const fallbackCwd = isGuest && personaRoot ? personaRoot : os15.homedir();
|
|
40058
|
-
const resolvedCwd =
|
|
40059
|
-
const target = args.path ?
|
|
39963
|
+
const resolvedCwd = path42.resolve(args.cwd ?? fallbackCwd);
|
|
39964
|
+
const target = args.path ? path42.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
40060
39965
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list");
|
|
40061
39966
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
40062
39967
|
return { response: { type: "workspace:list", ...res } };
|
|
40063
39968
|
};
|
|
40064
39969
|
const read = async (frame, _client, ctx) => {
|
|
40065
39970
|
const args = WorkspaceReadArgs.parse(frame);
|
|
40066
|
-
const target =
|
|
39971
|
+
const target = path42.isAbsolute(args.path) ? path42.resolve(args.path) : path42.resolve(args.cwd, args.path);
|
|
40067
39972
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read");
|
|
40068
39973
|
const res = workspace.read(args);
|
|
40069
39974
|
return { response: { type: "workspace:read", ...res } };
|
|
40070
39975
|
};
|
|
40071
39976
|
const skillsList = async (frame, _client, ctx) => {
|
|
40072
39977
|
const args = SkillsListArgs.parse(frame);
|
|
40073
|
-
const cwdAbs =
|
|
39978
|
+
const cwdAbs = path42.resolve(args.cwd);
|
|
40074
39979
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list");
|
|
40075
39980
|
const list2 = skills.list(args);
|
|
40076
39981
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -40082,7 +39987,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
40082
39987
|
};
|
|
40083
39988
|
const agentsList = async (frame, _client, ctx) => {
|
|
40084
39989
|
const args = AgentsListArgs.parse(frame);
|
|
40085
|
-
const cwdAbs =
|
|
39990
|
+
const cwdAbs = path42.resolve(args.cwd);
|
|
40086
39991
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list");
|
|
40087
39992
|
const list2 = agents.list(args);
|
|
40088
39993
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -40101,20 +40006,20 @@ function buildWorkspaceHandlers(deps) {
|
|
|
40101
40006
|
}
|
|
40102
40007
|
|
|
40103
40008
|
// src/handlers/git.ts
|
|
40104
|
-
var
|
|
40009
|
+
var path44 = __toESM(require("path"), 1);
|
|
40105
40010
|
init_protocol();
|
|
40106
40011
|
init_protocol();
|
|
40107
40012
|
|
|
40108
40013
|
// src/workspace/git.ts
|
|
40109
40014
|
var import_node_child_process6 = require("child_process");
|
|
40110
|
-
var
|
|
40111
|
-
var
|
|
40015
|
+
var import_node_fs28 = __toESM(require("fs"), 1);
|
|
40016
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
40112
40017
|
var import_node_util = require("util");
|
|
40113
40018
|
var pexec = (0, import_node_util.promisify)(import_node_child_process6.execFile);
|
|
40114
40019
|
function normalizePath(p2) {
|
|
40115
|
-
const resolved =
|
|
40020
|
+
const resolved = import_node_path32.default.resolve(p2);
|
|
40116
40021
|
try {
|
|
40117
|
-
return
|
|
40022
|
+
return import_node_fs28.default.realpathSync(resolved);
|
|
40118
40023
|
} catch {
|
|
40119
40024
|
return resolved;
|
|
40120
40025
|
}
|
|
@@ -40187,7 +40092,7 @@ async function listGitBranches(cwd) {
|
|
|
40187
40092
|
// src/handlers/git.ts
|
|
40188
40093
|
function assertGuestCwd(ctx, cwd, personaRoot, method) {
|
|
40189
40094
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
40190
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
40095
|
+
if (!isGuestPathAllowed(ctx.grants, path44.resolve(cwd), personaRoot, "read")) {
|
|
40191
40096
|
throw new ClawdError(
|
|
40192
40097
|
ERROR_CODES.UNAUTHORIZED,
|
|
40193
40098
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -40549,36 +40454,6 @@ function buildWhoamiHandler(deps) {
|
|
|
40549
40454
|
};
|
|
40550
40455
|
}
|
|
40551
40456
|
|
|
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
40457
|
// src/handlers/meta.ts
|
|
40583
40458
|
var import_node_os15 = __toESM(require("os"), 1);
|
|
40584
40459
|
init_protocol();
|
|
@@ -40706,7 +40581,7 @@ function buildPersonaHandlers(deps) {
|
|
|
40706
40581
|
}
|
|
40707
40582
|
|
|
40708
40583
|
// src/handlers/attachment.ts
|
|
40709
|
-
var
|
|
40584
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
40710
40585
|
init_protocol();
|
|
40711
40586
|
init_protocol();
|
|
40712
40587
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -40760,12 +40635,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
40760
40635
|
`session ${args.sessionId} scope unresolved`
|
|
40761
40636
|
);
|
|
40762
40637
|
}
|
|
40763
|
-
const cwdAbs =
|
|
40764
|
-
const candidateAbs =
|
|
40638
|
+
const cwdAbs = import_node_path33.default.resolve(sessionFile.cwd);
|
|
40639
|
+
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
40640
|
assertGuestAttachmentPath(ctx, candidateAbs, deps.personaRoot, "attachment.signUrl");
|
|
40766
40641
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
40767
40642
|
const entry = entries.find((e) => {
|
|
40768
|
-
const storedAbs =
|
|
40643
|
+
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
40644
|
return storedAbs === candidateAbs && !e.stale;
|
|
40770
40645
|
});
|
|
40771
40646
|
if (!entry) {
|
|
@@ -40789,7 +40664,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
40789
40664
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
40790
40665
|
const f = deps.sessionStore.read(sessionId);
|
|
40791
40666
|
if (!f) return;
|
|
40792
|
-
assertGuestAttachmentPath(ctx,
|
|
40667
|
+
assertGuestAttachmentPath(ctx, import_node_path33.default.resolve(f.cwd), deps.personaRoot, method);
|
|
40793
40668
|
}
|
|
40794
40669
|
const groupAdd = async (frame, _client, ctx) => {
|
|
40795
40670
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -40861,19 +40736,19 @@ function buildAttachmentHandlers(deps) {
|
|
|
40861
40736
|
|
|
40862
40737
|
// src/handlers/extension.ts
|
|
40863
40738
|
var import_promises7 = __toESM(require("fs/promises"), 1);
|
|
40864
|
-
var
|
|
40739
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
40865
40740
|
init_protocol();
|
|
40866
40741
|
|
|
40867
40742
|
// src/extension/bundle-zip.ts
|
|
40868
40743
|
var import_promises4 = __toESM(require("fs/promises"), 1);
|
|
40869
|
-
var
|
|
40870
|
-
var
|
|
40744
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
40745
|
+
var import_node_crypto11 = __toESM(require("crypto"), 1);
|
|
40871
40746
|
var import_jszip2 = __toESM(require_lib3(), 1);
|
|
40872
40747
|
async function bundleExtensionDir(dir) {
|
|
40873
40748
|
const entries = await listFilesSorted(dir);
|
|
40874
40749
|
const zip = new import_jszip2.default();
|
|
40875
40750
|
for (const rel of entries) {
|
|
40876
|
-
const abs =
|
|
40751
|
+
const abs = import_node_path34.default.join(dir, rel);
|
|
40877
40752
|
const content = await import_promises4.default.readFile(abs);
|
|
40878
40753
|
zip.file(rel, content, { date: FIXED_DATE });
|
|
40879
40754
|
}
|
|
@@ -40882,7 +40757,7 @@ async function bundleExtensionDir(dir) {
|
|
|
40882
40757
|
compression: "DEFLATE",
|
|
40883
40758
|
compressionOptions: { level: 6 }
|
|
40884
40759
|
});
|
|
40885
|
-
const sha256 =
|
|
40760
|
+
const sha256 = import_node_crypto11.default.createHash("sha256").update(buffer).digest("hex");
|
|
40886
40761
|
return { buffer, sha256 };
|
|
40887
40762
|
}
|
|
40888
40763
|
var FIXED_DATE = /* @__PURE__ */ new Date("2020-01-01T00:00:00.000Z");
|
|
@@ -40894,7 +40769,7 @@ async function listFilesSorted(rootDir) {
|
|
|
40894
40769
|
return out;
|
|
40895
40770
|
}
|
|
40896
40771
|
async function walk(absRoot, relPrefix, out) {
|
|
40897
|
-
const dirAbs =
|
|
40772
|
+
const dirAbs = import_node_path34.default.join(absRoot, relPrefix);
|
|
40898
40773
|
const entries = await import_promises4.default.readdir(dirAbs, { withFileTypes: true });
|
|
40899
40774
|
for (const e of entries) {
|
|
40900
40775
|
if (IGNORE_BASENAMES.has(e.name)) continue;
|
|
@@ -40948,25 +40823,25 @@ function computePublishCheck(args) {
|
|
|
40948
40823
|
|
|
40949
40824
|
// src/extension/install-flow.ts
|
|
40950
40825
|
var import_promises5 = __toESM(require("fs/promises"), 1);
|
|
40951
|
-
var
|
|
40826
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
40952
40827
|
var import_node_os17 = __toESM(require("os"), 1);
|
|
40953
|
-
var
|
|
40828
|
+
var import_node_crypto12 = __toESM(require("crypto"), 1);
|
|
40954
40829
|
var import_jszip3 = __toESM(require_lib3(), 1);
|
|
40955
40830
|
|
|
40956
40831
|
// src/extension/paths.ts
|
|
40957
40832
|
var import_node_os16 = __toESM(require("os"), 1);
|
|
40958
|
-
var
|
|
40833
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
40959
40834
|
function clawdHomeRoot(override) {
|
|
40960
|
-
return override ?? process.env.CLAWD_HOME ??
|
|
40835
|
+
return override ?? process.env.CLAWD_HOME ?? import_node_path35.default.join(import_node_os16.default.homedir(), ".clawd");
|
|
40961
40836
|
}
|
|
40962
40837
|
function extensionsRoot(override) {
|
|
40963
|
-
return
|
|
40838
|
+
return import_node_path35.default.join(clawdHomeRoot(override), "extensions");
|
|
40964
40839
|
}
|
|
40965
40840
|
function publishedChannelsFile(override) {
|
|
40966
|
-
return
|
|
40841
|
+
return import_node_path35.default.join(clawdHomeRoot(override), "extensions-published.json");
|
|
40967
40842
|
}
|
|
40968
40843
|
function bundleCacheRoot(override) {
|
|
40969
|
-
return
|
|
40844
|
+
return import_node_path35.default.join(clawdHomeRoot(override), "extension-bundles");
|
|
40970
40845
|
}
|
|
40971
40846
|
|
|
40972
40847
|
// src/extension/install-flow.ts
|
|
@@ -40979,7 +40854,7 @@ var InstallError = class extends Error {
|
|
|
40979
40854
|
};
|
|
40980
40855
|
async function installFromChannel(args, deps) {
|
|
40981
40856
|
const { channelRef, snapshotHash, bundleZip } = args;
|
|
40982
|
-
const computed =
|
|
40857
|
+
const computed = import_node_crypto12.default.createHash("sha256").update(bundleZip).digest("hex");
|
|
40983
40858
|
if (computed !== snapshotHash) {
|
|
40984
40859
|
throw new InstallError(
|
|
40985
40860
|
"HASH_MISMATCH",
|
|
@@ -40993,7 +40868,7 @@ async function installFromChannel(args, deps) {
|
|
|
40993
40868
|
throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
40994
40869
|
}
|
|
40995
40870
|
for (const name of Object.keys(zip.files)) {
|
|
40996
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
40871
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path36.default.isAbsolute(name)) {
|
|
40997
40872
|
throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
40998
40873
|
}
|
|
40999
40874
|
}
|
|
@@ -41025,7 +40900,7 @@ async function installFromChannel(args, deps) {
|
|
|
41025
40900
|
);
|
|
41026
40901
|
}
|
|
41027
40902
|
const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
|
|
41028
|
-
const destDir =
|
|
40903
|
+
const destDir = import_node_path36.default.join(deps.extensionsRoot, localExtId);
|
|
41029
40904
|
let destExists = false;
|
|
41030
40905
|
try {
|
|
41031
40906
|
await import_promises5.default.access(destDir);
|
|
@@ -41039,16 +40914,16 @@ async function installFromChannel(args, deps) {
|
|
|
41039
40914
|
);
|
|
41040
40915
|
}
|
|
41041
40916
|
const stage = await import_promises5.default.mkdtemp(
|
|
41042
|
-
|
|
40917
|
+
import_node_path36.default.join(import_node_os17.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
|
|
41043
40918
|
);
|
|
41044
40919
|
try {
|
|
41045
40920
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
41046
|
-
const dest =
|
|
40921
|
+
const dest = import_node_path36.default.join(stage, name);
|
|
41047
40922
|
if (entry.dir) {
|
|
41048
40923
|
await import_promises5.default.mkdir(dest, { recursive: true });
|
|
41049
40924
|
continue;
|
|
41050
40925
|
}
|
|
41051
|
-
await import_promises5.default.mkdir(
|
|
40926
|
+
await import_promises5.default.mkdir(import_node_path36.default.dirname(dest), { recursive: true });
|
|
41052
40927
|
if (name === "manifest.json") {
|
|
41053
40928
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
41054
40929
|
await import_promises5.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -41069,9 +40944,9 @@ async function installFromChannel(args, deps) {
|
|
|
41069
40944
|
|
|
41070
40945
|
// src/extension/update-flow.ts
|
|
41071
40946
|
var import_promises6 = __toESM(require("fs/promises"), 1);
|
|
41072
|
-
var
|
|
40947
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
41073
40948
|
var import_node_os18 = __toESM(require("os"), 1);
|
|
41074
|
-
var
|
|
40949
|
+
var import_node_crypto13 = __toESM(require("crypto"), 1);
|
|
41075
40950
|
var import_jszip4 = __toESM(require_lib3(), 1);
|
|
41076
40951
|
var UpdateError = class extends Error {
|
|
41077
40952
|
constructor(code, message) {
|
|
@@ -41086,11 +40961,11 @@ async function updateFromChannel(args, deps) {
|
|
|
41086
40961
|
channelRef.extId,
|
|
41087
40962
|
channelRef.ownerPrincipalId
|
|
41088
40963
|
);
|
|
41089
|
-
const liveDir =
|
|
40964
|
+
const liveDir = import_node_path37.default.join(deps.extensionsRoot, localExtId);
|
|
41090
40965
|
const prevDir = `${liveDir}.prev`;
|
|
41091
40966
|
let existingVersion;
|
|
41092
40967
|
try {
|
|
41093
|
-
const raw = await import_promises6.default.readFile(
|
|
40968
|
+
const raw = await import_promises6.default.readFile(import_node_path37.default.join(liveDir, "manifest.json"), "utf8");
|
|
41094
40969
|
const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
|
|
41095
40970
|
if (!parsed2.success) {
|
|
41096
40971
|
throw new UpdateError(
|
|
@@ -41109,7 +40984,7 @@ async function updateFromChannel(args, deps) {
|
|
|
41109
40984
|
if (e instanceof UpdateError) throw e;
|
|
41110
40985
|
throw e;
|
|
41111
40986
|
}
|
|
41112
|
-
const computed =
|
|
40987
|
+
const computed = import_node_crypto13.default.createHash("sha256").update(bundleZip).digest("hex");
|
|
41113
40988
|
if (computed !== snapshotHash) {
|
|
41114
40989
|
throw new UpdateError(
|
|
41115
40990
|
"HASH_MISMATCH",
|
|
@@ -41123,7 +40998,7 @@ async function updateFromChannel(args, deps) {
|
|
|
41123
40998
|
throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
41124
40999
|
}
|
|
41125
41000
|
for (const name of Object.keys(zip.files)) {
|
|
41126
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
41001
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path37.default.isAbsolute(name)) {
|
|
41127
41002
|
throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
41128
41003
|
}
|
|
41129
41004
|
}
|
|
@@ -41158,16 +41033,16 @@ async function updateFromChannel(args, deps) {
|
|
|
41158
41033
|
await import_promises6.default.rm(prevDir, { recursive: true, force: true });
|
|
41159
41034
|
await import_promises6.default.rename(liveDir, prevDir);
|
|
41160
41035
|
const stage = await import_promises6.default.mkdtemp(
|
|
41161
|
-
|
|
41036
|
+
import_node_path37.default.join(import_node_os18.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
|
|
41162
41037
|
);
|
|
41163
41038
|
try {
|
|
41164
41039
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
41165
|
-
const dest =
|
|
41040
|
+
const dest = import_node_path37.default.join(stage, name);
|
|
41166
41041
|
if (entry.dir) {
|
|
41167
41042
|
await import_promises6.default.mkdir(dest, { recursive: true });
|
|
41168
41043
|
continue;
|
|
41169
41044
|
}
|
|
41170
|
-
await import_promises6.default.mkdir(
|
|
41045
|
+
await import_promises6.default.mkdir(import_node_path37.default.dirname(dest), { recursive: true });
|
|
41171
41046
|
if (name === "manifest.json") {
|
|
41172
41047
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
41173
41048
|
await import_promises6.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -41260,7 +41135,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
41260
41135
|
);
|
|
41261
41136
|
}
|
|
41262
41137
|
}
|
|
41263
|
-
const manifestPath =
|
|
41138
|
+
const manifestPath = import_node_path38.default.join(root, extId, "manifest.json");
|
|
41264
41139
|
const manifest = await readManifest(root, extId);
|
|
41265
41140
|
const next = { ...manifest, version: newVersion };
|
|
41266
41141
|
const tmp = `${manifestPath}.tmp`;
|
|
@@ -41268,7 +41143,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
41268
41143
|
await import_promises7.default.rename(tmp, manifestPath);
|
|
41269
41144
|
}
|
|
41270
41145
|
async function readManifest(root, extId) {
|
|
41271
|
-
const file =
|
|
41146
|
+
const file = import_node_path38.default.join(root, extId, "manifest.json");
|
|
41272
41147
|
let raw;
|
|
41273
41148
|
try {
|
|
41274
41149
|
raw = await import_promises7.default.readFile(file, "utf8");
|
|
@@ -41359,7 +41234,7 @@ function buildExtensionHandlers(deps) {
|
|
|
41359
41234
|
};
|
|
41360
41235
|
async function buildSnapshotMeta(extId) {
|
|
41361
41236
|
const manifest = await readManifest(deps.root, extId);
|
|
41362
|
-
const { sha256, buffer } = await bundleExtensionDir(
|
|
41237
|
+
const { sha256, buffer } = await bundleExtensionDir(import_node_path38.default.join(deps.root, extId));
|
|
41363
41238
|
return { manifest, contentHash: sha256, buffer };
|
|
41364
41239
|
}
|
|
41365
41240
|
const publish = async (frame, _client, ctx) => {
|
|
@@ -41539,9 +41414,64 @@ function buildExtensionHandlers(deps) {
|
|
|
41539
41414
|
};
|
|
41540
41415
|
}
|
|
41541
41416
|
|
|
41417
|
+
// src/handlers/app-builder.ts
|
|
41418
|
+
function buildAppBuilderHandlers(deps) {
|
|
41419
|
+
const { store, deleteSessionsByProject, devServerLifecycle } = deps;
|
|
41420
|
+
const listProjects = async () => {
|
|
41421
|
+
const projects = await store.list();
|
|
41422
|
+
return {
|
|
41423
|
+
response: {
|
|
41424
|
+
projects: projects.map((p2) => ({
|
|
41425
|
+
...p2,
|
|
41426
|
+
isRunning: devServerLifecycle.isRunning(p2.name),
|
|
41427
|
+
boundSessionId: devServerLifecycle.boundSessionId(p2.name)
|
|
41428
|
+
}))
|
|
41429
|
+
}
|
|
41430
|
+
};
|
|
41431
|
+
};
|
|
41432
|
+
const createProject = async (frame) => {
|
|
41433
|
+
const name = frame.name;
|
|
41434
|
+
if (typeof name !== "string") throw new Error("createProject: name must be string");
|
|
41435
|
+
const project = await store.create(name);
|
|
41436
|
+
return { response: { project } };
|
|
41437
|
+
};
|
|
41438
|
+
const deleteProject = async (frame) => {
|
|
41439
|
+
const name = frame.name;
|
|
41440
|
+
if (typeof name !== "string") throw new Error("deleteProject: name must be string");
|
|
41441
|
+
await devServerLifecycle.stopForProject(name);
|
|
41442
|
+
await deleteSessionsByProject(name);
|
|
41443
|
+
await store.delete(name);
|
|
41444
|
+
return { response: {} };
|
|
41445
|
+
};
|
|
41446
|
+
const updateProjectPort = async (frame) => {
|
|
41447
|
+
const f = frame;
|
|
41448
|
+
if (typeof f.name !== "string") throw new Error("updateProjectPort: name must be string");
|
|
41449
|
+
if (typeof f.newPort !== "number") throw new Error("updateProjectPort: newPort must be number");
|
|
41450
|
+
const entry = devServerLifecycle.boundEntry(f.name);
|
|
41451
|
+
await devServerLifecycle.stopForProject(f.name);
|
|
41452
|
+
const project = await store.updatePort(f.name, f.newPort);
|
|
41453
|
+
if (entry) {
|
|
41454
|
+
await devServerLifecycle.restartForProjectAt({
|
|
41455
|
+
projectName: f.name,
|
|
41456
|
+
newPort: f.newPort,
|
|
41457
|
+
sessionId: entry.sessionId,
|
|
41458
|
+
cwd: entry.cwd,
|
|
41459
|
+
tunnelHost: entry.tunnelHost
|
|
41460
|
+
});
|
|
41461
|
+
}
|
|
41462
|
+
return { response: { project } };
|
|
41463
|
+
};
|
|
41464
|
+
return {
|
|
41465
|
+
"appBuilder:listProjects": listProjects,
|
|
41466
|
+
"appBuilder:createProject": createProject,
|
|
41467
|
+
"appBuilder:deleteProject": deleteProject,
|
|
41468
|
+
"appBuilder:updateProjectPort": updateProjectPort
|
|
41469
|
+
};
|
|
41470
|
+
}
|
|
41471
|
+
|
|
41542
41472
|
// src/extension/registry.ts
|
|
41543
41473
|
var import_promises8 = __toESM(require("fs/promises"), 1);
|
|
41544
|
-
var
|
|
41474
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
41545
41475
|
async function loadAll(root) {
|
|
41546
41476
|
let entries;
|
|
41547
41477
|
try {
|
|
@@ -41554,13 +41484,13 @@ async function loadAll(root) {
|
|
|
41554
41484
|
for (const ent of entries) {
|
|
41555
41485
|
if (!ent.isDirectory()) continue;
|
|
41556
41486
|
if (ent.name.startsWith(".")) continue;
|
|
41557
|
-
records.push(await loadOne(
|
|
41487
|
+
records.push(await loadOne(import_node_path39.default.join(root, ent.name), ent.name));
|
|
41558
41488
|
}
|
|
41559
41489
|
records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
|
|
41560
41490
|
return records;
|
|
41561
41491
|
}
|
|
41562
41492
|
async function loadOne(dir, dirName) {
|
|
41563
|
-
const manifestPath =
|
|
41493
|
+
const manifestPath = import_node_path39.default.join(dir, "manifest.json");
|
|
41564
41494
|
let raw;
|
|
41565
41495
|
try {
|
|
41566
41496
|
raw = await import_promises8.default.readFile(manifestPath, "utf8");
|
|
@@ -41605,7 +41535,7 @@ async function loadOne(dir, dirName) {
|
|
|
41605
41535
|
|
|
41606
41536
|
// src/extension/uninstall.ts
|
|
41607
41537
|
var import_promises9 = __toESM(require("fs/promises"), 1);
|
|
41608
|
-
var
|
|
41538
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
41609
41539
|
var UninstallError = class extends Error {
|
|
41610
41540
|
constructor(code, message) {
|
|
41611
41541
|
super(message);
|
|
@@ -41614,7 +41544,7 @@ var UninstallError = class extends Error {
|
|
|
41614
41544
|
code;
|
|
41615
41545
|
};
|
|
41616
41546
|
async function uninstall(deps) {
|
|
41617
|
-
const dir =
|
|
41547
|
+
const dir = import_node_path40.default.join(deps.root, deps.extId);
|
|
41618
41548
|
try {
|
|
41619
41549
|
await import_promises9.default.access(dir);
|
|
41620
41550
|
} catch {
|
|
@@ -41627,7 +41557,12 @@ async function uninstall(deps) {
|
|
|
41627
41557
|
// src/handlers/index.ts
|
|
41628
41558
|
function buildMethodHandlers(deps) {
|
|
41629
41559
|
return {
|
|
41630
|
-
...buildSessionHandlers(
|
|
41560
|
+
...buildSessionHandlers({
|
|
41561
|
+
...deps,
|
|
41562
|
+
devServerLifecycle: deps.devServerLifecycle,
|
|
41563
|
+
appBuilderStore: deps.appBuilderStore,
|
|
41564
|
+
getTunnelUrl: deps.getTunnelUrl
|
|
41565
|
+
}),
|
|
41631
41566
|
...buildPermissionHandlers(deps),
|
|
41632
41567
|
...buildHistoryHandlers(deps),
|
|
41633
41568
|
...buildWorkspaceHandlers(deps),
|
|
@@ -41660,7 +41595,6 @@ function buildMethodHandlers(deps) {
|
|
|
41660
41595
|
personaStore: deps.personaStore,
|
|
41661
41596
|
capabilityManager: deps.capabilityManager
|
|
41662
41597
|
}),
|
|
41663
|
-
...buildFeishuAuthHandlers(deps.feishuAuth),
|
|
41664
41598
|
...deps.attachment ? buildAttachmentHandlers(deps.attachment) : {},
|
|
41665
41599
|
...buildExtensionHandlers({
|
|
41666
41600
|
loadAll,
|
|
@@ -41669,10 +41603,186 @@ function buildMethodHandlers(deps) {
|
|
|
41669
41603
|
root: extensionsRoot(),
|
|
41670
41604
|
publishedChannelStore: deps.publishedChannelStore,
|
|
41671
41605
|
bundleCache: deps.bundleCache
|
|
41606
|
+
}),
|
|
41607
|
+
...buildAppBuilderHandlers({
|
|
41608
|
+
store: deps.appBuilderStore,
|
|
41609
|
+
deleteSessionsByProject: deps.deleteSessionsByProject,
|
|
41610
|
+
devServerLifecycle: deps.devServerLifecycle
|
|
41672
41611
|
})
|
|
41673
41612
|
};
|
|
41674
41613
|
}
|
|
41675
41614
|
|
|
41615
|
+
// src/app-builder/project-store.ts
|
|
41616
|
+
var import_node_fs29 = require("fs");
|
|
41617
|
+
var import_node_path41 = require("path");
|
|
41618
|
+
init_protocol();
|
|
41619
|
+
var PROJECTS_DIR = "projects";
|
|
41620
|
+
var META_FILE = ".clawd-project.json";
|
|
41621
|
+
var ProjectStore = class {
|
|
41622
|
+
/** @param personaRoot persona 目录,例如 `~/.clawd/personas/persona-app-builder/` */
|
|
41623
|
+
constructor(personaRoot) {
|
|
41624
|
+
this.personaRoot = personaRoot;
|
|
41625
|
+
}
|
|
41626
|
+
personaRoot;
|
|
41627
|
+
/** projects/<name>/.clawd-project.json 路径 */
|
|
41628
|
+
metaPath(name) {
|
|
41629
|
+
return (0, import_node_path41.join)(this.projectsRoot(), name, META_FILE);
|
|
41630
|
+
}
|
|
41631
|
+
/** projects/<name>/ 目录路径(cwd 用) */
|
|
41632
|
+
projectDir(name) {
|
|
41633
|
+
return (0, import_node_path41.join)(this.projectsRoot(), name);
|
|
41634
|
+
}
|
|
41635
|
+
projectsRoot() {
|
|
41636
|
+
return (0, import_node_path41.join)(this.personaRoot, PROJECTS_DIR);
|
|
41637
|
+
}
|
|
41638
|
+
async list() {
|
|
41639
|
+
let entries;
|
|
41640
|
+
try {
|
|
41641
|
+
entries = await import_node_fs29.promises.readdir(this.projectsRoot());
|
|
41642
|
+
} catch (err) {
|
|
41643
|
+
if (err.code === "ENOENT") return [];
|
|
41644
|
+
throw err;
|
|
41645
|
+
}
|
|
41646
|
+
const out = [];
|
|
41647
|
+
for (const name of entries) {
|
|
41648
|
+
try {
|
|
41649
|
+
const raw = await import_node_fs29.promises.readFile(this.metaPath(name), "utf8");
|
|
41650
|
+
const parsed = ProjectMetadataSchema.safeParse(JSON.parse(raw));
|
|
41651
|
+
if (parsed.success) out.push(parsed.data);
|
|
41652
|
+
} catch {
|
|
41653
|
+
}
|
|
41654
|
+
}
|
|
41655
|
+
return out.sort((a, b2) => a.name.localeCompare(b2.name));
|
|
41656
|
+
}
|
|
41657
|
+
async create(name) {
|
|
41658
|
+
const existing = await this.list();
|
|
41659
|
+
if (existing.some((p2) => p2.name === name)) {
|
|
41660
|
+
throw new Error(`project "${name}" already exists / \u5DF2\u5B58\u5728`);
|
|
41661
|
+
}
|
|
41662
|
+
const usedPorts = new Set(existing.map((p2) => p2.port));
|
|
41663
|
+
let port = -1;
|
|
41664
|
+
for (let p2 = PROJECT_PORT_MIN; p2 <= PROJECT_PORT_MAX; p2++) {
|
|
41665
|
+
if (!usedPorts.has(p2)) {
|
|
41666
|
+
port = p2;
|
|
41667
|
+
break;
|
|
41668
|
+
}
|
|
41669
|
+
}
|
|
41670
|
+
if (port < 0) {
|
|
41671
|
+
throw new Error(
|
|
41672
|
+
`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`
|
|
41673
|
+
);
|
|
41674
|
+
}
|
|
41675
|
+
const meta = {
|
|
41676
|
+
name,
|
|
41677
|
+
port,
|
|
41678
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
41679
|
+
};
|
|
41680
|
+
const validated = ProjectMetadataSchema.safeParse(meta);
|
|
41681
|
+
if (!validated.success) {
|
|
41682
|
+
throw new Error(`invalid name "${name}": ${validated.error.message}`);
|
|
41683
|
+
}
|
|
41684
|
+
const dir = this.projectDir(name);
|
|
41685
|
+
await import_node_fs29.promises.mkdir(dir, { recursive: true });
|
|
41686
|
+
await import_node_fs29.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
|
|
41687
|
+
return meta;
|
|
41688
|
+
}
|
|
41689
|
+
async delete(name) {
|
|
41690
|
+
const dir = this.projectDir(name);
|
|
41691
|
+
await import_node_fs29.promises.rm(dir, { recursive: true, force: true });
|
|
41692
|
+
}
|
|
41693
|
+
async updatePort(name, newPort) {
|
|
41694
|
+
if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
|
|
41695
|
+
throw new Error(
|
|
41696
|
+
`port range invalid: must be ${PROJECT_PORT_MIN}-${PROJECT_PORT_MAX}, got ${newPort}`
|
|
41697
|
+
);
|
|
41698
|
+
}
|
|
41699
|
+
const list = await this.list();
|
|
41700
|
+
const target = list.find((p2) => p2.name === name);
|
|
41701
|
+
if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
|
|
41702
|
+
const conflict = list.find((p2) => p2.name !== name && p2.port === newPort);
|
|
41703
|
+
if (conflict) {
|
|
41704
|
+
throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
|
|
41705
|
+
}
|
|
41706
|
+
const updated = { ...target, port: newPort };
|
|
41707
|
+
await import_node_fs29.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
|
|
41708
|
+
return updated;
|
|
41709
|
+
}
|
|
41710
|
+
};
|
|
41711
|
+
|
|
41712
|
+
// src/app-builder/dev-server-supervisor.ts
|
|
41713
|
+
var import_node_child_process7 = require("child_process");
|
|
41714
|
+
var import_node_events2 = require("events");
|
|
41715
|
+
var DevServerSupervisor = class extends import_node_events2.EventEmitter {
|
|
41716
|
+
running = /* @__PURE__ */ new Map();
|
|
41717
|
+
// key: sessionId
|
|
41718
|
+
startForSession(args) {
|
|
41719
|
+
if (this.running.has(args.sessionId)) return;
|
|
41720
|
+
const env = {
|
|
41721
|
+
...process.env,
|
|
41722
|
+
CLAWD_TUNNEL_HOST: args.tunnelHost ?? "",
|
|
41723
|
+
CLAWD_PREVIEW_PORT: String(args.port)
|
|
41724
|
+
};
|
|
41725
|
+
const child = (0, import_node_child_process7.spawn)("pnpm", ["dev"], { cwd: args.cwd, env, stdio: "pipe" });
|
|
41726
|
+
const entry = { ...args, process: child };
|
|
41727
|
+
this.running.set(args.sessionId, entry);
|
|
41728
|
+
child.on("exit", (code) => {
|
|
41729
|
+
this.running.delete(args.sessionId);
|
|
41730
|
+
if (code !== 0 && code !== null) {
|
|
41731
|
+
const ev = {
|
|
41732
|
+
sessionId: args.sessionId,
|
|
41733
|
+
projectName: args.projectName,
|
|
41734
|
+
port: args.port,
|
|
41735
|
+
exitCode: code
|
|
41736
|
+
};
|
|
41737
|
+
this.emit("devServer:failed", ev);
|
|
41738
|
+
}
|
|
41739
|
+
});
|
|
41740
|
+
}
|
|
41741
|
+
stopForSession(sessionId) {
|
|
41742
|
+
const entry = this.running.get(sessionId);
|
|
41743
|
+
if (!entry) return Promise.resolve();
|
|
41744
|
+
return new Promise((resolve6) => {
|
|
41745
|
+
entry.process.once("exit", () => {
|
|
41746
|
+
this.running.delete(sessionId);
|
|
41747
|
+
resolve6();
|
|
41748
|
+
});
|
|
41749
|
+
entry.process.kill("SIGTERM");
|
|
41750
|
+
});
|
|
41751
|
+
}
|
|
41752
|
+
async stopForProject(projectName) {
|
|
41753
|
+
const entry = [...this.running.values()].find((e) => e.projectName === projectName);
|
|
41754
|
+
if (!entry) return;
|
|
41755
|
+
await this.stopForSession(entry.sessionId);
|
|
41756
|
+
}
|
|
41757
|
+
async restartForProjectAt(args) {
|
|
41758
|
+
await this.stopForSession(args.sessionId);
|
|
41759
|
+
this.startForSession({
|
|
41760
|
+
sessionId: args.sessionId,
|
|
41761
|
+
projectName: args.projectName,
|
|
41762
|
+
port: args.newPort,
|
|
41763
|
+
cwd: args.cwd,
|
|
41764
|
+
tunnelHost: args.tunnelHost
|
|
41765
|
+
});
|
|
41766
|
+
}
|
|
41767
|
+
isRunning(projectName) {
|
|
41768
|
+
return [...this.running.values()].some((e) => e.projectName === projectName);
|
|
41769
|
+
}
|
|
41770
|
+
boundSessionId(projectName) {
|
|
41771
|
+
const entry = [...this.running.values()].find((e) => e.projectName === projectName);
|
|
41772
|
+
return entry?.sessionId ?? null;
|
|
41773
|
+
}
|
|
41774
|
+
boundEntry(projectName) {
|
|
41775
|
+
const entry = [...this.running.values()].find((e) => e.projectName === projectName);
|
|
41776
|
+
if (!entry) return null;
|
|
41777
|
+
return {
|
|
41778
|
+
sessionId: entry.sessionId,
|
|
41779
|
+
cwd: entry.cwd,
|
|
41780
|
+
port: entry.port,
|
|
41781
|
+
tunnelHost: entry.tunnelHost
|
|
41782
|
+
};
|
|
41783
|
+
}
|
|
41784
|
+
};
|
|
41785
|
+
|
|
41676
41786
|
// src/handlers/method-grants.ts
|
|
41677
41787
|
var ADMIN_ANY = {
|
|
41678
41788
|
kind: "fixed",
|
|
@@ -41803,11 +41913,14 @@ var METHOD_GRANT_MAP = {
|
|
|
41803
41913
|
// guest-self:guest 在自己 daemon 上触发安装与更新(无持久化 subscription 概念)
|
|
41804
41914
|
"extension.install-from-channel": ADMIN_ANY,
|
|
41805
41915
|
"extension.update-from-channel": ADMIN_ANY,
|
|
41806
|
-
// ----
|
|
41807
|
-
//
|
|
41808
|
-
|
|
41809
|
-
|
|
41810
|
-
"
|
|
41916
|
+
// ---- app-builder Project picker(spec 2026-06-01-app-builder-project-picker-design) ----
|
|
41917
|
+
// owner-only:picker UI 给 owner 管理本机 build 中的 project(fs + 端口分配)。
|
|
41918
|
+
// 即使 persona-app-builder 是 PreinstalledPersona,project 管理也属本机 owner 行为,
|
|
41919
|
+
// 不暴露给 guest(远端接入者)。
|
|
41920
|
+
"appBuilder:listProjects": ADMIN_ANY,
|
|
41921
|
+
"appBuilder:createProject": ADMIN_ANY,
|
|
41922
|
+
"appBuilder:deleteProject": ADMIN_ANY,
|
|
41923
|
+
"appBuilder:updateProjectPort": ADMIN_ANY
|
|
41811
41924
|
};
|
|
41812
41925
|
function computeGrantForFrame(method, frame) {
|
|
41813
41926
|
const rule = METHOD_GRANT_MAP[method];
|
|
@@ -41823,12 +41936,12 @@ function computeGrantForFrame(method, frame) {
|
|
|
41823
41936
|
}
|
|
41824
41937
|
|
|
41825
41938
|
// src/extension/runtime.ts
|
|
41826
|
-
var
|
|
41939
|
+
var import_node_child_process8 = require("child_process");
|
|
41827
41940
|
var import_node_path42 = __toESM(require("path"), 1);
|
|
41828
41941
|
var import_promises10 = require("timers/promises");
|
|
41829
41942
|
|
|
41830
41943
|
// src/extension/port-allocator.ts
|
|
41831
|
-
var
|
|
41944
|
+
var import_node_net2 = __toESM(require("net"), 1);
|
|
41832
41945
|
var PortExhaustedError = class extends Error {
|
|
41833
41946
|
constructor(min, max) {
|
|
41834
41947
|
super(`no free port in [${min},${max}]`);
|
|
@@ -41841,7 +41954,7 @@ var PortExhaustedError = class extends Error {
|
|
|
41841
41954
|
};
|
|
41842
41955
|
function probe(port) {
|
|
41843
41956
|
return new Promise((resolve6) => {
|
|
41844
|
-
const srv =
|
|
41957
|
+
const srv = import_node_net2.default.createServer();
|
|
41845
41958
|
srv.once("error", () => resolve6(false));
|
|
41846
41959
|
srv.once("listening", () => {
|
|
41847
41960
|
srv.close(() => resolve6(true));
|
|
@@ -41931,7 +42044,7 @@ var Runtime = class {
|
|
|
41931
42044
|
CLAWOS_EXT_PORT: String(port),
|
|
41932
42045
|
CLAWOS_EXT_ID: extId
|
|
41933
42046
|
};
|
|
41934
|
-
const child = (0,
|
|
42047
|
+
const child = (0, import_node_child_process8.spawn)("sh", ["-c", cmd], {
|
|
41935
42048
|
cwd: dir,
|
|
41936
42049
|
env,
|
|
41937
42050
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -42197,11 +42310,8 @@ async function startDaemon(config) {
|
|
|
42197
42310
|
} else if (config.tunnel) {
|
|
42198
42311
|
resolvedAuthToken = authFile.token;
|
|
42199
42312
|
}
|
|
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);
|
|
42313
|
+
const ownerPrincipalId = authFile.ownerPrincipalId;
|
|
42314
|
+
const ownerDisplayName = loadOwnerDisplayName(config.dataDir);
|
|
42205
42315
|
const authMode = resolvedAuthToken == null ? "none" : "first-message";
|
|
42206
42316
|
const inboxStore = new InboxStore(config.dataDir);
|
|
42207
42317
|
const inboxManager = new InboxManager(inboxStore, (_peerOwnerId, frame) => {
|
|
@@ -42243,9 +42353,7 @@ async function startDaemon(config) {
|
|
|
42243
42353
|
isOwnerToken: (x) => resolvedAuthToken != null && constantTimeEqual(x, resolvedAuthToken),
|
|
42244
42354
|
ownerPrincipalId,
|
|
42245
42355
|
ownerDisplayName,
|
|
42246
|
-
|
|
42247
|
-
// 不传 registry 让 guest token 一律 BAD_TOKEN。owner 自己连接不受影响。
|
|
42248
|
-
...feishuActive ? { capabilityRegistry } : {},
|
|
42356
|
+
capabilityRegistry,
|
|
42249
42357
|
selfPrincipalId,
|
|
42250
42358
|
selfDisplayName
|
|
42251
42359
|
});
|
|
@@ -42402,13 +42510,13 @@ async function startDaemon(config) {
|
|
|
42402
42510
|
const publishedChannelStore = new PublishedChannelStore(publishedChannelsFile());
|
|
42403
42511
|
await publishedChannelStore.load();
|
|
42404
42512
|
const bundleCache = new BundleCache(bundleCacheRoot());
|
|
42405
|
-
const
|
|
42406
|
-
|
|
42407
|
-
|
|
42408
|
-
|
|
42409
|
-
|
|
42410
|
-
}
|
|
42411
|
-
const
|
|
42513
|
+
const appBuilderStore = new ProjectStore(
|
|
42514
|
+
import_node_path45.default.join(config.dataDir, "personas/persona-app-builder")
|
|
42515
|
+
);
|
|
42516
|
+
const devServerSupervisor = new DevServerSupervisor();
|
|
42517
|
+
const deleteSessionsByProject = async (_name) => {
|
|
42518
|
+
};
|
|
42519
|
+
const handlers = buildMethodHandlers({
|
|
42412
42520
|
manager,
|
|
42413
42521
|
workspace,
|
|
42414
42522
|
skills,
|
|
@@ -42481,10 +42589,11 @@ async function startDaemon(config) {
|
|
|
42481
42589
|
// extension sharing v1 — owner-side published-channels store.
|
|
42482
42590
|
publishedChannelStore,
|
|
42483
42591
|
bundleCache,
|
|
42484
|
-
//
|
|
42485
|
-
|
|
42592
|
+
// app-builder
|
|
42593
|
+
appBuilderStore,
|
|
42594
|
+
deleteSessionsByProject,
|
|
42595
|
+
devServerLifecycle: devServerSupervisor
|
|
42486
42596
|
});
|
|
42487
|
-
let handlers = makeHandlers();
|
|
42488
42597
|
const authResolver = new AuthContextResolver({
|
|
42489
42598
|
ownerToken: resolvedAuthToken
|
|
42490
42599
|
});
|
|
@@ -42510,29 +42619,8 @@ async function startDaemon(config) {
|
|
|
42510
42619
|
},
|
|
42511
42620
|
// POST /extensions/import lands in ~/.clawd/extensions/<id>/
|
|
42512
42621
|
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
|
-
}
|
|
42622
|
+
// app-builder build 模式:/preview/<port>/ 反代 dev server 的端口白名单(见 spec §三.2)
|
|
42623
|
+
previewPorts: config.previewPorts ?? void 0
|
|
42536
42624
|
});
|
|
42537
42625
|
wsServer = new LocalWsServer({
|
|
42538
42626
|
host: config.host,
|
|
@@ -42571,6 +42659,8 @@ async function startDaemon(config) {
|
|
|
42571
42659
|
},
|
|
42572
42660
|
// file-sharing HTTP 路由复用 daemon 同端口(spec §5 第 3 条);router 自己处理 auth + 404
|
|
42573
42661
|
httpRequestHandler: httpRouter,
|
|
42662
|
+
// app-builder build 模式:/preview/<port>/ HMR websocket upgrade 转发的端口白名单(同 http-router 配置)
|
|
42663
|
+
previewPorts: config.previewPorts ?? void 0,
|
|
42574
42664
|
// 订阅成功后给该 client 重放 in-flight pendingQuestions(plan: clawd-question-server-truth)。
|
|
42575
42665
|
// daemon 是 pendingQuestions 的唯一 source of truth;新 client 接入 / 刷新页面时
|
|
42576
42666
|
// 把当前所有未决 question 以 session:question 帧定向回放,让 UI 不再误显示 Ended。
|
|
@@ -42615,12 +42705,6 @@ async function startDaemon(config) {
|
|
|
42615
42705
|
const requestId = typeof frame.requestId === "string" ? frame.requestId : void 0;
|
|
42616
42706
|
const handler = handlers[type];
|
|
42617
42707
|
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
42708
|
const ctx = wsServer.getClientContext(client.id) ?? ownerContext(ownerPrincipalId, ownerDisplayName);
|
|
42625
42709
|
const verdict = computeGrantForFrame(type, frame);
|
|
42626
42710
|
if (verdict.kind === "check") {
|
|
@@ -42693,6 +42777,7 @@ async function startDaemon(config) {
|
|
|
42693
42777
|
stateSnapshot = { ...stateSnapshot, tunnelUrl: r.url, tunnelError: void 0 };
|
|
42694
42778
|
stateMgr.write(stateSnapshot);
|
|
42695
42779
|
currentTunnelUrl = r.url;
|
|
42780
|
+
wss.broadcastAll({ type: "tunnel:ready", url: r.url, subdomain: r.subdomain });
|
|
42696
42781
|
const connectUrl = resolvedAuthToken ? `${r.url}#token=${resolvedAuthToken}` : r.url;
|
|
42697
42782
|
const lines = [
|
|
42698
42783
|
`Tunnel: ${r.url}`,
|