ai-project-manage-cli 7.1.1 → 7.1.2

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
@@ -449,6 +449,14 @@ var requestConfig = {
449
449
  method: "PUT",
450
450
  path: "/cli/webide/message-logs"
451
451
  }),
452
+ webideReplaceAssumptions: defineEndpoint({
453
+ method: "PUT",
454
+ path: "/cli/webide/assumptions"
455
+ }),
456
+ webideListAssumptions: defineEndpoint({
457
+ method: "GET",
458
+ path: "/cli/webide/assumptions"
459
+ }),
452
460
  branchBaseline: defineEndpoint({
453
461
  method: "GET",
454
462
  path: "/cli/tasks/branch-baseline"
@@ -2719,13 +2727,32 @@ function validateSessionCacheCleanupPush(o) {
2719
2727
  }
2720
2728
  };
2721
2729
  }
2730
+ function validateWebIdeCacheCleanupPush(o) {
2731
+ if (o.type !== "webide-cache-cleanup") {
2732
+ return { ok: false, reason: "\u671F\u671B webide-cache-cleanup" };
2733
+ }
2734
+ if (!nonEmptyString(o.taskId)) {
2735
+ return { ok: false, reason: "webide-cache-cleanup \u7F3A\u5C11 taskId" };
2736
+ }
2737
+ if (!nonEmptyString(o.workdir)) {
2738
+ return { ok: false, reason: "webide-cache-cleanup \u7F3A\u5C11 workdir" };
2739
+ }
2740
+ return {
2741
+ ok: true,
2742
+ data: {
2743
+ type: "webide-cache-cleanup",
2744
+ taskId: o.taskId.trim(),
2745
+ workdir: o.workdir.trim()
2746
+ }
2747
+ };
2748
+ }
2722
2749
  function validateAgentWsMessage(value, kind) {
2723
2750
  if (typeof value !== "object" || value === null) {
2724
2751
  return { ok: false, reason: "\u6D88\u606F\u4F53\u4E0D\u662F JSON \u5BF9\u8C61" };
2725
2752
  }
2726
2753
  const o = value;
2727
2754
  const type = o.type;
2728
- if (type !== "heartbeat" && type !== "message" && type !== "webide-message" && type !== "cancel" && type !== "deploy" && type !== "session-cache-cleanup") {
2755
+ if (type !== "heartbeat" && type !== "message" && type !== "webide-message" && type !== "cancel" && type !== "deploy" && type !== "session-cache-cleanup" && type !== "webide-cache-cleanup") {
2729
2756
  return { ok: false, reason: `\u672A\u77E5 type: ${String(type)}` };
2730
2757
  }
2731
2758
  if (kind === "heartbeat" || type === "heartbeat") {
@@ -2740,6 +2767,9 @@ function validateAgentWsMessage(value, kind) {
2740
2767
  if (type === "session-cache-cleanup") {
2741
2768
  return validateSessionCacheCleanupPush(o);
2742
2769
  }
2770
+ if (type === "webide-cache-cleanup") {
2771
+ return validateWebIdeCacheCleanupPush(o);
2772
+ }
2743
2773
  if (type === "webide-message") {
2744
2774
  return validateWebIdeMessagePush(o);
2745
2775
  }
@@ -3194,14 +3224,14 @@ var MinioClient = class {
3194
3224
  async deleteObjectsByPrefix(bucket, prefix) {
3195
3225
  const objectsStream = this.inner.listObjectsV2(bucket, prefix, true);
3196
3226
  const keys = [];
3197
- await new Promise((resolve6, reject) => {
3227
+ await new Promise((resolve7, reject) => {
3198
3228
  objectsStream.on("data", (obj) => {
3199
3229
  if (obj.name) {
3200
3230
  keys.push(obj.name);
3201
3231
  }
3202
3232
  });
3203
3233
  objectsStream.on("error", reject);
3204
- objectsStream.on("end", resolve6);
3234
+ objectsStream.on("end", resolve7);
3205
3235
  });
3206
3236
  const chunkSize = 500;
3207
3237
  for (let i = 0; i < keys.length; i += chunkSize) {
@@ -4661,7 +4691,7 @@ function buildSftpConnectOptions(settings) {
4661
4691
  };
4662
4692
  }
4663
4693
  async function sleep(ms) {
4664
- await new Promise((resolve6) => setTimeout(resolve6, ms));
4694
+ await new Promise((resolve7) => setTimeout(resolve7, ms));
4665
4695
  }
4666
4696
  async function uploadZipWithRetry(settings, localZip, remoteZipPath) {
4667
4697
  let lastError;
@@ -4705,7 +4735,7 @@ async function ensureRemoteDir(sftp, dir) {
4705
4735
  }
4706
4736
  }
4707
4737
  function execCommand(client, command) {
4708
- return new Promise((resolve6, reject) => {
4738
+ return new Promise((resolve7, reject) => {
4709
4739
  client.exec(command, (err, stream) => {
4710
4740
  if (err) return reject(err);
4711
4741
  let stdout = "";
@@ -4715,7 +4745,7 @@ function execCommand(client, command) {
4715
4745
  reject(new Error(`\u8FDC\u7A0B\u547D\u4EE4\u5931\u8D25 (${code}): ${stderr || stdout}`));
4716
4746
  return;
4717
4747
  }
4718
- resolve6(stdout);
4748
+ resolve7(stdout);
4719
4749
  }).on("data", (data) => {
4720
4750
  stdout += data.toString();
4721
4751
  });
@@ -5190,8 +5220,8 @@ function springbootOutputIndicatesSuccess(action, combined) {
5190
5220
  async function connectSsh(config) {
5191
5221
  const client = new Client2();
5192
5222
  log(`\u8FDE\u63A5\u670D\u52A1\u5668 ${config.username}@${config.host}:${config.port}`);
5193
- await new Promise((resolve6, reject) => {
5194
- client.on("ready", () => resolve6()).on("error", (err) => reject(err)).connect({
5223
+ await new Promise((resolve7, reject) => {
5224
+ client.on("ready", () => resolve7()).on("error", (err) => reject(err)).connect({
5195
5225
  host: config.host,
5196
5226
  port: config.port,
5197
5227
  username: config.username,
@@ -5259,7 +5289,7 @@ async function runRemoteCommand(client, command, options) {
5259
5289
  const check = options?.check ?? true;
5260
5290
  const stream = options?.stream ?? false;
5261
5291
  const label = options?.label ?? "\u8FDC\u7A0B\u547D\u4EE4";
5262
- return new Promise((resolve6, reject) => {
5292
+ return new Promise((resolve7, reject) => {
5263
5293
  client.exec(command, (err, execStream) => {
5264
5294
  if (err) {
5265
5295
  reject(err);
@@ -5289,7 +5319,7 @@ ${errText}`.trim();
5289
5319
  \u8F93\u51FA: ${combined}` : "")
5290
5320
  );
5291
5321
  }
5292
- resolve6({ exitCode: code, out: out.trim(), err: errText.trim() });
5322
+ resolve7({ exitCode: code, out: out.trim(), err: errText.trim() });
5293
5323
  });
5294
5324
  });
5295
5325
  });
@@ -6164,6 +6194,24 @@ function cleanSessionWorkspaceCache(sessionId, workdir) {
6164
6194
  clearPreStepCacheForSession(trimmedSessionId, trimmedWorkdir);
6165
6195
  }
6166
6196
 
6197
+ // src/commands/clean-webide-cache.ts
6198
+ import { existsSync as existsSync22, rmSync as rmSync5 } from "node:fs";
6199
+ import { resolve as resolve5 } from "node:path";
6200
+ function cleanWebIdeWorkspaceCache(taskId, workdir) {
6201
+ const trimmedTaskId = taskId.trim();
6202
+ const trimmedWorkdir = workdir.trim();
6203
+ if (!trimmedTaskId || !trimmedWorkdir) {
6204
+ return;
6205
+ }
6206
+ const dir = resolve5(trimmedWorkdir, ".apm", "webide", trimmedTaskId);
6207
+ if (existsSync22(dir)) {
6208
+ rmSync5(dir, { recursive: true, force: true });
6209
+ console.log(`[apm] \u5DF2\u6E05\u7406 WebIDE \u7F13\u5B58 ${dir}`);
6210
+ } else {
6211
+ console.log(`[apm] WebIDE \u7F13\u5B58\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7 ${dir}`);
6212
+ }
6213
+ }
6214
+
6167
6215
  // src/commands/connect/abort-signal-debug.ts
6168
6216
  import {
6169
6217
  getEventListeners,
@@ -6434,13 +6482,13 @@ ${JSON.stringify(event, null, 2)}
6434
6482
  }
6435
6483
 
6436
6484
  // src/commands/connect/agent-session-registry.ts
6437
- import { existsSync as existsSync22, mkdirSync as mkdirSync9, readFileSync as readFileSync16, writeFileSync as writeFileSync14 } from "node:fs";
6438
- import { dirname as dirname6, resolve as resolve5 } from "node:path";
6485
+ import { existsSync as existsSync23, mkdirSync as mkdirSync9, readFileSync as readFileSync16, writeFileSync as writeFileSync14 } from "node:fs";
6486
+ import { dirname as dirname6, resolve as resolve6 } from "node:path";
6439
6487
  function registryPath(workdir, sessionId) {
6440
- return resolve5(workdir, ".apm", "sessions", sessionId, "cursor-agents.json");
6488
+ return resolve6(workdir, ".apm", "sessions", sessionId, "cursor-agents.json");
6441
6489
  }
6442
6490
  function readRegistry(path19) {
6443
- if (!existsSync22(path19)) {
6491
+ if (!existsSync23(path19)) {
6444
6492
  return {};
6445
6493
  }
6446
6494
  try {
@@ -6600,50 +6648,54 @@ function createAppendMessageCustomTools(cfg, messageId, appendContent) {
6600
6648
  }
6601
6649
 
6602
6650
  // src/commands/connect/ask-question-tool.ts
6603
- function createAskQuestionMockTool(options) {
6651
+ var INPUT_SCHEMA = {
6652
+ type: "object",
6653
+ properties: {
6654
+ title: {
6655
+ type: "string",
6656
+ description: "Optional title for the questions form"
6657
+ },
6658
+ questions: {
6659
+ type: "array",
6660
+ minItems: 1,
6661
+ items: {
6662
+ type: "object",
6663
+ properties: {
6664
+ id: { type: "string" },
6665
+ prompt: { type: "string" },
6666
+ allow_multiple: { type: "boolean" },
6667
+ options: {
6668
+ type: "array",
6669
+ minItems: 2,
6670
+ items: {
6671
+ type: "object",
6672
+ properties: {
6673
+ id: { type: "string" },
6674
+ label: { type: "string" }
6675
+ },
6676
+ required: ["id", "label"]
6677
+ }
6678
+ }
6679
+ },
6680
+ required: ["id", "prompt", "options"]
6681
+ }
6682
+ }
6683
+ },
6684
+ required: ["questions"]
6685
+ };
6686
+ function createAskQuestionTool(options) {
6604
6687
  return {
6605
6688
  description: "Collect structured multiple-choice answers from the user. Use when blocked on a decision that is genuinely the user's to make.",
6606
- inputSchema: {
6607
- type: "object",
6608
- properties: {
6609
- title: {
6610
- type: "string",
6611
- description: "Optional title for the questions form"
6612
- },
6613
- questions: {
6614
- type: "array",
6615
- minItems: 1,
6616
- items: {
6617
- type: "object",
6618
- properties: {
6619
- id: { type: "string" },
6620
- prompt: { type: "string" },
6621
- allow_multiple: { type: "boolean" },
6622
- options: {
6623
- type: "array",
6624
- minItems: 2,
6625
- items: {
6626
- type: "object",
6627
- properties: {
6628
- id: { type: "string" },
6629
- label: { type: "string" }
6630
- },
6631
- required: ["id", "label"]
6632
- }
6633
- }
6634
- },
6635
- required: ["id", "prompt", "options"]
6636
- }
6637
- }
6638
- },
6639
- required: ["questions"]
6640
- },
6689
+ inputSchema: INPUT_SCHEMA,
6641
6690
  execute: async (args) => {
6691
+ options?.onInvoke?.(args);
6692
+ if (options?.execute) {
6693
+ return options.execute(args);
6694
+ }
6642
6695
  const payload = JSON.stringify(args, null, 2);
6643
- console.log(`[apm] AskQuestion mock \u8C03\u7528:
6696
+ console.log(`[apm] AskQuestion\uFF08\u672C\u5730\u5360\u4F4D\uFF0C\u672A\u7B49\u5F85\u7528\u6237\uFF09:
6644
6697
  ${payload}`);
6645
- options?.onInvoke?.(args);
6646
- return `[mock] AskQuestion \u5DF2\u8BB0\u5F55\uFF08\u672A\u521B\u5EFA\u4EFB\u52A1\u95EE\u9898\u3001\u672A\u7B49\u5F85\u7528\u6237\u56DE\u7B54\uFF09\u3002\u53C2\u6570:
6698
+ return `[local] AskQuestion \u5DF2\u8BB0\u5F55\uFF08\u672A\u521B\u5EFA\u4EFB\u52A1\u95EE\u9898\u3001\u672A\u7B49\u5F85\u7528\u6237\u56DE\u7B54\uFF09\u3002\u53C2\u6570:
6647
6699
  ${payload}`;
6648
6700
  }
6649
6701
  };
@@ -6661,8 +6713,9 @@ function createCursorCustomTools(cfg, messageId, options) {
6661
6713
  messageId,
6662
6714
  options?.appendMessageContent
6663
6715
  ),
6664
- AskQuestion: createAskQuestionMockTool({
6665
- onInvoke: options?.onAskQuestion
6716
+ AskQuestion: createAskQuestionTool({
6717
+ onInvoke: options?.onAskQuestion,
6718
+ execute: options?.askQuestionExecute
6666
6719
  })
6667
6720
  };
6668
6721
  }
@@ -6676,7 +6729,7 @@ ${PLAN_MODE_ASK_QUESTION_HINT}`;
6676
6729
  }
6677
6730
 
6678
6731
  // src/commands/connect/cursor-agent.ts
6679
- setMaxListeners2(50);
6732
+ setMaxListeners2(100);
6680
6733
  installAbortSignalDebug();
6681
6734
  var noopRemoteLogSync = {
6682
6735
  schedule(_session) {
@@ -6754,7 +6807,8 @@ async function runCursorAgent(cfg, ctx, options) {
6754
6807
  const workdir = resolveWorkdirPath(ctx.workdir);
6755
6808
  const customTools = createCursorCustomTools(cfg, ctx.messageId, {
6756
6809
  onAskQuestion: options?.onAskQuestion,
6757
- appendMessageContent: options?.appendMessageContent
6810
+ appendMessageContent: options?.appendMessageContent,
6811
+ askQuestionExecute: options?.askQuestionExecute
6758
6812
  });
6759
6813
  const prompt = withPlanModeToolHint(ctx.prompt, ctx.mode);
6760
6814
  console.log(
@@ -6919,7 +6973,7 @@ async function ensureMessageHasReply(cfg, sessionId, messageId, fallback) {
6919
6973
  }
6920
6974
 
6921
6975
  // src/commands/connect/cli-version-sync.ts
6922
- import { existsSync as existsSync23, readFileSync as readFileSync17, writeFileSync as writeFileSync15 } from "fs";
6976
+ import { existsSync as existsSync24, readFileSync as readFileSync17, writeFileSync as writeFileSync15 } from "fs";
6923
6977
  import { join as join18 } from "path";
6924
6978
  var CLI_VERSION_FILE = ".cli-version.json";
6925
6979
  function manifestPath(apmDir) {
@@ -6927,7 +6981,7 @@ function manifestPath(apmDir) {
6927
6981
  }
6928
6982
  function loadManifest4(apmDir) {
6929
6983
  const path19 = toFsPath(manifestPath(apmDir));
6930
- if (!existsSync23(path19)) {
6984
+ if (!existsSync24(path19)) {
6931
6985
  return null;
6932
6986
  }
6933
6987
  try {
@@ -6997,7 +7051,7 @@ function createRunSlotPool(maxConcurrent = DEFAULT_MAX_CONCURRENT, options = {})
6997
7051
  );
6998
7052
  }
6999
7053
  const queuedAt = Date.now();
7000
- return new Promise((resolve6) => {
7054
+ return new Promise((resolve7) => {
7001
7055
  waiters.push(() => {
7002
7056
  active += 1;
7003
7057
  const waitedMs = Date.now() - queuedAt;
@@ -7008,7 +7062,7 @@ function createRunSlotPool(maxConcurrent = DEFAULT_MAX_CONCURRENT, options = {})
7008
7062
  )}s\uFF0C\u5F53\u524D\u5360\u7528 ${active}/${maxConcurrent}`
7009
7063
  );
7010
7064
  }
7011
- resolve6();
7065
+ resolve7();
7012
7066
  });
7013
7067
  });
7014
7068
  };
@@ -7038,19 +7092,22 @@ function spawnWebIdeMessageWorker(cfg, msg) {
7038
7092
  workerData: { cfg, msg }
7039
7093
  });
7040
7094
  let resolveDone;
7041
- const done = new Promise((resolve6) => {
7042
- resolveDone = resolve6;
7095
+ const done = new Promise((resolve7) => {
7096
+ resolveDone = resolve7;
7043
7097
  });
7044
- worker.on("message", (m) => {
7045
- if (m?.type === "done" || m?.type === "error") {
7046
- if (m.type === "error") {
7047
- console.error(
7048
- `[apm] webide worker error messageId=${m.messageId}: ${m.error}`
7049
- );
7098
+ worker.on(
7099
+ "message",
7100
+ (m) => {
7101
+ if (m?.type === "done" || m?.type === "error") {
7102
+ if (m.type === "error") {
7103
+ console.error(
7104
+ `[apm] webide worker error messageId=${m.messageId}: ${m.error}`
7105
+ );
7106
+ }
7107
+ void worker.terminate().finally(() => resolveDone());
7050
7108
  }
7051
- void worker.terminate().finally(() => resolveDone());
7052
7109
  }
7053
- });
7110
+ );
7054
7111
  worker.on("error", (err) => {
7055
7112
  console.error("[apm] webide worker crashed:", err);
7056
7113
  resolveDone();
@@ -7061,7 +7118,6 @@ function spawnWebIdeMessageWorker(cfg, msg) {
7061
7118
  }
7062
7119
  resolveDone();
7063
7120
  });
7064
- worker.postMessage({ type: "run", cfg, msg });
7065
7121
  return {
7066
7122
  cancel(messageId) {
7067
7123
  worker.postMessage({ type: "cancel", messageId });
@@ -7228,11 +7284,11 @@ async function handleInboundMessage(cfg, msg, signal, ctx) {
7228
7284
  }
7229
7285
  function interruptibleSleep(ms, signal) {
7230
7286
  if (signal.aborted) return Promise.resolve();
7231
- return new Promise((resolve6) => {
7232
- const timer = setTimeout(resolve6, ms);
7287
+ return new Promise((resolve7) => {
7288
+ const timer = setTimeout(resolve7, ms);
7233
7289
  const onAbort = () => {
7234
7290
  clearTimeout(timer);
7235
- resolve6();
7291
+ resolve7();
7236
7292
  };
7237
7293
  signal.addEventListener("abort", onAbort, { once: true });
7238
7294
  });
@@ -7324,6 +7380,18 @@ function attachWsHandlers(ws, ctx, onOpen) {
7324
7380
  });
7325
7381
  return;
7326
7382
  }
7383
+ if (validated.data.type === "webide-cache-cleanup") {
7384
+ const msg2 = validated.data;
7385
+ const task2 = (async () => {
7386
+ const workdir = requireRemoteWorkdir(msg2.workdir);
7387
+ cleanWebIdeWorkspaceCache(msg2.taskId, workdir);
7388
+ })();
7389
+ activeTasks.add(task2);
7390
+ void task2.finally(() => {
7391
+ activeTasks.delete(task2);
7392
+ });
7393
+ return;
7394
+ }
7327
7395
  if (validated.data.type === "webide-message") {
7328
7396
  const msg2 = validated.data;
7329
7397
  const perMessageController2 = new AbortController();
@@ -7412,7 +7480,7 @@ function attachWsHandlers(ws, ctx, onOpen) {
7412
7480
  });
7413
7481
  }
7414
7482
  function connectOnce(url, ctx, connectionAbort, onConnected) {
7415
- return new Promise((resolve6, reject) => {
7483
+ return new Promise((resolve7, reject) => {
7416
7484
  const ws = new WebSocket(url);
7417
7485
  let stopHeartbeat;
7418
7486
  let settled = false;
@@ -7441,7 +7509,7 @@ function connectOnce(url, ctx, connectionAbort, onConnected) {
7441
7509
  finish(() => reject(new Error("shutdown")));
7442
7510
  return;
7443
7511
  }
7444
- finish(resolve6);
7512
+ finish(resolve7);
7445
7513
  });
7446
7514
  ws.on("error", (err) => {
7447
7515
  console.error("[apm] WebSocket \u9519\u8BEF:", err.message);
@@ -7838,7 +7906,7 @@ import path15 from "node:path";
7838
7906
  import Docker from "dockerode";
7839
7907
 
7840
7908
  // src/commands/deploy/internal/backend-deploy/dockerode-client/connection-options.ts
7841
- import { existsSync as existsSync24, readFileSync as readFileSync18 } from "node:fs";
7909
+ import { existsSync as existsSync25, readFileSync as readFileSync18 } from "node:fs";
7842
7910
  import path12 from "node:path";
7843
7911
  function asOptionalTlsBuffer(value) {
7844
7912
  if (typeof value !== "string") {
@@ -7850,7 +7918,7 @@ function asOptionalTlsBuffer(value) {
7850
7918
  if (normalized === "") {
7851
7919
  return void 0;
7852
7920
  }
7853
- if (existsSync24(normalized)) {
7921
+ if (existsSync25(normalized)) {
7854
7922
  return readFileSync18(normalized);
7855
7923
  }
7856
7924
  const looksLikePath = /[\\/]/.test(normalized) || normalized.endsWith(".pem");
@@ -7976,17 +8044,17 @@ var DockerodeClient = class {
7976
8044
  await this.client.getImage(image).remove({ force: true });
7977
8045
  }
7978
8046
  async pullImage(image, auth) {
7979
- const stream = await new Promise((resolve6, reject) => {
8047
+ const stream = await new Promise((resolve7, reject) => {
7980
8048
  const pullOptions = auth ? { authconfig: auth } : void 0;
7981
8049
  this.client.pull(image, pullOptions, (err, output) => {
7982
8050
  if (err || !output) {
7983
8051
  reject(err ?? new Error("docker pull \u8FD4\u56DE\u7A7A\u8F93\u51FA"));
7984
8052
  return;
7985
8053
  }
7986
- resolve6(output);
8054
+ resolve7(output);
7987
8055
  });
7988
8056
  });
7989
- await new Promise((resolve6, reject) => {
8057
+ await new Promise((resolve7, reject) => {
7990
8058
  this.client.modem.followProgress(
7991
8059
  stream,
7992
8060
  (err) => {
@@ -7994,7 +8062,7 @@ var DockerodeClient = class {
7994
8062
  reject(err);
7995
8063
  return;
7996
8064
  }
7997
- resolve6();
8065
+ resolve7();
7998
8066
  },
7999
8067
  () => void 0
8000
8068
  );
@@ -8061,7 +8129,7 @@ var DockerodeClient = class {
8061
8129
  var createDockerodeClient = (config) => new DockerodeClient(config);
8062
8130
 
8063
8131
  // src/commands/deploy/internal/backend-deploy/dockerode-client/env.ts
8064
- import { existsSync as existsSync25, readFileSync as readFileSync19, statSync as statSync10 } from "node:fs";
8132
+ import { existsSync as existsSync26, readFileSync as readFileSync19, statSync as statSync10 } from "node:fs";
8065
8133
  import path13 from "node:path";
8066
8134
  function stripSurroundingQuotes(value) {
8067
8135
  const t = value.trim();
@@ -8078,7 +8146,7 @@ function loadEnvFromFile(envFilePath) {
8078
8146
  return {};
8079
8147
  }
8080
8148
  const targetPath = path13.resolve(envFilePath);
8081
- if (!existsSync25(targetPath) || !statSync10(targetPath).isFile()) {
8149
+ if (!existsSync26(targetPath) || !statSync10(targetPath).isFile()) {
8082
8150
  return {};
8083
8151
  }
8084
8152
  const raw = readFileSync19(targetPath, "utf-8");
@@ -8252,12 +8320,12 @@ function dockerPushImage(params, cwd) {
8252
8320
  }
8253
8321
 
8254
8322
  // src/commands/deploy/internal/backend-deploy/resolve-dockerfile.ts
8255
- import { existsSync as existsSync26 } from "node:fs";
8323
+ import { existsSync as existsSync27 } from "node:fs";
8256
8324
  import path14 from "node:path";
8257
8325
  function resolveDockerBuildPaths(cwd) {
8258
8326
  const dockerfilePath = path14.join(cwd, "Dockerfile");
8259
8327
  Logger.info(`\u67E5\u627EDockerfile\u6587\u4EF6\uFF0C\u8DEF\u5F84: ${dockerfilePath}`);
8260
- if (!existsSync26(dockerfilePath)) {
8328
+ if (!existsSync27(dockerfilePath)) {
8261
8329
  throw new Error(`Dockerfile \u4E0D\u5B58\u5728\uFF1A${dockerfilePath}`);
8262
8330
  }
8263
8331
  Logger.info("\u2713 Dockerfile \u5B58\u5728");
@@ -80,6 +80,14 @@ var requestConfig = {
80
80
  method: "PUT",
81
81
  path: "/cli/webide/message-logs"
82
82
  }),
83
+ webideReplaceAssumptions: defineEndpoint({
84
+ method: "PUT",
85
+ path: "/cli/webide/assumptions"
86
+ }),
87
+ webideListAssumptions: defineEndpoint({
88
+ method: "GET",
89
+ path: "/cli/webide/assumptions"
90
+ }),
83
91
  branchBaseline: defineEndpoint({
84
92
  method: "GET",
85
93
  path: "/cli/tasks/branch-baseline"
@@ -883,50 +891,54 @@ function createAppendMessageCustomTools(cfg, messageId, appendContent2) {
883
891
  }
884
892
 
885
893
  // src/commands/connect/ask-question-tool.ts
886
- function createAskQuestionMockTool(options) {
894
+ var INPUT_SCHEMA = {
895
+ type: "object",
896
+ properties: {
897
+ title: {
898
+ type: "string",
899
+ description: "Optional title for the questions form"
900
+ },
901
+ questions: {
902
+ type: "array",
903
+ minItems: 1,
904
+ items: {
905
+ type: "object",
906
+ properties: {
907
+ id: { type: "string" },
908
+ prompt: { type: "string" },
909
+ allow_multiple: { type: "boolean" },
910
+ options: {
911
+ type: "array",
912
+ minItems: 2,
913
+ items: {
914
+ type: "object",
915
+ properties: {
916
+ id: { type: "string" },
917
+ label: { type: "string" }
918
+ },
919
+ required: ["id", "label"]
920
+ }
921
+ }
922
+ },
923
+ required: ["id", "prompt", "options"]
924
+ }
925
+ }
926
+ },
927
+ required: ["questions"]
928
+ };
929
+ function createAskQuestionTool(options) {
887
930
  return {
888
931
  description: "Collect structured multiple-choice answers from the user. Use when blocked on a decision that is genuinely the user's to make.",
889
- inputSchema: {
890
- type: "object",
891
- properties: {
892
- title: {
893
- type: "string",
894
- description: "Optional title for the questions form"
895
- },
896
- questions: {
897
- type: "array",
898
- minItems: 1,
899
- items: {
900
- type: "object",
901
- properties: {
902
- id: { type: "string" },
903
- prompt: { type: "string" },
904
- allow_multiple: { type: "boolean" },
905
- options: {
906
- type: "array",
907
- minItems: 2,
908
- items: {
909
- type: "object",
910
- properties: {
911
- id: { type: "string" },
912
- label: { type: "string" }
913
- },
914
- required: ["id", "label"]
915
- }
916
- }
917
- },
918
- required: ["id", "prompt", "options"]
919
- }
920
- }
921
- },
922
- required: ["questions"]
923
- },
932
+ inputSchema: INPUT_SCHEMA,
924
933
  execute: async (args) => {
934
+ options?.onInvoke?.(args);
935
+ if (options?.execute) {
936
+ return options.execute(args);
937
+ }
925
938
  const payload = JSON.stringify(args, null, 2);
926
- console.log(`[apm] AskQuestion mock \u8C03\u7528:
939
+ console.log(`[apm] AskQuestion\uFF08\u672C\u5730\u5360\u4F4D\uFF0C\u672A\u7B49\u5F85\u7528\u6237\uFF09:
927
940
  ${payload}`);
928
- options?.onInvoke?.(args);
929
- return `[mock] AskQuestion \u5DF2\u8BB0\u5F55\uFF08\u672A\u521B\u5EFA\u4EFB\u52A1\u95EE\u9898\u3001\u672A\u7B49\u5F85\u7528\u6237\u56DE\u7B54\uFF09\u3002\u53C2\u6570:
941
+ return `[local] AskQuestion \u5DF2\u8BB0\u5F55\uFF08\u672A\u521B\u5EFA\u4EFB\u52A1\u95EE\u9898\u3001\u672A\u7B49\u5F85\u7528\u6237\u56DE\u7B54\uFF09\u3002\u53C2\u6570:
930
942
  ${payload}`;
931
943
  }
932
944
  };
@@ -944,8 +956,9 @@ function createCursorCustomTools(cfg, messageId, options) {
944
956
  messageId,
945
957
  options?.appendMessageContent
946
958
  ),
947
- AskQuestion: createAskQuestionMockTool({
948
- onInvoke: options?.onAskQuestion
959
+ AskQuestion: createAskQuestionTool({
960
+ onInvoke: options?.onAskQuestion,
961
+ execute: options?.askQuestionExecute
949
962
  })
950
963
  };
951
964
  }
@@ -959,7 +972,7 @@ ${PLAN_MODE_ASK_QUESTION_HINT}`;
959
972
  }
960
973
 
961
974
  // src/commands/connect/cursor-agent.ts
962
- setMaxListeners2(50);
975
+ setMaxListeners2(100);
963
976
  installAbortSignalDebug();
964
977
  var noopRemoteLogSync = {
965
978
  schedule(_session) {
@@ -1037,7 +1050,8 @@ async function runCursorAgent(cfg, ctx, options) {
1037
1050
  const workdir = resolveWorkdirPath(ctx.workdir);
1038
1051
  const customTools = createCursorCustomTools(cfg, ctx.messageId, {
1039
1052
  onAskQuestion: options?.onAskQuestion,
1040
- appendMessageContent: options?.appendMessageContent
1053
+ appendMessageContent: options?.appendMessageContent,
1054
+ askQuestionExecute: options?.askQuestionExecute
1041
1055
  });
1042
1056
  const prompt = withPlanModeToolHint(ctx.prompt, ctx.mode);
1043
1057
  console.log(
@@ -1204,6 +1218,97 @@ function clearWebIdeAgentId(workdir, taskId) {
1204
1218
  writeRegistry2(path, {});
1205
1219
  }
1206
1220
 
1221
+ // src/commands/connect/webide-ask-question.ts
1222
+ import { setTimeout as delay } from "node:timers/promises";
1223
+ var POLL_INTERVAL_MS = 2e3;
1224
+ function asString(value) {
1225
+ return typeof value === "string" ? value.trim() : "";
1226
+ }
1227
+ function parseQuestions(args) {
1228
+ const title = asString(args.title) || void 0;
1229
+ const raw = args.questions;
1230
+ if (!Array.isArray(raw) || raw.length === 0) {
1231
+ throw new Error("AskQuestion \u7F3A\u5C11 questions");
1232
+ }
1233
+ const questions = [];
1234
+ for (const item of raw) {
1235
+ if (!item || typeof item !== "object" || Array.isArray(item)) continue;
1236
+ const row = item;
1237
+ const id = asString(row.id);
1238
+ const prompt = asString(row.prompt);
1239
+ const optionsRaw = row.options;
1240
+ if (!id || !prompt || !Array.isArray(optionsRaw)) continue;
1241
+ const options = [];
1242
+ for (const opt of optionsRaw) {
1243
+ if (!opt || typeof opt !== "object" || Array.isArray(opt)) continue;
1244
+ const o = opt;
1245
+ const oid = asString(o.id);
1246
+ const label = asString(o.label);
1247
+ if (oid && label) options.push({ id: oid, label });
1248
+ }
1249
+ if (options.length < 2) {
1250
+ throw new Error(`AskQuestion \u95EE\u9898 ${id} \u81F3\u5C11\u9700\u8981 2 \u4E2A\u9009\u9879`);
1251
+ }
1252
+ questions.push({ id, prompt, options });
1253
+ }
1254
+ if (questions.length === 0) {
1255
+ throw new Error("AskQuestion \u65E0\u6709\u6548\u95EE\u9898");
1256
+ }
1257
+ return { title, questions };
1258
+ }
1259
+ function createWebIdeAskQuestionExecute(options) {
1260
+ const { cfg, taskId, signal } = options;
1261
+ return async (args) => {
1262
+ const parsed = parseQuestions(args);
1263
+ const api = createApmApiClient(cfg);
1264
+ console.log(
1265
+ `[apm] AskQuestion \u521B\u5EFA\u5F85\u786E\u8BA4\u9879 taskId=${taskId} count=${parsed.questions.length}`
1266
+ );
1267
+ await api.cli.webideReplaceAssumptions({
1268
+ taskId,
1269
+ title: parsed.title,
1270
+ questions: parsed.questions
1271
+ });
1272
+ while (true) {
1273
+ if (signal?.aborted) {
1274
+ throw new Error("AskQuestion \u5DF2\u53D6\u6D88");
1275
+ }
1276
+ const list = await api.cli.webideListAssumptions({ taskId });
1277
+ const byId = new Map(
1278
+ list.assumptions.map((a) => [a.questionId, a])
1279
+ );
1280
+ const pending = parsed.questions.filter((q) => {
1281
+ const row = byId.get(q.id);
1282
+ return !row || row.status !== "RESOLVED";
1283
+ });
1284
+ if (pending.length === 0) {
1285
+ const answers = parsed.questions.map((q) => {
1286
+ const row = byId.get(q.id);
1287
+ return {
1288
+ questionId: q.id,
1289
+ prompt: q.prompt,
1290
+ selectedOptionId: row.selectedOptionId,
1291
+ customAnswer: row.customAnswer,
1292
+ resolution: row.resolution
1293
+ };
1294
+ });
1295
+ console.log(
1296
+ `[apm] AskQuestion \u7528\u6237\u5DF2\u786E\u8BA4 taskId=${taskId} count=${answers.length}`
1297
+ );
1298
+ return JSON.stringify(
1299
+ {
1300
+ title: parsed.title,
1301
+ answers
1302
+ },
1303
+ null,
1304
+ 2
1305
+ );
1306
+ }
1307
+ await delay(POLL_INTERVAL_MS);
1308
+ }
1309
+ };
1310
+ }
1311
+
1207
1312
  // src/commands/deploy/internal/minio.ts
1208
1313
  import * as Minio from "minio";
1209
1314
  var MinioClient = class {
@@ -1824,6 +1929,11 @@ async function handleWebIdeInboundMessage(cfg, msg, signal) {
1824
1929
  {
1825
1930
  signal,
1826
1931
  appendMessageContent: (content) => appendContent(cfg, messageId, content),
1932
+ askQuestionExecute: createWebIdeAskQuestionExecute({
1933
+ cfg,
1934
+ taskId,
1935
+ signal
1936
+ }),
1827
1937
  createRemoteLogSync: (agentId) => {
1828
1938
  saveWebIdeAgentId(workdir, taskId, agentId);
1829
1939
  logSyncRef.current = createThrottledWebIdeMessageLogSync(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "7.1.1",
3
+ "version": "7.1.2",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,