ai-project-manage-cli 8.1.7 → 8.1.8
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 +134 -246
- 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/dist/worker-script.js
CHANGED
|
@@ -14,6 +14,10 @@ var requestConfig = {
|
|
|
14
14
|
path: "/cli/me"
|
|
15
15
|
}
|
|
16
16
|
),
|
|
17
|
+
webideAgentConfig: defineEndpoint({
|
|
18
|
+
method: "GET",
|
|
19
|
+
path: "/cli/webide/agent-config"
|
|
20
|
+
}),
|
|
17
21
|
webideAppendMessageContent: defineEndpoint({
|
|
18
22
|
method: "PUT",
|
|
19
23
|
path: "/cli/webide/messages/content"
|
|
@@ -325,11 +329,8 @@ function requireRemoteWorkdir(workdir) {
|
|
|
325
329
|
}
|
|
326
330
|
|
|
327
331
|
// src/utils/workspace.ts
|
|
328
|
-
import {
|
|
329
|
-
import {
|
|
330
|
-
import { fileURLToPath } from "url";
|
|
331
|
-
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
332
|
-
var CLI_TEMPLATE_DIR = resolve2(__dirname, "../template");
|
|
332
|
+
import { existsSync, mkdirSync as mkdirSync2, readdirSync, statSync } from "fs";
|
|
333
|
+
import { join as join2, resolve as resolve2 } from "path";
|
|
333
334
|
function workspaceApmDir(cwd = resolveWorkdirPath()) {
|
|
334
335
|
return resolve2(resolve2(cwd), ".apm");
|
|
335
336
|
}
|
|
@@ -380,90 +381,6 @@ async function ensureWorkspaceApmDirForInit(cwd = resolveWorkdirPath()) {
|
|
|
380
381
|
}
|
|
381
382
|
mkdirSync2(fsDir, { recursive: true });
|
|
382
383
|
}
|
|
383
|
-
var WEBIDE_AGENTS_TEMPLATE_NAME = "AGENTS.webide.md";
|
|
384
|
-
function shouldSkipTemplateEntry(name) {
|
|
385
|
-
return name === ".DS_Store" || name === "Thumbs.db";
|
|
386
|
-
}
|
|
387
|
-
function isWebIdeRuleFileName(name) {
|
|
388
|
-
return name.startsWith("webide");
|
|
389
|
-
}
|
|
390
|
-
function copyTemplateEntry(src, dest) {
|
|
391
|
-
const fsSrc = toFsPath(src);
|
|
392
|
-
const fsDest = toFsPath(dest);
|
|
393
|
-
const st = statSync(fsSrc);
|
|
394
|
-
if (st.isDirectory()) {
|
|
395
|
-
mkdirSync2(fsDest, { recursive: true });
|
|
396
|
-
for (const name of readdirSync(fsSrc)) {
|
|
397
|
-
if (shouldSkipTemplateEntry(name)) continue;
|
|
398
|
-
copyTemplateEntry(join2(src, name), join2(dest, name));
|
|
399
|
-
}
|
|
400
|
-
return;
|
|
401
|
-
}
|
|
402
|
-
if (!st.isFile()) return;
|
|
403
|
-
mkdirSync2(toFsPath(dirname(dest)), { recursive: true });
|
|
404
|
-
copyFileSync(fsSrc, fsDest);
|
|
405
|
-
}
|
|
406
|
-
function listWebIdeRuleFileNames(rulesDir) {
|
|
407
|
-
const fsRulesDir = toFsPath(rulesDir);
|
|
408
|
-
if (!existsSync(fsRulesDir) || !statSync(fsRulesDir).isDirectory()) {
|
|
409
|
-
return [];
|
|
410
|
-
}
|
|
411
|
-
return readdirSync(fsRulesDir).filter((name) => {
|
|
412
|
-
if (shouldSkipTemplateEntry(name) || !isWebIdeRuleFileName(name)) {
|
|
413
|
-
return false;
|
|
414
|
-
}
|
|
415
|
-
return statSync(toFsPath(join2(rulesDir, name))).isFile();
|
|
416
|
-
});
|
|
417
|
-
}
|
|
418
|
-
function assertWebIdeTemplateCopiedToApm(apmDir, workdir) {
|
|
419
|
-
const required = ["AGENTS.md", "rules"];
|
|
420
|
-
for (const item of required) {
|
|
421
|
-
const path3 = join2(apmDir, item);
|
|
422
|
-
if (!existsSync(toFsPath(path3))) {
|
|
423
|
-
throw new Error(`[apm] WebIDE \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11: ${path3}`);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
const rulesDir = join2(apmDir, "rules");
|
|
427
|
-
const ruleNames = listWebIdeRuleFileNames(rulesDir);
|
|
428
|
-
if (ruleNames.length === 0) {
|
|
429
|
-
throw new Error(`[apm] WebIDE \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11 webide \u89C4\u5219: ${rulesDir}`);
|
|
430
|
-
}
|
|
431
|
-
const leakedRules = join2(workdir, "rules");
|
|
432
|
-
const apmRules = join2(apmDir, "rules");
|
|
433
|
-
if (existsSync(toFsPath(leakedRules)) && !existsSync(toFsPath(join2(apmRules, "webide_reply.md")))) {
|
|
434
|
-
throw new Error(
|
|
435
|
-
`[apm] \u6A21\u677F\u88AB\u590D\u5236\u5230\u9519\u8BEF\u4F4D\u7F6E: ${leakedRules}\uFF08\u5E94\u5728 ${apmRules}\uFF09`
|
|
436
|
-
);
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
async function copyWebIdeTemplateFiles(targetDir, workdir = resolveWorkdirPath()) {
|
|
440
|
-
const resolvedTarget = resolve2(targetDir);
|
|
441
|
-
const templateDir = resolve2(CLI_TEMPLATE_DIR);
|
|
442
|
-
const fsTemplateDir = toFsPath(templateDir);
|
|
443
|
-
if (!existsSync(fsTemplateDir) || !statSync(fsTemplateDir).isDirectory()) {
|
|
444
|
-
throw new Error(`[apm] \u672A\u627E\u5230 CLI \u6A21\u677F\u76EE\u5F55: ${templateDir}`);
|
|
445
|
-
}
|
|
446
|
-
const agentsSrc = join2(templateDir, WEBIDE_AGENTS_TEMPLATE_NAME);
|
|
447
|
-
if (!existsSync(toFsPath(agentsSrc))) {
|
|
448
|
-
throw new Error(`[apm] \u672A\u627E\u5230 WebIDE \u6307\u5357: ${agentsSrc}`);
|
|
449
|
-
}
|
|
450
|
-
const rulesSrc = join2(templateDir, "rules");
|
|
451
|
-
const ruleNames = listWebIdeRuleFileNames(rulesSrc);
|
|
452
|
-
if (ruleNames.length === 0) {
|
|
453
|
-
throw new Error(`[apm] CLI \u6A21\u677F\u4E2D\u6CA1\u6709 webide \u89C4\u5219: ${rulesSrc}`);
|
|
454
|
-
}
|
|
455
|
-
mkdirSync2(toFsPath(resolvedTarget), { recursive: true });
|
|
456
|
-
copyFileSync(
|
|
457
|
-
toFsPath(agentsSrc),
|
|
458
|
-
toFsPath(join2(resolvedTarget, "AGENTS.md"))
|
|
459
|
-
);
|
|
460
|
-
const rulesDest = join2(resolvedTarget, "rules");
|
|
461
|
-
mkdirSync2(toFsPath(rulesDest), { recursive: true });
|
|
462
|
-
for (const name of ruleNames) {
|
|
463
|
-
copyTemplateEntry(join2(rulesSrc, name), join2(rulesDest, name));
|
|
464
|
-
}
|
|
465
|
-
assertWebIdeTemplateCopiedToApm(resolvedTarget, resolve2(workdir));
|
|
466
|
-
}
|
|
467
384
|
|
|
468
385
|
// src/utils/git.ts
|
|
469
386
|
import { execFile as execFile2 } from "child_process";
|
|
@@ -664,7 +581,7 @@ import {
|
|
|
664
581
|
statSync as statSync2,
|
|
665
582
|
writeFileSync as writeFileSync2
|
|
666
583
|
} from "fs";
|
|
667
|
-
import { basename, dirname
|
|
584
|
+
import { basename, dirname, join as join3, relative, resolve as resolve3 } from "path";
|
|
668
585
|
var WORKSPACE_REPOS_MANIFEST = "workspace-repos.json";
|
|
669
586
|
var WORKSPACE_REPOS_VERSION = 1;
|
|
670
587
|
var SKIP_DIR_NAMES = /* @__PURE__ */ new Set([".apm", "node_modules"]);
|
|
@@ -3220,14 +3137,75 @@ function createThrottledWebIdeMessageLogSync(cfg2, ctx, onError, options) {
|
|
|
3220
3137
|
};
|
|
3221
3138
|
}
|
|
3222
3139
|
|
|
3223
|
-
// src/commands/
|
|
3224
|
-
|
|
3225
|
-
|
|
3140
|
+
// src/commands/sync-webide-agent.ts
|
|
3141
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
3142
|
+
import { join as join4 } from "path";
|
|
3143
|
+
var REVISION_FILE = ".webide-agent.json";
|
|
3144
|
+
var RULE_KEY = /^webide_[a-z0-9_]+$/;
|
|
3145
|
+
function withTrailingNewline(text) {
|
|
3146
|
+
return text.endsWith("\n") ? text : `${text}
|
|
3147
|
+
`;
|
|
3148
|
+
}
|
|
3149
|
+
function readRevision(apmDir) {
|
|
3150
|
+
const path3 = toFsPath(join4(apmDir, REVISION_FILE));
|
|
3151
|
+
if (!existsSync5(path3)) return null;
|
|
3152
|
+
try {
|
|
3153
|
+
const parsed = JSON.parse(readFileSync4(path3, "utf8"));
|
|
3154
|
+
if (parsed?.version === 1 && parsed.revision?.trim()) {
|
|
3155
|
+
return parsed.revision.trim();
|
|
3156
|
+
}
|
|
3157
|
+
} catch {
|
|
3158
|
+
return null;
|
|
3159
|
+
}
|
|
3160
|
+
return null;
|
|
3161
|
+
}
|
|
3162
|
+
function writeRevision(apmDir, revision) {
|
|
3163
|
+
writeFileSync3(
|
|
3164
|
+
toFsPath(join4(apmDir, REVISION_FILE)),
|
|
3165
|
+
`${JSON.stringify({ version: 1, revision }, null, 2)}
|
|
3166
|
+
`,
|
|
3167
|
+
"utf8"
|
|
3168
|
+
);
|
|
3169
|
+
}
|
|
3170
|
+
async function syncWebIdeAgentFiles(workdir, cfg2) {
|
|
3171
|
+
const api = createApmApiClient(cfg2);
|
|
3172
|
+
const bundle = await api.cli.webideAgentConfig();
|
|
3173
|
+
const revision = bundle.revision?.trim();
|
|
3174
|
+
if (!revision) {
|
|
3175
|
+
throw new Error("[apm] \u5E73\u53F0\u672A\u8FD4\u56DE WebIDE \u89C4\u5219\u7248\u672C");
|
|
3176
|
+
}
|
|
3226
3177
|
const apmDir = workspaceApmDir(workdir);
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3178
|
+
mkdirSync4(toFsPath(apmDir), { recursive: true });
|
|
3179
|
+
if (readRevision(apmDir) === revision) {
|
|
3180
|
+
return { revision, wrote: false, ruleCount: bundle.rules?.length ?? 0 };
|
|
3181
|
+
}
|
|
3182
|
+
const rulesDir = join4(apmDir, "rules");
|
|
3183
|
+
mkdirSync4(toFsPath(rulesDir), { recursive: true });
|
|
3184
|
+
writeFileSync3(
|
|
3185
|
+
toFsPath(join4(apmDir, "AGENTS.md")),
|
|
3186
|
+
withTrailingNewline(bundle.guide ?? ""),
|
|
3187
|
+
"utf8"
|
|
3188
|
+
);
|
|
3189
|
+
for (const rule of bundle.rules ?? []) {
|
|
3190
|
+
const key = rule.key?.trim() ?? "";
|
|
3191
|
+
if (!RULE_KEY.test(key)) {
|
|
3192
|
+
throw new Error(`[apm] \u975E\u6CD5\u89C4\u5219\u540D: ${key || "(\u7A7A)"}`);
|
|
3193
|
+
}
|
|
3194
|
+
writeFileSync3(
|
|
3195
|
+
toFsPath(join4(rulesDir, `${key}.md`)),
|
|
3196
|
+
withTrailingNewline(rule.body ?? ""),
|
|
3197
|
+
"utf8"
|
|
3198
|
+
);
|
|
3199
|
+
}
|
|
3200
|
+
writeRevision(apmDir, revision);
|
|
3201
|
+
return {
|
|
3202
|
+
revision,
|
|
3203
|
+
wrote: true,
|
|
3204
|
+
ruleCount: bundle.rules?.length ?? 0
|
|
3205
|
+
};
|
|
3230
3206
|
}
|
|
3207
|
+
|
|
3208
|
+
// src/commands/init.ts
|
|
3231
3209
|
async function ensureWorkspaceInitialized(workdir) {
|
|
3232
3210
|
if (isWorkspaceApmInitialized(workdir)) {
|
|
3233
3211
|
return { didInit: false };
|
|
@@ -3235,19 +3213,21 @@ async function ensureWorkspaceInitialized(workdir) {
|
|
|
3235
3213
|
console.log(
|
|
3236
3214
|
`[apm] \u5DE5\u4F5C\u76EE\u5F55 ${workdir} \u672A\u68C0\u6D4B\u5230\u5DF2\u521D\u59CB\u5316\u7684 .apm\uFF0C\u6B63\u5728\u6309 WebIDE \u81EA\u52A8\u521D\u59CB\u5316\u2026`
|
|
3237
3215
|
);
|
|
3238
|
-
|
|
3216
|
+
await ensureWorkspaceApmDirForInit(workdir);
|
|
3217
|
+
console.log(`[apm] \u5DF2\u521B\u5EFA\u5DE5\u4F5C\u533A\u76EE\u5F55\uFF1A${workspaceApmDir(workdir)}`);
|
|
3218
|
+
return { didInit: true };
|
|
3239
3219
|
}
|
|
3240
3220
|
|
|
3241
3221
|
// src/utils/project-documents.ts
|
|
3242
3222
|
import {
|
|
3243
|
-
existsSync as
|
|
3223
|
+
existsSync as existsSync6,
|
|
3244
3224
|
readdirSync as readdirSync3,
|
|
3245
|
-
readFileSync as
|
|
3225
|
+
readFileSync as readFileSync5,
|
|
3246
3226
|
rmSync,
|
|
3247
|
-
writeFileSync as
|
|
3227
|
+
writeFileSync as writeFileSync4
|
|
3248
3228
|
} from "fs";
|
|
3249
3229
|
import { createHash as createHash2 } from "crypto";
|
|
3250
|
-
import { dirname as
|
|
3230
|
+
import { dirname as dirname2, join as join5, relative as relative4, sep } from "path";
|
|
3251
3231
|
var MANIFEST_FILE = "manifest.json";
|
|
3252
3232
|
function normalizeProjectIdForPath(projectId) {
|
|
3253
3233
|
const id = projectId.trim();
|
|
@@ -3261,11 +3241,11 @@ function normalizeProjectIdForPath(projectId) {
|
|
|
3261
3241
|
}
|
|
3262
3242
|
function projectDocumentsDir(apmRoot, projectId) {
|
|
3263
3243
|
const id = normalizeProjectIdForPath(projectId);
|
|
3264
|
-
return
|
|
3244
|
+
return join5(apmRoot ?? workspaceApmDir(), "project", id);
|
|
3265
3245
|
}
|
|
3266
3246
|
function projectDocumentLocalPath(apmRoot, projectId, documentPath) {
|
|
3267
3247
|
const normalized = normalizeLocalDocumentPath(documentPath);
|
|
3268
|
-
return
|
|
3248
|
+
return join5(
|
|
3269
3249
|
projectDocumentsDir(apmRoot, projectId),
|
|
3270
3250
|
...normalized.split("/")
|
|
3271
3251
|
);
|
|
@@ -3285,16 +3265,16 @@ function hashLocalFileContent(content) {
|
|
|
3285
3265
|
return createHash2("sha256").update(content, "utf8").digest("hex");
|
|
3286
3266
|
}
|
|
3287
3267
|
function readLocalManifest(apmRoot, projectId) {
|
|
3288
|
-
const
|
|
3268
|
+
const manifestPath2 = join5(
|
|
3289
3269
|
projectDocumentsDir(apmRoot, projectId),
|
|
3290
3270
|
MANIFEST_FILE
|
|
3291
3271
|
);
|
|
3292
|
-
if (!
|
|
3272
|
+
if (!existsSync6(manifestPath2)) {
|
|
3293
3273
|
return null;
|
|
3294
3274
|
}
|
|
3295
3275
|
try {
|
|
3296
3276
|
return JSON.parse(
|
|
3297
|
-
|
|
3277
|
+
readFileSync5(manifestPath2, "utf8")
|
|
3298
3278
|
);
|
|
3299
3279
|
} catch {
|
|
3300
3280
|
return null;
|
|
@@ -3302,13 +3282,13 @@ function readLocalManifest(apmRoot, projectId) {
|
|
|
3302
3282
|
}
|
|
3303
3283
|
function listLocalDocumentPaths(apmRoot, projectId) {
|
|
3304
3284
|
const root = projectDocumentsDir(apmRoot, projectId);
|
|
3305
|
-
if (!
|
|
3285
|
+
if (!existsSync6(root)) {
|
|
3306
3286
|
return [];
|
|
3307
3287
|
}
|
|
3308
3288
|
const paths = [];
|
|
3309
3289
|
const walk = (dir) => {
|
|
3310
3290
|
for (const entry of readdirSync3(dir, { withFileTypes: true })) {
|
|
3311
|
-
const abs =
|
|
3291
|
+
const abs = join5(dir, entry.name);
|
|
3312
3292
|
if (entry.isDirectory()) {
|
|
3313
3293
|
walk(abs);
|
|
3314
3294
|
continue;
|
|
@@ -3427,8 +3407,8 @@ ${diagnostic ?? ""}`);
|
|
|
3427
3407
|
const absPath = toFsPath(
|
|
3428
3408
|
projectDocumentLocalPath(targetApmDir, projectId, doc.path)
|
|
3429
3409
|
);
|
|
3430
|
-
await ensureDirExists(
|
|
3431
|
-
|
|
3410
|
+
await ensureDirExists(dirname2(absPath));
|
|
3411
|
+
writeFileSync4(absPath, doc.content, "utf8");
|
|
3432
3412
|
downloaded += 1;
|
|
3433
3413
|
}
|
|
3434
3414
|
}
|
|
@@ -3437,13 +3417,13 @@ ${diagnostic ?? ""}`);
|
|
|
3437
3417
|
const absPath = toFsPath(
|
|
3438
3418
|
projectDocumentLocalPath(targetApmDir, projectId, path3)
|
|
3439
3419
|
);
|
|
3440
|
-
if (
|
|
3420
|
+
if (existsSync6(absPath)) {
|
|
3441
3421
|
rmSync(absPath, { force: true });
|
|
3442
3422
|
deleted += 1;
|
|
3443
3423
|
}
|
|
3444
3424
|
}
|
|
3445
|
-
|
|
3446
|
-
toFsPath(
|
|
3425
|
+
writeFileSync4(
|
|
3426
|
+
toFsPath(join5(docsDir, MANIFEST_FILE)),
|
|
3447
3427
|
`${JSON.stringify(remoteManifest, null, 2)}
|
|
3448
3428
|
`,
|
|
3449
3429
|
"utf8"
|
|
@@ -3486,7 +3466,7 @@ async function syncProjectDocumentsPush(cfg2, workdirPath, apmRoot, options) {
|
|
|
3486
3466
|
const absPath = toFsPath(
|
|
3487
3467
|
projectDocumentLocalPath(targetApmDir, projectId, path3)
|
|
3488
3468
|
);
|
|
3489
|
-
const content =
|
|
3469
|
+
const content = readFileSync5(absPath, "utf8");
|
|
3490
3470
|
const contentHash = hashLocalFileContent(content);
|
|
3491
3471
|
if (remoteHashByPath.get(path3) === contentHash) {
|
|
3492
3472
|
continue;
|
|
@@ -3506,71 +3486,6 @@ async function syncProjectDocumentsPush(cfg2, workdirPath, apmRoot, options) {
|
|
|
3506
3486
|
return synced;
|
|
3507
3487
|
}
|
|
3508
3488
|
|
|
3509
|
-
// src/version.ts
|
|
3510
|
-
import { readFileSync as readFileSync5 } from "fs";
|
|
3511
|
-
import { dirname as dirname4, join as join5 } from "path";
|
|
3512
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3513
|
-
function readCliVersion() {
|
|
3514
|
-
try {
|
|
3515
|
-
const dir = dirname4(fileURLToPath2(import.meta.url));
|
|
3516
|
-
const pkgPath = join5(dir, "..", "package.json");
|
|
3517
|
-
const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
|
|
3518
|
-
return pkg.version ?? "0.0.0";
|
|
3519
|
-
} catch {
|
|
3520
|
-
return "0.0.0";
|
|
3521
|
-
}
|
|
3522
|
-
}
|
|
3523
|
-
|
|
3524
|
-
// src/commands/connect/cli-version-sync.ts
|
|
3525
|
-
import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
3526
|
-
import { join as join6 } from "path";
|
|
3527
|
-
var CLI_VERSION_FILE = ".cli-version.json";
|
|
3528
|
-
function manifestPath2(apmDir) {
|
|
3529
|
-
return join6(apmDir, CLI_VERSION_FILE);
|
|
3530
|
-
}
|
|
3531
|
-
function loadManifest(apmDir) {
|
|
3532
|
-
const path3 = toFsPath(manifestPath2(apmDir));
|
|
3533
|
-
if (!existsSync6(path3)) {
|
|
3534
|
-
return null;
|
|
3535
|
-
}
|
|
3536
|
-
try {
|
|
3537
|
-
const parsed = JSON.parse(
|
|
3538
|
-
readFileSync6(path3, "utf8")
|
|
3539
|
-
);
|
|
3540
|
-
if (parsed?.version === 1 && typeof parsed.cliVersion === "string" && parsed.cliVersion.trim()) {
|
|
3541
|
-
return parsed;
|
|
3542
|
-
}
|
|
3543
|
-
} catch {
|
|
3544
|
-
}
|
|
3545
|
-
return null;
|
|
3546
|
-
}
|
|
3547
|
-
function saveManifest(apmDir, cliVersion) {
|
|
3548
|
-
const manifest = { version: 1, cliVersion };
|
|
3549
|
-
writeFileSync4(
|
|
3550
|
-
toFsPath(manifestPath2(apmDir)),
|
|
3551
|
-
`${JSON.stringify(manifest, null, 2)}
|
|
3552
|
-
`,
|
|
3553
|
-
"utf8"
|
|
3554
|
-
);
|
|
3555
|
-
}
|
|
3556
|
-
var syncedInSession = /* @__PURE__ */ new Map();
|
|
3557
|
-
function shouldSyncSkillsForCliVersion(workdir, currentVersion) {
|
|
3558
|
-
const cached = syncedInSession.get(workdir);
|
|
3559
|
-
if (cached === currentVersion) {
|
|
3560
|
-
return false;
|
|
3561
|
-
}
|
|
3562
|
-
const stored = loadManifest(workspaceApmDir(workdir));
|
|
3563
|
-
if (stored?.cliVersion === currentVersion) {
|
|
3564
|
-
syncedInSession.set(workdir, currentVersion);
|
|
3565
|
-
return false;
|
|
3566
|
-
}
|
|
3567
|
-
return true;
|
|
3568
|
-
}
|
|
3569
|
-
function markSkillsSyncedForCliVersion(workdir, cliVersion) {
|
|
3570
|
-
saveManifest(workspaceApmDir(workdir), cliVersion);
|
|
3571
|
-
syncedInSession.set(workdir, cliVersion);
|
|
3572
|
-
}
|
|
3573
|
-
|
|
3574
3489
|
// src/commands/connect/upload-package-artifact.ts
|
|
3575
3490
|
import fs2 from "node:fs";
|
|
3576
3491
|
import path2 from "node:path";
|
|
@@ -3690,26 +3605,12 @@ async function handleWebIdePackage(cfg2, msg2, signal) {
|
|
|
3690
3605
|
},
|
|
3691
3606
|
(didInit) => didInit ? "\u5DF2\u521D\u59CB\u5316\u5DE5\u4F5C\u533A" : "\u5DE5\u4F5C\u533A\u5DF2\u5C31\u7EEA"
|
|
3692
3607
|
);
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
await copyWebIdeTemplateFiles(workspaceApmDir(workdir), workdir);
|
|
3700
|
-
markSkillsSyncedForCliVersion(workdir, cliVersion);
|
|
3701
|
-
return cliVersion;
|
|
3702
|
-
},
|
|
3703
|
-
(version) => `\u5DF2\u540C\u6B65\u81F3 CLI ${version}`
|
|
3704
|
-
);
|
|
3705
|
-
} else {
|
|
3706
|
-
eventSession.addCliStep(
|
|
3707
|
-
"\u540C\u6B65 WebIDE \u89C4\u5219",
|
|
3708
|
-
`\u7248\u672C\u4E00\u81F4\uFF08${cliVersion}\uFF09\uFF0C\u8DF3\u8FC7`,
|
|
3709
|
-
"skip"
|
|
3710
|
-
);
|
|
3711
|
-
await syncPrepLog();
|
|
3712
|
-
}
|
|
3608
|
+
if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
|
|
3609
|
+
await runPrepStep(
|
|
3610
|
+
"\u540C\u6B65 WebIDE \u89C4\u5219",
|
|
3611
|
+
async () => syncWebIdeAgentFiles(workdir, cfg2),
|
|
3612
|
+
(result) => result.wrote ? `\u5DF2\u5199\u5165 ${result.ruleCount} \u6761\u89C4\u5219` : "\u89C4\u5219\u672A\u53D8\u5316\uFF0C\u8DF3\u8FC7"
|
|
3613
|
+
);
|
|
3713
3614
|
await runPrepStep(
|
|
3714
3615
|
"\u5DE5\u4F5C\u533A\u4ED3\u5E93\u6E05\u5355",
|
|
3715
3616
|
async () => {
|
|
@@ -3938,6 +3839,7 @@ async function handleStartProject(cfg2, msg2, signal) {
|
|
|
3938
3839
|
try {
|
|
3939
3840
|
if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
|
|
3940
3841
|
await ensureWorkspaceInitialized(workdir);
|
|
3842
|
+
await syncWebIdeAgentFiles(workdir, cfg2);
|
|
3941
3843
|
const api = createApmApiClient(cfg2);
|
|
3942
3844
|
const outcome = await runCursorAgent(
|
|
3943
3845
|
cfg2,
|
|
@@ -4049,8 +3951,8 @@ async function handleStartProject(cfg2, msg2, signal) {
|
|
|
4049
3951
|
}
|
|
4050
3952
|
|
|
4051
3953
|
// src/commands/connect/webide-agent-registry.ts
|
|
4052
|
-
import { existsSync as existsSync7, mkdirSync as
|
|
4053
|
-
import { dirname as
|
|
3954
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
|
|
3955
|
+
import { dirname as dirname3, resolve as resolve6 } from "node:path";
|
|
4054
3956
|
function registryPath(workdir, taskId, fileName = "cursor-agent.json") {
|
|
4055
3957
|
return resolve6(workdir, ".apm", "webide", taskId, fileName);
|
|
4056
3958
|
}
|
|
@@ -4060,7 +3962,7 @@ function readRegistry(path3) {
|
|
|
4060
3962
|
return {};
|
|
4061
3963
|
}
|
|
4062
3964
|
try {
|
|
4063
|
-
const parsed = JSON.parse(
|
|
3965
|
+
const parsed = JSON.parse(readFileSync6(path3, "utf8"));
|
|
4064
3966
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
4065
3967
|
const raw = parsed;
|
|
4066
3968
|
const state = {};
|
|
@@ -4089,7 +3991,7 @@ function readRegistry(path3) {
|
|
|
4089
3991
|
return {};
|
|
4090
3992
|
}
|
|
4091
3993
|
function writeRegistry(path3, registry) {
|
|
4092
|
-
|
|
3994
|
+
mkdirSync5(dirname3(path3), { recursive: true });
|
|
4093
3995
|
writeFileSync5(path3, `${JSON.stringify(registry, null, 2)}
|
|
4094
3996
|
`, "utf8");
|
|
4095
3997
|
}
|
|
@@ -4541,8 +4443,8 @@ async function ensureWebIdePullRequests(cfg2, taskId, workdir) {
|
|
|
4541
4443
|
}
|
|
4542
4444
|
|
|
4543
4445
|
// src/commands/sync-webide-attachments.ts
|
|
4544
|
-
import { existsSync as existsSync9, readFileSync as
|
|
4545
|
-
import { join as
|
|
4446
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
4447
|
+
import { join as join6 } from "path";
|
|
4546
4448
|
var MANIFEST_FILE2 = ".sync-manifest.json";
|
|
4547
4449
|
async function downloadAttachment(cfg2, attachmentId) {
|
|
4548
4450
|
const base = cfg2.baseUrl.trim().replace(/\/+$/, "");
|
|
@@ -4557,14 +4459,14 @@ async function downloadAttachment(cfg2, attachmentId) {
|
|
|
4557
4459
|
}
|
|
4558
4460
|
return Buffer.from(await res.arrayBuffer());
|
|
4559
4461
|
}
|
|
4560
|
-
function
|
|
4561
|
-
const path3 =
|
|
4462
|
+
function loadManifest(dir) {
|
|
4463
|
+
const path3 = join6(dir, MANIFEST_FILE2);
|
|
4562
4464
|
if (!existsSync9(path3)) {
|
|
4563
4465
|
return { version: 1, attachments: {} };
|
|
4564
4466
|
}
|
|
4565
4467
|
try {
|
|
4566
4468
|
const parsed = JSON.parse(
|
|
4567
|
-
|
|
4469
|
+
readFileSync7(path3, "utf8")
|
|
4568
4470
|
);
|
|
4569
4471
|
if (parsed?.version === 1 && parsed.attachments && typeof parsed.attachments === "object") {
|
|
4570
4472
|
return parsed;
|
|
@@ -4573,9 +4475,9 @@ function loadManifest2(dir) {
|
|
|
4573
4475
|
}
|
|
4574
4476
|
return { version: 1, attachments: {} };
|
|
4575
4477
|
}
|
|
4576
|
-
function
|
|
4478
|
+
function saveManifest(dir, manifest) {
|
|
4577
4479
|
writeFileSync6(
|
|
4578
|
-
|
|
4480
|
+
join6(dir, MANIFEST_FILE2),
|
|
4579
4481
|
`${JSON.stringify(manifest, null, 2)}
|
|
4580
4482
|
`,
|
|
4581
4483
|
"utf8"
|
|
@@ -4590,14 +4492,14 @@ function isAttachmentUpToDate(entry, item, dest) {
|
|
|
4590
4492
|
async function syncAttachmentsToDirectory(cfg2, attachments, dir, logLabel) {
|
|
4591
4493
|
await ensureDirExists(dir);
|
|
4592
4494
|
if (attachments.length === 0) {
|
|
4593
|
-
|
|
4495
|
+
saveManifest(dir, { version: 1, attachments: {} });
|
|
4594
4496
|
return [];
|
|
4595
4497
|
}
|
|
4596
|
-
const manifest =
|
|
4498
|
+
const manifest = loadManifest(dir);
|
|
4597
4499
|
const nextManifest = { version: 1, attachments: {} };
|
|
4598
4500
|
const names = [];
|
|
4599
4501
|
for (const item of attachments) {
|
|
4600
|
-
const dest =
|
|
4502
|
+
const dest = join6(dir, item.name);
|
|
4601
4503
|
const entry = manifest.attachments[item.id];
|
|
4602
4504
|
const createdAt = item.createdAt ?? "";
|
|
4603
4505
|
names.push(item.name);
|
|
@@ -4614,7 +4516,7 @@ async function syncAttachmentsToDirectory(cfg2, attachments, dir, logLabel) {
|
|
|
4614
4516
|
};
|
|
4615
4517
|
console.log(`[apm] \u5DF2\u4E0B\u8F7D\u9644\u4EF6: ${logLabel}/${item.name}`);
|
|
4616
4518
|
}
|
|
4617
|
-
|
|
4519
|
+
saveManifest(dir, nextManifest);
|
|
4618
4520
|
return names;
|
|
4619
4521
|
}
|
|
4620
4522
|
async function syncWebIdeAttachments(cfg2, taskId, workdir, attachments) {
|
|
@@ -4629,19 +4531,19 @@ async function syncWebIdeAttachments(cfg2, taskId, workdir, attachments) {
|
|
|
4629
4531
|
|
|
4630
4532
|
// src/commands/sync-webide-design.ts
|
|
4631
4533
|
import { createHash as createHash3 } from "crypto";
|
|
4632
|
-
import { existsSync as existsSync10, readdirSync as readdirSync4, readFileSync as
|
|
4633
|
-
import { join as
|
|
4534
|
+
import { existsSync as existsSync10, readdirSync as readdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
|
|
4535
|
+
import { join as join7 } from "path";
|
|
4634
4536
|
var MANIFEST_FILE3 = ".sync-manifest.json";
|
|
4635
4537
|
function hashBuffer(buf) {
|
|
4636
4538
|
return createHash3("sha256").update(buf).digest("hex");
|
|
4637
4539
|
}
|
|
4638
|
-
function
|
|
4639
|
-
const path3 =
|
|
4540
|
+
function loadManifest2(dir) {
|
|
4541
|
+
const path3 = join7(dir, MANIFEST_FILE3);
|
|
4640
4542
|
if (!existsSync10(path3)) {
|
|
4641
4543
|
return { version: 1, files: {} };
|
|
4642
4544
|
}
|
|
4643
4545
|
try {
|
|
4644
|
-
const parsed = JSON.parse(
|
|
4546
|
+
const parsed = JSON.parse(readFileSync8(path3, "utf8"));
|
|
4645
4547
|
if (parsed?.version === 1 && parsed.files && typeof parsed.files === "object") {
|
|
4646
4548
|
return parsed;
|
|
4647
4549
|
}
|
|
@@ -4649,9 +4551,9 @@ function loadManifest3(dir) {
|
|
|
4649
4551
|
}
|
|
4650
4552
|
return { version: 1, files: {} };
|
|
4651
4553
|
}
|
|
4652
|
-
function
|
|
4554
|
+
function saveManifest2(dir, manifest) {
|
|
4653
4555
|
writeFileSync7(
|
|
4654
|
-
|
|
4556
|
+
join7(dir, MANIFEST_FILE3),
|
|
4655
4557
|
`${JSON.stringify(manifest, null, 2)}
|
|
4656
4558
|
`,
|
|
4657
4559
|
"utf8"
|
|
@@ -4674,12 +4576,12 @@ async function downloadDesignFile(cfg2, taskId, name) {
|
|
|
4674
4576
|
async function syncWebIdeDesign(cfg2, taskId, workdir, artifacts) {
|
|
4675
4577
|
const dir = webideDesignDir(taskId, workdir);
|
|
4676
4578
|
await ensureDirExists(dir);
|
|
4677
|
-
const manifest =
|
|
4579
|
+
const manifest = loadManifest2(dir);
|
|
4678
4580
|
const synced = [];
|
|
4679
4581
|
for (const art of artifacts) {
|
|
4680
4582
|
const name = art.name?.trim();
|
|
4681
4583
|
if (!name || !name.toLowerCase().endsWith(".html")) continue;
|
|
4682
|
-
const localPath =
|
|
4584
|
+
const localPath = join7(dir, name);
|
|
4683
4585
|
const entry = manifest.files[name];
|
|
4684
4586
|
if (entry?.contentHash === art.contentHash && existsSync10(localPath)) {
|
|
4685
4587
|
continue;
|
|
@@ -4689,7 +4591,7 @@ async function syncWebIdeDesign(cfg2, taskId, workdir, artifacts) {
|
|
|
4689
4591
|
manifest.files[name] = { contentHash: hashBuffer(buf) };
|
|
4690
4592
|
synced.push(name);
|
|
4691
4593
|
}
|
|
4692
|
-
|
|
4594
|
+
saveManifest2(dir, manifest);
|
|
4693
4595
|
return synced;
|
|
4694
4596
|
}
|
|
4695
4597
|
function listLocalDesignHtmlFiles(taskId, workdir) {
|
|
@@ -4698,8 +4600,8 @@ function listLocalDesignHtmlFiles(taskId, workdir) {
|
|
|
4698
4600
|
const out = [];
|
|
4699
4601
|
for (const name of readdirSync4(dir)) {
|
|
4700
4602
|
if (!name.toLowerCase().endsWith(".html")) continue;
|
|
4701
|
-
const absPath =
|
|
4702
|
-
const buf =
|
|
4603
|
+
const absPath = join7(dir, name);
|
|
4604
|
+
const buf = readFileSync8(absPath);
|
|
4703
4605
|
if (buf.length === 0) continue;
|
|
4704
4606
|
out.push({ name, absPath, contentHash: hashBuffer(buf) });
|
|
4705
4607
|
}
|
|
@@ -4982,26 +4884,12 @@ async function handleWebIdeInboundMessage(cfg2, msg2, signal) {
|
|
|
4982
4884
|
},
|
|
4983
4885
|
(didInit) => didInit ? "\u5DF2\u521D\u59CB\u5316\u5DE5\u4F5C\u533A" : "\u5DE5\u4F5C\u533A\u5DF2\u5C31\u7EEA"
|
|
4984
4886
|
);
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
await copyWebIdeTemplateFiles(workspaceApmDir(workdir), workdir);
|
|
4992
|
-
markSkillsSyncedForCliVersion(workdir, cliVersion);
|
|
4993
|
-
return cliVersion;
|
|
4994
|
-
},
|
|
4995
|
-
(version) => `\u5DF2\u540C\u6B65\u81F3 CLI ${version}`
|
|
4996
|
-
);
|
|
4997
|
-
} else {
|
|
4998
|
-
eventSession.addCliStep(
|
|
4999
|
-
"\u540C\u6B65 WebIDE \u89C4\u5219",
|
|
5000
|
-
`\u7248\u672C\u4E00\u81F4\uFF08${cliVersion}\uFF09\uFF0C\u8DF3\u8FC7`,
|
|
5001
|
-
"skip"
|
|
5002
|
-
);
|
|
5003
|
-
await syncPrepLog();
|
|
5004
|
-
}
|
|
4887
|
+
if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
|
|
4888
|
+
await runPrepStep(
|
|
4889
|
+
"\u540C\u6B65 WebIDE \u89C4\u5219",
|
|
4890
|
+
async () => syncWebIdeAgentFiles(workdir, cfg2),
|
|
4891
|
+
(result) => result.wrote ? `\u5DF2\u5199\u5165 ${result.ruleCount} \u6761\u89C4\u5219` : "\u89C4\u5219\u672A\u53D8\u5316\uFF0C\u8DF3\u8FC7"
|
|
4892
|
+
);
|
|
5005
4893
|
await runPrepStep(
|
|
5006
4894
|
"\u5DE5\u4F5C\u533A\u4ED3\u5E93\u6E05\u5355",
|
|
5007
4895
|
async () => {
|
package/package.json
CHANGED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
## WebIDE 指南
|
|
2
|
-
|
|
3
|
-
你正在 WebIDE 工作区中处理任务。本轮要做什么以 prompt 里的 `action` 为准;先 Read 本文件和对应规则,再动手。
|
|
4
|
-
|
|
5
|
-
### 工作原则
|
|
6
|
-
|
|
7
|
-
1. **用户可见内容只走 `AppendMessage`**:进展、评估、改动说明、错误原因、下一步等,一律用 `AppendMessage` 写入(可多次追加)。细则见 `.apm/rules/webide_reply.md`。
|
|
8
|
-
2. **最终自然语言收尾极简**:最多 1 句状态确认(如「本轮已完成」)。禁止复述、扩写或总结 `AppendMessage` 已写内容。
|
|
9
|
-
3. **按本轮 `action` 执行**:不要自行跳阶段;未接到开发指令时不要改代码、不要写计划文档。
|
|
10
|
-
4. 文件读写、搜索与 Shell 必须限制在当前工作区 cwd 内。
|
|
11
|
-
|
|
12
|
-
### 规则(`.apm/rules/`,按需 Read,不要一次读完)
|
|
13
|
-
|
|
14
|
-
- `webide_reply.md`:输出通道(每轮必守)
|
|
15
|
-
- `webide_git_commit.md`:开发 / 修码时的 Git 提交与 push
|
|
16
|
-
- `webide_sql_change.md`:有表结构或 SQL 变更时,须在 `AppendMessage` 中醒目提示
|
|
17
|
-
- `webide_sql_execute.md`:execute-sql 轮次连库执行 SQL 时 Read
|
|
18
|
-
- `webide_terminal.md`:长驻进程禁止用 Shell;本地服务由顶栏「启动项目」触发,开发任务不要自行起服务
|
|
19
|
-
- `webide_testcase.md`:生成测试用例并调用 `UpsertWebIdeTestCases`
|
|
20
|
-
- `webide_merge.md`:验收通过后先 `UpsertWebIdeChecklist` 写验收清单,再 `MergeWebIdePullRequests`
|
|
21
|
-
|
|
22
|
-
### 目录
|
|
23
|
-
|
|
24
|
-
- 项目文档:`.apm/project/<项目ID>/`(索引 `manifest.json`;部署 / 本地 dev 命令以该目录下文件名或路径包含 `deploy` 的文档为准,不必恰好叫 `deploy.md`,禁止猜测)
|
|
25
|
-
- 任务附件:`.apm/webide/<taskId>/attachments/`(prompt 出现「任务附件」时按路径查看)
|
|
26
|
-
- 仓库清单:`.apm/workspace-repos.json`(先确认单仓 / 多仓;多仓必须写清改动范围并点名仓库)
|
|
27
|
-
|
|
28
|
-
计划、用例、验收清单、合并 PR 走 WebIDE 专用工具(`AskQuestion`、`RecommendPlan`、`UpsertWebIdePlan`、`UpsertWebIdeChecklist`、`GetWebIdeChecklist`、`UpsertWebIdeTestCases`、`MergeWebIdePullRequests` 等)。本地服务由用户在顶栏「启动项目」启动,开发任务不要自行起长驻进程。
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
## WebIDE Git 提交规范
|
|
2
|
-
|
|
3
|
-
适用场景:WebIDE 开发阶段(`skip-plan` / `start-develop`)及修码(`fix-and-retest` / `report-defect`)中涉及代码改动时。
|
|
4
|
-
|
|
5
|
-
### 分轮提交
|
|
6
|
-
|
|
7
|
-
1. 按需求点分轮实现:每完成一个可独立验收的需求点,立即 `git add` 并 commit,不要把多轮改动攒成一次提交。
|
|
8
|
-
2. commit message 用简短中文说明本轮改动(例:`feat: 实现登录表单校验`)。
|
|
9
|
-
3. 多仓工作区时,只在实际改动过的仓库提交。
|
|
10
|
-
|
|
11
|
-
### 结束前检查
|
|
12
|
-
|
|
13
|
-
本轮全部工作结束前:
|
|
14
|
-
|
|
15
|
-
1. 确认工作区干净(`git status` 无未提交变更);若仍有残留改动,补一次 commit。
|
|
16
|
-
2. 将当前分支推送到远程:已有 upstream 用 `git push`,否则 `git push -u origin HEAD`。多仓工作区时,只 push 实际有新 commit 的仓库。
|