ai-project-manage-cli 7.1.27 → 7.1.29

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
@@ -314,6 +314,10 @@ var init_request_config = __esm({
314
314
  });
315
315
 
316
316
  // src/api/client.ts
317
+ var client_exports = {};
318
+ __export(client_exports, {
319
+ createApmApiClient: () => createApmApiClient
320
+ });
317
321
  import { createApiClient } from "listpage-http";
318
322
  function createApmApiClient(cfg) {
319
323
  const baseURL = `${cfg.baseUrl.trim().replace(/\/+$/, "")}/api/v1`;
@@ -476,123 +480,33 @@ var init_minio = __esm({
476
480
  }
477
481
  });
478
482
 
479
- // src/commands/deploy/internal/deploy-artifact-minio.ts
480
- import { readFile as readFile2 } from "node:fs/promises";
481
- function formatDeployArtifactTimestamp(date = /* @__PURE__ */ new Date()) {
482
- const pad2 = (n) => String(n).padStart(2, "0");
483
- return `${date.getFullYear()}${pad2(date.getMonth() + 1)}${pad2(date.getDate())}${pad2(date.getHours())}${pad2(date.getMinutes())}${pad2(date.getSeconds())}`;
484
- }
485
- function sanitizeDeployProjectName(name) {
486
- const trimmed = name.trim().replace(/\\/g, "/");
487
- const base = trimmed.split("/").filter(Boolean).pop() ?? trimmed;
488
- try {
489
- return sanitizeRelativePath(base.replace(/[/\\:*?"<>|]/g, "_"));
490
- } catch {
491
- return "project";
492
- }
493
- }
494
- function buildDeployArtifactFileName(kind, projectName, timestamp = formatDeployArtifactTimestamp()) {
495
- const safeName = sanitizeDeployProjectName(projectName);
496
- const suffix = kind === "frontend" ? "dist.zip" : "jar.zip";
497
- return `${timestamp}-${safeName}.${suffix}`;
498
- }
499
- function buildDeployArtifactObjectKey(projectName, fileName) {
500
- const safeProject = sanitizeDeployProjectName(projectName);
501
- return `deploy/${safeProject}/${fileName}`;
502
- }
503
- function resolveDeploymentRunIdFromEnv() {
504
- const raw = process.env[APM_DEPLOYMENT_RUN_ID_ENV]?.trim();
505
- return raw || null;
506
- }
507
- async function fetchDeployArtifactStorage(api) {
508
- return api.cli.getDeployArtifactStorage(void 0);
509
- }
510
- async function uploadDeployArtifactZip(options) {
511
- const deploymentRunId = options.deploymentRunId ?? resolveDeploymentRunIdFromEnv();
512
- if (!deploymentRunId && !options.uploadWithoutRunId) {
513
- return null;
514
- }
515
- const cfg = await tryReadApmConfig();
516
- if (!cfg || !resolveApiKey(cfg)) {
517
- console.warn("[apm] \u672A\u767B\u5F55\uFF0C\u8DF3\u8FC7 MinIO \u90E8\u7F72\u4EA7\u7269\u5F52\u6863");
518
- return null;
519
- }
520
- const api = options.api ?? createApmApiClient(cfg);
521
- let storage;
522
- try {
523
- storage = await fetchDeployArtifactStorage(api);
524
- } catch (error) {
525
- const detail = error instanceof Error ? error.message : String(error);
526
- console.warn(`[apm] \u83B7\u53D6 MinIO \u914D\u7F6E\u5931\u8D25\uFF0C\u8DF3\u8FC7\u90E8\u7F72\u4EA7\u7269\u5F52\u6863: ${detail}`);
527
- return null;
528
- }
529
- const fileName = buildDeployArtifactFileName(
530
- options.kind,
531
- options.projectName,
532
- options.timestamp
533
- );
534
- const objectKey = buildDeployArtifactObjectKey(options.projectName, fileName);
535
- let body;
536
- try {
537
- body = await readFile2(options.zipPath);
538
- } catch (error) {
539
- const detail = error instanceof Error ? error.message : String(error);
540
- console.warn(`[apm] \u8BFB\u53D6\u90E8\u7F72\u4EA7\u7269 zip \u5931\u8D25\uFF0C\u8DF3\u8FC7 MinIO \u5F52\u6863: ${detail}`);
541
- return null;
542
- }
543
- try {
544
- const client = new MinioClient({
483
+ // src/commands/connect/apm-log-minio.ts
484
+ function createApmLogMinioClient() {
485
+ const storage = APM_LOG_MINIO_CONFIG;
486
+ return {
487
+ client: new MinioClient({
545
488
  endPoint: storage.endpoint,
546
489
  port: storage.port,
547
490
  useSSL: storage.useSsl,
548
491
  accessKey: storage.accessKey,
549
492
  secretKey: storage.secretKey
550
- });
551
- await client.ensureBucket(storage.bucket);
552
- await client.putObject(storage.bucket, objectKey, body, {
553
- "Content-Type": "application/zip"
554
- });
555
- console.error(
556
- `[apm] \u672C\u5730\u76F4\u4F20 MinIO\uFF08\u4E0D\u7ECF\u5E73\u53F0\u670D\u52A1\u5668\uFF09: ${storage.endpoint}:${storage.port}/${storage.bucket}/${objectKey} (${(body.length / 1024 / 1024).toFixed(
557
- 2
558
- )} MB)`
559
- );
560
- } catch (error) {
561
- const detail = error instanceof Error ? error.message : String(error);
562
- console.warn(`[apm] MinIO \u90E8\u7F72\u4EA7\u7269\u5F52\u6863\u5931\u8D25: ${detail}`);
563
- return null;
564
- }
565
- if (deploymentRunId) {
566
- try {
567
- await api.cli.attachTaskDeploymentArtifact({
568
- id: deploymentRunId,
569
- artifactObjectKey: objectKey,
570
- artifactFileName: fileName
571
- });
572
- console.error(
573
- `[apm] \u5DF2\u7ED1\u5B9A\u90E8\u7F72\u4EA7\u7269\u5230\u8BB0\u5F55 id=${deploymentRunId} file=${fileName}`
574
- );
575
- } catch (error) {
576
- const detail = error instanceof Error ? error.message : String(error);
577
- console.warn(`[apm] \u7ED1\u5B9A\u90E8\u7F72\u4EA7\u7269\u5230\u8BB0\u5F55\u5931\u8D25: ${detail}`);
578
- return null;
579
- }
580
- }
581
- return {
582
- objectKey,
583
- fileName,
493
+ }),
584
494
  bucket: storage.bucket
585
495
  };
586
496
  }
587
- var APM_DEPLOYMENT_RUN_ID_ENV;
588
- var init_deploy_artifact_minio = __esm({
589
- "src/commands/deploy/internal/deploy-artifact-minio.ts"() {
497
+ var APM_LOG_MINIO_CONFIG;
498
+ var init_apm_log_minio = __esm({
499
+ "src/commands/connect/apm-log-minio.ts"() {
590
500
  "use strict";
591
- init_client();
592
- init_config();
593
- init_minio();
594
501
  init_minio();
595
- APM_DEPLOYMENT_RUN_ID_ENV = "APM_DEPLOYMENT_RUN_ID";
502
+ APM_LOG_MINIO_CONFIG = {
503
+ endpoint: "objectstorageapi.gzg.sealos.run",
504
+ port: 443,
505
+ useSsl: true,
506
+ accessKey: "428hqav4",
507
+ secretKey: "68b8srk4vdbjdhlc",
508
+ bucket: "428hqav4-apm-log"
509
+ };
596
510
  }
597
511
  });
598
512
 
@@ -715,8 +629,7 @@ var init_webide_terminal_registry = __esm({
715
629
  "src/commands/connect/webide-terminal-registry.ts"() {
716
630
  "use strict";
717
631
  init_client();
718
- init_deploy_artifact_minio();
719
- init_minio();
632
+ init_apm_log_minio();
720
633
  execFileAsync3 = promisify3(execFile3);
721
634
  WEBIDE_TERMINAL_LINES_PER_CHUNK = 50;
722
635
  SYNC_INTERVAL_MS = 400;
@@ -734,17 +647,9 @@ var init_webide_terminal_registry = __esm({
734
647
  bucket = "";
735
648
  async ensureMinio() {
736
649
  if (this.minio) return;
737
- const storage = await fetchDeployArtifactStorage(
738
- createApmApiClient(this.cfg)
739
- );
740
- this.minio = new MinioClient({
741
- endPoint: storage.endpoint,
742
- port: storage.port,
743
- useSSL: storage.useSsl,
744
- accessKey: storage.accessKey,
745
- secretKey: storage.secretKey
746
- });
747
- this.bucket = storage.bucket;
650
+ const created = createApmLogMinioClient();
651
+ this.minio = created.client;
652
+ this.bucket = created.bucket;
748
653
  await this.minio.ensureBucket(this.bucket);
749
654
  }
750
655
  listLocal(taskId) {
@@ -4370,11 +4275,124 @@ var DeployExecutionError = class extends Error {
4370
4275
  };
4371
4276
 
4372
4277
  // src/commands/deploy/deploy-debug-log.ts
4373
- init_deploy_artifact_minio();
4374
4278
  import { spawnSync as spawnSync4 } from "node:child_process";
4375
4279
  import { existsSync as existsSync17 } from "node:fs";
4376
4280
  import { dirname as dirname6, join as join18 } from "node:path";
4377
4281
 
4282
+ // src/commands/deploy/internal/deploy-artifact-minio.ts
4283
+ init_client();
4284
+ init_config();
4285
+ init_minio();
4286
+ init_minio();
4287
+ import { readFile as readFile2 } from "node:fs/promises";
4288
+ var APM_DEPLOYMENT_RUN_ID_ENV = "APM_DEPLOYMENT_RUN_ID";
4289
+ function formatDeployArtifactTimestamp(date = /* @__PURE__ */ new Date()) {
4290
+ const pad2 = (n) => String(n).padStart(2, "0");
4291
+ return `${date.getFullYear()}${pad2(date.getMonth() + 1)}${pad2(date.getDate())}${pad2(date.getHours())}${pad2(date.getMinutes())}${pad2(date.getSeconds())}`;
4292
+ }
4293
+ function sanitizeDeployProjectName(name) {
4294
+ const trimmed = name.trim().replace(/\\/g, "/");
4295
+ const base = trimmed.split("/").filter(Boolean).pop() ?? trimmed;
4296
+ try {
4297
+ return sanitizeRelativePath(base.replace(/[/\\:*?"<>|]/g, "_"));
4298
+ } catch {
4299
+ return "project";
4300
+ }
4301
+ }
4302
+ function buildDeployArtifactFileName(kind, projectName, timestamp = formatDeployArtifactTimestamp()) {
4303
+ const safeName = sanitizeDeployProjectName(projectName);
4304
+ const suffix = kind === "frontend" ? "dist.zip" : "jar.zip";
4305
+ return `${timestamp}-${safeName}.${suffix}`;
4306
+ }
4307
+ function buildDeployArtifactObjectKey(projectName, fileName) {
4308
+ const safeProject = sanitizeDeployProjectName(projectName);
4309
+ return `deploy/${safeProject}/${fileName}`;
4310
+ }
4311
+ function resolveDeploymentRunIdFromEnv() {
4312
+ const raw = process.env[APM_DEPLOYMENT_RUN_ID_ENV]?.trim();
4313
+ return raw || null;
4314
+ }
4315
+ async function fetchDeployArtifactStorage(api) {
4316
+ return api.cli.getDeployArtifactStorage(void 0);
4317
+ }
4318
+ async function uploadDeployArtifactZip(options) {
4319
+ const deploymentRunId = options.deploymentRunId ?? resolveDeploymentRunIdFromEnv();
4320
+ if (!deploymentRunId && !options.uploadWithoutRunId) {
4321
+ return null;
4322
+ }
4323
+ const cfg = await tryReadApmConfig();
4324
+ if (!cfg || !resolveApiKey(cfg)) {
4325
+ console.warn("[apm] \u672A\u767B\u5F55\uFF0C\u8DF3\u8FC7 MinIO \u90E8\u7F72\u4EA7\u7269\u5F52\u6863");
4326
+ return null;
4327
+ }
4328
+ const api = options.api ?? createApmApiClient(cfg);
4329
+ let storage;
4330
+ try {
4331
+ storage = await fetchDeployArtifactStorage(api);
4332
+ } catch (error) {
4333
+ const detail = error instanceof Error ? error.message : String(error);
4334
+ console.warn(`[apm] \u83B7\u53D6 MinIO \u914D\u7F6E\u5931\u8D25\uFF0C\u8DF3\u8FC7\u90E8\u7F72\u4EA7\u7269\u5F52\u6863: ${detail}`);
4335
+ return null;
4336
+ }
4337
+ const fileName = buildDeployArtifactFileName(
4338
+ options.kind,
4339
+ options.projectName,
4340
+ options.timestamp
4341
+ );
4342
+ const objectKey = buildDeployArtifactObjectKey(options.projectName, fileName);
4343
+ let body;
4344
+ try {
4345
+ body = await readFile2(options.zipPath);
4346
+ } catch (error) {
4347
+ const detail = error instanceof Error ? error.message : String(error);
4348
+ console.warn(`[apm] \u8BFB\u53D6\u90E8\u7F72\u4EA7\u7269 zip \u5931\u8D25\uFF0C\u8DF3\u8FC7 MinIO \u5F52\u6863: ${detail}`);
4349
+ return null;
4350
+ }
4351
+ try {
4352
+ const client = new MinioClient({
4353
+ endPoint: storage.endpoint,
4354
+ port: storage.port,
4355
+ useSSL: storage.useSsl,
4356
+ accessKey: storage.accessKey,
4357
+ secretKey: storage.secretKey
4358
+ });
4359
+ await client.ensureBucket(storage.bucket);
4360
+ await client.putObject(storage.bucket, objectKey, body, {
4361
+ "Content-Type": "application/zip"
4362
+ });
4363
+ console.error(
4364
+ `[apm] \u672C\u5730\u76F4\u4F20 MinIO\uFF08\u4E0D\u7ECF\u5E73\u53F0\u670D\u52A1\u5668\uFF09: ${storage.endpoint}:${storage.port}/${storage.bucket}/${objectKey} (${(body.length / 1024 / 1024).toFixed(
4365
+ 2
4366
+ )} MB)`
4367
+ );
4368
+ } catch (error) {
4369
+ const detail = error instanceof Error ? error.message : String(error);
4370
+ console.warn(`[apm] MinIO \u90E8\u7F72\u4EA7\u7269\u5F52\u6863\u5931\u8D25: ${detail}`);
4371
+ return null;
4372
+ }
4373
+ if (deploymentRunId) {
4374
+ try {
4375
+ await api.cli.attachTaskDeploymentArtifact({
4376
+ id: deploymentRunId,
4377
+ artifactObjectKey: objectKey,
4378
+ artifactFileName: fileName
4379
+ });
4380
+ console.error(
4381
+ `[apm] \u5DF2\u7ED1\u5B9A\u90E8\u7F72\u4EA7\u7269\u5230\u8BB0\u5F55 id=${deploymentRunId} file=${fileName}`
4382
+ );
4383
+ } catch (error) {
4384
+ const detail = error instanceof Error ? error.message : String(error);
4385
+ console.warn(`[apm] \u7ED1\u5B9A\u90E8\u7F72\u4EA7\u7269\u5230\u8BB0\u5F55\u5931\u8D25: ${detail}`);
4386
+ return null;
4387
+ }
4388
+ }
4389
+ return {
4390
+ objectKey,
4391
+ fileName,
4392
+ bucket: storage.bucket
4393
+ };
4394
+ }
4395
+
4378
4396
  // src/commands/deploy/internal/deploy-shell-env.ts
4379
4397
  import { spawnSync as spawnSync3 } from "node:child_process";
4380
4398
  import { existsSync as existsSync16 } from "node:fs";
@@ -5523,7 +5541,6 @@ function runDeployShellCommand(command, cwd, captureOutput) {
5523
5541
 
5524
5542
  // src/commands/deploy/internal/wisdom-backend/index.ts
5525
5543
  import path9 from "node:path";
5526
- init_deploy_artifact_minio();
5527
5544
 
5528
5545
  // src/commands/deploy/internal/wisdom-backend/jar-incremental.ts
5529
5546
  import {
@@ -5592,7 +5609,6 @@ import SftpClient from "ssh2-sftp-client";
5592
5609
  import { readdir as readdir2, readFile as readFile3, unlink, writeFile } from "node:fs/promises";
5593
5610
  import path3 from "node:path";
5594
5611
  import JSZip from "jszip";
5595
- init_deploy_artifact_minio();
5596
5612
  init_minio();
5597
5613
  async function addDirToZip(dir, zipFolder) {
5598
5614
  const entries = await readdir2(dir, { withFileTypes: true });
@@ -5682,7 +5698,6 @@ async function packDirectoryWithMinioArchive(input) {
5682
5698
  }
5683
5699
 
5684
5700
  // src/commands/deploy/internal/wisdom-sftp.ts
5685
- init_deploy_artifact_minio();
5686
5701
  var SFTP_UPLOAD_MAX_ATTEMPTS = 3;
5687
5702
  var SFTP_FAST_PUT_OPTIONS = {
5688
5703
  chunkSize: 64 * 1024,
@@ -6892,9 +6907,6 @@ function printDeployExecutionError(error) {
6892
6907
  console.error(error.message);
6893
6908
  }
6894
6909
 
6895
- // src/commands/deploy/platform/deploy-run-coordinator.ts
6896
- init_deploy_artifact_minio();
6897
-
6898
6910
  // src/commands/deploy/platform/deploy-console-capture.ts
6899
6911
  function captureDeployConsole(logSyncer) {
6900
6912
  const chunks = [];
@@ -7424,6 +7436,37 @@ var EventSession = class {
7424
7436
  });
7425
7437
  this.markDirty(this.events.length - 1);
7426
7438
  }
7439
+ /**
7440
+ * CLI 本地准备步骤(工作区/分支/文档等),写入日志供 WebIDE 查看。
7441
+ * 同名 step 原地更新(进行中→完成合并为一行),终态时写入 durationMs。
7442
+ */
7443
+ addCliStep(step, text, status = "ok") {
7444
+ const existingIndex = this.events.findIndex(
7445
+ (e) => e.type === "cli_step" && e.step === step
7446
+ );
7447
+ const now = Date.now();
7448
+ if (existingIndex >= 0) {
7449
+ const existing = this.events[existingIndex];
7450
+ existing.status = status;
7451
+ existing.text = text;
7452
+ if (status !== "running") {
7453
+ const startedAt = typeof existing.at === "string" ? Date.parse(existing.at) : NaN;
7454
+ if (Number.isFinite(startedAt)) {
7455
+ existing.durationMs = Math.max(0, now - startedAt);
7456
+ }
7457
+ }
7458
+ this.markDirty(existingIndex);
7459
+ return;
7460
+ }
7461
+ this.events.push({
7462
+ type: "cli_step",
7463
+ step,
7464
+ status,
7465
+ text,
7466
+ at: new Date(now).toISOString()
7467
+ });
7468
+ this.markDirty(this.events.length - 1);
7469
+ }
7427
7470
  formatEvent(event) {
7428
7471
  switch (event.type) {
7429
7472
  case "assistant": {
@@ -8351,7 +8394,7 @@ async function runCursorAgent(cfg, ctx, options) {
8351
8394
  customTools,
8352
8395
  enableSandbox
8353
8396
  });
8354
- const eventSession = new EventSession(prompt);
8397
+ const eventSession = options?.eventSession ?? new EventSession(prompt);
8355
8398
  const syncRemoteLog = options?.createRemoteLogSync ? options.createRemoteLogSync(agent.agentId) : options?.skipRemoteLogSync ? noopRemoteLogSync : createThrottledCursorMessageLogSync(
8356
8399
  cfg,
8357
8400
  logCtx(ctx, agent.agentId),
@@ -8630,10 +8673,27 @@ function spawnWebIdeMessageWorker(cfg, msg) {
8630
8673
  workerData: { cfg, msg }
8631
8674
  });
8632
8675
  const registry = getWebIdeTerminalRegistry(cfg);
8676
+ let settled = false;
8633
8677
  let resolveDone;
8634
8678
  const done = new Promise((resolve8) => {
8635
8679
  resolveDone = resolve8;
8636
8680
  });
8681
+ const failIfStillQueued = async (reason) => {
8682
+ if (settled) return;
8683
+ try {
8684
+ const { createApmApiClient: createApmApiClient2 } = await Promise.resolve().then(() => (init_client(), client_exports));
8685
+ const api = createApmApiClient2(cfg);
8686
+ await api.cli.webideSetMessageError({
8687
+ id: msg.messageId,
8688
+ error: reason
8689
+ });
8690
+ } catch (err) {
8691
+ console.error(
8692
+ `[apm] webide worker \u5931\u8D25\u5199\u7EC8\u6001\u5931\u8D25 messageId=${msg.messageId}:`,
8693
+ err instanceof Error ? err.message : err
8694
+ );
8695
+ }
8696
+ };
8637
8697
  worker.on("message", (m) => {
8638
8698
  if (m?.type === "terminal-rpc") {
8639
8699
  const rpc = m;
@@ -8693,6 +8753,7 @@ function spawnWebIdeMessageWorker(cfg, msg) {
8693
8753
  return;
8694
8754
  }
8695
8755
  if (m?.type === "done" || m?.type === "error") {
8756
+ settled = true;
8696
8757
  if (m.type === "error") {
8697
8758
  console.error(
8698
8759
  `[apm] webide worker error messageId=${m.messageId}: ${m.error}`
@@ -8703,9 +8764,18 @@ function spawnWebIdeMessageWorker(cfg, msg) {
8703
8764
  });
8704
8765
  worker.on("error", (err) => {
8705
8766
  console.error("[apm] webide worker crashed:", err);
8706
- resolveDone();
8767
+ void failIfStillQueued(
8768
+ `WebIDE worker \u5D29\u6E83: ${err instanceof Error ? err.message : String(err)}`
8769
+ ).finally(() => resolveDone());
8707
8770
  });
8708
8771
  worker.on("exit", (code) => {
8772
+ if (!settled && code !== 0) {
8773
+ console.error(`[apm] webide worker exit code=${code}`);
8774
+ void failIfStillQueued(`WebIDE worker \u5F02\u5E38\u9000\u51FA code=${code}`).finally(
8775
+ () => resolveDone()
8776
+ );
8777
+ return;
8778
+ }
8709
8779
  if (code !== 0) {
8710
8780
  console.error(`[apm] webide worker exit code=${code}`);
8711
8781
  }
@@ -9012,6 +9082,24 @@ function attachWsHandlers(ws, ctx, onOpen) {
9012
9082
  if (pendingCancels.has(msg2.messageId)) {
9013
9083
  activeRuns.delete(msg2.messageId);
9014
9084
  pendingCancels.delete(msg2.messageId);
9085
+ const cancelTask = (async () => {
9086
+ try {
9087
+ const api = createApmApiClient(cfg);
9088
+ await api.cli.webideUpdateMessageStatus({
9089
+ id: msg2.messageId,
9090
+ status: "CANCELLED"
9091
+ });
9092
+ } catch (err) {
9093
+ console.error(
9094
+ `[apm] webide-message \u9884\u53D6\u6D88\u5199\u7EC8\u6001\u5931\u8D25 messageId=${msg2.messageId}:`,
9095
+ err instanceof Error ? err.message : err
9096
+ );
9097
+ }
9098
+ })();
9099
+ activeTasks.add(cancelTask);
9100
+ void cancelTask.finally(() => {
9101
+ activeTasks.delete(cancelTask);
9102
+ });
9015
9103
  return;
9016
9104
  }
9017
9105
  const task2 = (async () => {
@@ -1362,6 +1362,37 @@ var EventSession = class {
1362
1362
  });
1363
1363
  this.markDirty(this.events.length - 1);
1364
1364
  }
1365
+ /**
1366
+ * CLI 本地准备步骤(工作区/分支/文档等),写入日志供 WebIDE 查看。
1367
+ * 同名 step 原地更新(进行中→完成合并为一行),终态时写入 durationMs。
1368
+ */
1369
+ addCliStep(step, text, status = "ok") {
1370
+ const existingIndex = this.events.findIndex(
1371
+ (e) => e.type === "cli_step" && e.step === step
1372
+ );
1373
+ const now = Date.now();
1374
+ if (existingIndex >= 0) {
1375
+ const existing = this.events[existingIndex];
1376
+ existing.status = status;
1377
+ existing.text = text;
1378
+ if (status !== "running") {
1379
+ const startedAt = typeof existing.at === "string" ? Date.parse(existing.at) : NaN;
1380
+ if (Number.isFinite(startedAt)) {
1381
+ existing.durationMs = Math.max(0, now - startedAt);
1382
+ }
1383
+ }
1384
+ this.markDirty(existingIndex);
1385
+ return;
1386
+ }
1387
+ this.events.push({
1388
+ type: "cli_step",
1389
+ step,
1390
+ status,
1391
+ text,
1392
+ at: new Date(now).toISOString()
1393
+ });
1394
+ this.markDirty(this.events.length - 1);
1395
+ }
1365
1396
  formatEvent(event) {
1366
1397
  switch (event.type) {
1367
1398
  case "assistant": {
@@ -2360,7 +2391,7 @@ async function runCursorAgent(cfg, ctx, options) {
2360
2391
  customTools,
2361
2392
  enableSandbox
2362
2393
  });
2363
- const eventSession = new EventSession(prompt);
2394
+ const eventSession = options?.eventSession ?? new EventSession(prompt);
2364
2395
  const syncRemoteLog = options?.createRemoteLogSync ? options.createRemoteLogSync(agent.agentId) : options?.skipRemoteLogSync ? noopRemoteLogSync : createThrottledCursorMessageLogSync(
2365
2396
  cfg,
2366
2397
  logCtx(ctx, agent.agentId),
@@ -2672,9 +2703,27 @@ var MinioClient = class {
2672
2703
  }
2673
2704
  };
2674
2705
 
2675
- // src/commands/deploy/internal/deploy-artifact-minio.ts
2676
- async function fetchDeployArtifactStorage(api) {
2677
- return api.cli.getDeployArtifactStorage(void 0);
2706
+ // src/commands/connect/apm-log-minio.ts
2707
+ var APM_LOG_MINIO_CONFIG = {
2708
+ endpoint: "objectstorageapi.gzg.sealos.run",
2709
+ port: 443,
2710
+ useSsl: true,
2711
+ accessKey: "428hqav4",
2712
+ secretKey: "68b8srk4vdbjdhlc",
2713
+ bucket: "428hqav4-apm-log"
2714
+ };
2715
+ function createApmLogMinioClient() {
2716
+ const storage = APM_LOG_MINIO_CONFIG;
2717
+ return {
2718
+ client: new MinioClient({
2719
+ endPoint: storage.endpoint,
2720
+ port: storage.port,
2721
+ useSSL: storage.useSsl,
2722
+ accessKey: storage.accessKey,
2723
+ secretKey: storage.secretKey
2724
+ }),
2725
+ bucket: storage.bucket
2726
+ };
2678
2727
  }
2679
2728
 
2680
2729
  // src/commands/connect/webide-message-log.ts
@@ -2707,26 +2756,31 @@ async function upsertLogHeader(cfg, ctx, patch) {
2707
2756
  ...patch
2708
2757
  });
2709
2758
  }
2710
- function createThrottledWebIdeMessageLogSync(cfg, ctx, onError) {
2759
+ function createThrottledWebIdeMessageLogSync(cfg, ctx, onError, options) {
2711
2760
  let lastRunAt = 0;
2712
2761
  let timer;
2713
2762
  let latestSession;
2714
2763
  let syncChain = Promise.resolve();
2715
2764
  let minio;
2716
2765
  let bucket = "";
2766
+ let firstLogNotified = false;
2717
2767
  const ensureMinio = async () => {
2718
2768
  if (minio) return;
2719
- const storage = await fetchDeployArtifactStorage(createApmApiClient(cfg));
2720
- minio = new MinioClient({
2721
- endPoint: storage.endpoint,
2722
- port: storage.port,
2723
- useSSL: storage.useSsl,
2724
- accessKey: storage.accessKey,
2725
- secretKey: storage.secretKey
2726
- });
2727
- bucket = storage.bucket;
2769
+ const created = createApmLogMinioClient();
2770
+ minio = created.client;
2771
+ bucket = created.bucket;
2728
2772
  await minio.ensureBucket(bucket);
2729
2773
  };
2774
+ const notifyFirstLog = async () => {
2775
+ if (firstLogNotified) return;
2776
+ firstLogNotified = true;
2777
+ try {
2778
+ await options?.onFirstLogSynced?.();
2779
+ } catch (err) {
2780
+ firstLogNotified = false;
2781
+ onError(err);
2782
+ }
2783
+ };
2730
2784
  const syncDirtyEventsOnce = async (session) => {
2731
2785
  const events = session.getDirtyEvents();
2732
2786
  if (events.length === 0) return;
@@ -2739,6 +2793,7 @@ function createThrottledWebIdeMessageLogSync(cfg, ctx, onError) {
2739
2793
  eventCount: session.getEventCount()
2740
2794
  });
2741
2795
  session.clearDirtyIfUnchanged(events);
2796
+ await notifyFirstLog();
2742
2797
  } catch (err) {
2743
2798
  onError(err);
2744
2799
  }
@@ -3768,98 +3823,189 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
3768
3823
  `[apm] webide-message action=${msg.action} taskId=${taskId} messageId=${messageId}`
3769
3824
  );
3770
3825
  await updateStatus(cfg, messageId, "TYPING");
3826
+ const eventSession = new EventSession(msg.content);
3827
+ const prepAgentId = loadWebIdeAgentId(workdir, taskId) ?? "webide-cli-prep";
3828
+ const logSyncRef = {
3829
+ current: createThrottledWebIdeMessageLogSync(
3830
+ cfg,
3831
+ { taskId, messageId, agentId: prepAgentId },
3832
+ (err) => {
3833
+ console.warn(
3834
+ "[apm] WebIDE \u65E5\u5FD7\u540C\u6B65\u5931\u8D25:",
3835
+ err instanceof Error ? err.message : err
3836
+ );
3837
+ }
3838
+ )
3839
+ };
3840
+ const syncPrepLog = async () => {
3841
+ const sync = logSyncRef.current;
3842
+ if (!sync) return;
3843
+ sync.schedule(eventSession);
3844
+ await sync.flush(eventSession);
3845
+ };
3846
+ const runPrepStep = async (step, work, formatOk) => {
3847
+ eventSession.addCliStep(step, "\u8FDB\u884C\u4E2D\u2026", "running");
3848
+ await syncPrepLog();
3849
+ try {
3850
+ const result = await work();
3851
+ eventSession.addCliStep(step, formatOk(result), "ok");
3852
+ await syncPrepLog();
3853
+ return result;
3854
+ } catch (err) {
3855
+ const detail = err instanceof Error ? err.message : String(err);
3856
+ eventSession.addCliStep(step, detail, "error");
3857
+ await syncPrepLog();
3858
+ throw err;
3859
+ }
3860
+ };
3771
3861
  try {
3772
3862
  if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
3773
- const { didInit } = await ensureWorkspaceInitialized(workdir);
3774
- if (!didInit) {
3775
- assertApmGitignoredInRepo(workdir);
3776
- }
3863
+ await runPrepStep(
3864
+ "\u521D\u59CB\u5316\u5DE5\u4F5C\u533A",
3865
+ async () => {
3866
+ const { didInit } = await ensureWorkspaceInitialized(workdir);
3867
+ if (!didInit) {
3868
+ assertApmGitignoredInRepo(workdir);
3869
+ }
3870
+ return didInit;
3871
+ },
3872
+ (didInit) => didInit ? "\u5DF2\u521D\u59CB\u5316\u5DE5\u4F5C\u533A" : "\u5DE5\u4F5C\u533A\u5DF2\u5C31\u7EEA"
3873
+ );
3777
3874
  const cliVersion = readCliVersion();
3778
3875
  if (shouldSyncSkillsForCliVersion(workdir, cliVersion)) {
3779
3876
  if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
3780
- console.log(
3781
- `[apm] CLI \u7248\u672C ${cliVersion} \u4E0E\u5DE5\u4F5C\u533A\u8BB0\u5F55\u4E0D\u4E00\u81F4\uFF0C\u6267\u884C update-skills`
3877
+ await runPrepStep(
3878
+ "\u540C\u6B65 Skills",
3879
+ async () => {
3880
+ await syncWorkspaceSkills(cfg, workdir);
3881
+ markSkillsSyncedForCliVersion(workdir, cliVersion);
3882
+ return cliVersion;
3883
+ },
3884
+ (version) => `\u5DF2\u540C\u6B65\u81F3 CLI ${version}`
3782
3885
  );
3783
- await syncWorkspaceSkills(cfg, workdir);
3784
- markSkillsSyncedForCliVersion(workdir, cliVersion);
3785
- }
3786
- const workspaceRepos = resolveWorkspaceRepos(workdir);
3787
- try {
3788
- await enrichWorkspaceReposRemoteUrls(workspaceRepos);
3789
- } catch (err) {
3790
- console.warn(
3791
- "[apm] \u8865\u9F50 workspace-repos remoteUrl \u5931\u8D25:",
3792
- err instanceof Error ? err.message : err
3886
+ } else {
3887
+ eventSession.addCliStep(
3888
+ "\u540C\u6B65 Skills",
3889
+ `\u7248\u672C\u4E00\u81F4\uFF08${cliVersion}\uFF09\uFF0C\u8DF3\u8FC7`,
3890
+ "skip"
3793
3891
  );
3892
+ await syncPrepLog();
3794
3893
  }
3894
+ await runPrepStep(
3895
+ "\u5DE5\u4F5C\u533A\u4ED3\u5E93\u6E05\u5355",
3896
+ async () => {
3897
+ const workspaceRepos = resolveWorkspaceRepos(workdir);
3898
+ try {
3899
+ await enrichWorkspaceReposRemoteUrls(workspaceRepos);
3900
+ } catch (err) {
3901
+ console.warn(
3902
+ "[apm] \u8865\u9F50 workspace-repos remoteUrl \u5931\u8D25:",
3903
+ err instanceof Error ? err.message : err
3904
+ );
3905
+ }
3906
+ return workspaceRepos;
3907
+ },
3908
+ (repos) => `kind=${repos.kind} repos=${repos.repos.length}`
3909
+ );
3795
3910
  if (shouldRunBranch(branchCacheKey, workdir)) {
3796
3911
  if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
3797
- const branchResult = await runTaskBranch(taskId, { cwd: workdir });
3798
- markBranchDone(branchCacheKey, workdir);
3799
- console.log(
3800
- `[apm] webide branch ready kind=${branchResult.kind} branch=${branchResult.branch} repos=${branchResult.repos.length}`
3912
+ await runPrepStep(
3913
+ "\u51C6\u5907\u7279\u6027\u5206\u652F",
3914
+ async () => runTaskBranch(taskId, { cwd: workdir }),
3915
+ (branchResult) => {
3916
+ markBranchDone(branchCacheKey, workdir);
3917
+ return `kind=${branchResult.kind} branch=${branchResult.branch} repos=${branchResult.repos.length}`;
3918
+ }
3801
3919
  );
3802
3920
  } else {
3803
- console.log(
3804
- `[apm] step=branch skipped taskId=${taskId} workdir=${workdir}`
3805
- );
3921
+ eventSession.addCliStep("\u51C6\u5907\u7279\u6027\u5206\u652F", "\u5DF2\u7F13\u5B58\uFF0C\u8DF3\u8FC7", "skip");
3922
+ await syncPrepLog();
3806
3923
  }
3807
3924
  if (shouldEnsureWebIdePullRequests(msg.action)) {
3808
3925
  if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
3809
- const pushed = await pushWorkspaceRepos(workdir);
3810
- console.log(
3811
- `[apm] webide \u6D4B\u8BD5\u524D push action=${msg.action} repos=${pushed}`
3926
+ await runPrepStep(
3927
+ "\u6D4B\u8BD5\u524D\u63A8\u9001",
3928
+ async () => pushWorkspaceRepos(workdir),
3929
+ (pushed) => `\u5DF2 push ${pushed} \u4E2A\u4ED3\u5E93`
3812
3930
  );
3813
3931
  if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
3814
- await ensureWebIdePullRequests(cfg, taskId, workdir);
3932
+ await runPrepStep(
3933
+ "\u786E\u4FDD PR",
3934
+ async () => {
3935
+ await ensureWebIdePullRequests(cfg, taskId, workdir);
3936
+ return true;
3937
+ },
3938
+ () => "PR \u68C0\u67E5\u5B8C\u6210"
3939
+ );
3815
3940
  }
3816
3941
  if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
3817
3942
  const api = createApmApiClient(cfg);
3818
3943
  let projectId = null;
3819
- try {
3820
- const baseline = await api.cli.projectBaseBranch({ taskId });
3821
- projectId = baseline.projectId?.trim() || null;
3822
- if (projectId) {
3823
- const docs = await syncProjectDocumentsPull(workdir, void 0, {
3824
- projectId
3825
- });
3826
- if (docs.synced) {
3827
- console.log(
3828
- `[apm] webide \u9879\u76EE\u6587\u6863\u5DF2\u5C31\u7EEA projectId=${projectId} downloaded=${docs.downloaded} deleted=${docs.deleted}`
3944
+ await runPrepStep(
3945
+ "\u540C\u6B65\u9879\u76EE\u6587\u6863",
3946
+ async () => {
3947
+ try {
3948
+ const baseline = await api.cli.projectBaseBranch({ taskId });
3949
+ projectId = baseline.projectId?.trim() || null;
3950
+ if (!projectId) {
3951
+ return { synced: false, reason: "\u65E0 projectId" };
3952
+ }
3953
+ const docs = await syncProjectDocumentsPull(workdir, void 0, {
3954
+ projectId
3955
+ });
3956
+ return {
3957
+ synced: docs.synced,
3958
+ downloaded: docs.downloaded,
3959
+ deleted: docs.deleted
3960
+ };
3961
+ } catch (err) {
3962
+ console.warn(
3963
+ "[apm] WebIDE \u9879\u76EE\u6587\u6863\u540C\u6B65\u5931\u8D25:",
3964
+ err instanceof Error ? err.message : err
3829
3965
  );
3966
+ return {
3967
+ synced: false,
3968
+ reason: err instanceof Error ? err.message : String(err)
3969
+ };
3830
3970
  }
3831
- } else {
3832
- console.warn(
3833
- `[apm] WebIDE \u65E0\u6CD5\u89E3\u6790\u4EFB\u52A1\u6240\u5C5E\u9879\u76EE\uFF0C\u8DF3\u8FC7\u9879\u76EE\u6587\u6863\u540C\u6B65 taskId=${taskId}`
3834
- );
3835
- }
3836
- } catch (err) {
3837
- console.warn(
3838
- "[apm] WebIDE \u9879\u76EE\u6587\u6863\u540C\u6B65\u5931\u8D25:",
3839
- err instanceof Error ? err.message : err
3840
- );
3841
- }
3842
- try {
3843
- const attachments = await api.cli.webideListAttachments({ taskId });
3844
- const names = await syncWebIdeAttachments(
3845
- cfg,
3846
- taskId,
3847
- workdir,
3848
- attachments ?? []
3849
- );
3850
- if (names.length > 0) {
3851
- console.log(
3852
- `[apm] webide \u9644\u4EF6\u5DF2\u5C31\u7EEA count=${names.length} dir=.apm/webide/${taskId}/attachments`
3853
- );
3971
+ },
3972
+ (result) => {
3973
+ if ("reason" in result && result.reason) {
3974
+ return `\u8DF3\u8FC7\uFF1A${result.reason}`;
3975
+ }
3976
+ if (!result.synced) return "\u65E0\u9700\u540C\u6B65";
3977
+ return `downloaded=${result.downloaded ?? 0} deleted=${result.deleted ?? 0}`;
3854
3978
  }
3855
- } catch (err) {
3856
- console.warn(
3857
- "[apm] WebIDE \u9644\u4EF6\u540C\u6B65\u5931\u8D25:",
3858
- err instanceof Error ? err.message : err
3859
- );
3860
- }
3979
+ );
3980
+ await runPrepStep(
3981
+ "\u540C\u6B65\u4EFB\u52A1\u9644\u4EF6",
3982
+ async () => {
3983
+ try {
3984
+ const attachments = await api.cli.webideListAttachments({ taskId });
3985
+ const names = await syncWebIdeAttachments(
3986
+ cfg,
3987
+ taskId,
3988
+ workdir,
3989
+ attachments ?? []
3990
+ );
3991
+ return names;
3992
+ } catch (err) {
3993
+ console.warn(
3994
+ "[apm] WebIDE \u9644\u4EF6\u540C\u6B65\u5931\u8D25:",
3995
+ err instanceof Error ? err.message : err
3996
+ );
3997
+ return [];
3998
+ }
3999
+ },
4000
+ (names) => names.length > 0 ? `\u5DF2\u540C\u6B65 ${names.length} \u4E2A\u9644\u4EF6` : "\u65E0\u9644\u4EF6\u6216\u540C\u6B65\u8DF3\u8FC7"
4001
+ );
4002
+ eventSession.addCliStep(
4003
+ "\u542F\u52A8 Cursor Agent",
4004
+ "\u51C6\u5907 resume/create\u2026",
4005
+ "running"
4006
+ );
4007
+ await syncPrepLog();
3861
4008
  const savedAgentId = loadWebIdeAgentId(workdir, taskId);
3862
- const logSyncRef = { current: null };
3863
4009
  const outcome = await runCursorAgent(
3864
4010
  cfg,
3865
4011
  {
@@ -3874,8 +4020,8 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
3874
4020
  },
3875
4021
  {
3876
4022
  signal,
3877
- // IDE 重启/异常中断后 Cursor 可能仍认为旧 run active;强制清残留再 send
3878
4023
  forceSend: true,
4024
+ eventSession,
3879
4025
  appendMessageContent: (content) => appendContent(cfg, messageId, content),
3880
4026
  askQuestionExecute: createWebIdeAskQuestionExecute({
3881
4027
  cfg,
@@ -3883,7 +4029,6 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
3883
4029
  signal
3884
4030
  }),
3885
4031
  enableWebIdePlanTools: true,
3886
- // 本地 SDK sandbox 会拦截 custom-user-tools MCP,WebIDE 先关闭
3887
4032
  enableSandbox: false,
3888
4033
  taskId,
3889
4034
  terminalRpc: options?.terminalRpc,
@@ -3903,7 +4048,14 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
3903
4048
  },
3904
4049
  onRunStarted: async ({ agentId, runId }) => {
3905
4050
  saveWebIdeAgentId(workdir, taskId, agentId);
4051
+ eventSession.addCliStep(
4052
+ "\u542F\u52A8 Cursor Agent",
4053
+ `agentId=${agentId} runId=${runId}`,
4054
+ "ok"
4055
+ );
4056
+ logSyncRef.current?.schedule(eventSession);
3906
4057
  await logSyncRef.current?.markRun(runId, "running");
4058
+ await logSyncRef.current?.flush(eventSession);
3907
4059
  }
3908
4060
  }
3909
4061
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "7.1.27",
3
+ "version": "7.1.29",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,