ai-project-manage-cli 8.1.7 → 8.1.9
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/README.md +1 -1
- package/dist/index.js +209 -222
- package/dist/worker-script.js +157 -261
- package/package.json +1 -1
- package/template/AGENTS.webide.md +0 -28
- package/template/rules/webide_git_commit.md +0 -16
- package/template/rules/webide_merge.md +0 -24
- package/template/rules/webide_package.md +0 -70
- package/template/rules/webide_reply.md +0 -18
- package/template/rules/webide_sql_change.md +0 -28
- package/template/rules/webide_sql_execute.md +0 -29
- package/template/rules/webide_terminal.md +0 -45
- package/template/rules/webide_testcase.md +0 -47
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -79,179 +79,9 @@ function buildAgentWsUrl(httpBase, apiKey) {
|
|
|
79
79
|
return `${origin}/ws/agent?${q.toString()}`;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
// src/
|
|
83
|
-
import {
|
|
84
|
-
import {
|
|
85
|
-
import { fileURLToPath } from "url";
|
|
86
|
-
|
|
87
|
-
// src/utils/path.ts
|
|
88
|
-
import { realpathSync } from "fs";
|
|
89
|
-
import { platform } from "os";
|
|
90
|
-
import { resolve } from "path";
|
|
91
|
-
function toFsPath(inputPath) {
|
|
92
|
-
const absolute = resolve(inputPath);
|
|
93
|
-
if (platform() !== "win32") return absolute;
|
|
94
|
-
if (absolute.startsWith("\\\\?\\")) return absolute;
|
|
95
|
-
const normalized = absolute.replace(/\//g, "\\");
|
|
96
|
-
if (normalized.startsWith("\\\\")) {
|
|
97
|
-
return `\\\\?\\UNC\\${normalized.slice(2)}`;
|
|
98
|
-
}
|
|
99
|
-
return `\\\\?\\${normalized}`;
|
|
100
|
-
}
|
|
101
|
-
function normalizeWorkdirPath(path) {
|
|
102
|
-
let normalized = path.trim().replace(/\\/g, "/").normalize("NFC");
|
|
103
|
-
if (normalized.startsWith("//?/")) {
|
|
104
|
-
normalized = normalized.slice(4);
|
|
105
|
-
}
|
|
106
|
-
const windowsDrive = /^([A-Za-z]:)\/*(.*)$/.exec(normalized);
|
|
107
|
-
if (windowsDrive) {
|
|
108
|
-
const drive = windowsDrive[1].toLowerCase();
|
|
109
|
-
const rest = windowsDrive[2].replace(/\/+/g, "/").replace(/\/$/, "");
|
|
110
|
-
return rest ? `${drive}/${rest}` : drive;
|
|
111
|
-
}
|
|
112
|
-
normalized = normalized.replace(/\/+/g, "/");
|
|
113
|
-
if (normalized.length > 1 && normalized.endsWith("/")) {
|
|
114
|
-
normalized = normalized.slice(0, -1);
|
|
115
|
-
}
|
|
116
|
-
return normalized;
|
|
117
|
-
}
|
|
118
|
-
function resolveWorkdirPath(cwd = process.cwd()) {
|
|
119
|
-
const absolute = resolve(cwd);
|
|
120
|
-
try {
|
|
121
|
-
return normalizeWorkdirPath(realpathSync.native(absolute));
|
|
122
|
-
} catch {
|
|
123
|
-
return normalizeWorkdirPath(absolute);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// src/utils/workspace.ts
|
|
128
|
-
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
129
|
-
var CLI_TEMPLATE_DIR = resolve2(__dirname, "../template");
|
|
130
|
-
function workspaceApmDir(cwd = resolveWorkdirPath()) {
|
|
131
|
-
return resolve2(resolve2(cwd), ".apm");
|
|
132
|
-
}
|
|
133
|
-
async function ensureLoggedConfig() {
|
|
134
|
-
const cfg = await ensureApmConfig();
|
|
135
|
-
if (!resolveApiKey(cfg)) {
|
|
136
|
-
console.error(
|
|
137
|
-
"[apm] \u672A\u68C0\u6D4B\u5230 API Key\uFF0C\u8BF7\u5148\u6267\u884C: apm login --api-key cm_xxx"
|
|
138
|
-
);
|
|
139
|
-
process.exit(1);
|
|
140
|
-
}
|
|
141
|
-
return cfg;
|
|
142
|
-
}
|
|
143
|
-
async function ensureDirExists(dir) {
|
|
144
|
-
mkdirSync2(dir, { recursive: true });
|
|
145
|
-
}
|
|
146
|
-
async function ensureWorkspaceApmDirForInit(cwd = resolveWorkdirPath()) {
|
|
147
|
-
const dir = workspaceApmDir(cwd);
|
|
148
|
-
const fsDir = toFsPath(dir);
|
|
149
|
-
if (existsSync(fsDir) && !statSync(fsDir).isDirectory()) {
|
|
150
|
-
throw new Error(`[apm] \u8DEF\u5F84\u5DF2\u5B58\u5728\u4F46\u4E0D\u662F\u76EE\u5F55: ${dir}`);
|
|
151
|
-
}
|
|
152
|
-
mkdirSync2(fsDir, { recursive: true });
|
|
153
|
-
}
|
|
154
|
-
var WEBIDE_AGENTS_TEMPLATE_NAME = "AGENTS.webide.md";
|
|
155
|
-
function shouldSkipTemplateEntry(name) {
|
|
156
|
-
return name === ".DS_Store" || name === "Thumbs.db";
|
|
157
|
-
}
|
|
158
|
-
function isWebIdeRuleFileName(name) {
|
|
159
|
-
return name.startsWith("webide");
|
|
160
|
-
}
|
|
161
|
-
function copyTemplateEntry(src, dest) {
|
|
162
|
-
const fsSrc = toFsPath(src);
|
|
163
|
-
const fsDest = toFsPath(dest);
|
|
164
|
-
const st = statSync(fsSrc);
|
|
165
|
-
if (st.isDirectory()) {
|
|
166
|
-
mkdirSync2(fsDest, { recursive: true });
|
|
167
|
-
for (const name of readdirSync(fsSrc)) {
|
|
168
|
-
if (shouldSkipTemplateEntry(name)) continue;
|
|
169
|
-
copyTemplateEntry(join2(src, name), join2(dest, name));
|
|
170
|
-
}
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
if (!st.isFile()) return;
|
|
174
|
-
mkdirSync2(toFsPath(dirname(dest)), { recursive: true });
|
|
175
|
-
copyFileSync(fsSrc, fsDest);
|
|
176
|
-
}
|
|
177
|
-
function listWebIdeRuleFileNames(rulesDir) {
|
|
178
|
-
const fsRulesDir = toFsPath(rulesDir);
|
|
179
|
-
if (!existsSync(fsRulesDir) || !statSync(fsRulesDir).isDirectory()) {
|
|
180
|
-
return [];
|
|
181
|
-
}
|
|
182
|
-
return readdirSync(fsRulesDir).filter((name) => {
|
|
183
|
-
if (shouldSkipTemplateEntry(name) || !isWebIdeRuleFileName(name)) {
|
|
184
|
-
return false;
|
|
185
|
-
}
|
|
186
|
-
return statSync(toFsPath(join2(rulesDir, name))).isFile();
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
function assertWebIdeTemplateCopiedToApm(apmDir, workdir) {
|
|
190
|
-
const required = ["AGENTS.md", "rules"];
|
|
191
|
-
for (const item of required) {
|
|
192
|
-
const path = join2(apmDir, item);
|
|
193
|
-
if (!existsSync(toFsPath(path))) {
|
|
194
|
-
throw new Error(`[apm] WebIDE \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11: ${path}`);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
const rulesDir = join2(apmDir, "rules");
|
|
198
|
-
const ruleNames = listWebIdeRuleFileNames(rulesDir);
|
|
199
|
-
if (ruleNames.length === 0) {
|
|
200
|
-
throw new Error(`[apm] WebIDE \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11 webide \u89C4\u5219: ${rulesDir}`);
|
|
201
|
-
}
|
|
202
|
-
const leakedRules = join2(workdir, "rules");
|
|
203
|
-
const apmRules = join2(apmDir, "rules");
|
|
204
|
-
if (existsSync(toFsPath(leakedRules)) && !existsSync(toFsPath(join2(apmRules, "webide_reply.md")))) {
|
|
205
|
-
throw new Error(
|
|
206
|
-
`[apm] \u6A21\u677F\u88AB\u590D\u5236\u5230\u9519\u8BEF\u4F4D\u7F6E: ${leakedRules}\uFF08\u5E94\u5728 ${apmRules}\uFF09`
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
async function copyWebIdeTemplateFiles(targetDir, workdir = resolveWorkdirPath()) {
|
|
211
|
-
const resolvedTarget = resolve2(targetDir);
|
|
212
|
-
const templateDir = resolve2(CLI_TEMPLATE_DIR);
|
|
213
|
-
const fsTemplateDir = toFsPath(templateDir);
|
|
214
|
-
if (!existsSync(fsTemplateDir) || !statSync(fsTemplateDir).isDirectory()) {
|
|
215
|
-
throw new Error(`[apm] \u672A\u627E\u5230 CLI \u6A21\u677F\u76EE\u5F55: ${templateDir}`);
|
|
216
|
-
}
|
|
217
|
-
const agentsSrc = join2(templateDir, WEBIDE_AGENTS_TEMPLATE_NAME);
|
|
218
|
-
if (!existsSync(toFsPath(agentsSrc))) {
|
|
219
|
-
throw new Error(`[apm] \u672A\u627E\u5230 WebIDE \u6307\u5357: ${agentsSrc}`);
|
|
220
|
-
}
|
|
221
|
-
const rulesSrc = join2(templateDir, "rules");
|
|
222
|
-
const ruleNames = listWebIdeRuleFileNames(rulesSrc);
|
|
223
|
-
if (ruleNames.length === 0) {
|
|
224
|
-
throw new Error(`[apm] CLI \u6A21\u677F\u4E2D\u6CA1\u6709 webide \u89C4\u5219: ${rulesSrc}`);
|
|
225
|
-
}
|
|
226
|
-
mkdirSync2(toFsPath(resolvedTarget), { recursive: true });
|
|
227
|
-
copyFileSync(
|
|
228
|
-
toFsPath(agentsSrc),
|
|
229
|
-
toFsPath(join2(resolvedTarget, "AGENTS.md"))
|
|
230
|
-
);
|
|
231
|
-
const rulesDest = join2(resolvedTarget, "rules");
|
|
232
|
-
mkdirSync2(toFsPath(rulesDest), { recursive: true });
|
|
233
|
-
for (const name of ruleNames) {
|
|
234
|
-
copyTemplateEntry(join2(rulesSrc, name), join2(rulesDest, name));
|
|
235
|
-
}
|
|
236
|
-
assertWebIdeTemplateCopiedToApm(resolvedTarget, resolve2(workdir));
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// src/commands/init.ts
|
|
240
|
-
async function initializeWorkspace(workdir) {
|
|
241
|
-
await ensureWorkspaceApmDirForInit(workdir);
|
|
242
|
-
const apmDir = workspaceApmDir(workdir);
|
|
243
|
-
await copyWebIdeTemplateFiles(apmDir, workdir);
|
|
244
|
-
console.log(`[apm] \u5DF2\u6309 WebIDE \u521D\u59CB\u5316\u5DE5\u4F5C\u533A\uFF1A${apmDir}`);
|
|
245
|
-
return { didInit: true };
|
|
246
|
-
}
|
|
247
|
-
async function runInit() {
|
|
248
|
-
const workdir = resolveWorkdirPath();
|
|
249
|
-
await initializeWorkspace(workdir);
|
|
250
|
-
console.log(`[apm] \u5DE5\u4F5C\u76EE\u5F55\u8DEF\u5F84\uFF1A${workdir}`);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// src/commands/login.ts
|
|
254
|
-
import { ApiError } from "listpage-http";
|
|
82
|
+
// src/commands/sync-webide-agent.ts
|
|
83
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
84
|
+
import { join as join3 } from "path";
|
|
255
85
|
|
|
256
86
|
// src/api/client.ts
|
|
257
87
|
import { createApiClient } from "listpage-http";
|
|
@@ -266,6 +96,10 @@ var requestConfig = {
|
|
|
266
96
|
path: "/cli/me"
|
|
267
97
|
}
|
|
268
98
|
),
|
|
99
|
+
webideAgentConfig: defineEndpoint({
|
|
100
|
+
method: "GET",
|
|
101
|
+
path: "/cli/webide/agent-config"
|
|
102
|
+
}),
|
|
269
103
|
webideAppendMessageContent: defineEndpoint({
|
|
270
104
|
method: "PUT",
|
|
271
105
|
path: "/cli/webide/messages/content"
|
|
@@ -464,7 +298,157 @@ function createApmApiClient(cfg) {
|
|
|
464
298
|
});
|
|
465
299
|
}
|
|
466
300
|
|
|
301
|
+
// src/utils/path.ts
|
|
302
|
+
import { realpathSync } from "fs";
|
|
303
|
+
import { platform } from "os";
|
|
304
|
+
import { resolve } from "path";
|
|
305
|
+
function toFsPath(inputPath) {
|
|
306
|
+
const absolute = resolve(inputPath);
|
|
307
|
+
if (platform() !== "win32") return absolute;
|
|
308
|
+
if (absolute.startsWith("\\\\?\\")) return absolute;
|
|
309
|
+
const normalized = absolute.replace(/\//g, "\\");
|
|
310
|
+
if (normalized.startsWith("\\\\")) {
|
|
311
|
+
return `\\\\?\\UNC\\${normalized.slice(2)}`;
|
|
312
|
+
}
|
|
313
|
+
return `\\\\?\\${normalized}`;
|
|
314
|
+
}
|
|
315
|
+
function normalizeWorkdirPath(path) {
|
|
316
|
+
let normalized = path.trim().replace(/\\/g, "/").normalize("NFC");
|
|
317
|
+
if (normalized.startsWith("//?/")) {
|
|
318
|
+
normalized = normalized.slice(4);
|
|
319
|
+
}
|
|
320
|
+
const windowsDrive = /^([A-Za-z]:)\/*(.*)$/.exec(normalized);
|
|
321
|
+
if (windowsDrive) {
|
|
322
|
+
const drive = windowsDrive[1].toLowerCase();
|
|
323
|
+
const rest = windowsDrive[2].replace(/\/+/g, "/").replace(/\/$/, "");
|
|
324
|
+
return rest ? `${drive}/${rest}` : drive;
|
|
325
|
+
}
|
|
326
|
+
normalized = normalized.replace(/\/+/g, "/");
|
|
327
|
+
if (normalized.length > 1 && normalized.endsWith("/")) {
|
|
328
|
+
normalized = normalized.slice(0, -1);
|
|
329
|
+
}
|
|
330
|
+
return normalized;
|
|
331
|
+
}
|
|
332
|
+
function resolveWorkdirPath(cwd = process.cwd()) {
|
|
333
|
+
const absolute = resolve(cwd);
|
|
334
|
+
try {
|
|
335
|
+
return normalizeWorkdirPath(realpathSync.native(absolute));
|
|
336
|
+
} catch {
|
|
337
|
+
return normalizeWorkdirPath(absolute);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// src/utils/workspace.ts
|
|
342
|
+
import { existsSync, mkdirSync as mkdirSync2, readdirSync, statSync } from "fs";
|
|
343
|
+
import { join as join2, resolve as resolve2 } from "path";
|
|
344
|
+
function workspaceApmDir(cwd = resolveWorkdirPath()) {
|
|
345
|
+
return resolve2(resolve2(cwd), ".apm");
|
|
346
|
+
}
|
|
347
|
+
async function ensureLoggedConfig() {
|
|
348
|
+
const cfg = await ensureApmConfig();
|
|
349
|
+
if (!resolveApiKey(cfg)) {
|
|
350
|
+
console.error(
|
|
351
|
+
"[apm] \u672A\u68C0\u6D4B\u5230 API Key\uFF0C\u8BF7\u5148\u6267\u884C: apm login --api-key cm_xxx"
|
|
352
|
+
);
|
|
353
|
+
process.exit(1);
|
|
354
|
+
}
|
|
355
|
+
return cfg;
|
|
356
|
+
}
|
|
357
|
+
async function ensureDirExists(dir) {
|
|
358
|
+
mkdirSync2(dir, { recursive: true });
|
|
359
|
+
}
|
|
360
|
+
async function ensureWorkspaceApmDirForInit(cwd = resolveWorkdirPath()) {
|
|
361
|
+
const dir = workspaceApmDir(cwd);
|
|
362
|
+
const fsDir = toFsPath(dir);
|
|
363
|
+
if (existsSync(fsDir) && !statSync(fsDir).isDirectory()) {
|
|
364
|
+
throw new Error(`[apm] \u8DEF\u5F84\u5DF2\u5B58\u5728\u4F46\u4E0D\u662F\u76EE\u5F55: ${dir}`);
|
|
365
|
+
}
|
|
366
|
+
mkdirSync2(fsDir, { recursive: true });
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// src/commands/sync-webide-agent.ts
|
|
370
|
+
var REVISION_FILE = ".webide-agent.json";
|
|
371
|
+
var RULE_KEY = /^webide_[a-z0-9_]+$/;
|
|
372
|
+
function withTrailingNewline(text) {
|
|
373
|
+
return text.endsWith("\n") ? text : `${text}
|
|
374
|
+
`;
|
|
375
|
+
}
|
|
376
|
+
function readRevision(apmDir) {
|
|
377
|
+
const path = toFsPath(join3(apmDir, REVISION_FILE));
|
|
378
|
+
if (!existsSync2(path)) return null;
|
|
379
|
+
try {
|
|
380
|
+
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
381
|
+
if (parsed?.version === 1 && parsed.revision?.trim()) {
|
|
382
|
+
return parsed.revision.trim();
|
|
383
|
+
}
|
|
384
|
+
} catch {
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
return null;
|
|
388
|
+
}
|
|
389
|
+
function writeRevision(apmDir, revision) {
|
|
390
|
+
writeFileSync2(
|
|
391
|
+
toFsPath(join3(apmDir, REVISION_FILE)),
|
|
392
|
+
`${JSON.stringify({ version: 1, revision }, null, 2)}
|
|
393
|
+
`,
|
|
394
|
+
"utf8"
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
async function syncWebIdeAgentFiles(workdir, cfg) {
|
|
398
|
+
const api = createApmApiClient(cfg);
|
|
399
|
+
const bundle = await api.cli.webideAgentConfig();
|
|
400
|
+
const revision = bundle.revision?.trim();
|
|
401
|
+
if (!revision) {
|
|
402
|
+
throw new Error("[apm] \u5E73\u53F0\u672A\u8FD4\u56DE WebIDE \u89C4\u5219\u7248\u672C");
|
|
403
|
+
}
|
|
404
|
+
const apmDir = workspaceApmDir(workdir);
|
|
405
|
+
mkdirSync3(toFsPath(apmDir), { recursive: true });
|
|
406
|
+
if (readRevision(apmDir) === revision) {
|
|
407
|
+
return { revision, wrote: false, ruleCount: bundle.rules?.length ?? 0 };
|
|
408
|
+
}
|
|
409
|
+
const rulesDir = join3(apmDir, "rules");
|
|
410
|
+
mkdirSync3(toFsPath(rulesDir), { recursive: true });
|
|
411
|
+
writeFileSync2(
|
|
412
|
+
toFsPath(join3(apmDir, "AGENTS.md")),
|
|
413
|
+
withTrailingNewline(bundle.guide ?? ""),
|
|
414
|
+
"utf8"
|
|
415
|
+
);
|
|
416
|
+
for (const rule of bundle.rules ?? []) {
|
|
417
|
+
const key = rule.key?.trim() ?? "";
|
|
418
|
+
if (!RULE_KEY.test(key)) {
|
|
419
|
+
throw new Error(`[apm] \u975E\u6CD5\u89C4\u5219\u540D: ${key || "(\u7A7A)"}`);
|
|
420
|
+
}
|
|
421
|
+
writeFileSync2(
|
|
422
|
+
toFsPath(join3(rulesDir, `${key}.md`)),
|
|
423
|
+
withTrailingNewline(rule.body ?? ""),
|
|
424
|
+
"utf8"
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
writeRevision(apmDir, revision);
|
|
428
|
+
return {
|
|
429
|
+
revision,
|
|
430
|
+
wrote: true,
|
|
431
|
+
ruleCount: bundle.rules?.length ?? 0
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// src/commands/init.ts
|
|
436
|
+
async function initializeWorkspace(workdir, cfg) {
|
|
437
|
+
await ensureWorkspaceApmDirForInit(workdir);
|
|
438
|
+
await syncWebIdeAgentFiles(workdir, cfg);
|
|
439
|
+
const apmDir = workspaceApmDir(workdir);
|
|
440
|
+
console.log(`[apm] \u5DF2\u6309 WebIDE \u521D\u59CB\u5316\u5DE5\u4F5C\u533A\uFF1A${apmDir}`);
|
|
441
|
+
return { didInit: true };
|
|
442
|
+
}
|
|
443
|
+
async function runInit() {
|
|
444
|
+
const workdir = resolveWorkdirPath();
|
|
445
|
+
const cfg = await ensureLoggedConfig();
|
|
446
|
+
await initializeWorkspace(workdir, cfg);
|
|
447
|
+
console.log(`[apm] \u5DE5\u4F5C\u76EE\u5F55\u8DEF\u5F84\uFF1A${workdir}`);
|
|
448
|
+
}
|
|
449
|
+
|
|
467
450
|
// src/commands/login.ts
|
|
451
|
+
import { ApiError } from "listpage-http";
|
|
468
452
|
async function runLogin(opts) {
|
|
469
453
|
const baseUrl = (opts.server?.trim() || process.env.AI_PM_SERVER?.trim() || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
470
454
|
const apiKey = (opts.apiKey?.trim() || process.env.APM_API_KEY?.trim() || "").replace(/^Bearer\s+/i, "");
|
|
@@ -520,19 +504,19 @@ async function runLogin(opts) {
|
|
|
520
504
|
|
|
521
505
|
// src/commands/update.ts
|
|
522
506
|
import { spawnSync } from "child_process";
|
|
523
|
-
import { existsSync as
|
|
524
|
-
import { join as
|
|
507
|
+
import { existsSync as existsSync3 } from "fs";
|
|
508
|
+
import { join as join5 } from "path";
|
|
525
509
|
|
|
526
510
|
// src/version.ts
|
|
527
|
-
import { readFileSync as
|
|
528
|
-
import { dirname
|
|
529
|
-
import { fileURLToPath
|
|
511
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
512
|
+
import { dirname, join as join4 } from "path";
|
|
513
|
+
import { fileURLToPath } from "url";
|
|
530
514
|
var CLI_PACKAGE_NAME = "ai-project-manage-cli";
|
|
531
515
|
function readCliVersion() {
|
|
532
516
|
try {
|
|
533
|
-
const dir =
|
|
534
|
-
const pkgPath =
|
|
535
|
-
const pkg = JSON.parse(
|
|
517
|
+
const dir = dirname(fileURLToPath(import.meta.url));
|
|
518
|
+
const pkgPath = join4(dir, "..", "package.json");
|
|
519
|
+
const pkg = JSON.parse(readFileSync3(pkgPath, "utf8"));
|
|
536
520
|
return pkg.version ?? "0.0.0";
|
|
537
521
|
} catch {
|
|
538
522
|
return "0.0.0";
|
|
@@ -701,14 +685,14 @@ function resolveApmEntryPath(entryArg = process.argv[1]) {
|
|
|
701
685
|
if (npmResult.status === 0) {
|
|
702
686
|
const globalRoot = npmResult.stdout?.toString().trim();
|
|
703
687
|
if (globalRoot) {
|
|
704
|
-
const candidate =
|
|
705
|
-
if (
|
|
688
|
+
const candidate = join5(globalRoot, CLI_PACKAGE_NAME, "dist", "index.js");
|
|
689
|
+
if (existsSync3(candidate)) {
|
|
706
690
|
return candidate;
|
|
707
691
|
}
|
|
708
692
|
}
|
|
709
693
|
}
|
|
710
694
|
const fromArgv = entryArg?.trim();
|
|
711
|
-
if (fromArgv &&
|
|
695
|
+
if (fromArgv && existsSync3(fromArgv)) {
|
|
712
696
|
return fromArgv;
|
|
713
697
|
}
|
|
714
698
|
if (fromArgv) {
|
|
@@ -737,23 +721,26 @@ function reexecConnectAfterUpdate(options) {
|
|
|
737
721
|
}
|
|
738
722
|
|
|
739
723
|
// src/commands/update-skills.ts
|
|
740
|
-
import { existsSync as
|
|
724
|
+
import { existsSync as existsSync4, statSync as statSync2 } from "fs";
|
|
741
725
|
async function syncWorkspaceSkills(workdir) {
|
|
742
726
|
const apmDir = workspaceApmDir(workdir);
|
|
743
727
|
const fsApmDir = toFsPath(apmDir);
|
|
744
|
-
if (!
|
|
728
|
+
if (!existsSync4(fsApmDir)) {
|
|
745
729
|
throw new Error("[apm] \u672A\u627E\u5230 .apm \u76EE\u5F55\uFF0C\u8BF7\u5148\u6267\u884C apm init");
|
|
746
730
|
}
|
|
747
731
|
const apmStat = statSync2(fsApmDir);
|
|
748
732
|
if (!apmStat.isDirectory()) {
|
|
749
733
|
throw new Error(`[apm] \u8DEF\u5F84\u5DF2\u5B58\u5728\u4F46\u4E0D\u662F\u76EE\u5F55: ${apmDir}`);
|
|
750
734
|
}
|
|
751
|
-
await
|
|
752
|
-
|
|
735
|
+
const cfg = await ensureLoggedConfig();
|
|
736
|
+
const result = await syncWebIdeAgentFiles(workdir, cfg);
|
|
737
|
+
console.log(
|
|
738
|
+
result.wrote ? `[apm] \u5DF2\u540C\u6B65 WebIDE \u6307\u5357\u4E0E ${result.ruleCount} \u6761\u89C4\u5219` : "[apm] WebIDE \u6307\u5357\u4E0E\u89C4\u5219\u672A\u53D8\u5316"
|
|
739
|
+
);
|
|
753
740
|
}
|
|
754
741
|
async function runUpdateSkills() {
|
|
755
742
|
const apmDir = workspaceApmDir();
|
|
756
|
-
if (!
|
|
743
|
+
if (!existsSync4(apmDir)) {
|
|
757
744
|
console.error("[apm] \u672A\u627E\u5230 .apm \u76EE\u5F55\uFF0C\u8BF7\u5148\u6267\u884C apm init");
|
|
758
745
|
process.exit(1);
|
|
759
746
|
}
|
|
@@ -766,14 +753,14 @@ async function runUpdateSkills() {
|
|
|
766
753
|
|
|
767
754
|
// src/utils/project-documents.ts
|
|
768
755
|
import {
|
|
769
|
-
existsSync as
|
|
756
|
+
existsSync as existsSync5,
|
|
770
757
|
readdirSync as readdirSync2,
|
|
771
|
-
readFileSync as
|
|
758
|
+
readFileSync as readFileSync4,
|
|
772
759
|
rmSync,
|
|
773
|
-
writeFileSync as
|
|
760
|
+
writeFileSync as writeFileSync3
|
|
774
761
|
} from "fs";
|
|
775
762
|
import { createHash } from "crypto";
|
|
776
|
-
import { dirname as
|
|
763
|
+
import { dirname as dirname2, join as join6, relative, sep } from "path";
|
|
777
764
|
|
|
778
765
|
// src/utils/git.ts
|
|
779
766
|
import { execFile as execFile2 } from "child_process";
|
|
@@ -847,11 +834,11 @@ function normalizeProjectIdForPath(projectId) {
|
|
|
847
834
|
}
|
|
848
835
|
function projectDocumentsDir(apmRoot, projectId) {
|
|
849
836
|
const id = normalizeProjectIdForPath(projectId);
|
|
850
|
-
return
|
|
837
|
+
return join6(apmRoot ?? workspaceApmDir(), "project", id);
|
|
851
838
|
}
|
|
852
839
|
function projectDocumentLocalPath(apmRoot, projectId, documentPath) {
|
|
853
840
|
const normalized = normalizeLocalDocumentPath(documentPath);
|
|
854
|
-
return
|
|
841
|
+
return join6(
|
|
855
842
|
projectDocumentsDir(apmRoot, projectId),
|
|
856
843
|
...normalized.split("/")
|
|
857
844
|
);
|
|
@@ -871,16 +858,16 @@ function hashLocalFileContent(content) {
|
|
|
871
858
|
return createHash("sha256").update(content, "utf8").digest("hex");
|
|
872
859
|
}
|
|
873
860
|
function readLocalManifest(apmRoot, projectId) {
|
|
874
|
-
const manifestPath =
|
|
861
|
+
const manifestPath = join6(
|
|
875
862
|
projectDocumentsDir(apmRoot, projectId),
|
|
876
863
|
MANIFEST_FILE
|
|
877
864
|
);
|
|
878
|
-
if (!
|
|
865
|
+
if (!existsSync5(manifestPath)) {
|
|
879
866
|
return null;
|
|
880
867
|
}
|
|
881
868
|
try {
|
|
882
869
|
return JSON.parse(
|
|
883
|
-
|
|
870
|
+
readFileSync4(manifestPath, "utf8")
|
|
884
871
|
);
|
|
885
872
|
} catch {
|
|
886
873
|
return null;
|
|
@@ -888,13 +875,13 @@ function readLocalManifest(apmRoot, projectId) {
|
|
|
888
875
|
}
|
|
889
876
|
function listLocalDocumentPaths(apmRoot, projectId) {
|
|
890
877
|
const root = projectDocumentsDir(apmRoot, projectId);
|
|
891
|
-
if (!
|
|
878
|
+
if (!existsSync5(root)) {
|
|
892
879
|
return [];
|
|
893
880
|
}
|
|
894
881
|
const paths = [];
|
|
895
882
|
const walk = (dir) => {
|
|
896
883
|
for (const entry of readdirSync2(dir, { withFileTypes: true })) {
|
|
897
|
-
const abs =
|
|
884
|
+
const abs = join6(dir, entry.name);
|
|
898
885
|
if (entry.isDirectory()) {
|
|
899
886
|
walk(abs);
|
|
900
887
|
continue;
|
|
@@ -1013,8 +1000,8 @@ ${diagnostic ?? ""}`);
|
|
|
1013
1000
|
const absPath = toFsPath(
|
|
1014
1001
|
projectDocumentLocalPath(targetApmDir, projectId, doc.path)
|
|
1015
1002
|
);
|
|
1016
|
-
await ensureDirExists(
|
|
1017
|
-
|
|
1003
|
+
await ensureDirExists(dirname2(absPath));
|
|
1004
|
+
writeFileSync3(absPath, doc.content, "utf8");
|
|
1018
1005
|
downloaded += 1;
|
|
1019
1006
|
}
|
|
1020
1007
|
}
|
|
@@ -1023,13 +1010,13 @@ ${diagnostic ?? ""}`);
|
|
|
1023
1010
|
const absPath = toFsPath(
|
|
1024
1011
|
projectDocumentLocalPath(targetApmDir, projectId, path)
|
|
1025
1012
|
);
|
|
1026
|
-
if (
|
|
1013
|
+
if (existsSync5(absPath)) {
|
|
1027
1014
|
rmSync(absPath, { force: true });
|
|
1028
1015
|
deleted += 1;
|
|
1029
1016
|
}
|
|
1030
1017
|
}
|
|
1031
|
-
|
|
1032
|
-
toFsPath(
|
|
1018
|
+
writeFileSync3(
|
|
1019
|
+
toFsPath(join6(docsDir, MANIFEST_FILE)),
|
|
1033
1020
|
`${JSON.stringify(remoteManifest, null, 2)}
|
|
1034
1021
|
`,
|
|
1035
1022
|
"utf8"
|
|
@@ -1072,7 +1059,7 @@ async function syncProjectDocumentsPush(cfg, workdirPath, apmRoot, options) {
|
|
|
1072
1059
|
const absPath = toFsPath(
|
|
1073
1060
|
projectDocumentLocalPath(targetApmDir, projectId, path)
|
|
1074
1061
|
);
|
|
1075
|
-
const content =
|
|
1062
|
+
const content = readFileSync4(absPath, "utf8");
|
|
1076
1063
|
const contentHash = hashLocalFileContent(content);
|
|
1077
1064
|
if (remoteHashByPath.get(path) === contentHash) {
|
|
1078
1065
|
continue;
|
|
@@ -1347,8 +1334,8 @@ function handleCancelAction(payload, ctx) {
|
|
|
1347
1334
|
}
|
|
1348
1335
|
|
|
1349
1336
|
// src/commands/connect/core/worker/worker.ts
|
|
1350
|
-
import { dirname as
|
|
1351
|
-
import { fileURLToPath as
|
|
1337
|
+
import { dirname as dirname3, join as join7 } from "path";
|
|
1338
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1352
1339
|
import { Worker } from "node:worker_threads";
|
|
1353
1340
|
|
|
1354
1341
|
// src/commands/connect/core/worker/config.ts
|
|
@@ -1373,8 +1360,8 @@ function resolveWebIdeWorkerHeapMb(env = process.env, totalMemoryBytes = totalme
|
|
|
1373
1360
|
}
|
|
1374
1361
|
|
|
1375
1362
|
// src/commands/connect/core/worker/worker.ts
|
|
1376
|
-
var workerFile =
|
|
1377
|
-
|
|
1363
|
+
var workerFile = join7(
|
|
1364
|
+
dirname3(fileURLToPath2(import.meta.url)),
|
|
1378
1365
|
"worker-script.js"
|
|
1379
1366
|
);
|
|
1380
1367
|
var ActionWorker = class {
|
|
@@ -1726,14 +1713,14 @@ function dispatchConnectAction(payload, ctx) {
|
|
|
1726
1713
|
|
|
1727
1714
|
// src/commands/connect-lock.ts
|
|
1728
1715
|
import {
|
|
1729
|
-
existsSync as
|
|
1730
|
-
mkdirSync as
|
|
1731
|
-
readFileSync as
|
|
1716
|
+
existsSync as existsSync6,
|
|
1717
|
+
mkdirSync as mkdirSync4,
|
|
1718
|
+
readFileSync as readFileSync5,
|
|
1732
1719
|
unlinkSync,
|
|
1733
|
-
writeFileSync as
|
|
1720
|
+
writeFileSync as writeFileSync4
|
|
1734
1721
|
} from "fs";
|
|
1735
|
-
import { join as
|
|
1736
|
-
var CONNECT_LOCK_PATH =
|
|
1722
|
+
import { join as join8 } from "path";
|
|
1723
|
+
var CONNECT_LOCK_PATH = join8(APM_CONFIG_DIR, "connect.lock");
|
|
1737
1724
|
function isProcessAlive(pid) {
|
|
1738
1725
|
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
1739
1726
|
try {
|
|
@@ -1744,9 +1731,9 @@ function isProcessAlive(pid) {
|
|
|
1744
1731
|
}
|
|
1745
1732
|
}
|
|
1746
1733
|
function readConnectLock() {
|
|
1747
|
-
if (!
|
|
1734
|
+
if (!existsSync6(CONNECT_LOCK_PATH)) return null;
|
|
1748
1735
|
try {
|
|
1749
|
-
const raw =
|
|
1736
|
+
const raw = readFileSync5(CONNECT_LOCK_PATH, "utf8");
|
|
1750
1737
|
const parsed = JSON.parse(raw);
|
|
1751
1738
|
if (typeof parsed.pid !== "number" || typeof parsed.startedAt !== "string") {
|
|
1752
1739
|
return null;
|
|
@@ -1778,12 +1765,12 @@ function acquireConnectLock() {
|
|
|
1778
1765
|
console.error(`[apm] \u5DF2\u6709 apm connect \u5728\u8FD0\u884C (pid=${existing.pid})`);
|
|
1779
1766
|
process.exit(1);
|
|
1780
1767
|
}
|
|
1781
|
-
|
|
1768
|
+
mkdirSync4(APM_CONFIG_DIR, { recursive: true });
|
|
1782
1769
|
const lock = {
|
|
1783
1770
|
pid: process.pid,
|
|
1784
1771
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1785
1772
|
};
|
|
1786
|
-
|
|
1773
|
+
writeFileSync4(
|
|
1787
1774
|
CONNECT_LOCK_PATH,
|
|
1788
1775
|
JSON.stringify(lock, null, 2) + "\n",
|
|
1789
1776
|
"utf8"
|
|
@@ -2018,7 +2005,7 @@ function buildProgram() {
|
|
|
2018
2005
|
).option("--api-key <key>", "\u8FDC\u7A0B\u4E3B\u673A API Key\uFF08cm_ \u5F00\u5934\uFF09").option("--server <url>", "API \u6839\u5730\u5740\uFF0C\u4F8B\u5982 http://127.0.0.1:3000").action(async (opts) => {
|
|
2019
2006
|
await runLogin(opts);
|
|
2020
2007
|
});
|
|
2021
|
-
program.command("init").description("\u5728\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6309 WebIDE \u5DE5\u4F5C\u533A\u521D\u59CB\u5316\uFF1A\u5199\u5165\u6307\u5357\u4E0E
|
|
2008
|
+
program.command("init").description("\u5728\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6309 WebIDE \u5DE5\u4F5C\u533A\u521D\u59CB\u5316\uFF1A\u4ECE\u5E73\u53F0\u5199\u5165\u6307\u5357\u4E0E\u89C4\u5219").action(async () => {
|
|
2022
2009
|
await runInit();
|
|
2023
2010
|
});
|
|
2024
2011
|
program.command("update").description(
|
|
@@ -2031,7 +2018,7 @@ function buildProgram() {
|
|
|
2031
2018
|
).action(async (opts) => {
|
|
2032
2019
|
await runUpdate({ allowMajorUpgrade: opts.major === true });
|
|
2033
2020
|
});
|
|
2034
|
-
program.command("update-skills").description("\u540C\u6B65 .apm/ \u4E0B\u7684 WebIDE \u6307\u5357\u4E0E\u89C4\u5219").action(async () => {
|
|
2021
|
+
program.command("update-skills").description("\u4ECE\u5E73\u53F0\u540C\u6B65 .apm/ \u4E0B\u7684 WebIDE \u6307\u5357\u4E0E\u89C4\u5219").action(async () => {
|
|
2035
2022
|
await runUpdateSkills();
|
|
2036
2023
|
});
|
|
2037
2024
|
program.command("sync-project-documents").description(
|