ai-project-manage-cli 6.0.37 → 6.0.38
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 +130 -61
- package/package.json +1 -1
- package/template/deploy/README.md +15 -0
- package/template/sessions/.gitkeep +0 -0
package/dist/index.js
CHANGED
|
@@ -84,13 +84,55 @@ import { join as join3 } from "path";
|
|
|
84
84
|
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
85
85
|
|
|
86
86
|
// src/command-utils.ts
|
|
87
|
-
import {
|
|
88
|
-
import { basename, dirname, extname, join as join2, resolve } from "path";
|
|
87
|
+
import { copyFileSync, existsSync, mkdirSync as mkdirSync2, readdirSync, statSync } from "fs";
|
|
88
|
+
import { basename, dirname, extname, join as join2, resolve as resolve2 } from "path";
|
|
89
89
|
import { fileURLToPath } from "url";
|
|
90
|
+
|
|
91
|
+
// src/workdir-path.ts
|
|
92
|
+
import { realpathSync } from "fs";
|
|
93
|
+
import { platform } from "os";
|
|
94
|
+
import { resolve } from "path";
|
|
95
|
+
function toFsPath(inputPath) {
|
|
96
|
+
const absolute = resolve(inputPath);
|
|
97
|
+
if (platform() !== "win32") return absolute;
|
|
98
|
+
if (absolute.startsWith("\\\\?\\")) return absolute;
|
|
99
|
+
const normalized = absolute.replace(/\//g, "\\");
|
|
100
|
+
if (normalized.startsWith("\\\\")) {
|
|
101
|
+
return `\\\\?\\UNC\\${normalized.slice(2)}`;
|
|
102
|
+
}
|
|
103
|
+
return `\\\\?\\${normalized}`;
|
|
104
|
+
}
|
|
105
|
+
function normalizeWorkdirPath(path10) {
|
|
106
|
+
let normalized = path10.trim().replace(/\\/g, "/").normalize("NFC");
|
|
107
|
+
if (normalized.startsWith("//?/")) {
|
|
108
|
+
normalized = normalized.slice(4);
|
|
109
|
+
}
|
|
110
|
+
const windowsDrive = /^([A-Za-z]:)\/*(.*)$/.exec(normalized);
|
|
111
|
+
if (windowsDrive) {
|
|
112
|
+
const drive = windowsDrive[1].toLowerCase();
|
|
113
|
+
const rest = windowsDrive[2].replace(/\/+/g, "/").replace(/\/$/, "");
|
|
114
|
+
return rest ? `${drive}/${rest}` : drive;
|
|
115
|
+
}
|
|
116
|
+
normalized = normalized.replace(/\/+/g, "/");
|
|
117
|
+
if (normalized.length > 1 && normalized.endsWith("/")) {
|
|
118
|
+
normalized = normalized.slice(0, -1);
|
|
119
|
+
}
|
|
120
|
+
return normalized;
|
|
121
|
+
}
|
|
122
|
+
function resolveWorkdirPath(cwd = process.cwd()) {
|
|
123
|
+
const absolute = resolve(cwd);
|
|
124
|
+
try {
|
|
125
|
+
return normalizeWorkdirPath(realpathSync.native(absolute));
|
|
126
|
+
} catch {
|
|
127
|
+
return normalizeWorkdirPath(absolute);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// src/command-utils.ts
|
|
90
132
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
91
|
-
var CLI_TEMPLATE_DIR =
|
|
92
|
-
function workspaceApmDir(cwd =
|
|
93
|
-
return
|
|
133
|
+
var CLI_TEMPLATE_DIR = resolve2(__dirname, "../template");
|
|
134
|
+
function workspaceApmDir(cwd = resolveWorkdirPath()) {
|
|
135
|
+
return resolve2(resolve2(cwd), ".apm");
|
|
94
136
|
}
|
|
95
137
|
var SESSIONS_SUBDIR = "sessions";
|
|
96
138
|
var SESSION_DOCS_SUBDIR = "docs";
|
|
@@ -147,78 +189,106 @@ async function ensureLoggedConfig() {
|
|
|
147
189
|
async function ensureDirExists(dir) {
|
|
148
190
|
mkdirSync2(dir, { recursive: true });
|
|
149
191
|
}
|
|
150
|
-
async function ensureWorkspaceApmDirForInit() {
|
|
151
|
-
const dir = workspaceApmDir();
|
|
152
|
-
|
|
153
|
-
|
|
192
|
+
async function ensureWorkspaceApmDirForInit(cwd = resolveWorkdirPath()) {
|
|
193
|
+
const dir = workspaceApmDir(cwd);
|
|
194
|
+
const fsDir = toFsPath(dir);
|
|
195
|
+
if (!existsSync(fsDir)) {
|
|
196
|
+
mkdirSync2(fsDir, { recursive: true });
|
|
154
197
|
return;
|
|
155
198
|
}
|
|
156
|
-
const st = statSync(
|
|
199
|
+
const st = statSync(fsDir);
|
|
157
200
|
if (!st.isDirectory()) {
|
|
158
201
|
throw new Error(`[apm] \u8DEF\u5F84\u5DF2\u5B58\u5728\u4F46\u4E0D\u662F\u76EE\u5F55: ${dir}`);
|
|
159
202
|
}
|
|
160
|
-
if (readdirSync(
|
|
203
|
+
if (readdirSync(fsDir).length > 0) {
|
|
161
204
|
throw new Error(
|
|
162
205
|
"[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"
|
|
163
206
|
);
|
|
164
207
|
}
|
|
165
208
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
209
|
+
var WORKSPACE_TEMPLATE_SUBDIRS = [
|
|
210
|
+
"sessions",
|
|
211
|
+
"skills",
|
|
212
|
+
"rules",
|
|
213
|
+
"deploy"
|
|
214
|
+
];
|
|
215
|
+
function shouldSkipTemplateEntry(name) {
|
|
216
|
+
return name === ".DS_Store" || name === "Thumbs.db";
|
|
217
|
+
}
|
|
218
|
+
function copyTemplateEntry(src, dest) {
|
|
219
|
+
const fsSrc = toFsPath(src);
|
|
220
|
+
const fsDest = toFsPath(dest);
|
|
221
|
+
const st = statSync(fsSrc);
|
|
222
|
+
if (st.isDirectory()) {
|
|
223
|
+
mkdirSync2(fsDest, { recursive: true });
|
|
224
|
+
for (const name of readdirSync(fsSrc)) {
|
|
225
|
+
if (shouldSkipTemplateEntry(name)) continue;
|
|
226
|
+
copyTemplateEntry(join2(src, name), join2(dest, name));
|
|
227
|
+
}
|
|
228
|
+
return;
|
|
173
229
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
230
|
+
if (!st.isFile()) return;
|
|
231
|
+
mkdirSync2(toFsPath(dirname(dest)), { recursive: true });
|
|
232
|
+
copyFileSync(fsSrc, fsDest);
|
|
233
|
+
}
|
|
234
|
+
function assertTemplateCopiedToApm(apmDir, workdir) {
|
|
235
|
+
const required = [
|
|
236
|
+
"AGENTS.md",
|
|
237
|
+
"apm.config.json",
|
|
238
|
+
"rules",
|
|
239
|
+
"skills",
|
|
240
|
+
"sessions"
|
|
241
|
+
];
|
|
242
|
+
for (const item of required) {
|
|
243
|
+
const path10 = join2(apmDir, item);
|
|
244
|
+
if (!existsSync(toFsPath(path10))) {
|
|
245
|
+
throw new Error(`[apm] \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11: ${path10}`);
|
|
246
|
+
}
|
|
177
247
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
248
|
+
const leakedRules = join2(workdir, "rules");
|
|
249
|
+
const apmRules = join2(apmDir, "rules");
|
|
250
|
+
if (existsSync(toFsPath(leakedRules)) && !existsSync(toFsPath(join2(apmRules, "reply.md")))) {
|
|
251
|
+
throw new Error(
|
|
252
|
+
`[apm] \u6A21\u677F\u88AB\u590D\u5236\u5230\u9519\u8BEF\u4F4D\u7F6E: ${leakedRules}\uFF08\u5E94\u5728 ${apmRules}\uFF09`
|
|
253
|
+
);
|
|
182
254
|
}
|
|
183
255
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
if (normalized.startsWith("//?/")) {
|
|
191
|
-
normalized = normalized.slice(4);
|
|
256
|
+
async function copyTemplateFiles(targetDir, workdir = resolveWorkdirPath()) {
|
|
257
|
+
const resolvedTarget = resolve2(targetDir);
|
|
258
|
+
const templateDir = resolve2(CLI_TEMPLATE_DIR);
|
|
259
|
+
const fsTemplateDir = toFsPath(templateDir);
|
|
260
|
+
if (!existsSync(fsTemplateDir)) {
|
|
261
|
+
throw new Error(`[apm] \u672A\u627E\u5230 CLI \u6A21\u677F\u76EE\u5F55: ${templateDir}`);
|
|
192
262
|
}
|
|
193
|
-
const
|
|
194
|
-
if (
|
|
195
|
-
|
|
196
|
-
const rest = windowsDrive[2].replace(/\/+/g, "/").replace(/\/$/, "");
|
|
197
|
-
return rest ? `${drive}/${rest}` : drive;
|
|
263
|
+
const dirStat = statSync(fsTemplateDir);
|
|
264
|
+
if (!dirStat.isDirectory()) {
|
|
265
|
+
throw new Error(`[apm] CLI \u6A21\u677F\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55: ${templateDir}`);
|
|
198
266
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
267
|
+
const entries = readdirSync(fsTemplateDir).filter(
|
|
268
|
+
(name) => !shouldSkipTemplateEntry(name)
|
|
269
|
+
);
|
|
270
|
+
if (entries.length === 0) {
|
|
271
|
+
throw new Error(`[apm] CLI \u6A21\u677F\u76EE\u5F55\u4E3A\u7A7A: ${templateDir}`);
|
|
202
272
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
const absolute = resolve2(cwd);
|
|
207
|
-
try {
|
|
208
|
-
return normalizeWorkdirPath(realpathSync.native(absolute));
|
|
209
|
-
} catch {
|
|
210
|
-
return normalizeWorkdirPath(absolute);
|
|
273
|
+
mkdirSync2(toFsPath(resolvedTarget), { recursive: true });
|
|
274
|
+
for (const name of entries) {
|
|
275
|
+
copyTemplateEntry(join2(templateDir, name), join2(resolvedTarget, name));
|
|
211
276
|
}
|
|
277
|
+
for (const subdir of WORKSPACE_TEMPLATE_SUBDIRS) {
|
|
278
|
+
mkdirSync2(toFsPath(join2(resolvedTarget, subdir)), { recursive: true });
|
|
279
|
+
}
|
|
280
|
+
assertTemplateCopiedToApm(resolvedTarget, resolve2(workdir));
|
|
212
281
|
}
|
|
213
282
|
|
|
214
283
|
// src/commands/init.ts
|
|
215
284
|
async function runInit(name) {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
285
|
+
const workdir = resolveWorkdirPath();
|
|
286
|
+
await ensureWorkspaceApmDirForInit(workdir);
|
|
287
|
+
const apmDir = workspaceApmDir(workdir);
|
|
288
|
+
await copyTemplateFiles(apmDir, workdir);
|
|
219
289
|
const trimmedName = name?.trim();
|
|
220
290
|
if (trimmedName) {
|
|
221
|
-
const apmConfigPath = join3(apmDir, "apm.config.json");
|
|
291
|
+
const apmConfigPath = toFsPath(join3(apmDir, "apm.config.json"));
|
|
222
292
|
const config = readFileSync2(apmConfigPath, "utf8");
|
|
223
293
|
const configJson = JSON.parse(config);
|
|
224
294
|
configJson.name = trimmedName;
|
|
@@ -229,7 +299,6 @@ async function runInit(name) {
|
|
|
229
299
|
"utf8"
|
|
230
300
|
);
|
|
231
301
|
}
|
|
232
|
-
const workdir = resolveWorkdirPath();
|
|
233
302
|
console.log(`[apm] \u5DF2\u521D\u59CB\u5316\u5DE5\u4F5C\u533A\uFF1A${apmDir}`);
|
|
234
303
|
console.log(`[apm] \u5DE5\u4F5C\u76EE\u5F55\u8DEF\u5F84\uFF1A${workdir}`);
|
|
235
304
|
console.log("[apm] \u8BF7\u5728\u5E73\u53F0\u300C\u5BA2\u6237\u673A\u7BA1\u7406 \u2192 \u5DE5\u4F5C\u7A7A\u95F4\u300D\u767B\u8BB0\u4E0A\u8FF0\u76EE\u5F55\u8DEF\u5F84");
|
|
@@ -795,8 +864,8 @@ import { join as join8 } from "path";
|
|
|
795
864
|
|
|
796
865
|
// src/skills-sync.ts
|
|
797
866
|
import {
|
|
798
|
-
copyFileSync,
|
|
799
|
-
cpSync
|
|
867
|
+
copyFileSync as copyFileSync2,
|
|
868
|
+
cpSync,
|
|
800
869
|
existsSync as existsSync3,
|
|
801
870
|
mkdirSync as mkdirSync3,
|
|
802
871
|
readdirSync as readdirSync2,
|
|
@@ -823,7 +892,7 @@ function listBaseSkillDirNames() {
|
|
|
823
892
|
function syncAgentsGuide(apmDir) {
|
|
824
893
|
if (!existsSync3(AGENTS_TEMPLATE_PATH)) return false;
|
|
825
894
|
mkdirSync3(apmDir, { recursive: true });
|
|
826
|
-
|
|
895
|
+
copyFileSync2(AGENTS_TEMPLATE_PATH, join7(apmDir, "AGENTS.md"));
|
|
827
896
|
return true;
|
|
828
897
|
}
|
|
829
898
|
function listBaseRuleFileNames() {
|
|
@@ -839,7 +908,7 @@ function syncBaseRules(rulesDir) {
|
|
|
839
908
|
for (const name of names) {
|
|
840
909
|
const src = join7(BASE_RULES_TEMPLATE_DIR, name);
|
|
841
910
|
const dest = join7(rulesDir, name);
|
|
842
|
-
|
|
911
|
+
copyFileSync2(src, dest);
|
|
843
912
|
}
|
|
844
913
|
return names;
|
|
845
914
|
}
|
|
@@ -849,7 +918,7 @@ function syncBaseSkills(skillsDir) {
|
|
|
849
918
|
for (const name of names) {
|
|
850
919
|
const src = join7(BASE_SKILLS_TEMPLATE_DIR, name);
|
|
851
920
|
const dest = join7(skillsDir, name);
|
|
852
|
-
|
|
921
|
+
cpSync(src, dest, { recursive: true, force: true });
|
|
853
922
|
}
|
|
854
923
|
return names;
|
|
855
924
|
}
|
|
@@ -2346,7 +2415,7 @@ function assertDeployImageTag(tag) {
|
|
|
2346
2415
|
}
|
|
2347
2416
|
|
|
2348
2417
|
// src/commands/deploy/internal/backend-deploy/local-docker-build.ts
|
|
2349
|
-
import { platform } from "node:os";
|
|
2418
|
+
import { platform as platform2 } from "node:os";
|
|
2350
2419
|
|
|
2351
2420
|
// src/commands/deploy/internal/backend-deploy/command-runner.ts
|
|
2352
2421
|
import { execSync } from "child_process";
|
|
@@ -2406,7 +2475,7 @@ var CommandRunner = class {
|
|
|
2406
2475
|
|
|
2407
2476
|
// src/commands/deploy/internal/backend-deploy/local-docker-build.ts
|
|
2408
2477
|
function dockerBuildPlatformFlags() {
|
|
2409
|
-
return
|
|
2478
|
+
return platform2() === "darwin" ? ["--platform", "linux/amd64"] : [];
|
|
2410
2479
|
}
|
|
2411
2480
|
function buildDockerImageLocally(params, cwd) {
|
|
2412
2481
|
const platformFlags = dockerBuildPlatformFlags();
|
package/package.json
CHANGED
|
File without changes
|