ai-project-manage-cli 7.1.15 → 7.1.16

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/index.js CHANGED
@@ -184,6 +184,10 @@ var init_request_config = __esm({
184
184
  method: "GET",
185
185
  path: "/cli/webide/assumptions"
186
186
  }),
187
+ webideListAttachments: defineEndpoint({
188
+ method: "GET",
189
+ path: "/cli/webide/attachments"
190
+ }),
187
191
  webideRecommendPlan: defineEndpoint({
188
192
  method: "PUT",
189
193
  path: "/cli/webide/plan-recommendation"
@@ -220,10 +224,12 @@ var init_request_config = __esm({
220
224
  method: "GET",
221
225
  path: "/cli/tasks/branch-baseline"
222
226
  }),
223
- projectBaseBranch: defineEndpoint({
224
- method: "GET",
225
- path: "/cli/tasks/project-base-branch"
226
- }),
227
+ projectBaseBranch: defineEndpoint(
228
+ {
229
+ method: "GET",
230
+ path: "/cli/tasks/project-base-branch"
231
+ }
232
+ ),
227
233
  listSessionsForBranchCleanup: defineEndpoint({
228
234
  method: "GET",
229
235
  path: "/cli/sessions/branch-cleanup"
@@ -2498,7 +2504,9 @@ import { join as join6 } from "path";
2498
2504
  var MANIFEST_FILE2 = ".sync-manifest.json";
2499
2505
  async function downloadAttachment(cfg, attachmentId) {
2500
2506
  const base = cfg.baseUrl.trim().replace(/\/+$/, "");
2501
- const url = `${base}/api/v1/tasks/attachments/file?${new URLSearchParams({ attachmentId })}`;
2507
+ const url = `${base}/api/v1/tasks/attachments/file?${new URLSearchParams({
2508
+ attachmentId
2509
+ })}`;
2502
2510
  const res = await fetch(url);
2503
2511
  if (!res.ok) {
2504
2512
  throw new Error(
@@ -2537,24 +2545,23 @@ function isAttachmentUpToDate(entry, item, dest) {
2537
2545
  const createdAt = item.createdAt ?? "";
2538
2546
  return entry.createdAt === createdAt;
2539
2547
  }
2540
- async function syncSessionAttachments(cfg, sessionId, attachments, apmRoot) {
2541
- const dir = join6(sessionDir(sessionId, apmRoot), SESSION_ATTACHMENTS_SUBDIR);
2548
+ async function syncAttachmentsToDirectory(cfg, attachments, dir, logLabel) {
2542
2549
  await ensureDirExists(dir);
2543
2550
  if (attachments.length === 0) {
2544
2551
  saveManifest(dir, { version: 1, attachments: {} });
2545
- return;
2552
+ return [];
2546
2553
  }
2547
2554
  const manifest = loadManifest(dir);
2548
2555
  const nextManifest = { version: 1, attachments: {} };
2556
+ const names = [];
2549
2557
  for (const item of attachments) {
2550
2558
  const dest = join6(dir, item.name);
2551
2559
  const entry = manifest.attachments[item.id];
2552
2560
  const createdAt = item.createdAt ?? "";
2561
+ names.push(item.name);
2553
2562
  if (isAttachmentUpToDate(entry, item, dest)) {
2554
2563
  nextManifest.attachments[item.id] = entry;
2555
- console.log(
2556
- `[apm] \u9644\u4EF6\u65E0\u53D8\u5316\uFF0C\u5DF2\u8DF3\u8FC7: ${SESSION_ATTACHMENTS_SUBDIR}/${item.name}`
2557
- );
2564
+ console.log(`[apm] \u9644\u4EF6\u65E0\u53D8\u5316\uFF0C\u5DF2\u8DF3\u8FC7: ${logLabel}/${item.name}`);
2558
2565
  continue;
2559
2566
  }
2560
2567
  const buffer = await downloadAttachment(cfg, item.id);
@@ -2563,9 +2570,19 @@ async function syncSessionAttachments(cfg, sessionId, attachments, apmRoot) {
2563
2570
  name: item.name,
2564
2571
  createdAt
2565
2572
  };
2566
- console.log(`[apm] \u5DF2\u4E0B\u8F7D\u9644\u4EF6: ${SESSION_ATTACHMENTS_SUBDIR}/${item.name}`);
2573
+ console.log(`[apm] \u5DF2\u4E0B\u8F7D\u9644\u4EF6: ${logLabel}/${item.name}`);
2567
2574
  }
2568
2575
  saveManifest(dir, nextManifest);
2576
+ return names;
2577
+ }
2578
+ async function syncSessionAttachments(cfg, sessionId, attachments, apmRoot) {
2579
+ const dir = join6(sessionDir(sessionId, apmRoot), SESSION_ATTACHMENTS_SUBDIR);
2580
+ return syncAttachmentsToDirectory(
2581
+ cfg,
2582
+ attachments,
2583
+ dir,
2584
+ SESSION_ATTACHMENTS_SUBDIR
2585
+ );
2569
2586
  }
2570
2587
 
2571
2588
  // src/rules-sync.ts
@@ -88,6 +88,10 @@ var requestConfig = {
88
88
  method: "GET",
89
89
  path: "/cli/webide/assumptions"
90
90
  }),
91
+ webideListAttachments: defineEndpoint({
92
+ method: "GET",
93
+ path: "/cli/webide/attachments"
94
+ }),
91
95
  webideRecommendPlan: defineEndpoint({
92
96
  method: "PUT",
93
97
  path: "/cli/webide/plan-recommendation"
@@ -124,10 +128,12 @@ var requestConfig = {
124
128
  method: "GET",
125
129
  path: "/cli/tasks/branch-baseline"
126
130
  }),
127
- projectBaseBranch: defineEndpoint({
128
- method: "GET",
129
- path: "/cli/tasks/project-base-branch"
130
- }),
131
+ projectBaseBranch: defineEndpoint(
132
+ {
133
+ method: "GET",
134
+ path: "/cli/tasks/project-base-branch"
135
+ }
136
+ ),
131
137
  listSessionsForBranchCleanup: defineEndpoint({
132
138
  method: "GET",
133
139
  path: "/cli/sessions/branch-cleanup"
@@ -591,6 +597,14 @@ function assertApmGitignoredInRepo(workdir) {
591
597
  );
592
598
  }
593
599
  }
600
+ var SESSION_ATTACHMENTS_SUBDIR = "attachments";
601
+ var WEBIDE_SUBDIR = "webide";
602
+ function webideTaskDir(taskId, workdir) {
603
+ return join2(workdir, ".apm", WEBIDE_SUBDIR, taskId);
604
+ }
605
+ function webideAttachmentsDir(taskId, workdir) {
606
+ return join2(webideTaskDir(taskId, workdir), SESSION_ATTACHMENTS_SUBDIR);
607
+ }
594
608
  async function ensureLoggedConfig() {
595
609
  const cfg = await ensureApmConfig();
596
610
  if (!resolveApiKey(cfg)) {
@@ -3087,21 +3101,108 @@ async function syncWorkspaceSkills(cfg, workdir) {
3087
3101
  );
3088
3102
  }
3089
3103
 
3090
- // src/commands/connect/cli-version-sync.ts
3104
+ // src/commands/sync-session-attachments.ts
3091
3105
  import { existsSync as existsSync8, readFileSync as readFileSync9, writeFileSync as writeFileSync10 } from "fs";
3092
3106
  import { join as join11 } from "path";
3107
+ var MANIFEST_FILE2 = ".sync-manifest.json";
3108
+ async function downloadAttachment(cfg, attachmentId) {
3109
+ const base = cfg.baseUrl.trim().replace(/\/+$/, "");
3110
+ const url = `${base}/api/v1/tasks/attachments/file?${new URLSearchParams({
3111
+ attachmentId
3112
+ })}`;
3113
+ const res = await fetch(url);
3114
+ if (!res.ok) {
3115
+ throw new Error(
3116
+ `[apm] \u4E0B\u8F7D\u9644\u4EF6\u5931\u8D25 (${res.status}): attachmentId=${attachmentId}`
3117
+ );
3118
+ }
3119
+ return Buffer.from(await res.arrayBuffer());
3120
+ }
3121
+ function loadManifest(dir) {
3122
+ const path = join11(dir, MANIFEST_FILE2);
3123
+ if (!existsSync8(path)) {
3124
+ return { version: 1, attachments: {} };
3125
+ }
3126
+ try {
3127
+ const parsed = JSON.parse(
3128
+ readFileSync9(path, "utf8")
3129
+ );
3130
+ if (parsed?.version === 1 && parsed.attachments && typeof parsed.attachments === "object") {
3131
+ return parsed;
3132
+ }
3133
+ } catch {
3134
+ }
3135
+ return { version: 1, attachments: {} };
3136
+ }
3137
+ function saveManifest(dir, manifest) {
3138
+ writeFileSync10(
3139
+ join11(dir, MANIFEST_FILE2),
3140
+ `${JSON.stringify(manifest, null, 2)}
3141
+ `,
3142
+ "utf8"
3143
+ );
3144
+ }
3145
+ function isAttachmentUpToDate(entry, item, dest) {
3146
+ if (!entry || !existsSync8(dest)) return false;
3147
+ if (entry.name !== item.name) return false;
3148
+ const createdAt = item.createdAt ?? "";
3149
+ return entry.createdAt === createdAt;
3150
+ }
3151
+ async function syncAttachmentsToDirectory(cfg, attachments, dir, logLabel) {
3152
+ await ensureDirExists(dir);
3153
+ if (attachments.length === 0) {
3154
+ saveManifest(dir, { version: 1, attachments: {} });
3155
+ return [];
3156
+ }
3157
+ const manifest = loadManifest(dir);
3158
+ const nextManifest = { version: 1, attachments: {} };
3159
+ const names = [];
3160
+ for (const item of attachments) {
3161
+ const dest = join11(dir, item.name);
3162
+ const entry = manifest.attachments[item.id];
3163
+ const createdAt = item.createdAt ?? "";
3164
+ names.push(item.name);
3165
+ if (isAttachmentUpToDate(entry, item, dest)) {
3166
+ nextManifest.attachments[item.id] = entry;
3167
+ console.log(`[apm] \u9644\u4EF6\u65E0\u53D8\u5316\uFF0C\u5DF2\u8DF3\u8FC7: ${logLabel}/${item.name}`);
3168
+ continue;
3169
+ }
3170
+ const buffer = await downloadAttachment(cfg, item.id);
3171
+ writeFileSync10(dest, buffer);
3172
+ nextManifest.attachments[item.id] = {
3173
+ name: item.name,
3174
+ createdAt
3175
+ };
3176
+ console.log(`[apm] \u5DF2\u4E0B\u8F7D\u9644\u4EF6: ${logLabel}/${item.name}`);
3177
+ }
3178
+ saveManifest(dir, nextManifest);
3179
+ return names;
3180
+ }
3181
+ async function syncWebIdeAttachments(cfg, taskId, workdir, attachments) {
3182
+ const dir = webideAttachmentsDir(taskId, workdir);
3183
+ return syncAttachmentsToDirectory(
3184
+ cfg,
3185
+ attachments,
3186
+ dir,
3187
+ `.apm/webide/${taskId}/attachments`
3188
+ );
3189
+ }
3190
+
3191
+ // src/commands/connect/cli-version-sync.ts
3192
+ import { existsSync as existsSync9, readFileSync as readFileSync10, writeFileSync as writeFileSync11 } from "fs";
3193
+ import { join as join12 } from "path";
3093
3194
  var CLI_VERSION_FILE = ".cli-version.json";
3094
3195
  function manifestPath2(apmDir) {
3095
- return join11(apmDir, CLI_VERSION_FILE);
3196
+ return join12(apmDir, CLI_VERSION_FILE);
3096
3197
  }
3097
- function loadManifest(apmDir) {
3198
+ function loadManifest2(apmDir) {
3098
3199
  const path = toFsPath(manifestPath2(apmDir));
3099
- if (!existsSync8(path)) {
3200
+ if (!existsSync9(path)) {
3100
3201
  return null;
3101
3202
  }
3102
3203
  try {
3103
3204
  const parsed = JSON.parse(
3104
- readFileSync9(path, "utf8")
3205
+ readFileSync10(path, "utf8")
3105
3206
  );
3106
3207
  if (parsed?.version === 1 && typeof parsed.cliVersion === "string" && parsed.cliVersion.trim()) {
3107
3208
  return parsed;
@@ -3110,9 +3211,9 @@ function loadManifest(apmDir) {
3110
3211
  }
3111
3212
  return null;
3112
3213
  }
3113
- function saveManifest(apmDir, cliVersion) {
3214
+ function saveManifest2(apmDir, cliVersion) {
3114
3215
  const manifest = { version: 1, cliVersion };
3115
- writeFileSync10(
3216
+ writeFileSync11(
3116
3217
  toFsPath(manifestPath2(apmDir)),
3117
3218
  `${JSON.stringify(manifest, null, 2)}
3118
3219
  `,
@@ -3125,7 +3226,7 @@ function shouldSyncSkillsForCliVersion(workdir, currentVersion) {
3125
3226
  if (cached === currentVersion) {
3126
3227
  return false;
3127
3228
  }
3128
- const stored = loadManifest(workspaceApmDir(workdir));
3229
+ const stored = loadManifest2(workspaceApmDir(workdir));
3129
3230
  if (stored?.cliVersion === currentVersion) {
3130
3231
  syncedInSession.set(workdir, currentVersion);
3131
3232
  return false;
@@ -3133,7 +3234,7 @@ function shouldSyncSkillsForCliVersion(workdir, currentVersion) {
3133
3234
  return true;
3134
3235
  }
3135
3236
  function markSkillsSyncedForCliVersion(workdir, cliVersion) {
3136
- saveManifest(workspaceApmDir(workdir), cliVersion);
3237
+ saveManifest2(workspaceApmDir(workdir), cliVersion);
3137
3238
  syncedInSession.set(workdir, cliVersion);
3138
3239
  }
3139
3240
 
@@ -3206,6 +3307,27 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
3206
3307
  if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
3207
3308
  await ensureWebIdePullRequests(cfg, taskId, workdir);
3208
3309
  }
3310
+ if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
3311
+ const api = createApmApiClient(cfg);
3312
+ try {
3313
+ const attachments = await api.cli.webideListAttachments({ taskId });
3314
+ const names = await syncWebIdeAttachments(
3315
+ cfg,
3316
+ taskId,
3317
+ workdir,
3318
+ attachments ?? []
3319
+ );
3320
+ if (names.length > 0) {
3321
+ console.log(
3322
+ `[apm] webide \u9644\u4EF6\u5DF2\u5C31\u7EEA count=${names.length} dir=.apm/webide/${taskId}/attachments`
3323
+ );
3324
+ }
3325
+ } catch (err) {
3326
+ console.warn(
3327
+ "[apm] WebIDE \u9644\u4EF6\u540C\u6B65\u5931\u8D25:",
3328
+ err instanceof Error ? err.message : err
3329
+ );
3330
+ }
3209
3331
  const savedAgentId = loadWebIdeAgentId(workdir, taskId);
3210
3332
  const logSyncRef = { current: null };
3211
3333
  const outcome = await runCursorAgent(
@@ -3272,7 +3394,6 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
3272
3394
  result: outcome.result,
3273
3395
  createPlan: outcome.createPlan
3274
3396
  });
3275
- const api = createApmApiClient(cfg);
3276
3397
  await api.cli.webideEnsureMessageContent({
3277
3398
  id: messageId,
3278
3399
  content: fallback
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "7.1.15",
3
+ "version": "7.1.16",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,
@@ -40,6 +40,7 @@
40
40
  - 任务涉及菜单名、路由、业务术语等时,**先 Read manifest 与相关文档**,禁止猜测路径
41
41
 
42
42
  - 本轮任务需要关注的文档指引(.apm/sessions/<会话 ID>/\*):
43
+
43
44
  - 本轮会话状态: `session.yaml`,从这里可以看到每个成员的信息,找到可以协助你一起解决问题的人,可以结合 `RULE.md`一起看
44
45
  - 群文档: `docs/xxxx.md`,当需要相关上下文可以在这里查找,按需阅读
45
46
  - 附件列表: `attachments/*`,当有文档中提及附件时,从这里查找
@@ -47,3 +48,6 @@
47
48
  - 协作 TODO: `TODO.md`,跨轮次任务清单(待办与已完成项),按需阅读
48
49
  - 历史消息记录: `messages.xml`,历史消息列表,数据量很大,按需阅读
49
50
  - 初始目标: `TASK.md`,最初的目标,不一定具体,团队成员会有人负责让这个任务变得具体,仅供参考。如果你是相关的角色,则你需要先读取这个目标,然后规划接下来的动作。
51
+
52
+ - WebIDE 任务附件(`.apm/webide/<taskId>/attachments/`):
53
+ - `apm connect` 处理 webide-message 时会自动同步;prompt 中若出现「任务附件」指引,请按路径查看相关文件