@teammy/server 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +2 -2
  2. package/dist/main.js +10936 -6840
  3. package/dist/native-pi-entry.js +14 -1
  4. package/dist/project-pi-entry.js +51 -11
  5. package/dist/runtime/workflows/task-bootstrap/prompt.md +2 -0
  6. package/dist/web/assets/Assistant-BeYamS0w.js +1 -0
  7. package/dist/web/assets/Assistant-C7QfFYLo.css +1 -0
  8. package/dist/web/assets/Dashboard-BzmrE4Xv.js +1 -0
  9. package/dist/web/assets/Files-BvCYgjVV.js +1 -0
  10. package/dist/web/assets/{Markdown-oZagG-wy.js → Markdown-BRPMsc7D.js} +4 -4
  11. package/dist/web/assets/Materials-CK-mbNmo.css +1 -0
  12. package/dist/web/assets/Materials-DK3CkLr0.js +6 -0
  13. package/dist/web/assets/Sessions-D_579m-e.js +1 -0
  14. package/dist/web/assets/WorkspaceTree-fMDtGIFa.js +1 -0
  15. package/dist/web/assets/{file-links-CD346_jf.js → file-links-I1K8CwVK.js} +1 -1
  16. package/dist/web/assets/{index-Be5hGscJ.css → index-CTIAGUGG.css} +1 -1
  17. package/dist/web/assets/index-DQsx-e5d.js +66 -0
  18. package/dist/web/downloads/teammy-skill.zip +0 -0
  19. package/dist/web/index.html +2 -2
  20. package/node_modules/@isaacs/nonrecursive-glob-match/LICENSE.md +55 -0
  21. package/node_modules/@isaacs/nonrecursive-glob-match/README.md +333 -0
  22. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/index.d.ts +114 -0
  23. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/index.d.ts.map +1 -0
  24. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/index.js +762 -0
  25. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/index.js.map +1 -0
  26. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/index.min.js +3 -0
  27. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/index.min.js.map +7 -0
  28. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/package.json +3 -0
  29. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/parse-class.d.ts +4 -0
  30. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/parse-class.d.ts.map +1 -0
  31. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/parse-class.js +142 -0
  32. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/parse-class.js.map +1 -0
  33. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/index.d.ts +114 -0
  34. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/index.d.ts.map +1 -0
  35. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/index.js +758 -0
  36. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/index.js.map +1 -0
  37. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/index.min.js +3 -0
  38. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/index.min.js.map +7 -0
  39. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/package.json +3 -0
  40. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/parse-class.d.ts +4 -0
  41. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/parse-class.d.ts.map +1 -0
  42. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/parse-class.js +138 -0
  43. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/parse-class.js.map +1 -0
  44. package/node_modules/@isaacs/nonrecursive-glob-match/package.json +56 -0
  45. package/node_modules/@isaacs/nonrecursive-glob-match/src/index.ts +900 -0
  46. package/node_modules/@isaacs/nonrecursive-glob-match/src/parse-class.ts +158 -0
  47. package/node_modules/glob/README.md +388 -214
  48. package/node_modules/glob/dist/commonjs/glob.d.ts +20 -11
  49. package/node_modules/glob/dist/commonjs/glob.d.ts.map +1 -1
  50. package/node_modules/glob/dist/commonjs/glob.js +22 -29
  51. package/node_modules/glob/dist/commonjs/glob.js.map +1 -1
  52. package/node_modules/glob/dist/commonjs/has-magic.d.ts +1 -1
  53. package/node_modules/glob/dist/commonjs/has-magic.d.ts.map +1 -1
  54. package/node_modules/glob/dist/commonjs/has-magic.js +1 -4
  55. package/node_modules/glob/dist/commonjs/has-magic.js.map +1 -1
  56. package/node_modules/glob/dist/commonjs/ignore.d.ts +16 -4
  57. package/node_modules/glob/dist/commonjs/ignore.d.ts.map +1 -1
  58. package/node_modules/glob/dist/commonjs/ignore.js +24 -4
  59. package/node_modules/glob/dist/commonjs/ignore.js.map +1 -1
  60. package/node_modules/glob/dist/commonjs/index.d.ts +3 -2
  61. package/node_modules/glob/dist/commonjs/index.d.ts.map +1 -1
  62. package/node_modules/glob/dist/commonjs/index.js.map +1 -1
  63. package/node_modules/glob/dist/commonjs/index.min.js +2 -3
  64. package/node_modules/glob/dist/commonjs/index.min.js.map +4 -4
  65. package/node_modules/glob/dist/commonjs/pattern.d.ts +10 -3
  66. package/node_modules/glob/dist/commonjs/pattern.d.ts.map +1 -1
  67. package/node_modules/glob/dist/commonjs/pattern.js +27 -15
  68. package/node_modules/glob/dist/commonjs/pattern.js.map +1 -1
  69. package/node_modules/glob/dist/commonjs/processor.d.ts +23 -10
  70. package/node_modules/glob/dist/commonjs/processor.d.ts.map +1 -1
  71. package/node_modules/glob/dist/commonjs/processor.js +36 -23
  72. package/node_modules/glob/dist/commonjs/processor.js.map +1 -1
  73. package/node_modules/glob/dist/commonjs/walker.d.ts +19 -17
  74. package/node_modules/glob/dist/commonjs/walker.d.ts.map +1 -1
  75. package/node_modules/glob/dist/commonjs/walker.js +50 -35
  76. package/node_modules/glob/dist/commonjs/walker.js.map +1 -1
  77. package/node_modules/glob/dist/esm/glob.d.ts +20 -11
  78. package/node_modules/glob/dist/esm/glob.d.ts.map +1 -1
  79. package/node_modules/glob/dist/esm/glob.js +22 -29
  80. package/node_modules/glob/dist/esm/glob.js.map +1 -1
  81. package/node_modules/glob/dist/esm/has-magic.d.ts +1 -1
  82. package/node_modules/glob/dist/esm/has-magic.d.ts.map +1 -1
  83. package/node_modules/glob/dist/esm/has-magic.js +1 -4
  84. package/node_modules/glob/dist/esm/has-magic.js.map +1 -1
  85. package/node_modules/glob/dist/esm/ignore.d.ts +16 -4
  86. package/node_modules/glob/dist/esm/ignore.d.ts.map +1 -1
  87. package/node_modules/glob/dist/esm/ignore.js +25 -5
  88. package/node_modules/glob/dist/esm/ignore.js.map +1 -1
  89. package/node_modules/glob/dist/esm/index.d.ts +3 -2
  90. package/node_modules/glob/dist/esm/index.d.ts.map +1 -1
  91. package/node_modules/glob/dist/esm/index.js.map +1 -1
  92. package/node_modules/glob/dist/esm/index.min.js +2 -3
  93. package/node_modules/glob/dist/esm/index.min.js.map +4 -4
  94. package/node_modules/glob/dist/esm/pattern.d.ts +10 -3
  95. package/node_modules/glob/dist/esm/pattern.d.ts.map +1 -1
  96. package/node_modules/glob/dist/esm/pattern.js +27 -15
  97. package/node_modules/glob/dist/esm/pattern.js.map +1 -1
  98. package/node_modules/glob/dist/esm/processor.d.ts +23 -10
  99. package/node_modules/glob/dist/esm/processor.d.ts.map +1 -1
  100. package/node_modules/glob/dist/esm/processor.js +36 -23
  101. package/node_modules/glob/dist/esm/processor.js.map +1 -1
  102. package/node_modules/glob/dist/esm/walker.d.ts +19 -17
  103. package/node_modules/glob/dist/esm/walker.d.ts.map +1 -1
  104. package/node_modules/glob/dist/esm/walker.js +51 -36
  105. package/node_modules/glob/dist/esm/walker.js.map +1 -1
  106. package/node_modules/glob/package.json +28 -12
  107. package/node_modules/glob/src/glob.ts +655 -0
  108. package/node_modules/glob/src/has-magic.ts +23 -0
  109. package/node_modules/glob/src/ignore.ts +162 -0
  110. package/node_modules/glob/src/index.ts +225 -0
  111. package/node_modules/glob/src/pattern.ts +286 -0
  112. package/node_modules/glob/src/processor.ts +333 -0
  113. package/node_modules/glob/src/walker.ts +523 -0
  114. package/node_modules/minimatch/README.md +125 -107
  115. package/node_modules/minimatch/dist/commonjs/index.d.ts +49 -38
  116. package/node_modules/minimatch/dist/commonjs/index.d.ts.map +1 -1
  117. package/node_modules/minimatch/dist/commonjs/index.js +782 -359
  118. package/node_modules/minimatch/dist/commonjs/index.js.map +1 -1
  119. package/node_modules/minimatch/dist/esm/index.d.ts +49 -38
  120. package/node_modules/minimatch/dist/esm/index.d.ts.map +1 -1
  121. package/node_modules/minimatch/dist/esm/index.js +781 -356
  122. package/node_modules/minimatch/dist/esm/index.js.map +1 -1
  123. package/node_modules/minimatch/package.json +5 -4
  124. package/node_modules/path-scurry/README.md +0 -1
  125. package/node_modules/path-scurry/dist/commonjs/index.d.ts +7 -0
  126. package/node_modules/path-scurry/dist/commonjs/index.d.ts.map +1 -1
  127. package/node_modules/path-scurry/dist/commonjs/index.js +59 -21
  128. package/node_modules/path-scurry/dist/commonjs/index.js.map +1 -1
  129. package/node_modules/path-scurry/dist/esm/index.d.ts +7 -0
  130. package/node_modules/path-scurry/dist/esm/index.d.ts.map +1 -1
  131. package/node_modules/path-scurry/dist/esm/index.js +42 -14
  132. package/node_modules/path-scurry/dist/esm/index.js.map +1 -1
  133. package/node_modules/path-scurry/package.json +4 -4
  134. package/package.json +2 -1
  135. package/dist/web/assets/Assistant-B3h2yQF3.css +0 -1
  136. package/dist/web/assets/Assistant-Dm_p8EZl.js +0 -1
  137. package/dist/web/assets/Dashboard-fwW9NxcC.js +0 -1
  138. package/dist/web/assets/Files-D-KCDWmO.js +0 -1
  139. package/dist/web/assets/Sessions-BQhGiLvz.js +0 -1
  140. package/dist/web/assets/WorkspaceTree-B9733pV3.js +0 -1
  141. package/dist/web/assets/index-BiiPuwDi.js +0 -66
  142. package/node_modules/minimatch/dist/commonjs/ast.d.ts +0 -22
  143. package/node_modules/minimatch/dist/commonjs/ast.d.ts.map +0 -1
  144. package/node_modules/minimatch/dist/commonjs/ast.js +0 -845
  145. package/node_modules/minimatch/dist/commonjs/ast.js.map +0 -1
  146. package/node_modules/minimatch/dist/commonjs/brace-expressions.d.ts +0 -8
  147. package/node_modules/minimatch/dist/commonjs/brace-expressions.d.ts.map +0 -1
  148. package/node_modules/minimatch/dist/commonjs/brace-expressions.js +0 -150
  149. package/node_modules/minimatch/dist/commonjs/brace-expressions.js.map +0 -1
  150. package/node_modules/minimatch/dist/esm/ast.d.ts +0 -22
  151. package/node_modules/minimatch/dist/esm/ast.d.ts.map +0 -1
  152. package/node_modules/minimatch/dist/esm/ast.js +0 -841
  153. package/node_modules/minimatch/dist/esm/ast.js.map +0 -1
  154. package/node_modules/minimatch/dist/esm/brace-expressions.d.ts +0 -8
  155. package/node_modules/minimatch/dist/esm/brace-expressions.d.ts.map +0 -1
  156. package/node_modules/minimatch/dist/esm/brace-expressions.js +0 -146
  157. package/node_modules/minimatch/dist/esm/brace-expressions.js.map +0 -1
@@ -97,6 +97,18 @@ function modelAccess(profile, key, reasoning = false) {
97
97
  return { models, model };
98
98
  }
99
99
 
100
+ // apps/server/agent-skills.ts
101
+ import { existsSync } from "node:fs";
102
+ import { loadSkillsFromDir } from "@earendil-works/pi-coding-agent";
103
+
104
+ // apps/server/agent-resources.ts
105
+ var agentResourcesPath = "/opt/teammy-resources";
106
+
107
+ // apps/server/agent-skills.ts
108
+ function loadAgentSkills(directory = `${agentResourcesPath}/skills`) {
109
+ return existsSync(directory) ? loadSkillsFromDir({ dir: directory, source: "teammy-deployment" }) : { skills: [], diagnostics: [] };
110
+ }
111
+
100
112
  // apps/server/ai/native-pi-entry.ts
101
113
  var channel = new AgentChannel(process.stdin, process.stdout);
102
114
  var sequence = 0;
@@ -131,9 +143,10 @@ async function run(config) {
131
143
  model.reasoning
132
144
  );
133
145
  modelRuntime.registerNativeProvider(bridge.models.getProvider(model.provider));
146
+ const skills = loadAgentSkills();
134
147
  const loader = {
135
148
  getExtensions: () => ({ extensions: [], errors: [], runtime: createExtensionRuntime() }),
136
- getSkills: () => ({ skills: [], diagnostics: [] }),
149
+ getSkills: () => skills,
137
150
  getPrompts: () => ({ prompts: [], diagnostics: [] }),
138
151
  getThemes: () => ({ themes: [], diagnostics: [] }),
139
152
  getAgentsFiles: () => ({ agentsFiles: [] }),
@@ -1,8 +1,8 @@
1
1
  // apps/server/agents/pi-entry.ts
2
2
  import { spawn } from "node:child_process";
3
- import { existsSync } from "node:fs";
4
- import { mkdir } from "node:fs/promises";
5
- import { join } from "node:path";
3
+ import { existsSync as existsSync2 } from "node:fs";
4
+ import { mkdir, readFile } from "node:fs/promises";
5
+ import { join, basename } from "node:path";
6
6
  import { InMemoryCredentialStore, InMemoryModelsStore, Type as Type2 } from "@earendil-works/pi-ai";
7
7
  import { createAssistantMessageEventStream } from "@earendil-works/pi-ai/utils/event-stream";
8
8
  import {
@@ -91,6 +91,18 @@ function modelAccess(profile, key, reasoning = false) {
91
91
  return { models, model };
92
92
  }
93
93
 
94
+ // apps/server/agent-skills.ts
95
+ import { existsSync } from "node:fs";
96
+ import { loadSkillsFromDir } from "@earendil-works/pi-coding-agent";
97
+
98
+ // apps/server/agent-resources.ts
99
+ var agentResourcesPath = "/opt/teammy-resources";
100
+
101
+ // apps/server/agent-skills.ts
102
+ function loadAgentSkills(directory = `${agentResourcesPath}/skills`) {
103
+ return existsSync(directory) ? loadSkillsFromDir({ dir: directory, source: "teammy-deployment" }) : { skills: [], diagnostics: [] };
104
+ }
105
+
94
106
  // apps/server/agents/pi-entry.ts
95
107
  async function piChild() {
96
108
  const channel = new AgentChannel(process.stdin, process.stdout);
@@ -106,6 +118,7 @@ async function piChild() {
106
118
  };
107
119
  async function open(input) {
108
120
  const key = JSON.stringify([
121
+ input.cwd,
109
122
  input.model,
110
123
  input.compactAt,
111
124
  input.prompt,
@@ -115,7 +128,7 @@ async function piChild() {
115
128
  if (session && key === configKey) return;
116
129
  session?.dispose();
117
130
  await mkdir(input.sessionDir, { recursive: true });
118
- manager = input.sessionFile && existsSync(input.sessionFile) ? SessionManager.open(input.sessionFile, input.sessionDir, "/project") : SessionManager.create("/project", input.sessionDir);
131
+ manager = input.sessionFile && existsSync2(input.sessionFile) ? SessionManager.open(input.sessionFile, input.sessionDir, input.cwd ?? "/project") : SessionManager.create(input.cwd ?? "/project", input.sessionDir);
119
132
  const modelRuntime = await ModelRuntime.create({
120
133
  credentials: new InMemoryCredentialStore(),
121
134
  modelsStore: new InMemoryModelsStore(),
@@ -140,9 +153,10 @@ async function piChild() {
140
153
  getModels: () => [input.model],
141
154
  getAllModels: () => [input.model]
142
155
  });
156
+ const skills = loadAgentSkills();
143
157
  const loader = {
144
158
  getExtensions: () => ({ extensions: [], errors: [], runtime: createExtensionRuntime() }),
145
- getSkills: () => ({ skills: [], diagnostics: [] }),
159
+ getSkills: () => skills,
146
160
  getPrompts: () => ({ prompts: [], diagnostics: [] }),
147
161
  getThemes: () => ({ themes: [], diagnostics: [] }),
148
162
  getAgentsFiles: () => ({ agentsFiles: [] }),
@@ -161,12 +175,28 @@ async function piChild() {
161
175
  description: tool.description,
162
176
  parameters: Type2.Unsafe(tool.schema),
163
177
  execute: async (_id, params) => {
164
- const value = await rpc(tool.name, params);
178
+ let input2 = params;
179
+ if (tool.name === "save_material") {
180
+ const source = params;
181
+ input2 = {
182
+ ...source,
183
+ ...source.contentFile ? { _content: await readFile(source.contentFile, "utf8") } : {},
184
+ ...source.originals ? {
185
+ _files: await Promise.all(
186
+ source.originals.map(async (file) => ({
187
+ name: file.name ?? basename(file.path),
188
+ base64: (await readFile(file.path)).toString("base64")
189
+ }))
190
+ )
191
+ } : {}
192
+ };
193
+ }
194
+ const value = await rpc(tool.name, input2);
165
195
  return { content: [{ type: "text", text: JSON.stringify(value) }], details: value };
166
196
  }
167
197
  }));
168
198
  const created = await createAgentSession({
169
- cwd: "/project",
199
+ cwd: input.cwd ?? "/project",
170
200
  agentDir: join(input.sessionDir, "agent"),
171
201
  modelRuntime,
172
202
  model: input.model,
@@ -178,7 +208,15 @@ async function piChild() {
178
208
  retry: { enabled: false, maxRetries: 0 },
179
209
  cacheWarming: "off"
180
210
  }),
181
- tools: ["read", "bash", "grep", "find", "ls", ...input.tools.map((tool) => tool.name)],
211
+ tools: [
212
+ "read",
213
+ "bash",
214
+ "grep",
215
+ "find",
216
+ "ls",
217
+ ...input.cwd === "/work" ? ["write", "edit"] : [],
218
+ ...input.tools.map((tool) => tool.name)
219
+ ],
182
220
  customTools
183
221
  });
184
222
  session = created.session;
@@ -234,6 +272,7 @@ async function piChild() {
234
272
  return;
235
273
  }
236
274
  const interrupted = markers.some((entry) => entry.runId === input.runId);
275
+ await channel.send({ type: "attempt_start" });
237
276
  state.appendCustomEntry("teammy-run", {
238
277
  runId: input.runId,
239
278
  attempt: input.attempt,
@@ -242,8 +281,9 @@ async function piChild() {
242
281
  let text = "", textStarted = false;
243
282
  const unsubscribe = native.subscribe((event) => {
244
283
  if (event.type === "message_start" && event.message.role === "assistant" && textStarted) {
245
- text += "\n\n";
246
- void channel.send({ type: "delta", text: "\n\n" }).catch(() => {
284
+ text = "";
285
+ textStarted = false;
286
+ void channel.send({ type: "answer_reset" }).catch(() => {
247
287
  });
248
288
  }
249
289
  if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
@@ -256,7 +296,7 @@ async function piChild() {
256
296
  });
257
297
  try {
258
298
  await native.prompt(
259
- interrupted ? `\u6B64\u524D\u8FD9\u4E00\u8F6E\u6267\u884C\u4E2D\u65AD\u6216\u672A\u6210\u529F\uFF0C\u8BF7\u7ED3\u5408\u5DF2\u7ECF\u4FDD\u5B58\u7684\u4E0A\u4E0B\u6587\u7EE7\u7EED\u3002\u4E0D\u8981\u91CD\u590D\u5DF2\u6210\u529F\u7684\u8F93\u51FA\u3002\u539F\u8F93\u5165\uFF1A
299
+ interrupted ? `\u6B64\u524D\u8FD9\u4E00\u8F6E\u6267\u884C\u4E2D\u65AD\u6216\u672A\u6210\u529F\uFF0C\u8BF7\u7ED3\u5408\u5DF2\u4FDD\u5B58\u7684\u4E0A\u4E0B\u6587\u7EE7\u7EED\u3002\u5DF2\u63D0\u4EA4\u64CD\u4F5C\u7684\u56DE\u6267\u4ECD\u6709\u6548\uFF0C\u4E0D\u8981\u91CD\u590D\u53D1\u9001\uFF1B\u6682\u5B58\u56DE\u7B54\u548C\u5B8C\u6210\u62A5\u544A\u5C1A\u672A\u63D0\u4EA4\uFF0C\u8BF7\u91CD\u65B0\u6838\u5BF9\u540E\u7ED9\u51FA\u672C\u8F6E\u7ED3\u8BBA\u3002\u539F\u8F93\u5165\uFF1A
260
300
  ${input.text}` : input.text
261
301
  );
262
302
  await native.waitForIdle();
@@ -42,6 +42,8 @@
42
42
 
43
43
  更新关注任务表达和来源的实质变化,无需为了措辞或附带统计的变化重写任务。
44
44
 
45
+ 已有任务也可能由成员确认创建(origin 为 confirmed),来源中的 material 表示项目资料,不在本轮成员目录内。结合已有任务避免重复;不能因成员文件缺少对应记录而撤下这类任务。人工确认的字段由系统保留,本轮只补充工作区中的实际变化。
46
+
45
47
  ## 分析范围与复核
46
48
 
47
49
  工作区和基线只读,`/tmp` 可用于临时分析。公共资料用于理解约定,本轮只维护指定成员的任务。
@@ -0,0 +1 @@
1
+ import{$ as e,A as t,D as n,J as r,M as i,O as a,S as o,W as ee,a as te,b as s,et as ne,f as c,i as l,k as re,n as u,o as d,q as f,r as ie,t as ae,u as oe,v as p,y as se}from"./index-DQsx-e5d.js";import{t as m}from"./Markdown-BRPMsc7D.js";var h=e(),g=t(),_=e=>new Date(e).toLocaleTimeString([],{hour:`2-digit`,minute:`2-digit`}),v=e=>e.replace(/[#*_`>]/g,``).replace(/\s+/g,` `).trim();function y({mine:e=!1,author:t,time:n,children:r}){return(0,g.jsx)(`div`,{className:`assistant-bubble-row ${e?`mine`:``}`,children:(0,g.jsxs)(`div`,{className:`assistant-bubble`,children:[(0,g.jsxs)(`div`,{className:`assistant-bubble-meta`,children:[(0,g.jsx)(`span`,{children:t}),(0,g.jsx)(`time`,{dateTime:n,children:_(n)})]}),r]})})}function b({me:e}){let{projectId:t,request:b}=oe(),S=re(),C=a(t,e,`assistant-selection`),w=a(t,e,`assistant-drafts`),ce=(0,h.useCallback)(e=>b(`agents/outbox`,te,{signal:e}),[b]),T=n(ce,3e3,a(t,e,`outbox`)),le=(0,h.useCallback)(e=>b(`agents/chats`,ae,{signal:e}),[b]),E=n(le,3e3,a(t,e,`chats`)),[D,ue]=(0,h.useState)(()=>{let e=new URLSearchParams(location.search),t=e.get(`chat`);return t?`chat:${t}`:e.get(`message`)??S?.get(C)??``}),O=D.startsWith(`chat:`)?D.slice(5):``,k=!D||!!O,[A,j]=(0,h.useState)(()=>S?.get(a(t,e,`chat`,O))),M=A?.id===O?A:S?.get(a(t,e,`chat`,O)),de=E.data?.chats.find(e=>e.id===O),[fe,N]=(0,h.useState)(),[P,F]=(0,h.useState)(()=>S?.get(w)??{}),I=P[D]??``,L=e=>F(t=>({...t,[D]:e})),[R,z]=(0,h.useState)(!1),[B,V]=(0,h.useState)(!1),[pe,H]=(0,h.useState)(``),[U,W]=(0,h.useState)(``),G=(0,h.useRef)(new Map),K=(0,h.useRef)(null),q=(0,h.useRef)(!0),J=(0,h.useRef)(D);J.current=D,(0,h.useEffect)(()=>{A&&S?.set(a(t,e,`chat`,A.id),A)},[S,t,e,A]),(0,h.useEffect)(()=>{S?.set(w,P)},[S,w,P]);function Y(e){J.current=e,ue(e),S?.set(C,e);let t=new URL(location.href);e.startsWith(`chat:`)?t.searchParams.set(`chat`,e.slice(5)):t.searchParams.delete(`chat`),e&&!e.startsWith(`chat:`)&&e!==`debug`?t.searchParams.set(`message`,e):t.searchParams.delete(`message`),history.replaceState(history.state,``,t)}(0,h.useEffect)(()=>{!D&&E.data?.chats.length&&Y(`chat:${E.data.chats[0].id}`)},[D,E.data]);let X=(T.data?.messages??[]).filter(e=>e.box===`debug`).reverse(),Z=T.data?.messages.find(e=>e.id===(D===`debug`?fe:D));(0,h.useEffect)(()=>{D!==`debug`&&Z?.conversationId&&Y(`chat:${Z.conversationId}`)},[D,Z?.conversationId]);let Q=X.filter(e=>!e.readAt).map(e=>e.id).join(`,`);(0,h.useEffect)(()=>{Z&&!Z.readAt&&D!==`debug`&&b(`agents/outbox/${Z.id}/read`,d,{method:`POST`}).then(()=>{window.dispatchEvent(new Event(`teammy:outbox`)),T.reload()}).catch(e=>H(i(e)))},[Z?.id,Z?.readAt,D,b,T.reload]),(0,h.useEffect)(()=>{D===`debug`&&Q&&Promise.all(Q.split(`,`).map(e=>b(`agents/outbox/${e}/read`,d,{method:`POST`}))).then(()=>{window.dispatchEvent(new Event(`teammy:outbox`)),T.reload()}).catch(e=>H(i(e)))},[D,Q,b,T.reload]),(0,h.useEffect)(()=>{if(W(``),!O)return;let e=!0,n=new EventSource(ne(`/api/v1/projects/${encodeURIComponent(t)}/agents/chats/${encodeURIComponent(O)}/events`));n.addEventListener(`snapshot`,t=>{if(e)try{let e=u.parse(JSON.parse(t.data));if(e.redirect){Y(`chat:${e.redirect}`);return}j(e),W(``)}catch(e){W(i(e))}}),n.onerror=()=>{e&&W(`对话连接中断,正在重新连接…`)},n.addEventListener(`context`,t=>{if(!e)return;let n=u.pick({kind:!0,title:!0,status:!0,visibility:!0,participants:!0,pending:!0,hold:!0,redirect:!0}).parse(JSON.parse(t.data));n.redirect?Y(`chat:${n.redirect}`):j(e=>e?.id===O?{...e,...n}:e)}),n.addEventListener(`message`,t=>{if(!e)return;let n=ie.parse(JSON.parse(t.data));j(e=>e&&{...e,readCursor:Math.max(e.readCursor,n.seq),cursor:Math.max(e.cursor,Number(t.lastEventId)||0),messages:[...e.messages.filter(e=>e.id!==n.id),n].sort((e,t)=>e.seq-t.seq)})}),n.addEventListener(`message_removed`,t=>{if(!e)return;let{id:n}=f({id:r()}).parse(JSON.parse(t.data));j(e=>e?.id===O?{...e,messages:e.messages.filter(e=>e.id!==n)}:e)}),n.addEventListener(`run`,t=>{if(!e)return;let n=l.parse(JSON.parse(t.data));j(e=>e&&{...e,cursor:Math.max(e.cursor,Number(t.lastEventId)||0),runs:e.runs.some(e=>e.id===n.id)?e.runs:[...e.runs,n]})});for(let t of[`delta`,`reset`,`state`])n.addEventListener(t,n=>{if(!e)return;let r=JSON.parse(n.data);j(e=>e&&{...e,cursor:Math.max(e.cursor,Number(n.lastEventId)||0),messages:e.messages.map(e=>e.runId!==r.id||e.role!==`assistant`?e:{...e,body:t===`delta`?e.body+(r.text??``):t===`reset`?``:r.answer??e.body,state:r.state??e.state}),runs:e.runs.map(e=>e.id===r.id?{...e,answer:t===`delta`?e.answer+(r.text??``):t===`reset`?``:r.answer??e.answer,state:r.state??e.state,error:r.error===void 0?e.error:r.error}:e)})});return()=>{e=!1,n.close()}},[t,O]),(0,h.useEffect)(()=>{if(!M?.kind||M.id!==O)return;let e=()=>{document.visibilityState===`visible`&&b(`agents/chats/${O}/read`,f({ok:ee()}),{method:`POST`,body:{cursor:M.readCursor}}).then(()=>{E.reload(),window.dispatchEvent(new Event(`teammy:outbox`))}).catch(e=>H(i(e)))},t=setTimeout(e,300);return document.addEventListener(`visibilitychange`,e),()=>{clearTimeout(t),document.removeEventListener(`visibilitychange`,e)}},[O,M?.readCursor,M?.kind,b]),(0,h.useEffect)(()=>{q.current&&K.current?.scrollIntoView({block:`end`})},[D,A?.messages,Z?.recipients,X.length]);function me(){window.dispatchEvent(new Event(`teammy:outbox`)),T.reload()}async function $(e){if(q.current=!0,Y(e),H(``),N(void 0),e.startsWith(`chat:`)||e===`debug`)return;let t=T.data?.messages.find(t=>t.id===e)?.conversationId;if(t)Y(`chat:${t}`);else try{await b(`agents/outbox/${e}/read`,d,{method:`POST`}),me()}catch(e){H(i(e))}}async function he(){if(!B){V(!0),H(``);try{let e=await b(`agents/chats`,u,{method:`POST`});j(e),await $(`chat:${e.id}`),E.reload()}catch(e){H(i(e))}finally{V(!1)}}}async function ge(e){e.preventDefault();let t=I.trim();if(!t||R||B)return;z(!0),H(``);let n=G.current.get(D);n&&n.text===t||(n={text:t,id:crypto.randomUUID()},G.current.set(D,n));try{if(k){let e=n.target??O;if(!e){let r=await b(`agents/chats`,u,{method:`POST`});e=r.id,n.target=e,G.current.set(`chat:${e}`,n),F(n=>({...n,[`chat:${e}`]:t})),J.current===D&&(j(r),Y(`chat:${e}`))}let i=await b(`agents/chats/${e}`,l.extend({conversationId:r().optional()}),{method:`POST`,body:{text:t,requestId:n.id}});i.conversationId&&i.conversationId!==e&&(J.current===D||J.current===`chat:${e}`)&&Y(`chat:${i.conversationId}`),j(t=>t?.id===e?{...t,runs:t.runs.some(e=>e.id===i.id)?t.runs:[...t.runs,i]}:t),E.reload()}else{let e=await b(`agents/outbox/${Z.id}/reply`,f({conversationId:r()}),{method:`POST`,body:{body:t,requestId:n.id}});me(),J.current===D&&Y(`chat:${e.conversationId}`),E.reload(),N(void 0)}G.current.delete(D),n.target&&G.current.delete(`chat:${n.target}`),F(e=>({...e,[D]:``,...n.target?{[`chat:${n.target}`]:``}:{}}))}catch(e){H(i(e))}finally{z(!1)}}let _e=k||!!Z&&!Z.archivedAt,ve=k&&!M&&(!!O||!E.data);return(0,g.jsxs)(`div`,{className:`split-layout assistant-layout`,"data-testid":`assistant-page`,children:[(0,g.jsxs)(`aside`,{className:`assistant-list`,"aria-label":`消息列表`,children:[(0,g.jsxs)(`header`,{className:`assistant-list-heading`,children:[(0,g.jsx)(`h1`,{children:`消息`}),(0,g.jsx)(se,{className:`assistant-new-chat`,icon:`plus`,label:`新建对话`,disabled:B,onClick:()=>void he(),"data-testid":`assistant-launcher`})]}),(0,g.jsxs)(`div`,{className:`assistant-message-scroll`,children:[E.loading&&!E.data&&(0,g.jsx)(`p`,{className:`assistant-list-status`,role:`status`,children:`加载中…`}),E.data?.chats.map(e=>(0,g.jsxs)(`button`,{type:`button`,"data-testid":`assistant-chat-${e.id}`,className:`assistant-message-item assistant-chat-item ${O===e.id?`selected`:``}`,"aria-pressed":O===e.id,onClick:()=>void $(`chat:${e.id}`),children:[(0,g.jsx)(`span`,{className:`assistant-message-dot ${e.unread||e.state===`running`||e.state===`queued`?`unread`:``}`}),(0,g.jsxs)(`span`,{className:`assistant-message-copy`,children:[(0,g.jsx)(c,{selected:O===e.id,children:(0,g.jsx)(`strong`,{children:e.title})}),(0,g.jsxs)(`time`,{dateTime:e.updatedAt,children:[new Date(e.updatedAt).toLocaleDateString([],{month:`numeric`,day:`numeric`}),` `,_(e.updatedAt)]})]})]},e.id)),!!X.length&&(0,g.jsxs)(`button`,{type:`button`,"data-testid":`debug-outbox`,className:`assistant-message-item ${D===`debug`?`selected`:``}`,onClick:()=>void $(`debug`),children:[(0,g.jsx)(`span`,{className:`assistant-message-dot ${Q?`unread`:``}`}),(0,g.jsxs)(`span`,{className:`assistant-message-copy`,children:[(0,g.jsx)(c,{selected:D===`debug`,children:(0,g.jsx)(`strong`,{children:`运行提醒`})}),(0,g.jsx)(`span`,{children:v(X.at(-1).body)})]})]}),T.data?.messages.filter(e=>e.box!==`debug`&&!e.conversationId).sort((e,t)=>Number(!!e.archivedAt)-Number(!!t.archivedAt)).map(e=>(0,g.jsxs)(`button`,{type:`button`,"data-testid":`outbox-${e.id}`,className:`assistant-message-item ${e.archivedAt?`archived`:``} ${D===e.id?`selected`:``}`,onClick:()=>void $(e.id),children:[(0,g.jsx)(`span`,{className:`assistant-message-dot ${e.readAt?``:`unread`}`}),(0,g.jsxs)(`span`,{className:`assistant-message-copy`,children:[(0,g.jsx)(c,{selected:D===e.id,children:(0,g.jsx)(`strong`,{children:v(e.body)})}),(0,g.jsxs)(`time`,{dateTime:e.createdAt,children:[new Date(e.createdAt).toLocaleDateString([],{month:`numeric`,day:`numeric`}),` `,_(e.createdAt)]})]})]},e.id))]}),(0,g.jsx)(o,{error:!0,children:T.error||E.error})]}),(0,g.jsxs)(`section`,{className:`assistant-thread`,"aria-label":k?`Tim对话`:`消息内容`,children:[(0,g.jsxs)(`header`,{className:`assistant-thread-heading`,children:[(0,g.jsx)(`h2`,{children:k?de?.title??M?.title??(O?`无标题`:`Tim`):D===`debug`?`运行提醒`:`项目消息`}),M?.kind===`matter`&&(0,g.jsxs)(`span`,{className:`assistant-participants`,title:M.participants?.join(`、`),children:[M.visibility===`project`?`项目共享 · `:``,M.participants?.join(`、`)]})]}),M?.kind===`matter`&&(M.hold||M.pending||M.status===`completed`)&&(0,g.jsx)(`div`,{className:`assistant-matter-state`,role:`status`,children:M.hold?`${M.hold.scope===`all`?`已暂停`:`暂缓修改`} · ${M.hold.reason}`:M.pending?`待确认 · ${M.pending.members.join(`、`)}:${M.pending.question}`:`已完成`}),(0,g.jsxs)(`div`,{className:`assistant-transcript`,role:`log`,"aria-live":`polite`,"data-testid":`assistant-transcript`,onScroll:e=>{let t=e.currentTarget;q.current=t.scrollHeight-t.scrollTop-t.clientHeight<100},children:[k?ve?(0,g.jsxs)(`div`,{className:`assistant-empty`,"data-testid":`assistant-loading`,children:[(0,g.jsx)(s,{}),(0,g.jsx)(`p`,{role:`status`,children:U||E.error?`暂时无法加载对话`:`加载中…`})]}):M?.messages.length?M.messages.filter(e=>e.body||[`queued`,`running`,`failed`].includes(e.state)).map(t=>(0,g.jsx)(`div`,{className:`assistant-turn`,children:(0,g.jsxs)(y,{mine:t.role===`user`&&t.author===e,author:`${t.role===`assistant`?`Tim`:t.author}${t.source===`wecom`?` · 企业微信`:``}`,time:t.createdAt,children:[t.body&&(0,g.jsx)(`div`,{className:`markdown`,children:(0,g.jsx)(m,{children:t.body})}),t.role===`assistant`&&[`queued`,`running`].includes(t.state)&&(0,g.jsxs)(`span`,{className:`assistant-typing`,"aria-label":`正在回答`,children:[(0,g.jsx)(`i`,{}),(0,g.jsx)(`i`,{}),(0,g.jsx)(`i`,{})]}),t.state===`failed`&&(0,g.jsx)(o,{error:!0,children:M.runs.find(e=>e.id===t.runId)?.error||`本次回答未完成。`})]})},t.id)):(0,g.jsxs)(`div`,{className:`assistant-empty`,children:[(0,g.jsx)(s,{}),(0,g.jsx)(`p`,{children:`有什么项目问题想聊聊?`})]}):!T.data&&T.loading?(0,g.jsx)(`div`,{className:`assistant-empty`,children:(0,g.jsx)(`p`,{role:`status`,children:`加载中…`})}):D===`debug`?X.map(e=>(0,g.jsx)(x,{item:e,onReply:e.archivedAt?void 0:()=>{N(e.id),L(``),H(``)}},e.id)):Z&&(0,g.jsx)(x,{item:Z}),(0,g.jsx)(`div`,{ref:K})]}),(0,g.jsx)(o,{error:!0,children:pe||(k?U:``)}),_e?(0,g.jsxs)(`form`,{className:`assistant-composer`,onSubmit:e=>void ge(e),children:[(0,g.jsx)(`textarea`,{value:I,disabled:B,onChange:e=>L(e.target.value),"aria-label":k?`向Tim提问`:`回复消息`,placeholder:k?`问问Tim…`:`回复…`,rows:2,onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&!e.nativeEvent.isComposing&&(e.preventDefault(),e.currentTarget.form?.requestSubmit())}}),(0,g.jsx)(`button`,{className:`primary assistant-send`,type:`submit`,disabled:R||B||ve||!I.trim(),"aria-label":`发送`,children:(0,g.jsx)(p,{name:`send`})})]}):D!==`debug`&&Z&&(0,g.jsxs)(`div`,{className:`assistant-archived`,children:[(0,g.jsx)(p,{name:`archive`}),`已归档`]})]})]})}function x({item:e,onReply:t}){return(0,g.jsx)(`div`,{"data-testid":`outbox-thread-${e.id}`,children:(0,g.jsxs)(y,{author:e.box===`debug`?`运行提醒`:`Tim`,time:e.createdAt,children:[(0,g.jsx)(`div`,{className:`markdown`,children:(0,g.jsx)(m,{children:e.body})}),t&&(0,g.jsx)(`button`,{type:`button`,className:`assistant-debug-reply`,onClick:t,children:`回复`})]})})}export{b as Assistant};
@@ -0,0 +1 @@
1
+ main#main[data-page=assistant]{height:100dvh;padding:0}.assistant-layout{grid-template-columns:var(--pane-width) minmax(0, 1fr);height:100%;min-height:0}.assistant-list{border-right:1px solid var(--color-line);background:var(--color-surface);flex-direction:column;min-height:0;display:flex}.assistant-list-heading,.assistant-thread-heading{border-bottom:1px solid var(--color-line);flex:0 0 76px;justify-content:space-between;align-items:center;padding:0 24px;display:flex}.assistant-list-heading h1{margin:0;font-size:20px}.assistant-thread-heading h2{text-overflow:ellipsis;white-space:nowrap;margin:0;font-size:17px;overflow:hidden}.assistant-message-scroll{flex:1;min-height:0;overflow-y:auto}.assistant-list-status{color:var(--color-muted);font-size:var(--text-sm);margin:20px 24px}.assistant-message-item{border:0;border-bottom:1px solid var(--color-line);text-align:left;width:100%;color:var(--color-text);background:0 0;border-radius:0;align-items:center;gap:12px;padding:20px 24px;display:flex}.assistant-message-item:hover{background:var(--color-hover)}.assistant-message-item.selected{background:var(--color-soft)}.assistant-message-item.archived{color:var(--color-muted)}.assistant-message-item.archived strong{font-weight:400}.assistant-new-chat{width:32px;height:32px;min-height:32px;color:var(--brand-orange);background:var(--color-accent-soft);padding:6px}.assistant-new-chat .icon{width:20px;height:20px}.assistant-new-chat:after{top:calc(100% + 6px);bottom:auto}.assistant-message-copy{flex-direction:column;flex:1;gap:6px;min-width:0;display:flex}.assistant-message-copy>.selection-content{width:fit-content;max-width:100%;color:var(--color-text);margin:-5px -8px;padding:5px 8px;display:block;overflow:visible}.assistant-message-item.archived .selection-content{color:inherit}.assistant-message-copy .selection-inner{min-width:0;display:block}.assistant-message-copy .selection-inner strong{display:block}.assistant-message-copy strong,.assistant-message-copy>span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.assistant-message-copy strong{font-size:var(--text-base);font-weight:600}.assistant-message-copy>span,.assistant-message-copy time{font-size:var(--text-xs);color:var(--color-muted)}.assistant-message-dot{border-radius:50%;flex:0 0 7px;width:7px;height:7px}.assistant-message-dot.unread{background:var(--brand-orange)}.assistant-thread{background:var(--color-canvas);flex-direction:column;min-width:0;min-height:0;display:flex}.assistant-transcript{flex:1;min-height:0;padding:28px clamp(20px,4vw,64px);overflow-y:auto}.assistant-matter-state{border-bottom:1px solid var(--color-line);color:var(--color-muted);font-size:var(--text-xs);overflow-wrap:anywhere;padding:10px 28px;line-height:1.6}.assistant-bubble-row{margin:0 0 24px;display:flex}.assistant-bubble-row.mine{justify-content:flex-end}.assistant-bubble{border-radius:4px var(--radius-lg) var(--radius-lg);background:var(--color-soft);overflow-wrap:anywhere;min-width:100px;max-width:min(88%,800px);padding:14px 18px}.assistant-bubble-row.mine .assistant-bubble{background:var(--color-accent-soft);border-radius:var(--radius-lg) 4px var(--radius-lg) var(--radius-lg)}.assistant-bubble-meta{font-size:var(--text-xs);color:var(--color-muted);align-items:baseline;gap:16px;margin-bottom:8px;display:flex}.assistant-debug-reply{font-size:var(--text-xs);background:var(--color-surface);margin-top:12px;padding:4px 10px}.assistant-bubble .markdown>:first-child{margin-top:0}.assistant-bubble .markdown>:last-child{margin-bottom:0}.assistant-bubble .markdown{font-size:var(--text-base);line-height:1.75}.assistant-bubble .markdown h1,.assistant-bubble .markdown h2{font-size:18px}.assistant-bubble .markdown h3,.assistant-bubble .markdown h4,.assistant-bubble .markdown h5,.assistant-bubble .markdown h6{font-size:var(--text-base)}.assistant-bubble .markdown :is(h1,h2,h3,h4,h5,h6){margin:18px 0 8px;line-height:1.5}.assistant-bubble .markdown :is(p,ul,ol){margin:10px 0}.assistant-bubble .markdown :is(ul,ol){padding-left:1.5em}.assistant-bubble .markdown li+li{margin-top:4px}.assistant-bubble .markdown li>:is(ul,ol){margin:4px 0}.assistant-bubble pre{max-width:100%;overflow-x:auto}.assistant-composer{background:var(--color-surface);border:1px solid var(--color-line);border-radius:var(--radius-lg);align-items:flex-end;gap:12px;margin:0 28px 28px;padding:12px;display:flex}.assistant-reply-hint{font-size:var(--text-xs);color:var(--color-muted);margin:0 28px 10px;line-height:1.7}.assistant-composer:focus-within{border-color:var(--color-muted)}.assistant-composer textarea{box-shadow:none;resize:vertical;background:0 0;border:0;flex:1;min-height:56px;max-height:220px;padding:8px}.assistant-composer textarea:focus{box-shadow:none;outline:none}.assistant-send{flex:0 0 40px;place-items:center;width:40px;height:40px;padding:0;display:grid}.assistant-empty{height:100%;min-height:240px;color:var(--color-muted);flex-direction:column;justify-content:center;align-items:center;gap:20px;display:flex}.assistant-empty .mascot{width:96px;height:144px}.assistant-empty p{margin:0}.assistant-archived{color:var(--color-muted);font-size:var(--text-sm);justify-content:center;align-items:center;gap:8px;padding:24px;display:flex}.assistant-thread>.notice{margin:0 28px 12px}.assistant-typing{gap:5px;padding:8px 0;display:inline-flex}.assistant-typing i{background:var(--color-muted);border-radius:50%;width:5px;height:5px;animation:1.4s infinite assistant-pulse}.assistant-typing i:nth-child(2){animation-delay:.15s}.assistant-typing i:nth-child(3){animation-delay:.3s}@keyframes assistant-pulse{0%,70%,to{opacity:.35}35%{opacity:1}}@media (prefers-reduced-motion:reduce){.assistant-typing i{animation:none}}@media (width<=900px){.assistant-layout{grid-template-columns:240px minmax(0,1fr)}.assistant-message-item{padding:16px}.assistant-composer{margin:0 16px 16px}.assistant-reply-hint{margin:0 16px 10px}.assistant-bubble{max-width:96%}}@media (width<=600px){.assistant-layout{grid-template-columns:150px minmax(0,1fr)}.assistant-list-heading,.assistant-thread-heading{padding:0 12px}.assistant-transcript{padding:16px 10px}.assistant-composer{gap:4px;margin:0 8px 12px;padding:6px}.assistant-reply-hint{margin:0 8px 10px}}.assistant-participants{text-overflow:ellipsis;white-space:nowrap;min-width:0;max-width:45%;color:var(--color-muted);font-size:var(--text-sm);margin-left:16px;overflow:hidden}
@@ -0,0 +1 @@
1
+ import{$ as e,A as t,C as n,D as r,E as i,M as a,O as o,S as s,T as c,_ as l,et as u,h as d,m as f,p,u as m,v as h,x as g,y as _}from"./index-DQsx-e5d.js";import{t as v}from"./project-links-XbF78Bal.js";import"./file-links-I1K8CwVK.js";var y=e(),b=t(),x=[{status:`planned`,label:`计划`},{status:`in_progress`,label:`进行中`},{status:`in_review`,label:`待验收`},{status:`completed`,label:`已完成`},{status:null,label:`未明确`}];function S({members:e,project:t}){let{request:i,projectId:a}=m(),c=(0,y.useCallback)(e=>i(`tasks`,p,{signal:e}),[i]),l=r(c,3e3,o(a,`tasks`)),[u,f]=(0,y.useState)(),h=l.data,g=new Map(e.map(e=>[e.id,e.displayName||e.id]));return(0,b.jsxs)(`div`,{className:`task-board`,children:[(0,b.jsx)(n,{title:t?.projectName.trim()?`${t.projectName.trim()}|工作看板`:`工作看板`,description:t?.description.trim()||``}),(0,b.jsx)(s,{error:!0,children:l.error}),(0,b.jsx)(`section`,{className:`task-board-lanes`,"aria-label":`任务进度`,"data-testid":`progress-board`,children:x.filter(e=>e.status!==null||h?.tasks.some(e=>e.status===null)).map(e=>{let t=h?.tasks.filter(t=>t.status===e.status)??[];return(0,b.jsxs)(`section`,{className:`task-lane`,"aria-label":e.label,"data-stage":e.status??`unknown`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`span`,{className:`lane-dot`}),e.label,(0,b.jsx)(d,{children:h?t.length:`—`})]}),(0,b.jsx)(`div`,{className:`task-lane-content`,children:t.length?t.map(e=>(0,b.jsx)(C,{task:e,names:g,onEdit:()=>f(e),onSaved:()=>void l.reload()},e.id)):(0,b.jsx)(`p`,{className:`task-lane-empty`,children:l.error&&!h?`读取失败`:h?`暂无任务`:`读取中…`})})]},e.label)})}),u&&(0,b.jsx)(T,{task:u,onClose:()=>f(void 0),onSaved:()=>{f(void 0),l.reload()}},u.id)]})}function C({task:e,names:t,onEdit:n,onSaved:r}){let{projectId:o,request:l}=m(),d=i(),[p,g]=(0,y.useState)(!1),[x,S]=(0,y.useState)(``);async function C(){if(!p){g(!0),S(``);try{await l(`tasks/${e.id}/correction`,f,{method:`PATCH`,signal:d,body:{needsConfirmation:!1,expectedRevision:e.revision}}),d.aborted||r()}catch(e){d.aborted||S(a(e))}finally{g(!1)}}}return(0,b.jsxs)(`details`,{className:`task-card`,"data-testid":`task-card`,"data-task-id":e.id,"data-owner":e.owner,"data-status":e.status??`unknown`,children:[(0,b.jsxs)(`summary`,{className:`task-card-heading`,"data-testid":`task-toggle`,children:[(0,b.jsx)(`h3`,{children:e.title}),(0,b.jsxs)(`span`,{className:`task-card-meta`,children:[(0,b.jsx)(`small`,{children:t.get(e.owner)??e.owner}),e.needsConfirmation&&(0,b.jsxs)(`span`,{className:`task-confirmation`,"data-testid":`task-confirmation`,children:[(0,b.jsx)(h,{name:`attention`,size:`small`}),`需要确认`]})]})]}),(0,b.jsx)(_,{icon:`edit`,className:`task-card-edit`,label:`纠正任务:${e.title}`,"data-testid":`task-correct`,disabled:p,onClick:n}),(0,b.jsxs)(`div`,{className:`task-card-details`,children:[e.corrected&&!e.needsConfirmation&&(0,b.jsx)(`small`,{children:`已确认`}),e.needsReview&&(0,b.jsx)(`p`,{children:`本次整理未能明确对应,请核对来源。`}),(0,b.jsx)(`h4`,{children:`目标`}),(0,b.jsx)(`p`,{children:e.goal?(0,b.jsx)(w,{value:e.goal,names:t}):`目标未明确`}),(0,b.jsx)(`h4`,{children:`当前进展`}),(0,b.jsx)(`p`,{className:`task-progress`,children:(0,b.jsx)(w,{value:e.progress,names:t})}),(0,b.jsx)(`div`,{className:`task-card-sources`,children:e.sources.map(t=>(0,b.jsxs)(`a`,{"data-testid":`task-source`,href:u(t.kind===`material`?`/projects/${o}/materials?id=${t.materialId}&revision=${t.revision}`:v(o,e.owner,t.path)),children:[(0,b.jsx)(h,{name:`file`,size:`small`}),(0,b.jsx)(`span`,{children:t.path})]},t.path))}),e.syncedAt&&(0,b.jsxs)(`small`,{children:[`资料同步于 `,(0,b.jsx)(c,{value:e.syncedAt})]}),e.needsConfirmation&&(0,b.jsxs)(`div`,{className:`task-card-confirm`,children:[(0,b.jsx)(s,{error:!0,children:x}),(0,b.jsx)(`button`,{className:`primary`,"data-testid":`task-confirm-save`,disabled:p,onClick:()=>void C(),children:p?`正在保存…`:`保存`})]})]})]})}function w({value:e,names:t}){return e.split(/(@[a-z][a-z0-9_-]*)/gi).map((e,n)=>e.startsWith(`@`)&&t.has(e.slice(1))?(0,b.jsx)(`mark`,{className:`task-mention`,children:e},n):e)}function T({task:e,onClose:t,onSaved:n}){let{request:r}=m(),o=i(),[c,u]=(0,y.useState)(e.title),[d,p]=(0,y.useState)(e.status??``),[h,_]=(0,y.useState)(e.goal??``),[v,S]=(0,y.useState)(e.progress),[C,w]=(0,y.useState)(!1),[T,E]=(0,y.useState)(``),D={...c===e.title?{}:{title:c},...d===(e.status??``)?{}:{status:d||null},...h===(e.goal??``)?{}:{goal:h||null},...v===e.progress?{}:{progress:v},...e.needsConfirmation?{needsConfirmation:!1}:{}};async function O(t=!1){if(!(C||!t&&!Object.keys(D).length)){w(!0),E(``);try{await r(`tasks/${e.id}/correction`,f,{method:t?`DELETE`:`PATCH`,signal:o,...t?{}:{body:{...D,expectedRevision:e.revision}}}),o.aborted||n()}catch(e){o.aborted||E(a(e))}finally{w(!1)}}}return(0,b.jsx)(g,{id:`task-correction`,title:`纠正任务`,onClose:t,children:(0,b.jsxs)(`form`,{className:`stack`,"aria-busy":C,onSubmit:e=>{e.preventDefault(),O()},children:[(0,b.jsx)(l,{id:`task-title`,label:`标题`,children:(0,b.jsx)(`input`,{value:c,required:!0,onChange:e=>u(e.target.value)})}),(0,b.jsxs)(`fieldset`,{className:`task-status-field`,disabled:C,children:[(0,b.jsx)(`legend`,{children:`状态`}),(0,b.jsx)(`div`,{className:`task-status-options`,"data-testid":`task-status`,children:x.filter(e=>e.status!==null).map(e=>(0,b.jsxs)(`label`,{className:`task-status-choice`,children:[(0,b.jsx)(`input`,{type:`radio`,name:`task-status`,value:e.status,checked:d===e.status,onChange:()=>p(e.status)}),(0,b.jsx)(`span`,{children:e.label})]},e.status))})]}),(0,b.jsx)(l,{id:`task-goal`,label:`目标`,children:(0,b.jsx)(`textarea`,{value:h,onChange:e=>_(e.target.value)})}),(0,b.jsx)(l,{id:`task-progress`,label:`当前进展`,children:(0,b.jsx)(`textarea`,{value:v,onChange:e=>S(e.target.value)})}),(0,b.jsx)(s,{error:!0,children:T}),(0,b.jsxs)(`div`,{className:`row wrap`,children:[(0,b.jsx)(`button`,{type:`submit`,className:`primary`,disabled:C||!Object.keys(D).length,"data-testid":`task-correction-save`,children:`保存`}),e.corrected&&e.jobId&&(0,b.jsx)(`button`,{type:`button`,disabled:C,"data-testid":`task-correction-reset`,onClick:()=>void O(!0),children:`恢复自动结果`})]})]})})}function E({members:e,config:t}){return(0,b.jsx)(S,{members:e,project:t})}export{E as Dashboard};
@@ -0,0 +1 @@
1
+ import{$ as e,A as t,D as n,F as r,L as i,O as a,S as o,c as s,et as c,g as l,j as u,l as d,s as f,u as p,v as m,w as h,y as g}from"./index-DQsx-e5d.js";import{t as _}from"./Markdown-BRPMsc7D.js";import{t as v}from"./project-links-XbF78Bal.js";import{t as y}from"./file-links-I1K8CwVK.js";import{n as b,t as x}from"./WorkspaceTree-fMDtGIFa.js";var S=e(),C=t();function w(e,t){let n=t.split(`/`).slice(0,-1);return n.map((t,r)=>b(e,n.slice(0,r+1).join(`/`))).concat(b(e,``))}function T({members:e,me:t,onRefresh:a}){let{api:m,projectId:h}=p(),[_,T]=(0,S.useState)(()=>{let t=new URLSearchParams(location.search),n=t.get(`owner`),r=i.safeParse(t.get(`path`));return n&&(n===`_project`||e.some(e=>e.id===n))&&r.success&&!s(r.data)?{owner:n,path:r.data}:void 0}),[D,O]=(0,S.useState)(()=>new Set(_?w(_.owner,_.path):[b(t,``)])),[k,A]=(0,S.useState)(()=>_?{..._,kind:`file`}:void 0),[j,M]=(0,S.useState)(0),[N,P]=(0,S.useState)(()=>{let e=new URLSearchParams(location.search);return!_&&(e.has(`owner`)||e.has(`path`))?`文件链接不完整或目标已不可用。`:``}),F=(0,S.useCallback)(async e=>{if(_)try{return{owner:_.owner,...await m.file(_.owner,_.path,void 0,e)}}catch(e){throw e instanceof u&&e.code===`FILE_NOT_FOUND`?Error(`找不到这个文件,可能已被删除或移动。`):e}},[_?.owner,_?.path,j]),I=n(F),L=I.data?.owner===_?.owner&&I.data?.file.path===_?.path?I.data:void 0;function R(e,t){let n=t.split(`/`).filter(Boolean);O(t=>{let r=new Set(t);for(let t=0;t<=n.length;t++)r.add(b(e,n.slice(0,t).join(`/`)));return r})}function z(e,t){P(``),R(e,t.split(`/`).slice(0,-1).join(`/`)),T({owner:e,path:t}),A({owner:e,path:t,kind:`file`}),history.replaceState(null,``,c(v(h,e,t)))}function B(t){if(!_)return!1;let n=y(_.owner===`_project`?_.path:`${_.owner}/${_.path}`,t);if(!n)return!/^[a-z][a-z0-9+.-]*:/i.test(t)&&!t.startsWith(`//`)&&(P(`该链接超出工作区,请在原仓库查看。`),!0);if(s(n.path))return P(`配置文件不在文件浏览中显示。`),!0;let[r,...i]=n.path.split(`/`),a=e.some(e=>e.id===r),o=a?r:f,c=a?i.join(`/`):n.path;return P(``),n.directory?(R(o,c),A({owner:o,path:c,kind:`directory`})):o===_.owner&&c===_.path?n.anchor&&[...document.querySelectorAll(`.markdown h1,.markdown h2,.markdown h3,.markdown h4`)].find(e=>e.textContent?.trim().toLowerCase().replace(/\s+/g,`-`)===n.anchor.toLowerCase())?.scrollIntoView({block:`center`}):z(o,c),!0}return(0,C.jsxs)(`div`,{className:`split-layout file-explorer`,"data-testid":`file-browser`,children:[(0,C.jsxs)(`aside`,{className:`file-tree-pane`,"aria-label":`文件资源管理器`,children:[(0,C.jsx)(d,{title:`工作区`,icon:`files`,children:(0,C.jsx)(g,{icon:`refresh`,label:`刷新文件`,"data-testid":`files-refresh`,onClick:()=>{P(``),M(e=>e+1),a()}})}),(0,C.jsx)(x,{members:e,expanded:D,selected:k,revealed:!I.loading&&!I.error&&L?{owner:L.owner,path:L.file.path,file:L.file}:void 0,onSelect:z,onToggle:(e,t)=>{A({owner:e,path:t,kind:`directory`}),O(n=>{let r=new Set(n),i=b(e,t);return r.has(i)?r.delete(i):r.add(i),r})}},j)]}),(0,C.jsx)(`section`,{className:`file-detail`,"data-testid":`file-preview`,"data-owner-id":_?.owner,"data-file-path":_?.path,"aria-label":r.filePreview,children:_?(0,C.jsxs)(C.Fragment,{children:[(0,C.jsx)(o,{error:!0,children:N||!I.loading&&I.error}),I.error&&(0,C.jsx)(`button`,{className:`file-entry-retry`,"data-testid":`files-retry`,onClick:()=>void I.reload(),children:r.retry}),I.loading?(0,C.jsx)(`p`,{className:`preview-body`,role:`status`,children:r.loading}):!I.error&&L&&(0,C.jsx)(E,{owner:L.owner,file:L.file,onLink:B},`${L.owner}:${L.file.path}:${L.file.sha256}`)]}):N?(0,C.jsx)(o,{error:!0,children:N}):(0,C.jsx)(l,{mascot:!0,title:`从一份资料开始`,description:r.pickFile})})]})}function E({owner:e,file:t,onLink:i}){let{readTextBlob:s,blobUrl:c,projectId:l}=p(),[u,d]=(0,S.useState)(!1),f=t.size>524288,v=/\.(md|markdown)$/i.test(t.path),y=(0,S.useCallback)(e=>f?Promise.resolve(void 0):s(t,e),[t.sha256,t.size,f]),b=n(y,!1,a(l,`file-body`,t.sha256));return(0,C.jsxs)(C.Fragment,{children:[(0,C.jsxs)(`header`,{className:`file-detail-header`,children:[(0,C.jsxs)(`span`,{className:`file-detail-path`,title:`${e===`_project`?`workspaces`:e}/${t.path}`,children:[(0,C.jsxs)(`span`,{children:[e===`_project`?`workspaces`:e,` / `]}),t.path]}),(0,C.jsxs)(h,{label:`文件操作`,children:[v&&(0,C.jsx)(g,{icon:u?`preview`:`code`,label:u?`切换为预览`:`切换为原文`,"data-testid":`file-toggle-raw`,"aria-pressed":u,onClick:()=>d(!u)}),(0,C.jsx)(`a`,{className:`icon-button`,"data-testid":`file-download`,"aria-label":r.download,title:r.download,href:c(t.sha256),download:t.path.split(`/`).at(-1),children:(0,C.jsx)(m,{name:`download`})})]})]}),f?(0,C.jsx)(`div`,{className:`empty`,children:(0,C.jsx)(`p`,{children:r.previewLarge})}):b.error?(0,C.jsxs)(`div`,{className:`preview-body`,children:[(0,C.jsx)(o,{error:!0,children:b.error}),(0,C.jsx)(`button`,{"data-testid":`file-preview-retry`,onClick:()=>void b.reload(),children:r.retry})]}):b.loading?(0,C.jsx)(`p`,{className:`preview-body`,role:`status`,children:r.loading}):(0,C.jsx)(`div`,{className:`preview-body`,children:v&&!u?(0,C.jsx)(`article`,{className:`markdown`,"data-testid":`file-content`,"data-format":`markdown`,children:(0,C.jsx)(_,{onLink:i,children:b.data??``})}):(0,C.jsx)(`pre`,{className:`raw`,"data-testid":`file-content`,"data-format":`text`,children:b.data})})]})}export{T as Files};