ai-project-manage-cli 5.0.14 → 5.0.15
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 +40 -83
- package/package.json +2 -2
- package/template/AGENTS.md +1 -1
package/dist/index.js
CHANGED
|
@@ -10,6 +10,12 @@ import { join } from "path";
|
|
|
10
10
|
var APM_CONFIG_DIR = join(homedir(), ".config", "apm");
|
|
11
11
|
var APM_CONFIG_PATH = join(APM_CONFIG_DIR, "config.json");
|
|
12
12
|
var DEFAULT_BASE_URL = "http://127.0.0.1:3000";
|
|
13
|
+
function resolveClientMachineId(cfg) {
|
|
14
|
+
return (cfg.clientMachineId ?? cfg.userId ?? "").trim();
|
|
15
|
+
}
|
|
16
|
+
function resolveAccount(cfg) {
|
|
17
|
+
return (cfg.account ?? cfg.email ?? "").trim();
|
|
18
|
+
}
|
|
13
19
|
async function readApmConfig() {
|
|
14
20
|
try {
|
|
15
21
|
const raw = readFileSync(APM_CONFIG_PATH, "utf8");
|
|
@@ -18,14 +24,17 @@ async function readApmConfig() {
|
|
|
18
24
|
return null;
|
|
19
25
|
}
|
|
20
26
|
const rawCfg = v;
|
|
21
|
-
if (typeof rawCfg.baseUrl !== "string" || typeof rawCfg.
|
|
27
|
+
if (typeof rawCfg.baseUrl !== "string" || typeof rawCfg.token !== "string") {
|
|
22
28
|
return null;
|
|
23
29
|
}
|
|
24
30
|
const cfg = v;
|
|
31
|
+
const clientMachineId = resolveClientMachineId(cfg);
|
|
32
|
+
const account = resolveAccount(cfg);
|
|
25
33
|
return {
|
|
26
34
|
baseUrl: cfg.baseUrl.trim().replace(/\/+$/, ""),
|
|
27
|
-
userId: cfg.userId,
|
|
28
35
|
token: cfg.token,
|
|
36
|
+
...clientMachineId ? { clientMachineId } : {},
|
|
37
|
+
...account ? { account } : {},
|
|
29
38
|
...typeof cfg.email === "string" ? { email: cfg.email } : {}
|
|
30
39
|
};
|
|
31
40
|
} catch {
|
|
@@ -35,8 +44,9 @@ async function readApmConfig() {
|
|
|
35
44
|
function defaultApmConfig() {
|
|
36
45
|
return {
|
|
37
46
|
baseUrl: DEFAULT_BASE_URL,
|
|
38
|
-
|
|
47
|
+
clientMachineId: "",
|
|
39
48
|
token: "",
|
|
49
|
+
account: "",
|
|
40
50
|
email: ""
|
|
41
51
|
};
|
|
42
52
|
}
|
|
@@ -54,11 +64,13 @@ async function ensureApmConfig() {
|
|
|
54
64
|
return defaults;
|
|
55
65
|
}
|
|
56
66
|
async function writeApmConfig(cfg) {
|
|
67
|
+
const clientMachineId = resolveClientMachineId(cfg);
|
|
68
|
+
const account = resolveAccount(cfg);
|
|
57
69
|
const normalized = {
|
|
58
70
|
baseUrl: cfg.baseUrl.trim().replace(/\/+$/, ""),
|
|
59
|
-
userId: cfg.userId,
|
|
60
71
|
token: cfg.token,
|
|
61
|
-
...
|
|
72
|
+
...clientMachineId ? { clientMachineId } : {},
|
|
73
|
+
...account ? { account, email: account } : {}
|
|
62
74
|
};
|
|
63
75
|
mkdirSync(APM_CONFIG_DIR, { recursive: true });
|
|
64
76
|
writeFileSync(APM_CONFIG_PATH, JSON.stringify(normalized, null, 2) + "\n", {
|
|
@@ -256,13 +268,13 @@ async function runLogin(opts) {
|
|
|
256
268
|
const baseUrl = (opts.server?.trim() || process.env.AI_PM_SERVER?.trim() || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
257
269
|
const api = createApmApiClient({
|
|
258
270
|
baseUrl,
|
|
259
|
-
|
|
271
|
+
clientMachineId: "",
|
|
260
272
|
token: ""
|
|
261
273
|
});
|
|
262
274
|
let data;
|
|
263
275
|
try {
|
|
264
276
|
data = await api.auth.login({
|
|
265
|
-
|
|
277
|
+
account: opts.email,
|
|
266
278
|
password: opts.password
|
|
267
279
|
});
|
|
268
280
|
} catch (raw) {
|
|
@@ -277,24 +289,29 @@ async function runLogin(opts) {
|
|
|
277
289
|
console.error("[apm] \u8BF7\u6C42\u5931\u8D25:", raw instanceof Error ? raw.message : raw);
|
|
278
290
|
process.exit(1);
|
|
279
291
|
}
|
|
280
|
-
const
|
|
292
|
+
const clientMachineId = data?.clientMachine?.id;
|
|
281
293
|
const token = data?.token;
|
|
282
|
-
if (!
|
|
294
|
+
if (!clientMachineId || !token) {
|
|
283
295
|
console.error(
|
|
284
|
-
"[apm] \u54CD\u5E94\u7F3A\u5C11
|
|
296
|
+
"[apm] \u54CD\u5E94\u7F3A\u5C11 clientMachine.id / token\uFF08\u8BF7\u786E\u8BA4\u670D\u52A1\u7AEF\u4E3A /api/v1/auth/login\uFF09"
|
|
285
297
|
);
|
|
286
298
|
process.exit(1);
|
|
287
299
|
}
|
|
288
300
|
const cfg = {
|
|
289
301
|
baseUrl,
|
|
290
|
-
|
|
302
|
+
clientMachineId,
|
|
291
303
|
token,
|
|
304
|
+
account: opts.email,
|
|
292
305
|
email: opts.email
|
|
293
306
|
};
|
|
294
307
|
await writeApmConfig(cfg);
|
|
295
308
|
console.error(`[apm] \u5DF2\u4FDD\u5B58\u767B\u5F55\u4FE1\u606F: ${APM_CONFIG_PATH}`);
|
|
296
309
|
console.log(
|
|
297
|
-
JSON.stringify(
|
|
310
|
+
JSON.stringify(
|
|
311
|
+
{ clientMachineId: cfg.clientMachineId, baseUrl: cfg.baseUrl },
|
|
312
|
+
null,
|
|
313
|
+
2
|
|
314
|
+
)
|
|
298
315
|
);
|
|
299
316
|
}
|
|
300
317
|
|
|
@@ -489,7 +506,7 @@ function formatSessionMessagesXml(sessionId, messages) {
|
|
|
489
506
|
lines.push(
|
|
490
507
|
` <message id="${escapeXmlAttr(message.id)}" name="${escapeXmlAttr(
|
|
491
508
|
message.name
|
|
492
|
-
)}"
|
|
509
|
+
)}" expert="${escapeXmlAttr(message.expert)}"${roundAttr}>`,
|
|
493
510
|
` <content>${wrapCdata(message.content)}</content>`,
|
|
494
511
|
" </message>"
|
|
495
512
|
);
|
|
@@ -613,7 +630,7 @@ async function runPull(sessionId, apmRoot) {
|
|
|
613
630
|
description: "./RULE.md",
|
|
614
631
|
members: members.map((m) => ({
|
|
615
632
|
name: m.displayName,
|
|
616
|
-
|
|
633
|
+
expert: m.expert,
|
|
617
634
|
system_persona: m.systemPersona,
|
|
618
635
|
skills: []
|
|
619
636
|
})),
|
|
@@ -1102,6 +1119,7 @@ async function handleInboundMessage(cfg, raw) {
|
|
|
1102
1119
|
try {
|
|
1103
1120
|
await runBranch(msg.sessionId, { cwd: msg.workdir });
|
|
1104
1121
|
await runPull(msg.sessionId, workspaceApmDir(msg.workdir));
|
|
1122
|
+
await commitWorkingTreeIfDirty(msg.workdir, "fix: apm pull");
|
|
1105
1123
|
await updateMessageStatus(cfg, messageId, "TYPING");
|
|
1106
1124
|
await runCursorAgent(cfg, {
|
|
1107
1125
|
messageId: msg.messageId,
|
|
@@ -1134,13 +1152,13 @@ async function handleInboundMessage(cfg, raw) {
|
|
|
1134
1152
|
}
|
|
1135
1153
|
}
|
|
1136
1154
|
}
|
|
1137
|
-
function startHeartbeat(ws,
|
|
1155
|
+
function startHeartbeat(ws, clientMachineId) {
|
|
1138
1156
|
const send = () => {
|
|
1139
1157
|
if (ws.readyState === WebSocket.OPEN) {
|
|
1140
1158
|
ws.send(
|
|
1141
1159
|
serializeAgentWsMessage({
|
|
1142
1160
|
type: "heartbeat",
|
|
1143
|
-
userId
|
|
1161
|
+
userId: clientMachineId
|
|
1144
1162
|
})
|
|
1145
1163
|
);
|
|
1146
1164
|
}
|
|
@@ -1154,8 +1172,9 @@ async function runConnect(options) {
|
|
|
1154
1172
|
if (options.server?.trim()) {
|
|
1155
1173
|
cfg.baseUrl = options.server.trim().replace(/\/+$/, "");
|
|
1156
1174
|
}
|
|
1157
|
-
|
|
1158
|
-
|
|
1175
|
+
const clientMachineId = resolveClientMachineId(cfg);
|
|
1176
|
+
if (!clientMachineId) {
|
|
1177
|
+
console.error("[apm] config \u7F3A\u5C11 clientMachineId\uFF0C\u8BF7\u91CD\u65B0 apm login");
|
|
1159
1178
|
process.exit(1);
|
|
1160
1179
|
}
|
|
1161
1180
|
const url = buildAgentWsUrl(cfg.baseUrl, cfg.token);
|
|
@@ -1178,7 +1197,7 @@ async function runConnect(options) {
|
|
|
1178
1197
|
};
|
|
1179
1198
|
ws.on("open", () => {
|
|
1180
1199
|
console.log("[apm] WebSocket \u5DF2\u8FDE\u63A5");
|
|
1181
|
-
stopHeartbeat = startHeartbeat(ws,
|
|
1200
|
+
stopHeartbeat = startHeartbeat(ws, clientMachineId);
|
|
1182
1201
|
});
|
|
1183
1202
|
ws.on("message", (data) => {
|
|
1184
1203
|
const text = Buffer.isBuffer(data) ? data.toString("utf8") : String(data);
|
|
@@ -1862,40 +1881,6 @@ function registerDeployBackendCommands(program) {
|
|
|
1862
1881
|
import { copyFile, readdir as readdir2, stat } from "node:fs/promises";
|
|
1863
1882
|
import path7 from "node:path";
|
|
1864
1883
|
|
|
1865
|
-
// src/commands/deploy/internal/load-apm-dotenv.ts
|
|
1866
|
-
import { existsSync as existsSync10, readFileSync as readFileSync9 } from "node:fs";
|
|
1867
|
-
import { join as join9 } from "node:path";
|
|
1868
|
-
function loadApmDotEnvIfPresent() {
|
|
1869
|
-
const p = join9(workspaceApmDir(), ".env");
|
|
1870
|
-
if (!existsSync10(p)) {
|
|
1871
|
-
return;
|
|
1872
|
-
}
|
|
1873
|
-
let text;
|
|
1874
|
-
try {
|
|
1875
|
-
text = readFileSync9(p, "utf8");
|
|
1876
|
-
} catch {
|
|
1877
|
-
return;
|
|
1878
|
-
}
|
|
1879
|
-
for (const line of text.split("\n")) {
|
|
1880
|
-
const t = line.trim();
|
|
1881
|
-
if (!t || t.startsWith("#")) {
|
|
1882
|
-
continue;
|
|
1883
|
-
}
|
|
1884
|
-
const eq = t.indexOf("=");
|
|
1885
|
-
if (eq <= 0) {
|
|
1886
|
-
continue;
|
|
1887
|
-
}
|
|
1888
|
-
const key = t.slice(0, eq).trim();
|
|
1889
|
-
let val = t.slice(eq + 1).trim();
|
|
1890
|
-
if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'")) {
|
|
1891
|
-
val = val.slice(1, -1);
|
|
1892
|
-
}
|
|
1893
|
-
if (process.env[key] === void 0) {
|
|
1894
|
-
process.env[key] = val;
|
|
1895
|
-
}
|
|
1896
|
-
}
|
|
1897
|
-
}
|
|
1898
|
-
|
|
1899
1884
|
// src/commands/deploy/internal/minio.ts
|
|
1900
1885
|
import { statSync as statSync5 } from "node:fs";
|
|
1901
1886
|
import { readdir, readFile } from "node:fs/promises";
|
|
@@ -2059,31 +2044,6 @@ function artifactObjectKey(namePrefix, branchSegment, relativePath) {
|
|
|
2059
2044
|
const rel = sanitizeRelativePath(relativePath);
|
|
2060
2045
|
return `${base}/${branchSegment}/dist/${rel}`;
|
|
2061
2046
|
}
|
|
2062
|
-
function mergeMinioFromEnv(settings) {
|
|
2063
|
-
const ep = process.env.MINIO_ENDPOINT?.trim();
|
|
2064
|
-
const portRaw = process.env.MINIO_PORT?.trim();
|
|
2065
|
-
const sslRaw = process.env.MINIO_USE_SSL?.trim().toLowerCase();
|
|
2066
|
-
const ak = process.env.MINIO_ACCESS_KEY?.trim();
|
|
2067
|
-
const sk = process.env.MINIO_SECRET_KEY?.trim();
|
|
2068
|
-
const bucket = process.env.MINIO_BUCKET?.trim();
|
|
2069
|
-
const port = portRaw ? Number.parseInt(portRaw, 10) : void 0;
|
|
2070
|
-
let useSsl = settings.useSsl;
|
|
2071
|
-
if (sslRaw === "true" || sslRaw === "1") {
|
|
2072
|
-
useSsl = true;
|
|
2073
|
-
}
|
|
2074
|
-
if (sslRaw === "false" || sslRaw === "0") {
|
|
2075
|
-
useSsl = false;
|
|
2076
|
-
}
|
|
2077
|
-
return {
|
|
2078
|
-
...settings,
|
|
2079
|
-
endpoint: ep || settings.endpoint,
|
|
2080
|
-
port: port !== void 0 && Number.isFinite(port) && port > 0 ? port : settings.port,
|
|
2081
|
-
useSsl,
|
|
2082
|
-
accessKey: ak || settings.accessKey,
|
|
2083
|
-
secretKey: sk || settings.secretKey,
|
|
2084
|
-
bucket: bucket || settings.bucket
|
|
2085
|
-
};
|
|
2086
|
-
}
|
|
2087
2047
|
async function ensureArtifactRootIndexHtml(root) {
|
|
2088
2048
|
const indexHtmlPath = path7.join(root, "index.html");
|
|
2089
2049
|
try {
|
|
@@ -2124,7 +2084,7 @@ async function ensureArtifactRootIndexHtml(root) {
|
|
|
2124
2084
|
}
|
|
2125
2085
|
function registerDeployFrontendCommands(program) {
|
|
2126
2086
|
program.command("deploy-frontend").description(
|
|
2127
|
-
"\u9012\u5F52\u4E0A\u4F20\u524D\u7AEF\u4EA7\u7269\u76EE\u5F55\u5230 MinIO\uFF0C\u5E76\u5728\u6210\u529F\u540E\u4E3A\u8BE5\u6876\u8BBE\u7F6E\u533F\u540D\u53EF\u8BFB\u7B56\u7565\
|
|
2087
|
+
"\u9012\u5F52\u4E0A\u4F20\u524D\u7AEF\u4EA7\u7269\u76EE\u5F55\u5230 MinIO\uFF0C\u5E76\u5728\u6210\u529F\u540E\u4E3A\u8BE5\u6876\u8BBE\u7F6E\u533F\u540D\u53EF\u8BFB\u7B56\u7565\uFF08MinIO \u8FDE\u63A5\u4FE1\u606F\u4EC5\u6765\u81EA apm.config.json frontendDeploy\uFF09"
|
|
2128
2088
|
).argument("[name]", "\u73AF\u5883\u540D", "online").option(
|
|
2129
2089
|
"--dir <path>",
|
|
2130
2090
|
"\u4EA7\u7269\u76EE\u5F55\uFF1B\u5355\u4ED3\u9ED8\u8BA4 apps/web/dist\uFF08\u9700\u5148 rush build / vite build\uFF09",
|
|
@@ -2138,12 +2098,9 @@ function registerDeployFrontendCommands(program) {
|
|
|
2138
2098
|
(v) => Number.parseInt(String(v), 10)
|
|
2139
2099
|
).action(
|
|
2140
2100
|
async (name, opts) => {
|
|
2141
|
-
loadApmDotEnvIfPresent();
|
|
2142
2101
|
const cfg = loadApmConfig({ configPath: opts.config });
|
|
2143
2102
|
const namePrefix = resolveArtifactNamePrefix(cfg);
|
|
2144
|
-
const settings =
|
|
2145
|
-
resolveFrontendDeployFromApmConfig(cfg)
|
|
2146
|
-
);
|
|
2103
|
+
const settings = resolveFrontendDeployFromApmConfig(cfg);
|
|
2147
2104
|
const minio = new MinioClient({
|
|
2148
2105
|
endPoint: settings.endpoint,
|
|
2149
2106
|
port: settings.port,
|
package/package.json
CHANGED
package/template/AGENTS.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
2. 根据你的名字从 session.yaml 中找到你对应的人设(system_persona)
|
|
19
19
|
3. 根据人设完成用户指定的任务
|
|
20
20
|
4. 任务有阶段行进展或者任务完成后必须使用 `apm append-message` 回复消息,回复要求简洁不用对本轮工作进行总结
|
|
21
|
-
5. 工作日志放到 `.apm/sessions/<会话ID>/docs/<
|
|
21
|
+
5. 工作日志放到 `.apm/sessions/<会话ID>/docs/<expert>.md` 中,并执行`apm sync-document <会话ID> --file=<expert>`同步到远程
|
|
22
22
|
|
|
23
23
|
## 目录声明
|
|
24
24
|
|