ai-project-manage-cli 2.0.26 → 3.0.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 +500 -20
- package/package.json +27 -25
- package/template/apm.config.json +5 -0
- package/template/deploy/README.md +3 -0
- package/template/skills/apm-review/SKILL.md +38 -0
- package/template/skills/apm-review/apm-review-reference.md +89 -0
- package/template/workitems/README.md +19 -0
- package/README.md +0 -171
- package/dist/api/cli.d.ts +0 -228
- package/dist/api/cli.d.ts.map +0 -1
- package/dist/api/cli.js +0 -3
- package/dist/api/cli.js.map +0 -1
- package/dist/api/client.d.ts +0 -5
- package/dist/api/client.d.ts.map +0 -1
- package/dist/api/client.js +0 -30
- package/dist/api/client.js.map +0 -1
- package/dist/api/http.d.ts +0 -21
- package/dist/api/http.d.ts.map +0 -1
- package/dist/api/http.js +0 -108
- package/dist/api/http.js.map +0 -1
- package/dist/api/index.d.ts +0 -6
- package/dist/api/index.d.ts.map +0 -1
- package/dist/api/index.js +0 -13
- package/dist/api/index.js.map +0 -1
- package/dist/api/request-config.d.ts +0 -25
- package/dist/api/request-config.d.ts.map +0 -1
- package/dist/api/request-config.js +0 -73
- package/dist/api/request-config.js.map +0 -1
- package/dist/api/requirement.d.ts +0 -1
- package/dist/api/requirement.d.ts.map +0 -1
- package/dist/api/requirement.js +0 -2
- package/dist/api/requirement.js.map +0 -1
- package/dist/apm-dotenv.d.ts +0 -8
- package/dist/apm-dotenv.d.ts.map +0 -1
- package/dist/apm-dotenv.js +0 -73
- package/dist/apm-dotenv.js.map +0 -1
- package/dist/cli/agent-stream-log.d.ts +0 -41
- package/dist/cli/agent-stream-log.d.ts.map +0 -1
- package/dist/cli/agent-stream-log.js +0 -364
- package/dist/cli/agent-stream-log.js.map +0 -1
- package/dist/cli/commands/auth.d.ts +0 -3
- package/dist/cli/commands/auth.d.ts.map +0 -1
- package/dist/cli/commands/auth.js +0 -51
- package/dist/cli/commands/auth.js.map +0 -1
- package/dist/cli/commands/chat.d.ts +0 -3
- package/dist/cli/commands/chat.d.ts.map +0 -1
- package/dist/cli/commands/chat.js +0 -32
- package/dist/cli/commands/chat.js.map +0 -1
- package/dist/cli/commands/comment.d.ts +0 -3
- package/dist/cli/commands/comment.d.ts.map +0 -1
- package/dist/cli/commands/comment.js +0 -66
- package/dist/cli/commands/comment.js.map +0 -1
- package/dist/cli/commands/config.d.ts +0 -3
- package/dist/cli/commands/config.d.ts.map +0 -1
- package/dist/cli/commands/config.js +0 -39
- package/dist/cli/commands/config.js.map +0 -1
- package/dist/cli/commands/deploy-backend.d.ts +0 -7
- package/dist/cli/commands/deploy-backend.d.ts.map +0 -1
- package/dist/cli/commands/deploy-backend.js +0 -77
- package/dist/cli/commands/deploy-backend.js.map +0 -1
- package/dist/cli/commands/deploy-frontend.d.ts +0 -3
- package/dist/cli/commands/deploy-frontend.d.ts.map +0 -1
- package/dist/cli/commands/deploy-frontend.js +0 -167
- package/dist/cli/commands/deploy-frontend.js.map +0 -1
- package/dist/cli/commands/get.d.ts +0 -3
- package/dist/cli/commands/get.d.ts.map +0 -1
- package/dist/cli/commands/get.js +0 -145
- package/dist/cli/commands/get.js.map +0 -1
- package/dist/cli/commands/init.d.ts +0 -3
- package/dist/cli/commands/init.d.ts.map +0 -1
- package/dist/cli/commands/init.js +0 -179
- package/dist/cli/commands/init.js.map +0 -1
- package/dist/cli/commands/minio.d.ts +0 -3
- package/dist/cli/commands/minio.d.ts.map +0 -1
- package/dist/cli/commands/minio.js +0 -65
- package/dist/cli/commands/minio.js.map +0 -1
- package/dist/cli/commands/publish.d.ts +0 -3
- package/dist/cli/commands/publish.d.ts.map +0 -1
- package/dist/cli/commands/publish.js +0 -130
- package/dist/cli/commands/publish.js.map +0 -1
- package/dist/cli/commands/release.d.ts +0 -3
- package/dist/cli/commands/release.d.ts.map +0 -1
- package/dist/cli/commands/release.js +0 -37
- package/dist/cli/commands/release.js.map +0 -1
- package/dist/cli/commands/requirement.d.ts +0 -3
- package/dist/cli/commands/requirement.d.ts.map +0 -1
- package/dist/cli/commands/requirement.js +0 -169
- package/dist/cli/commands/requirement.js.map +0 -1
- package/dist/cli/commands/set.d.ts +0 -3
- package/dist/cli/commands/set.d.ts.map +0 -1
- package/dist/cli/commands/set.js +0 -103
- package/dist/cli/commands/set.js.map +0 -1
- package/dist/cli/commands/status.d.ts +0 -3
- package/dist/cli/commands/status.d.ts.map +0 -1
- package/dist/cli/commands/status.js +0 -42
- package/dist/cli/commands/status.js.map +0 -1
- package/dist/cli/commands/update.d.ts +0 -3
- package/dist/cli/commands/update.d.ts.map +0 -1
- package/dist/cli/commands/update.js +0 -36
- package/dist/cli/commands/update.js.map +0 -1
- package/dist/cli/commands/ws.d.ts +0 -3
- package/dist/cli/commands/ws.d.ts.map +0 -1
- package/dist/cli/commands/ws.js +0 -25
- package/dist/cli/commands/ws.js.map +0 -1
- package/dist/cli/credentials.d.ts +0 -30
- package/dist/cli/credentials.d.ts.map +0 -1
- package/dist/cli/credentials.js +0 -52
- package/dist/cli/credentials.js.map +0 -1
- package/dist/cli/exit-api-error.d.ts +0 -2
- package/dist/cli/exit-api-error.d.ts.map +0 -1
- package/dist/cli/exit-api-error.js +0 -18
- package/dist/cli/exit-api-error.js.map +0 -1
- package/dist/cli/instruction-log-stream-sink.d.ts +0 -31
- package/dist/cli/instruction-log-stream-sink.d.ts.map +0 -1
- package/dist/cli/instruction-log-stream-sink.js +0 -59
- package/dist/cli/instruction-log-stream-sink.js.map +0 -1
- package/dist/cli/session.d.ts +0 -26
- package/dist/cli/session.d.ts.map +0 -1
- package/dist/cli/session.js +0 -41
- package/dist/cli/session.js.map +0 -1
- package/dist/cli/utils/parse.d.ts +0 -2
- package/dist/cli/utils/parse.d.ts.map +0 -1
- package/dist/cli/utils/parse.js +0 -12
- package/dist/cli/utils/parse.js.map +0 -1
- package/dist/cli/ws-run-command.d.ts +0 -13
- package/dist/cli/ws-run-command.d.ts.map +0 -1
- package/dist/cli/ws-run-command.js +0 -330
- package/dist/cli/ws-run-command.js.map +0 -1
- package/dist/cli-version.d.ts +0 -9
- package/dist/cli-version.d.ts.map +0 -1
- package/dist/cli-version.js +0 -61
- package/dist/cli-version.js.map +0 -1
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -36
- package/dist/cli.js.map +0 -1
- package/dist/config-store.d.ts +0 -38
- package/dist/config-store.d.ts.map +0 -1
- package/dist/config-store.js +0 -131
- package/dist/config-store.js.map +0 -1
- package/dist/core/apm-config.d.ts +0 -81
- package/dist/core/apm-config.d.ts.map +0 -1
- package/dist/core/apm-config.js +0 -147
- package/dist/core/apm-config.js.map +0 -1
- package/dist/core/backend-deploy/backend-deploy-workflow.d.ts +0 -20
- package/dist/core/backend-deploy/backend-deploy-workflow.d.ts.map +0 -1
- package/dist/core/backend-deploy/backend-deploy-workflow.js +0 -86
- package/dist/core/backend-deploy/backend-deploy-workflow.js.map +0 -1
- package/dist/core/backend-deploy/command-runner.d.ts +0 -11
- package/dist/core/backend-deploy/command-runner.d.ts.map +0 -1
- package/dist/core/backend-deploy/command-runner.js +0 -47
- package/dist/core/backend-deploy/command-runner.js.map +0 -1
- package/dist/core/backend-deploy/dockerode-client/client.d.ts +0 -18
- package/dist/core/backend-deploy/dockerode-client/client.d.ts.map +0 -1
- package/dist/core/backend-deploy/dockerode-client/client.js +0 -114
- package/dist/core/backend-deploy/dockerode-client/client.js.map +0 -1
- package/dist/core/backend-deploy/dockerode-client/connection-options.d.ts +0 -6
- package/dist/core/backend-deploy/dockerode-client/connection-options.d.ts.map +0 -1
- package/dist/core/backend-deploy/dockerode-client/connection-options.js +0 -62
- package/dist/core/backend-deploy/dockerode-client/connection-options.js.map +0 -1
- package/dist/core/backend-deploy/dockerode-client/container-inspect-format.d.ts +0 -3
- package/dist/core/backend-deploy/dockerode-client/container-inspect-format.d.ts.map +0 -1
- package/dist/core/backend-deploy/dockerode-client/container-inspect-format.js +0 -23
- package/dist/core/backend-deploy/dockerode-client/container-inspect-format.js.map +0 -1
- package/dist/core/backend-deploy/dockerode-client/container-options.d.ts +0 -4
- package/dist/core/backend-deploy/dockerode-client/container-options.d.ts.map +0 -1
- package/dist/core/backend-deploy/dockerode-client/container-options.js +0 -44
- package/dist/core/backend-deploy/dockerode-client/container-options.js.map +0 -1
- package/dist/core/backend-deploy/dockerode-client/env.d.ts +0 -3
- package/dist/core/backend-deploy/dockerode-client/env.d.ts.map +0 -1
- package/dist/core/backend-deploy/dockerode-client/env.js +0 -40
- package/dist/core/backend-deploy/dockerode-client/env.js.map +0 -1
- package/dist/core/backend-deploy/dockerode-client/index.d.ts +0 -8
- package/dist/core/backend-deploy/dockerode-client/index.d.ts.map +0 -1
- package/dist/core/backend-deploy/dockerode-client/index.js +0 -17
- package/dist/core/backend-deploy/dockerode-client/index.js.map +0 -1
- package/dist/core/backend-deploy/dockerode-client/ports.d.ts +0 -9
- package/dist/core/backend-deploy/dockerode-client/ports.d.ts.map +0 -1
- package/dist/core/backend-deploy/dockerode-client/ports.js +0 -35
- package/dist/core/backend-deploy/dockerode-client/ports.js.map +0 -1
- package/dist/core/backend-deploy/dockerode-client/runtime.d.ts +0 -7
- package/dist/core/backend-deploy/dockerode-client/runtime.d.ts.map +0 -1
- package/dist/core/backend-deploy/dockerode-client/runtime.js +0 -26
- package/dist/core/backend-deploy/dockerode-client/runtime.js.map +0 -1
- package/dist/core/backend-deploy/dockerode-client/types.d.ts +0 -64
- package/dist/core/backend-deploy/dockerode-client/types.d.ts.map +0 -1
- package/dist/core/backend-deploy/dockerode-client/types.js +0 -3
- package/dist/core/backend-deploy/dockerode-client/types.js.map +0 -1
- package/dist/core/backend-deploy/image-tag.d.ts +0 -2
- package/dist/core/backend-deploy/image-tag.d.ts.map +0 -1
- package/dist/core/backend-deploy/image-tag.js +0 -15
- package/dist/core/backend-deploy/image-tag.js.map +0 -1
- package/dist/core/backend-deploy/index.d.ts +0 -3
- package/dist/core/backend-deploy/index.d.ts.map +0 -1
- package/dist/core/backend-deploy/index.js +0 -6
- package/dist/core/backend-deploy/index.js.map +0 -1
- package/dist/core/backend-deploy/local-docker-build.d.ts +0 -8
- package/dist/core/backend-deploy/local-docker-build.d.ts.map +0 -1
- package/dist/core/backend-deploy/local-docker-build.js +0 -25
- package/dist/core/backend-deploy/local-docker-build.js.map +0 -1
- package/dist/core/backend-deploy/logger.d.ts +0 -10
- package/dist/core/backend-deploy/logger.d.ts.map +0 -1
- package/dist/core/backend-deploy/logger.js +0 -22
- package/dist/core/backend-deploy/logger.js.map +0 -1
- package/dist/core/backend-deploy/registry-login-push.d.ts +0 -24
- package/dist/core/backend-deploy/registry-login-push.d.ts.map +0 -1
- package/dist/core/backend-deploy/registry-login-push.js +0 -37
- package/dist/core/backend-deploy/registry-login-push.js.map +0 -1
- package/dist/core/backend-deploy/remote-docker-client.d.ts +0 -11
- package/dist/core/backend-deploy/remote-docker-client.d.ts.map +0 -1
- package/dist/core/backend-deploy/remote-docker-client.js +0 -34
- package/dist/core/backend-deploy/remote-docker-client.js.map +0 -1
- package/dist/core/backend-deploy/remote-pull-image.d.ts +0 -9
- package/dist/core/backend-deploy/remote-pull-image.d.ts.map +0 -1
- package/dist/core/backend-deploy/remote-pull-image.js +0 -39
- package/dist/core/backend-deploy/remote-pull-image.js.map +0 -1
- package/dist/core/backend-deploy/resolve-dockerfile.d.ts +0 -7
- package/dist/core/backend-deploy/resolve-dockerfile.d.ts.map +0 -1
- package/dist/core/backend-deploy/resolve-dockerfile.js +0 -24
- package/dist/core/backend-deploy/resolve-dockerfile.js.map +0 -1
- package/dist/core/backend-deploy/run-docker-cli.d.ts +0 -9
- package/dist/core/backend-deploy/run-docker-cli.d.ts.map +0 -1
- package/dist/core/backend-deploy/run-docker-cli.js +0 -14
- package/dist/core/backend-deploy/run-docker-cli.js.map +0 -1
- package/dist/core/backend-deploy/types.d.ts +0 -23
- package/dist/core/backend-deploy/types.d.ts.map +0 -1
- package/dist/core/backend-deploy/types.js +0 -3
- package/dist/core/backend-deploy/types.js.map +0 -1
- package/dist/core/branch-name.d.ts +0 -8
- package/dist/core/branch-name.d.ts.map +0 -1
- package/dist/core/branch-name.js +0 -37
- package/dist/core/branch-name.js.map +0 -1
- package/dist/core/constants.d.ts +0 -4
- package/dist/core/constants.d.ts.map +0 -1
- package/dist/core/constants.js +0 -16
- package/dist/core/constants.js.map +0 -1
- package/dist/core/cursor-cmd.d.ts +0 -30
- package/dist/core/cursor-cmd.d.ts.map +0 -1
- package/dist/core/cursor-cmd.js +0 -193
- package/dist/core/cursor-cmd.js.map +0 -1
- package/dist/core/minio.d.ts +0 -37
- package/dist/core/minio.d.ts.map +0 -1
- package/dist/core/minio.js +0 -159
- package/dist/core/minio.js.map +0 -1
- package/dist/core/parse-testcase-md.d.ts +0 -17
- package/dist/core/parse-testcase-md.d.ts.map +0 -1
- package/dist/core/parse-testcase-md.js +0 -79
- package/dist/core/parse-testcase-md.js.map +0 -1
- package/dist/core/std-event-handler.d.ts +0 -25
- package/dist/core/std-event-handler.d.ts.map +0 -1
- package/dist/core/std-event-handler.js +0 -90
- package/dist/core/std-event-handler.js.map +0 -1
- package/dist/core/utils.d.ts +0 -19
- package/dist/core/utils.d.ts.map +0 -1
- package/dist/core/utils.js +0 -71
- package/dist/core/utils.js.map +0 -1
- package/dist/core/ws-client.d.ts +0 -29
- package/dist/core/ws-client.d.ts.map +0 -1
- package/dist/core/ws-client.js +0 -81
- package/dist/core/ws-client.js.map +0 -1
- package/dist/employee-ws-client.d.ts +0 -42
- package/dist/employee-ws-client.d.ts.map +0 -1
- package/dist/employee-ws-client.js +0 -99
- package/dist/employee-ws-client.js.map +0 -1
- package/dist/index.d.ts +0 -6
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/templates/commands/apm-auto-dev.md +0 -6
- package/templates/commands/apm-fixbug.md +0 -6
- package/templates/commands/apm-prd-review.md +0 -6
- package/templates/commands/apm-prd-sync.md +0 -6
- package/templates/skills/apm-apply-change/SKILL.md +0 -191
- package/templates/skills/apm-auto-dev/SKILL.md +0 -170
- package/templates/skills/apm-fixbug/SKILL.md +0 -97
- package/templates/skills/apm-propose/SKILL.md +0 -123
- package/templates/skills/apm-propose/design-instruction.md +0 -94
- package/templates/skills/apm-propose/propose-instruction.md +0 -81
- package/templates/skills/apm-propose/specs-instruction.md +0 -114
- package/templates/skills/apm-propose/tasks-instruction.md +0 -90
- package/templates/skills/apm-release/SKILL.md +0 -87
- package/templates/skills/code-change-summary/SKILL.md +0 -84
- package/templates/skills/code-change-summary/summary-template.md +0 -55
- package/templates/skills/code-deploy/SKILL.md +0 -39
- package/templates/skills/prd-review/SKILL.md +0 -48
- package/templates/skills/prd-review/output-template.md +0 -47
- package/templates/skills/prd-sync/SKILL.md +0 -74
- package/templates/skills/prd-sync/updated-requirement-template.md +0 -39
- package/templates/skills/prd-testcase/SKILL.md +0 -82
- package/templates/skills/prd-testcase/reference.md +0 -44
- package/templates/skills/product-capability-inventory/SKILL.md +0 -131
- package/templates/skills/product-capability-inventory/template.md +0 -80
- package/templates/skills/product-capability-inventory//344/275/277/347/224/250/350/257/264/346/230/216/344/271/246.md +0 -36
- package/templates/skills/product-capability-inventory//347/233/256/345/275/225/350/247/204/350/214/203.md +0 -58
package/dist/index.js
CHANGED
|
@@ -1,22 +1,502 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
5
|
+
import { dirname as dirname2, join as join6 } from "path";
|
|
6
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
7
|
+
import { Command } from "commander";
|
|
8
|
+
|
|
9
|
+
// src/config.ts
|
|
10
|
+
import { mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
11
|
+
import { homedir } from "os";
|
|
12
|
+
import { join } from "path";
|
|
13
|
+
var APM_CONFIG_DIR = join(homedir(), ".config", "apm");
|
|
14
|
+
var APM_CONFIG_PATH = join(APM_CONFIG_DIR, "config.json");
|
|
15
|
+
var DEFAULT_BASE_URL = "http://127.0.0.1:3000";
|
|
16
|
+
async function readApmConfig() {
|
|
17
|
+
try {
|
|
18
|
+
const raw = readFileSync(APM_CONFIG_PATH, "utf8");
|
|
19
|
+
const v = JSON.parse(raw);
|
|
20
|
+
if (typeof v !== "object" || v === null) {
|
|
21
|
+
return null;
|
|
7
22
|
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
23
|
+
const rawCfg = v;
|
|
24
|
+
if (typeof rawCfg.baseUrl !== "string" || typeof rawCfg.userId !== "string" || typeof rawCfg.token !== "string") {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const cfg = v;
|
|
28
|
+
return {
|
|
29
|
+
baseUrl: cfg.baseUrl.trim().replace(/\/+$/, ""),
|
|
30
|
+
userId: cfg.userId,
|
|
31
|
+
token: cfg.token,
|
|
32
|
+
...typeof cfg.email === "string" ? { email: cfg.email } : {}
|
|
33
|
+
};
|
|
34
|
+
} catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function defaultApmConfig() {
|
|
39
|
+
return {
|
|
40
|
+
baseUrl: DEFAULT_BASE_URL,
|
|
41
|
+
userId: "",
|
|
42
|
+
token: "",
|
|
43
|
+
email: ""
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function httpBaseToWsOrigin(httpBase) {
|
|
47
|
+
const u = httpBase.trim().replace(/\/+$/, "");
|
|
48
|
+
if (u.startsWith("https://")) return "wss://" + u.slice("https://".length);
|
|
49
|
+
if (u.startsWith("http://")) return "ws://" + u.slice("http://".length);
|
|
50
|
+
throw new Error("baseUrl \u5FC5\u987B\u4EE5 http:// \u6216 https:// \u5F00\u5934");
|
|
51
|
+
}
|
|
52
|
+
async function ensureApmConfig() {
|
|
53
|
+
const existing = await readApmConfig();
|
|
54
|
+
if (existing) return existing;
|
|
55
|
+
const defaults = defaultApmConfig();
|
|
56
|
+
await writeApmConfig(defaults);
|
|
57
|
+
return defaults;
|
|
58
|
+
}
|
|
59
|
+
async function writeApmConfig(cfg) {
|
|
60
|
+
const normalized = {
|
|
61
|
+
baseUrl: cfg.baseUrl.trim().replace(/\/+$/, ""),
|
|
62
|
+
userId: cfg.userId,
|
|
63
|
+
token: cfg.token,
|
|
64
|
+
...typeof cfg.email === "string" ? { email: cfg.email } : {}
|
|
65
|
+
};
|
|
66
|
+
mkdirSync(APM_CONFIG_DIR, { recursive: true });
|
|
67
|
+
writeFileSync(APM_CONFIG_PATH, JSON.stringify(normalized, null, 2) + "\n", {
|
|
68
|
+
mode: 384
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function buildAgentWsUrl(httpBase, token) {
|
|
72
|
+
const origin = httpBaseToWsOrigin(httpBase);
|
|
73
|
+
const q = new URLSearchParams({ token });
|
|
74
|
+
return `${origin}/ws/agent?${q.toString()}`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/commands/comment.ts
|
|
78
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
79
|
+
|
|
80
|
+
// src/api/client.ts
|
|
81
|
+
import { createApiClient } from "listpage-http";
|
|
82
|
+
|
|
83
|
+
// src/api/request-config.ts
|
|
84
|
+
import { defineEndpoint } from "listpage-http";
|
|
85
|
+
var requestConfig = {
|
|
86
|
+
auth: {
|
|
87
|
+
login: defineEndpoint({
|
|
88
|
+
method: "POST",
|
|
89
|
+
path: "/auth/login",
|
|
90
|
+
authRequired: false
|
|
91
|
+
})
|
|
92
|
+
},
|
|
93
|
+
cliRequirements: {
|
|
94
|
+
pull: defineEndpoint({
|
|
95
|
+
method: "GET",
|
|
96
|
+
path: "/cli/requirements/pull"
|
|
97
|
+
}),
|
|
98
|
+
comment: defineEndpoint({
|
|
99
|
+
method: "POST",
|
|
100
|
+
path: "/cli/requirements/comment"
|
|
101
|
+
}),
|
|
102
|
+
refine: defineEndpoint({
|
|
103
|
+
method: "POST",
|
|
104
|
+
path: "/cli/requirements/refine"
|
|
105
|
+
}),
|
|
106
|
+
updateStatus: defineEndpoint({
|
|
107
|
+
method: "POST",
|
|
108
|
+
path: "/cli/requirements/update-status"
|
|
109
|
+
}),
|
|
110
|
+
updateDevStatus: defineEndpoint({
|
|
111
|
+
method: "POST",
|
|
112
|
+
path: "/cli/requirements/update-dev-status"
|
|
113
|
+
})
|
|
114
|
+
}
|
|
15
115
|
};
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
116
|
+
|
|
117
|
+
// src/api/client.ts
|
|
118
|
+
function createApmApiClient(cfg) {
|
|
119
|
+
const baseURL = `${cfg.baseUrl.trim().replace(/\/+$/, "")}/api`;
|
|
120
|
+
return createApiClient(requestConfig, {
|
|
121
|
+
baseURL,
|
|
122
|
+
getToken: () => cfg.token || void 0,
|
|
123
|
+
successCodes: [200, 201],
|
|
124
|
+
unauthorizedCodes: [401]
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// src/command-utils.ts
|
|
129
|
+
import { cpSync, existsSync, mkdirSync as mkdirSync2, readdirSync, statSync } from "fs";
|
|
130
|
+
import { dirname, join as join2, resolve } from "path";
|
|
131
|
+
import { fileURLToPath } from "url";
|
|
132
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
133
|
+
var CLI_TEMPLATE_DIR = resolve(__dirname, "../template");
|
|
134
|
+
var WORKSPACE_APM_DIR = resolve(process.cwd(), ".apm");
|
|
135
|
+
async function ensureLoggedConfig() {
|
|
136
|
+
const cfg = await ensureApmConfig();
|
|
137
|
+
if (!cfg.token) {
|
|
138
|
+
console.error(
|
|
139
|
+
"[apm] \u672A\u68C0\u6D4B\u5230 token\uFF0C\u8BF7\u5148\u6267\u884C: apm login --email ... --password ..."
|
|
140
|
+
);
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
return cfg;
|
|
144
|
+
}
|
|
145
|
+
async function ensureDirExists(dir) {
|
|
146
|
+
mkdirSync2(dir, { recursive: true });
|
|
147
|
+
}
|
|
148
|
+
async function ensureWorkspaceApmDirForInit() {
|
|
149
|
+
const dir = WORKSPACE_APM_DIR;
|
|
150
|
+
if (!existsSync(dir)) {
|
|
151
|
+
mkdirSync2(dir, { recursive: true });
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const st = statSync(dir);
|
|
155
|
+
if (!st.isDirectory()) {
|
|
156
|
+
throw new Error(`[apm] \u8DEF\u5F84\u5DF2\u5B58\u5728\u4F46\u4E0D\u662F\u76EE\u5F55: ${dir}`);
|
|
157
|
+
}
|
|
158
|
+
if (readdirSync(dir).length > 0) {
|
|
159
|
+
throw new Error(
|
|
160
|
+
"[apm] .apm \u76EE\u5F55\u5DF2\u5B58\u5728\u4E14\u975E\u7A7A\uFF0C\u8BF7\u5148\u5907\u4EFD\u3001\u6E05\u7A7A\u6216\u5220\u9664\u540E\u518D\u6267\u884C init"
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
async function copyTemplateFiles(targetDir) {
|
|
165
|
+
try {
|
|
166
|
+
const dirStat = statSync(CLI_TEMPLATE_DIR);
|
|
167
|
+
if (!dirStat.isDirectory()) return;
|
|
168
|
+
} catch {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const entries = readdirSync(CLI_TEMPLATE_DIR);
|
|
172
|
+
await Promise.all(
|
|
173
|
+
entries.map(async (name) => {
|
|
174
|
+
const src = join2(CLI_TEMPLATE_DIR, name);
|
|
175
|
+
const dest = join2(targetDir, name);
|
|
176
|
+
cpSync(src, dest, { recursive: true, force: false });
|
|
177
|
+
})
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
function xmlEscape(v) {
|
|
181
|
+
return v.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
182
|
+
}
|
|
183
|
+
function resolveCwdPath(file) {
|
|
184
|
+
return resolve(process.cwd(), file);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// src/commands/comment.ts
|
|
188
|
+
async function runComment(requirementId, file, model) {
|
|
189
|
+
const cfg = await ensureLoggedConfig();
|
|
190
|
+
const content = readFileSync2(resolveCwdPath(file), "utf8");
|
|
191
|
+
const api = createApmApiClient(cfg);
|
|
192
|
+
const data = await api.cliRequirements.comment({
|
|
193
|
+
requirementId,
|
|
194
|
+
content,
|
|
195
|
+
model
|
|
196
|
+
});
|
|
197
|
+
console.log(JSON.stringify(data, null, 2));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// src/commands/connect.ts
|
|
201
|
+
import { randomUUID } from "crypto";
|
|
202
|
+
import WebSocket from "ws";
|
|
203
|
+
function runConnect(opts) {
|
|
204
|
+
void (async () => {
|
|
205
|
+
const cfg = await ensureApmConfig();
|
|
206
|
+
const server = opts.server?.trim();
|
|
207
|
+
if (server) {
|
|
208
|
+
cfg.baseUrl = server.replace(/\/+$/, "");
|
|
209
|
+
await writeApmConfig(cfg);
|
|
210
|
+
}
|
|
211
|
+
if (!cfg.token) {
|
|
212
|
+
console.error(
|
|
213
|
+
"[apm] \u672A\u68C0\u6D4B\u5230 token\uFF0C\u8BF7\u5148\u6267\u884C: apm login --email ... --password ..."
|
|
214
|
+
);
|
|
215
|
+
console.error(`[apm] \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84: ${APM_CONFIG_PATH}`);
|
|
216
|
+
process.exit(1);
|
|
217
|
+
}
|
|
218
|
+
const url = buildAgentWsUrl(cfg.baseUrl, cfg.token);
|
|
219
|
+
console.error(`[apm] \u8FDE\u63A5 ${url.replace(cfg.token, "<token>")} \u2026`);
|
|
220
|
+
const ws = new WebSocket(url);
|
|
221
|
+
ws.on("open", () => {
|
|
222
|
+
console.error("[apm] \u5DF2\u8FDE\u63A5");
|
|
223
|
+
const sendHeartbeat = () => {
|
|
224
|
+
const frame = {
|
|
225
|
+
type: "HEARTBEAT",
|
|
226
|
+
msg_id: randomUUID(),
|
|
227
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
228
|
+
payload: {}
|
|
229
|
+
};
|
|
230
|
+
ws.send(JSON.stringify(frame));
|
|
231
|
+
};
|
|
232
|
+
sendHeartbeat();
|
|
233
|
+
const interval = setInterval(sendHeartbeat, 15e3);
|
|
234
|
+
ws.on("close", () => clearInterval(interval));
|
|
235
|
+
});
|
|
236
|
+
ws.on("message", (data) => {
|
|
237
|
+
const text = typeof data === "string" ? data : data.toString();
|
|
238
|
+
console.log(text);
|
|
239
|
+
});
|
|
240
|
+
ws.on("error", (err) => {
|
|
241
|
+
console.error("[apm] WebSocket \u9519\u8BEF:", err.message);
|
|
242
|
+
});
|
|
243
|
+
ws.on("close", (code, reason) => {
|
|
244
|
+
console.error(`[apm] \u8FDE\u63A5\u5173\u95ED code=${code} reason=${reason.toString()}`);
|
|
245
|
+
process.exit(code === 1e3 ? 0 : 1);
|
|
246
|
+
});
|
|
247
|
+
})();
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// src/commands/init.ts
|
|
251
|
+
import { join as join3 } from "path";
|
|
252
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
253
|
+
async function runInit(name) {
|
|
254
|
+
await ensureWorkspaceApmDirForInit();
|
|
255
|
+
await copyTemplateFiles(WORKSPACE_APM_DIR);
|
|
256
|
+
if (name) {
|
|
257
|
+
const apmConfigPath = join3(WORKSPACE_APM_DIR, "apm.config.json");
|
|
258
|
+
const config = readFileSync3(apmConfigPath, "utf8");
|
|
259
|
+
const configJson = JSON.parse(config);
|
|
260
|
+
configJson.name = name;
|
|
261
|
+
writeFileSync2(apmConfigPath, JSON.stringify(configJson, null, 2), "utf8");
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// src/commands/login.ts
|
|
266
|
+
import { ApiError } from "listpage-http";
|
|
267
|
+
async function runLogin(opts) {
|
|
268
|
+
const baseUrl = (opts.server?.trim() || process.env.AI_PM_SERVER?.trim() || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
269
|
+
const api = createApmApiClient({
|
|
270
|
+
baseUrl,
|
|
271
|
+
userId: "",
|
|
272
|
+
token: ""
|
|
273
|
+
});
|
|
274
|
+
let data;
|
|
275
|
+
try {
|
|
276
|
+
data = await api.auth.login({
|
|
277
|
+
email: opts.email,
|
|
278
|
+
password: opts.password
|
|
279
|
+
});
|
|
280
|
+
} catch (raw) {
|
|
281
|
+
if (raw instanceof ApiError) {
|
|
282
|
+
const err = raw;
|
|
283
|
+
console.error(
|
|
284
|
+
`[apm] \u767B\u5F55\u5931\u8D25 (${err.httpStatus ?? err.code}):`,
|
|
285
|
+
err.message
|
|
286
|
+
);
|
|
287
|
+
process.exit(1);
|
|
288
|
+
}
|
|
289
|
+
console.error(
|
|
290
|
+
"[apm] \u8BF7\u6C42\u5931\u8D25:",
|
|
291
|
+
raw instanceof Error ? raw.message : raw
|
|
292
|
+
);
|
|
293
|
+
process.exit(1);
|
|
294
|
+
}
|
|
295
|
+
if (!data?.id || !data?.token) {
|
|
296
|
+
console.error("[apm] \u54CD\u5E94\u7F3A\u5C11 id / token\uFF08\u8BF7\u786E\u8BA4\u670D\u52A1\u7AEF\u4E3A /api/auth/login\uFF09");
|
|
297
|
+
process.exit(1);
|
|
298
|
+
}
|
|
299
|
+
const cfg = {
|
|
300
|
+
baseUrl,
|
|
301
|
+
userId: data.id,
|
|
302
|
+
token: data.token,
|
|
303
|
+
email: opts.email
|
|
304
|
+
};
|
|
305
|
+
await writeApmConfig(cfg);
|
|
306
|
+
console.error(`[apm] \u5DF2\u4FDD\u5B58\u767B\u5F55\u4FE1\u606F: ${APM_CONFIG_PATH}`);
|
|
307
|
+
console.log(JSON.stringify({ userId: cfg.userId, baseUrl: cfg.baseUrl }, null, 2));
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// src/commands/pull.ts
|
|
311
|
+
import { writeFileSync as writeFileSync3 } from "fs";
|
|
312
|
+
import { join as join4 } from "path";
|
|
313
|
+
import { stringify as yamlStringify } from "yaml";
|
|
314
|
+
function valueToXmlContent(value) {
|
|
315
|
+
if (value === null || value === void 0) return "";
|
|
316
|
+
if (typeof value === "string") return xmlEscape(value);
|
|
317
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
318
|
+
return xmlEscape(String(value));
|
|
319
|
+
}
|
|
320
|
+
return `<![CDATA[${JSON.stringify(value)}]]>`;
|
|
321
|
+
}
|
|
322
|
+
function recordToXmlLines(record, indent) {
|
|
323
|
+
const lines = [];
|
|
324
|
+
for (const [rawKey, val] of Object.entries(record)) {
|
|
325
|
+
const key = /^[a-zA-Z_][\w.-]*$/.test(rawKey) ? rawKey : "field";
|
|
326
|
+
lines.push(`${indent}<${key}>${valueToXmlContent(val)}</${key}>`);
|
|
327
|
+
}
|
|
328
|
+
return lines;
|
|
329
|
+
}
|
|
330
|
+
function unknownArrayToXml(rootName, itemName, items) {
|
|
331
|
+
const lines = [`<${rootName}>`];
|
|
332
|
+
items.forEach((item, index) => {
|
|
333
|
+
if (item !== null && typeof item === "object" && !Array.isArray(item)) {
|
|
334
|
+
lines.push(` <${itemName} index="${index}">`);
|
|
335
|
+
lines.push(...recordToXmlLines(item, " "));
|
|
336
|
+
lines.push(` </${itemName}>`);
|
|
337
|
+
} else {
|
|
338
|
+
lines.push(
|
|
339
|
+
` <${itemName} index="${index}">${valueToXmlContent(
|
|
340
|
+
item
|
|
341
|
+
)}</${itemName}>`
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
lines.push(`</${rootName}>`, "");
|
|
346
|
+
return lines.join("\n");
|
|
347
|
+
}
|
|
348
|
+
function tasksForStatusYaml(tasks) {
|
|
349
|
+
return tasks.map((t) => ({
|
|
350
|
+
id: t.id,
|
|
351
|
+
title: t.title,
|
|
352
|
+
status: t.status,
|
|
353
|
+
executor: t.executorType
|
|
354
|
+
}));
|
|
355
|
+
}
|
|
356
|
+
async function runPull(requirementId) {
|
|
357
|
+
const cfg = await ensureLoggedConfig();
|
|
358
|
+
const api = createApmApiClient(cfg);
|
|
359
|
+
const data = await api.cliRequirements.pull({ requirementId });
|
|
360
|
+
const WORKITEMS_DIR = join4(WORKSPACE_APM_DIR, "workitems", requirementId);
|
|
361
|
+
await ensureDirExists(WORKITEMS_DIR);
|
|
362
|
+
const req = data.requirement;
|
|
363
|
+
const statusYaml = yamlStringify(
|
|
364
|
+
{
|
|
365
|
+
id: req.id,
|
|
366
|
+
status: req.status,
|
|
367
|
+
...req.urgency != null && req.urgency !== "" ? { urgency: req.urgency } : {},
|
|
368
|
+
title: req.title,
|
|
369
|
+
...req.pauseReason != null && req.pauseReason.trim() !== "" ? { pauseReason: req.pauseReason } : {},
|
|
370
|
+
tasks: tasksForStatusYaml(data.tasks ?? [])
|
|
371
|
+
},
|
|
372
|
+
{ lineWidth: 0 }
|
|
373
|
+
);
|
|
374
|
+
writeFileSync3(
|
|
375
|
+
join4(WORKITEMS_DIR, "requirement-status.yaml"),
|
|
376
|
+
statusYaml.endsWith("\n") ? statusYaml : `${statusYaml}
|
|
377
|
+
`,
|
|
378
|
+
"utf8"
|
|
379
|
+
);
|
|
380
|
+
writeFileSync3(join4(WORKITEMS_DIR, "prd.md"), req.content || "", "utf8");
|
|
381
|
+
const reviews = data.reviews ?? [];
|
|
382
|
+
const reviewsXml = [
|
|
383
|
+
"<reviews>",
|
|
384
|
+
...reviews.map((r) => {
|
|
385
|
+
return [
|
|
386
|
+
` <review id="${xmlEscape(r.id)}">`,
|
|
387
|
+
` <model>${xmlEscape(r.model ?? "")}</model>`,
|
|
388
|
+
` <content>`,
|
|
389
|
+
`${xmlEscape(r.content ?? "")}`,
|
|
390
|
+
` </content>`,
|
|
391
|
+
` <reply>`,
|
|
392
|
+
`${xmlEscape(r.reply ?? "")}`,
|
|
393
|
+
` </reply>`,
|
|
394
|
+
" </review>"
|
|
395
|
+
].join("\n");
|
|
396
|
+
}),
|
|
397
|
+
"</reviews>",
|
|
398
|
+
""
|
|
399
|
+
].join("\n");
|
|
400
|
+
writeFileSync3(join4(WORKITEMS_DIR, "reviews.xml"), reviewsXml, "utf8");
|
|
401
|
+
const defectsXml = unknownArrayToXml("defects", "defect", data.defects ?? []);
|
|
402
|
+
writeFileSync3(join4(WORKITEMS_DIR, "defect.xml"), defectsXml, "utf8");
|
|
403
|
+
const testCasesXml = unknownArrayToXml(
|
|
404
|
+
"testcases",
|
|
405
|
+
"case",
|
|
406
|
+
data.testCases ?? []
|
|
407
|
+
);
|
|
408
|
+
writeFileSync3(join4(WORKITEMS_DIR, "testcase.xml"), testCasesXml, "utf8");
|
|
409
|
+
return WORKITEMS_DIR;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// src/commands/refine.ts
|
|
413
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
414
|
+
import { join as join5 } from "path";
|
|
415
|
+
async function runRefine(requirementId) {
|
|
416
|
+
const cfg = await ensureLoggedConfig();
|
|
417
|
+
const filePath = join5(WORKSPACE_APM_DIR, "workitems", requirementId, "prd.md");
|
|
418
|
+
const content = readFileSync4(filePath, "utf8");
|
|
419
|
+
const api = createApmApiClient(cfg);
|
|
420
|
+
const data = await api.cliRequirements.refine({ requirementId, content });
|
|
421
|
+
console.log(JSON.stringify(data, null, 2));
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// src/commands/update-dev-status.ts
|
|
425
|
+
async function runUpdateDevStatus(requirementId, status) {
|
|
426
|
+
const cfg = await ensureLoggedConfig();
|
|
427
|
+
const api = createApmApiClient(cfg);
|
|
428
|
+
const data = await api.cliRequirements.updateDevStatus({
|
|
429
|
+
requirementId,
|
|
430
|
+
status
|
|
431
|
+
});
|
|
432
|
+
console.log(JSON.stringify(data, null, 2));
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// src/commands/update-status.ts
|
|
436
|
+
async function runUpdateStatus(requirementId, status) {
|
|
437
|
+
const cfg = await ensureLoggedConfig();
|
|
438
|
+
const api = createApmApiClient(cfg);
|
|
439
|
+
const data = await api.cliRequirements.updateStatus({
|
|
440
|
+
requirementId,
|
|
441
|
+
status
|
|
442
|
+
});
|
|
443
|
+
console.log(JSON.stringify(data, null, 2));
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// src/index.ts
|
|
447
|
+
function readCliVersion() {
|
|
448
|
+
try {
|
|
449
|
+
const dir = dirname2(fileURLToPath2(import.meta.url));
|
|
450
|
+
const pkgPath = join6(dir, "..", "package.json");
|
|
451
|
+
const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
|
|
452
|
+
return pkg.version ?? "0.0.0";
|
|
453
|
+
} catch {
|
|
454
|
+
return "0.0.0";
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
function buildProgram() {
|
|
458
|
+
const program = new Command();
|
|
459
|
+
program.name("apm").description(
|
|
460
|
+
`\u5E73\u53F0\u547D\u4EE4\u884C\uFF08Agent \u901A\u9053\u4E0E\u9700\u6C42 CLI\uFF09\u3002
|
|
461
|
+
\u672A\u4F20 --server \u65F6\u4F18\u5148\u4F7F\u7528\u73AF\u5883\u53D8\u91CF AI_PM_SERVER\uFF0C\u5426\u5219\u9ED8\u8BA4 ${DEFAULT_BASE_URL}\u3002`
|
|
462
|
+
).version(readCliVersion(), "-V, --version", "\u663E\u793A\u7248\u672C\u53F7").helpOption("-h, --help", "\u663E\u793A\u5E2E\u52A9").showHelpAfterError(true);
|
|
463
|
+
program.command("login").description(
|
|
464
|
+
"\u8C03\u7528 POST /api/auth/login\uFF0C\u5C06 token \u5199\u5165 ~/.config/apm/config.json"
|
|
465
|
+
).requiredOption("--email <\u90AE\u7BB1>", "\u767B\u5F55\u90AE\u7BB1").requiredOption("--password <\u5BC6\u7801>", "\u767B\u5F55\u5BC6\u7801").option("--server <url>", "API \u6839\u5730\u5740\uFF0C\u4F8B\u5982 http://127.0.0.1:3000").action(async (opts) => {
|
|
466
|
+
await runLogin(opts);
|
|
467
|
+
});
|
|
468
|
+
program.command("connect").description("\u8FDE\u63A5 WebSocket /ws/agent\uFF0C\u5E76\u6309\u56FA\u5B9A\u95F4\u9694\u53D1\u9001 HEARTBEAT").option("--server <url>", "API \u6839\u5730\u5740\uFF08\u5199\u5165\u672C\u5730\u914D\u7F6E\uFF09").action((opts) => {
|
|
469
|
+
runConnect(opts);
|
|
470
|
+
});
|
|
471
|
+
program.command("init").description(
|
|
472
|
+
"\u5728\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u521D\u59CB\u5316 .apm \u6A21\u677F\uFF08\u82E5 .apm \u5DF2\u5B58\u5728\u4E14\u975E\u7A7A\u5219\u62A5\u9519\uFF09"
|
|
473
|
+
).option("--name <name>", "\u5DE5\u4F5C\u76EE\u5F55\u540D\u79F0").action(async (opts) => {
|
|
474
|
+
await runInit(opts.name);
|
|
475
|
+
});
|
|
476
|
+
program.command("pull").description("GET /api/cli/requirements/pull\uFF0C\u540C\u6B65\u6570\u636E\u5230 .apm \u76EE\u5F55").argument("<requirementId>", "\u9700\u6C42 ID").action(async (requirementId) => {
|
|
477
|
+
await runPull(requirementId);
|
|
478
|
+
});
|
|
479
|
+
program.command("comment").description("POST /api/cli/requirements/comment\uFF08\u6B63\u6587\u6765\u81EA\u6587\u4EF6\uFF09").argument("<requirementId>", "\u9700\u6C42 ID").requiredOption("--file <path>", "\u8BC4\u8BBA\u6B63\u6587\u6587\u4EF6\u8DEF\u5F84").option("--model <model>", "\u8BC4\u8BBA\u6A21\u578B").action(
|
|
480
|
+
async (requirementId, options) => {
|
|
481
|
+
await runComment(requirementId, options.file, options.model);
|
|
482
|
+
}
|
|
483
|
+
);
|
|
484
|
+
program.command("refine").description("POST /api/cli/requirements/refine\uFF08\u6B63\u6587\u6765\u81EA\u6587\u4EF6\uFF09").argument("<requirementId>", "\u9700\u6C42 ID").action(async (requirementId) => {
|
|
485
|
+
await runRefine(requirementId);
|
|
486
|
+
});
|
|
487
|
+
program.command("update-status").description("POST /api/cli/requirements/update-status").argument("<requirementId>", "\u9700\u6C42 ID").requiredOption("--status <RequirementStatus>", "\u9700\u6C42\u72B6\u6001\u679A\u4E3E\u503C").action(async (requirementId, options) => {
|
|
488
|
+
await runUpdateStatus(requirementId, options.status);
|
|
489
|
+
});
|
|
490
|
+
program.command("update-dev-status").description("POST /api/cli/requirements/update-dev-status").argument("<requirementId>", "\u9700\u6C42 ID").requiredOption("--status <status>", "\u6210\u5458\u5F00\u53D1\u72B6\u6001\uFF08\u81EA\u7531\u6587\u672C\uFF09").action(async (requirementId, options) => {
|
|
491
|
+
await runUpdateDevStatus(requirementId, options.status);
|
|
492
|
+
});
|
|
493
|
+
return program;
|
|
494
|
+
}
|
|
495
|
+
async function main() {
|
|
496
|
+
const program = buildProgram();
|
|
497
|
+
await program.parseAsync(process.argv);
|
|
498
|
+
}
|
|
499
|
+
main().catch((err) => {
|
|
500
|
+
console.error("[apm]", err instanceof Error ? err.message : err);
|
|
501
|
+
process.exit(1);
|
|
502
|
+
});
|
package/package.json
CHANGED
|
@@ -1,38 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-project-manage-cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.2",
|
|
4
|
+
"description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
|
|
5
|
+
"type": "module",
|
|
4
6
|
"private": false,
|
|
5
|
-
"
|
|
6
|
-
"main": "./dist/index.js",
|
|
7
|
-
"types": "./dist/index.d.ts",
|
|
7
|
+
"license": "UNLICENSED",
|
|
8
8
|
"bin": {
|
|
9
|
-
"apm": "dist/
|
|
10
|
-
},
|
|
11
|
-
"exports": {
|
|
12
|
-
".": {
|
|
13
|
-
"types": "./dist/index.d.ts",
|
|
14
|
-
"import": "./dist/index.js",
|
|
15
|
-
"require": "./dist/index.js"
|
|
16
|
-
}
|
|
9
|
+
"apm": "./dist/index.js"
|
|
17
10
|
},
|
|
11
|
+
"main": "./dist/index.js",
|
|
18
12
|
"files": [
|
|
19
13
|
"dist",
|
|
20
|
-
"
|
|
14
|
+
"template"
|
|
21
15
|
],
|
|
22
16
|
"scripts": {
|
|
23
|
-
"build": "tsc -p tsconfig.json"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"minio": "~8.0.7",
|
|
30
|
-
"dockerode": "~4.0.10"
|
|
17
|
+
"build": "rm -rf dist && esbuild src/index.ts --bundle --platform=node --format=esm --packages=external --outfile=dist/index.js && tsc --noEmit -p tsconfig.json",
|
|
18
|
+
"prepublishOnly": "npm run build",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"test:watch": "vitest",
|
|
21
|
+
"test:init": "vitest run tests/cli-init.test.ts",
|
|
22
|
+
"test:pull": "vitest run tests/cli-pull.test.ts"
|
|
31
23
|
},
|
|
32
24
|
"devDependencies": {
|
|
33
|
-
"@types/node": "^22.
|
|
34
|
-
"typescript": "~5.
|
|
25
|
+
"@types/node": "^22.0.0",
|
|
26
|
+
"typescript": "~5.6.0",
|
|
35
27
|
"@types/ws": "~8.18.1",
|
|
36
|
-
"
|
|
28
|
+
"esbuild": "~0.28.0",
|
|
29
|
+
"vitest": "~4.1.5"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=18"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"ws": "~8.20.0",
|
|
36
|
+
"listpage-http": "~0.0.318",
|
|
37
|
+
"commander": "~14.0.3",
|
|
38
|
+
"yaml": "~2.8.4"
|
|
37
39
|
}
|
|
38
|
-
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: apm-review
|
|
3
|
+
description: 根据需求 ID 读取工作项 prd.md,对照代码做需求评审;评审立场依可见代码而定(仅前台 / 仅后台 / 全栈);提交到评论的正文用 Markdown 拉出层次与重点,业务白话、避免代码与工程术语;结合代码交付面过滤与现状无关的空头边界质疑,当用户在对话中 @ 本技能时使用。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# APM 需求评审(对照代码)
|
|
7
|
+
|
|
8
|
+
用户仅提供 **需求 ID**(workitem id)。缺 ID 时索要,不猜测。
|
|
9
|
+
|
|
10
|
+
**评审规范与评审模板**(受众与用语、立场与范围、书写约束、正文示例等)见同目录 **[apm-review-reference.md](./apm-review-reference.md)**;执行本技能时须按该文件撰写评审正文。
|
|
11
|
+
|
|
12
|
+
## 强制执行顺序(三步)
|
|
13
|
+
|
|
14
|
+
### 步骤 1:读取 `prd.md`
|
|
15
|
+
|
|
16
|
+
1. 使用 **Read** 读取 `.apm/workitems/<需求ID>/prd.md`。
|
|
17
|
+
2. 若 Read **失败**(文件不存在或无法读取):本步骤记为失败,**终止**,不执行步骤 2、3。
|
|
18
|
+
|
|
19
|
+
### 步骤 2:撰写评审、落盘、推送、清理
|
|
20
|
+
|
|
21
|
+
1. 使用 **Read** 读取 [apm-review-reference.md](./apm-review-reference.md)(与 `SKILL.md` 同目录),并依其中规范对照代码撰写 **Markdown 评审正文**:**只写确实存在的问题**;用「需求背景 / 需求范围 / 交互与功能要求第 X 节 / 非目标」等文档自有结构**点名条款**,不先单独铺一节「对用户意图的理解」。撰写前须完成代码检索并锁定本轮**评审立场**(见 reference 中「评审立场」),正文内容与措辞须与该立场一致,**不得超越可见范围下断定**。
|
|
22
|
+
2. 使用 **Write** 将正文写入**临时文件**,路径建议使用**绝对路径**,例如 `/tmp/apm-review-<需求ID>.md`(避免与相对 cwd 混淆)。
|
|
23
|
+
3. 在项目根目录下执行:`apm comment <需求ID> --file=<临时文件绝对路径> --model=<评论使用的模型名称>`。
|
|
24
|
+
4. 命令结束后 **删除临时文件**(**Delete** 工具或 `rm`),无论命令成功或失败都尽量清理(失败时保留文件仅供用户排错——技能默认仍删除,若需保留应在表格备注中说明)。
|
|
25
|
+
|
|
26
|
+
### 步骤 3:回复用户
|
|
27
|
+
|
|
28
|
+
对用户可见回复 **仅限一张 Markdown 表格**,汇总三步的**结果**(成功/失败、摘要信息)。**不得**在表格外输出任何其他内容(不在对话中粘贴完整评审正文;正文已通过 `apm comment` 提交)。
|
|
29
|
+
|
|
30
|
+
建议表头:
|
|
31
|
+
|
|
32
|
+
| 步骤 | 结果 | 说明 |
|
|
33
|
+
|------|------|------|
|
|
34
|
+
| 1. 读取 prd.md | 成功 / 失败 | 例如实际读取路径;失败时写错误原因 |
|
|
35
|
+
| 2. 评审与 comment | 成功 / 失败 | 临时文件路径(已删可写「已清理」);`apm comment` 退出情况或 API 返回摘要;**建议**注明本轮评审立场(仅前台 / 仅后台 / 全栈) |
|
|
36
|
+
| 3. 清理临时文件 | 成功 / 失败 | — |
|
|
37
|
+
|
|
38
|
+
内部编排:**通读 prd → 检索并对照与需求相关的代码 → 判定本轮可见范围(仅前台 / 仅后台 / 全栈)并选定评审立场 → 将技术发现改写为业务白话 → 只输出有问题之处**;唯**对用户输出**遵守上表约束。
|