pai-zero 0.11.0 → 0.11.1
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 +62 -0
- package/dist/bin/pai.js +547 -363
- package/dist/bin/pai.js.map +1 -1
- package/dist/cli/index.js +547 -363
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
package/dist/bin/pai.js
CHANGED
|
@@ -53,6 +53,124 @@ var init_logger = __esm({
|
|
|
53
53
|
}
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
+
// src/core/config.ts
|
|
57
|
+
import path from "path";
|
|
58
|
+
import { createRequire } from "module";
|
|
59
|
+
import fs from "fs-extra";
|
|
60
|
+
function normalizeMode(value) {
|
|
61
|
+
if (value === "prototype" || value === "poc" || value === "production") return value;
|
|
62
|
+
if (value === "mockup") return "prototype";
|
|
63
|
+
return "prototype";
|
|
64
|
+
}
|
|
65
|
+
async function loadConfig(cwd) {
|
|
66
|
+
const configPath = path.join(cwd, CONFIG_DIR, CONFIG_FILE);
|
|
67
|
+
if (!await fs.pathExists(configPath)) return null;
|
|
68
|
+
const raw = await fs.readJson(configPath);
|
|
69
|
+
return {
|
|
70
|
+
...raw,
|
|
71
|
+
mode: normalizeMode(raw.mode)
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async function saveConfig(cwd, config) {
|
|
75
|
+
const configDir = path.join(cwd, CONFIG_DIR);
|
|
76
|
+
await fs.ensureDir(configDir);
|
|
77
|
+
await fs.writeJson(path.join(configDir, CONFIG_FILE), config, { spaces: 2 });
|
|
78
|
+
}
|
|
79
|
+
function createDefaultConfig(projectName, mode) {
|
|
80
|
+
return {
|
|
81
|
+
version: pkg.version,
|
|
82
|
+
mode: normalizeMode(mode),
|
|
83
|
+
projectName,
|
|
84
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
85
|
+
plugins: []
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
var require2, pkg, CONFIG_DIR, CONFIG_FILE;
|
|
89
|
+
var init_config = __esm({
|
|
90
|
+
"src/core/config.ts"() {
|
|
91
|
+
"use strict";
|
|
92
|
+
require2 = createRequire(import.meta.url);
|
|
93
|
+
pkg = require2("../../package.json");
|
|
94
|
+
CONFIG_DIR = ".pai";
|
|
95
|
+
CONFIG_FILE = "config.json";
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// src/cli/commands/welcome.cmd.ts
|
|
100
|
+
var welcome_cmd_exports = {};
|
|
101
|
+
__export(welcome_cmd_exports, {
|
|
102
|
+
welcomeCommand: () => welcomeCommand
|
|
103
|
+
});
|
|
104
|
+
import { createRequire as createRequire2 } from "module";
|
|
105
|
+
import fs2 from "fs";
|
|
106
|
+
import path2 from "path";
|
|
107
|
+
async function welcomeCommand(cwd) {
|
|
108
|
+
const paiConfig = await loadConfig(cwd);
|
|
109
|
+
const inPaiProject = paiConfig !== null;
|
|
110
|
+
const hasGit = fs2.existsSync(path2.join(cwd, ".git"));
|
|
111
|
+
const hasPackageJson = fs2.existsSync(path2.join(cwd, "package.json"));
|
|
112
|
+
console.log("");
|
|
113
|
+
console.log(colors.accent(" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E"));
|
|
114
|
+
console.log(colors.accent(` \u2502 \u{1F527} PAI Zero v${pkg2.version.padEnd(22)}\u2502`));
|
|
115
|
+
console.log(colors.accent(" \u2502 Plugin AI for ProjectZero \u2502"));
|
|
116
|
+
console.log(colors.accent(" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F"));
|
|
117
|
+
console.log("");
|
|
118
|
+
if (inPaiProject) {
|
|
119
|
+
console.log(colors.dim(" \uD604\uC7AC PAI \uD504\uB85C\uC81D\uD2B8\uAC00 \uAC10\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4"));
|
|
120
|
+
console.log(colors.dim(` \u2500 \uBAA8\uB4DC: ${paiConfig.mode}`));
|
|
121
|
+
console.log(colors.dim(` \u2500 \uD50C\uB7EC\uADF8\uC778: ${paiConfig.plugins.length}\uAC1C \uC124\uCE58\uB428`));
|
|
122
|
+
console.log("");
|
|
123
|
+
console.log(colors.accent(" \uBC14\uB85C \uC4F8 \uC218 \uC788\uB294 \uBA85\uB839\uC5B4"));
|
|
124
|
+
console.log(colors.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
125
|
+
console.log(` ${colors.success("\u25CF")} ${"pai status".padEnd(18)} ${colors.dim("\uC124\uCE58\uB41C \uD50C\uB7EC\uADF8\uC778 \uD655\uC778")}`);
|
|
126
|
+
console.log(` ${colors.success("\u25CF")} ${"pai grade".padEnd(18)} ${colors.dim("AI \uAC1C\uBC1C \uC900\uBE44\uB3C4 \uD3C9\uAC00 (6\uCE74\uD14C\uACE0\uB9AC)")}`);
|
|
127
|
+
console.log(` ${colors.success("\u25CF")} ${"pai add".padEnd(18)} ${colors.dim("\uD50C\uB7EC\uADF8\uC778 \uCD94\uAC00 \xB7 \uBAA8\uB4DC \uC2B9\uACA9 (prototype\u2192poc\u2192production)")}`);
|
|
128
|
+
console.log(` ${colors.success("\u25CF")} ${"pai design".padEnd(18)} ${colors.dim("PRD/OMC \uC124\uACC4 \uAD00\uB9AC")}`);
|
|
129
|
+
console.log(` ${colors.success("\u25CF")} ${"pai test".padEnd(18)} ${colors.dim("\uD14C\uC2A4\uD2B8 + \uD558\uB124\uC2A4 \uAC80\uC99D")}`);
|
|
130
|
+
console.log(` ${colors.success("\u25CF")} ${"pai check".padEnd(18)} ${colors.dim("\uD658\uACBD \uC810\uAC80")}`);
|
|
131
|
+
console.log("");
|
|
132
|
+
console.log(colors.dim(" \uC804\uCCB4 \uBAA9\uB85D: ") + colors.accent("pai help"));
|
|
133
|
+
} else if (hasGit || hasPackageJson) {
|
|
134
|
+
console.log(colors.dim(" \uAE30\uC874 \uD504\uB85C\uC81D\uD2B8\uAC00 \uAC10\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4 (PAI \uBBF8\uC124\uCE58)"));
|
|
135
|
+
console.log("");
|
|
136
|
+
console.log(colors.accent(" \uC2DC\uC791\uD558\uAE30"));
|
|
137
|
+
console.log(colors.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
138
|
+
console.log(` ${colors.success("\u25B8")} ${"pai init".padEnd(18)} ${colors.dim("\uC774 \uD504\uB85C\uC81D\uD2B8\uC5D0 PAI \uC801\uC6A9 (\uC790\uB3D9 \uC9C4\uB2E8 \uD3EC\uD568)")}`);
|
|
139
|
+
console.log(` ${colors.success("\u25B8")} ${"pai check".padEnd(18)}${colors.dim("\uD658\uACBD\uBD80\uD130 \uC810\uAC80")}`);
|
|
140
|
+
console.log("");
|
|
141
|
+
console.log(colors.dim(" \uC804\uCCB4 \uBAA9\uB85D: ") + colors.accent("pai help"));
|
|
142
|
+
} else {
|
|
143
|
+
console.log(colors.accent(" \uCC98\uC74C\uC774\uC2E0\uAC00\uC694?"));
|
|
144
|
+
console.log(colors.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
145
|
+
console.log(` ${colors.success("\u25B8")} ${"pai init <\uD504\uB85C\uC81D\uD2B8\uBA85>".padEnd(24)}${colors.dim("\uC0C8 \uD504\uB85C\uC81D\uD2B8 \uC2DC\uC791")}`);
|
|
146
|
+
console.log("");
|
|
147
|
+
console.log(colors.accent(" \uC774\uBBF8 PAI \uD504\uB85C\uC81D\uD2B8\uC5D0 \uC788\uB2E4\uBA74?"));
|
|
148
|
+
console.log(colors.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
149
|
+
console.log(` ${colors.success("\u25CF")} ${"pai status".padEnd(18)} ${colors.dim("\uC124\uCE58\uB41C \uD50C\uB7EC\uADF8\uC778 \uD655\uC778")}`);
|
|
150
|
+
console.log(` ${colors.success("\u25CF")} ${"pai grade".padEnd(18)} ${colors.dim("AI \uAC1C\uBC1C \uC900\uBE44\uB3C4 \uD3C9\uAC00")}`);
|
|
151
|
+
console.log(` ${colors.success("\u25CF")} ${"pai add".padEnd(18)} ${colors.dim("\uD50C\uB7EC\uADF8\uC778 \uCD94\uAC00 (\uBAA8\uB4DC \uC2B9\uACA9)")}`);
|
|
152
|
+
console.log("");
|
|
153
|
+
console.log(colors.accent(" \uBB38\uC81C\uAC00 \uC788\uB098\uC694?"));
|
|
154
|
+
console.log(colors.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
155
|
+
console.log(` ${colors.success("\u25CF")} ${"pai check".padEnd(18)} ${colors.dim("Node / Git / Claude Code / OMC \uC810\uAC80")}`);
|
|
156
|
+
console.log("");
|
|
157
|
+
console.log(colors.dim(" \uC804\uCCB4 \uBA85\uB839\uC5B4: ") + colors.accent("pai help"));
|
|
158
|
+
}
|
|
159
|
+
console.log("");
|
|
160
|
+
console.log(colors.dim(" \uBB38\uC11C: https://github.com/SoInKyu/pai"));
|
|
161
|
+
console.log("");
|
|
162
|
+
}
|
|
163
|
+
var require3, pkg2;
|
|
164
|
+
var init_welcome_cmd = __esm({
|
|
165
|
+
"src/cli/commands/welcome.cmd.ts"() {
|
|
166
|
+
"use strict";
|
|
167
|
+
init_logger();
|
|
168
|
+
init_config();
|
|
169
|
+
require3 = createRequire2(import.meta.url);
|
|
170
|
+
pkg2 = require3("../../package.json");
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
56
174
|
// src/ui/banner.ts
|
|
57
175
|
function printBanner() {
|
|
58
176
|
const c2 = colors;
|
|
@@ -158,7 +276,7 @@ __export(analyzer_exports, {
|
|
|
158
276
|
});
|
|
159
277
|
import { readdir, access } from "fs/promises";
|
|
160
278
|
import { join } from "path";
|
|
161
|
-
import
|
|
279
|
+
import fs3 from "fs-extra";
|
|
162
280
|
async function analyzeProject(targetPath) {
|
|
163
281
|
try {
|
|
164
282
|
await access(targetPath);
|
|
@@ -180,16 +298,16 @@ async function detectStack(cwd) {
|
|
|
180
298
|
packageManager: null,
|
|
181
299
|
hasTypeScript: false
|
|
182
300
|
};
|
|
183
|
-
if (await
|
|
301
|
+
if (await fs3.pathExists(join(cwd, "package.json"))) {
|
|
184
302
|
info2.languages.push("JavaScript");
|
|
185
303
|
info2.packageManager = "npm";
|
|
186
304
|
try {
|
|
187
|
-
const
|
|
305
|
+
const pkg5 = await fs3.readJson(join(cwd, "package.json"));
|
|
188
306
|
const allDeps = {
|
|
189
|
-
...
|
|
190
|
-
...
|
|
307
|
+
...pkg5.dependencies ?? {},
|
|
308
|
+
...pkg5.devDependencies ?? {}
|
|
191
309
|
};
|
|
192
|
-
if (allDeps["typescript"] || await
|
|
310
|
+
if (allDeps["typescript"] || await fs3.pathExists(join(cwd, "tsconfig.json"))) {
|
|
193
311
|
info2.hasTypeScript = true;
|
|
194
312
|
info2.languages.push("TypeScript");
|
|
195
313
|
}
|
|
@@ -211,16 +329,16 @@ async function detectStack(cwd) {
|
|
|
211
329
|
}
|
|
212
330
|
} catch {
|
|
213
331
|
}
|
|
214
|
-
if (await
|
|
215
|
-
else if (await
|
|
216
|
-
else if (await
|
|
332
|
+
if (await fs3.pathExists(join(cwd, "pnpm-lock.yaml"))) info2.packageManager = "pnpm";
|
|
333
|
+
else if (await fs3.pathExists(join(cwd, "yarn.lock"))) info2.packageManager = "yarn";
|
|
334
|
+
else if (await fs3.pathExists(join(cwd, "bun.lockb"))) info2.packageManager = "bun";
|
|
217
335
|
}
|
|
218
|
-
if (await
|
|
336
|
+
if (await fs3.pathExists(join(cwd, "pyproject.toml")) || await fs3.pathExists(join(cwd, "requirements.txt"))) {
|
|
219
337
|
info2.languages.push("Python");
|
|
220
338
|
}
|
|
221
|
-
if (await
|
|
222
|
-
if (await
|
|
223
|
-
if (await
|
|
339
|
+
if (await fs3.pathExists(join(cwd, "go.mod"))) info2.languages.push("Go");
|
|
340
|
+
if (await fs3.pathExists(join(cwd, "Cargo.toml"))) info2.languages.push("Rust");
|
|
341
|
+
if (await fs3.pathExists(join(cwd, "pom.xml")) || await fs3.pathExists(join(cwd, "build.gradle"))) {
|
|
224
342
|
info2.languages.push("Java");
|
|
225
343
|
}
|
|
226
344
|
return info2;
|
|
@@ -238,18 +356,18 @@ async function scanStructure(cwd) {
|
|
|
238
356
|
}
|
|
239
357
|
async function checkExistingConfig(cwd) {
|
|
240
358
|
const [hasClaudeMd, hasClaudeDir, hasPaiDir, hasOpenSpec, hasOmc] = await Promise.all([
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
(r) => r ? r :
|
|
359
|
+
fs3.pathExists(join(cwd, "CLAUDE.md")),
|
|
360
|
+
fs3.pathExists(join(cwd, ".claude")),
|
|
361
|
+
fs3.pathExists(join(cwd, ".pai")),
|
|
362
|
+
fs3.pathExists(join(cwd, "docs", "openspec.md")).then(
|
|
363
|
+
(r) => r ? r : fs3.pathExists(join(cwd, "openspec.md"))
|
|
246
364
|
),
|
|
247
|
-
|
|
365
|
+
fs3.pathExists(join(cwd, ".pai", "omc.md"))
|
|
248
366
|
]);
|
|
249
367
|
let claudeSettings = null;
|
|
250
368
|
try {
|
|
251
|
-
if (await
|
|
252
|
-
claudeSettings = await
|
|
369
|
+
if (await fs3.pathExists(join(cwd, ".claude", "settings.json"))) {
|
|
370
|
+
claudeSettings = await fs3.readJson(join(cwd, ".claude", "settings.json"));
|
|
253
371
|
}
|
|
254
372
|
} catch {
|
|
255
373
|
}
|
|
@@ -275,7 +393,7 @@ async function listDirNames(dirPath) {
|
|
|
275
393
|
}
|
|
276
394
|
}
|
|
277
395
|
async function getGitInfo(cwd) {
|
|
278
|
-
const isGitRepo = await
|
|
396
|
+
const isGitRepo = await fs3.pathExists(join(cwd, ".git"));
|
|
279
397
|
if (!isGitRepo) {
|
|
280
398
|
return { isGitRepo: false, remoteUrl: null, repoName: null, currentBranch: null };
|
|
281
399
|
}
|
|
@@ -323,11 +441,14 @@ async function aiInterview(analysis, _cwd, projectName) {
|
|
|
323
441
|
options: {
|
|
324
442
|
maxTurns: 10,
|
|
325
443
|
systemPrompt: `You are PAI, an AI assistant that helps set up vibe coding environments.
|
|
326
|
-
Analyze the repository and ask the user targeted questions about project
|
|
444
|
+
Analyze the repository and ask the user targeted questions about project level (prototype/poc/production), authentication, and domain.
|
|
445
|
+
- prototype: quick idea validation, UI mockup, concept demo
|
|
446
|
+
- poc: PoC web development, working demo with basic features
|
|
447
|
+
- production: operational service with tests, QA, deployment, monitoring
|
|
327
448
|
Output your final recommendation as a JSON code block with this schema:
|
|
328
449
|
\`\`\`json
|
|
329
450
|
{
|
|
330
|
-
"mode": "
|
|
451
|
+
"mode": "prototype" | "poc" | "production",
|
|
331
452
|
"projectName": string,
|
|
332
453
|
"authMethods": string[],
|
|
333
454
|
"setupDomains": { "claudeEnv": true, "processDocs": boolean, "cicd": boolean },
|
|
@@ -367,7 +488,7 @@ function parseAiResult(result, analysis, projectName) {
|
|
|
367
488
|
try {
|
|
368
489
|
const parsed = JSON.parse(jsonMatch[1]);
|
|
369
490
|
return {
|
|
370
|
-
mode: parsed.mode
|
|
491
|
+
mode: normalizeMode(parsed.mode),
|
|
371
492
|
projectName,
|
|
372
493
|
authMethods: parsed.authMethods ?? [],
|
|
373
494
|
extraTools: parsed.extraTools ?? [],
|
|
@@ -393,24 +514,39 @@ function parseAiResult(result, analysis, projectName) {
|
|
|
393
514
|
async function interactiveInterview(analysis, _cwd, projectName) {
|
|
394
515
|
const { default: inquirer } = await import("inquirer");
|
|
395
516
|
const chalk8 = (await import("chalk")).default;
|
|
396
|
-
step(1, 3, "\
|
|
397
|
-
hint("\
|
|
517
|
+
step(1, 3, "\uD504\uB85C\uC81D\uD2B8 \uC218\uC900\uC744 \uC120\uD0DD\uD574\uC8FC\uC138\uC694");
|
|
518
|
+
hint("\uC120\uD0DD\uC5D0 \uB530\uB77C \uC124\uCE58\uB418\uB294 \uD50C\uB7EC\uADF8\uC778 \uC138\uD2B8\uAC00 \uB2EC\uB77C\uC9D1\uB2C8\uB2E4.");
|
|
398
519
|
console.log("");
|
|
399
520
|
const { mode } = await inquirer.prompt([{
|
|
400
521
|
type: "list",
|
|
401
522
|
name: "mode",
|
|
402
|
-
message: "\uC5B4\uB5A4 \uD504\uB85C\uC81D\uD2B8\
|
|
523
|
+
message: "\uC5B4\uB5A4 \uC218\uC900\uC758 \uD504\uB85C\uC81D\uD2B8\uC778\uAC00\uC694?",
|
|
403
524
|
choices: [
|
|
404
525
|
{
|
|
405
|
-
name: `\
|
|
406
|
-
value: "
|
|
526
|
+
name: `\u{1F9EA} prototype ${colors.dim("\u2500 \uBE60\uB978 \uAC80\uC99D (\uC544\uC774\uB514\uC5B4\xB7UI \uBAA9\uC5C5\xB7\uCEE8\uC149 \uC2DC\uC5F0)")}`,
|
|
527
|
+
value: "prototype"
|
|
407
528
|
},
|
|
408
529
|
{
|
|
409
|
-
name: `\
|
|
530
|
+
name: `\u{1F52C} poc ${colors.dim("\u2500 PoC \uC6F9\uAC1C\uBC1C (\uB3D9\uC791 \uB370\uBAA8\xB7\uAE30\uBCF8 \uAE30\uB2A5 \uAD6C\uD604)")}`,
|
|
531
|
+
value: "poc"
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
name: `\u{1F3ED} production ${colors.dim("\u2500 \uC6B4\uC601 \uC11C\uBE44\uC2A4 (\uD14C\uC2A4\uD2B8\xB7QA\xB7\uBC30\uD3EC\xB7\uBAA8\uB2C8\uD130\uB9C1)")}`,
|
|
410
535
|
value: "production"
|
|
411
536
|
}
|
|
412
537
|
]
|
|
413
538
|
}]);
|
|
539
|
+
console.log("");
|
|
540
|
+
console.log(colors.dim(" \uC774 \uC218\uC900\uC5D0 \uC124\uCE58\uB420 \uD56D\uBAA9"));
|
|
541
|
+
console.log(colors.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
542
|
+
const matrix = {
|
|
543
|
+
prototype: ["GitHub \uAD6C\uC870", "OpenSpec (PRD)", "roboco (\uC9C4\uB2E8)"],
|
|
544
|
+
poc: ["GitHub \uAD6C\uC870", "OpenSpec (PRD)", "roboco (\uC9C4\uB2E8)", "OMC (\uAC1D\uCCB4\uBAA8\uB378)", "Vercel \uBC30\uD3EC (\uC120\uD0DD)"],
|
|
545
|
+
production: ["GitHub \uAD6C\uC870", "OpenSpec (PRD)", "roboco (\uC9C4\uB2E8)", "OMC (\uAC1D\uCCB4\uBAA8\uB378)", "gstack (\uD14C\uC2A4\uD2B8)", "Harness (\uAC80\uC99D)", "Vercel \uBC30\uD3EC (\uC120\uD0DD)", "Supabase DB (\uC120\uD0DD)"]
|
|
546
|
+
};
|
|
547
|
+
for (const item of matrix[mode] ?? []) {
|
|
548
|
+
console.log(` ${colors.success("\u2713")} ${item}`);
|
|
549
|
+
}
|
|
414
550
|
step(2, 3, "\uB85C\uADF8\uC778 \uAE30\uB2A5");
|
|
415
551
|
hint("\uB098\uC911\uC5D0 \uCD94\uAC00\uD560 \uC218\uB3C4 \uC788\uC2B5\uB2C8\uB2E4.");
|
|
416
552
|
console.log("");
|
|
@@ -469,7 +605,10 @@ async function interactiveInterview(analysis, _cwd, projectName) {
|
|
|
469
605
|
}
|
|
470
606
|
}
|
|
471
607
|
let extraTools = [];
|
|
472
|
-
if (mode === "production") {
|
|
608
|
+
if (mode === "poc" || mode === "production") {
|
|
609
|
+
extraTools.push("omc");
|
|
610
|
+
}
|
|
611
|
+
if (mode === "poc" || mode === "production") {
|
|
473
612
|
console.log("");
|
|
474
613
|
const { hosting } = await inquirer.prompt([{
|
|
475
614
|
type: "list",
|
|
@@ -477,10 +616,14 @@ async function interactiveInterview(analysis, _cwd, projectName) {
|
|
|
477
616
|
message: "\uBC30\uD3EC \uD658\uACBD:",
|
|
478
617
|
choices: [
|
|
479
618
|
{ name: `Vercel ${colors.dim("\u2500 \uC790\uB3D9 \uBC30\uD3EC (Preview + Production)")}`, value: "vercel" },
|
|
480
|
-
{ name: `\uB2E4\uB978 \uC11C\uBE44\uC2A4 \uC0AC\uC6A9 ${colors.dim("\u2500 AWS, GCP, Netlify \uB4F1")}`, value: "other" },
|
|
481
|
-
{ name: `\
|
|
619
|
+
{ name: `\uB2E4\uB978 \uC11C\uBE44\uC2A4 \uC0AC\uC6A9 ${colors.dim("\u2500 AWS, GCP, Netlify \uB4F1)")}`, value: "other" },
|
|
620
|
+
{ name: `\uB098\uC911\uC5D0 \uC815\uD558\uAE30 ${colors.dim("\u2500 \uBC30\uD3EC \uC124\uC815 \uC5C6\uC774 \uC2DC\uC791")}`, value: "skip" }
|
|
482
621
|
]
|
|
483
622
|
}]);
|
|
623
|
+
if (hosting === "vercel") extraTools.push("vercel");
|
|
624
|
+
}
|
|
625
|
+
if (mode === "production") {
|
|
626
|
+
console.log("");
|
|
484
627
|
const { database } = await inquirer.prompt([{
|
|
485
628
|
type: "list",
|
|
486
629
|
name: "database",
|
|
@@ -488,10 +631,9 @@ async function interactiveInterview(analysis, _cwd, projectName) {
|
|
|
488
631
|
choices: [
|
|
489
632
|
{ name: `Supabase ${colors.dim("\u2500 PostgreSQL + Auth + Storage")}`, value: "supabase" },
|
|
490
633
|
{ name: `\uB2E4\uB978 \uC11C\uBE44\uC2A4 \uC0AC\uC6A9 ${colors.dim("\u2500 PlanetScale, Neon, Firebase \uB4F1")}`, value: "other" },
|
|
491
|
-
{ name: `\
|
|
634
|
+
{ name: `\uB098\uC911\uC5D0 \uC815\uD558\uAE30 ${colors.dim("\u2500 DB \uC124\uC815 \uC5C6\uC774 \uC2DC\uC791")}`, value: "skip" }
|
|
492
635
|
]
|
|
493
636
|
}]);
|
|
494
|
-
if (hosting === "vercel") extraTools.push("vercel");
|
|
495
637
|
if (database === "supabase") extraTools.push("supabase");
|
|
496
638
|
extraTools.push("gstack", "harness");
|
|
497
639
|
}
|
|
@@ -603,6 +745,7 @@ var init_interviewer = __esm({
|
|
|
603
745
|
"use strict";
|
|
604
746
|
init_ui();
|
|
605
747
|
init_logger();
|
|
748
|
+
init_config();
|
|
606
749
|
}
|
|
607
750
|
});
|
|
608
751
|
|
|
@@ -612,7 +755,7 @@ __export(generator_exports, {
|
|
|
612
755
|
generateFiles: () => generateFiles
|
|
613
756
|
});
|
|
614
757
|
import { join as join2 } from "path";
|
|
615
|
-
import
|
|
758
|
+
import fs4 from "fs-extra";
|
|
616
759
|
async function generateFiles(cwd, analysis, interview) {
|
|
617
760
|
const files = [];
|
|
618
761
|
files.push(generateClaudeMd(cwd, analysis, interview));
|
|
@@ -625,11 +768,11 @@ async function generateFiles(cwd, analysis, interview) {
|
|
|
625
768
|
}
|
|
626
769
|
const created = [];
|
|
627
770
|
for (const file of files) {
|
|
628
|
-
if (await
|
|
771
|
+
if (await fs4.pathExists(file.path) && !file.overwrite) {
|
|
629
772
|
continue;
|
|
630
773
|
}
|
|
631
|
-
await
|
|
632
|
-
await
|
|
774
|
+
await fs4.ensureDir(join2(file.path, ".."));
|
|
775
|
+
await fs4.writeFile(file.path, file.content, "utf8");
|
|
633
776
|
created.push(file.path);
|
|
634
777
|
}
|
|
635
778
|
return created;
|
|
@@ -876,8 +1019,8 @@ __export(platform_exports, {
|
|
|
876
1019
|
writeEnvFile: () => writeEnvFile
|
|
877
1020
|
});
|
|
878
1021
|
import os from "os";
|
|
879
|
-
import
|
|
880
|
-
import
|
|
1022
|
+
import fs5 from "fs";
|
|
1023
|
+
import path3 from "path";
|
|
881
1024
|
import { execFileSync } from "child_process";
|
|
882
1025
|
function diagnoseWindowsEnv() {
|
|
883
1026
|
const issues = [];
|
|
@@ -905,7 +1048,7 @@ function diagnoseWindowsEnv() {
|
|
|
905
1048
|
}
|
|
906
1049
|
function writeEnvFile(filePath, entries) {
|
|
907
1050
|
const content = Object.entries(entries).map(([k, v]) => `${k}=${v}`).join("\n");
|
|
908
|
-
|
|
1051
|
+
fs5.writeFileSync(filePath, content + "\n", { encoding: "utf8" });
|
|
909
1052
|
}
|
|
910
1053
|
function getPlatformInfo() {
|
|
911
1054
|
return {
|
|
@@ -920,13 +1063,13 @@ function getPlatformInfo() {
|
|
|
920
1063
|
function getShellRcPath() {
|
|
921
1064
|
const home = os.homedir();
|
|
922
1065
|
if (isWindows) {
|
|
923
|
-
const ps7 =
|
|
924
|
-
const ps5 =
|
|
925
|
-
if (
|
|
1066
|
+
const ps7 = path3.join(home, "Documents", "PowerShell", "Microsoft.PowerShell_profile.ps1");
|
|
1067
|
+
const ps5 = path3.join(home, "Documents", "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1");
|
|
1068
|
+
if (fs5.existsSync(path3.dirname(ps7))) return ps7;
|
|
926
1069
|
return ps5;
|
|
927
1070
|
}
|
|
928
1071
|
const shell = process.env["SHELL"] || "";
|
|
929
|
-
return shell.includes("zsh") ?
|
|
1072
|
+
return shell.includes("zsh") ? path3.join(home, ".zshrc") : path3.join(home, ".bashrc");
|
|
930
1073
|
}
|
|
931
1074
|
function spawnSubshell(cwd) {
|
|
932
1075
|
try {
|
|
@@ -969,14 +1112,14 @@ __export(mcp_exports, {
|
|
|
969
1112
|
provisionMcp: () => provisionMcp
|
|
970
1113
|
});
|
|
971
1114
|
import { join as join3 } from "path";
|
|
972
|
-
import
|
|
1115
|
+
import fs6 from "fs-extra";
|
|
973
1116
|
async function provisionMcp(ctx) {
|
|
974
1117
|
const mcp = ctx.mcp;
|
|
975
1118
|
if (!mcp?.enabled) return;
|
|
976
1119
|
const mcpDir = join3(ctx.cwd, "mcp-server");
|
|
977
|
-
await
|
|
978
|
-
await
|
|
979
|
-
await
|
|
1120
|
+
await fs6.ensureDir(mcpDir);
|
|
1121
|
+
await fs6.ensureDir(join3(mcpDir, "src"));
|
|
1122
|
+
await fs6.ensureDir(join3(mcpDir, "tests"));
|
|
980
1123
|
const isPublicDeps = mcp.type === "tools-public";
|
|
981
1124
|
const pkgJson = {
|
|
982
1125
|
name: mcp.name,
|
|
@@ -1002,8 +1145,8 @@ async function provisionMcp(ctx) {
|
|
|
1002
1145
|
}
|
|
1003
1146
|
};
|
|
1004
1147
|
const pkgPath = join3(mcpDir, "package.json");
|
|
1005
|
-
if (!await
|
|
1006
|
-
await
|
|
1148
|
+
if (!await fs6.pathExists(pkgPath)) {
|
|
1149
|
+
await fs6.writeJson(pkgPath, pkgJson, { spaces: 2 });
|
|
1007
1150
|
}
|
|
1008
1151
|
const tsconfig = {
|
|
1009
1152
|
compilerOptions: {
|
|
@@ -1022,103 +1165,103 @@ async function provisionMcp(ctx) {
|
|
|
1022
1165
|
exclude: ["node_modules", "dist", "tests"]
|
|
1023
1166
|
};
|
|
1024
1167
|
const tsPath = join3(mcpDir, "tsconfig.json");
|
|
1025
|
-
if (!await
|
|
1026
|
-
await
|
|
1168
|
+
if (!await fs6.pathExists(tsPath)) {
|
|
1169
|
+
await fs6.writeJson(tsPath, tsconfig, { spaces: 2 });
|
|
1027
1170
|
}
|
|
1028
1171
|
const indexPath = join3(mcpDir, "src", "index.ts");
|
|
1029
|
-
if (!await
|
|
1030
|
-
await
|
|
1172
|
+
if (!await fs6.pathExists(indexPath)) {
|
|
1173
|
+
await fs6.writeFile(indexPath, buildIndexTs(mcp), "utf8");
|
|
1031
1174
|
}
|
|
1032
1175
|
const isTools = mcp.type === "tools" || mcp.type === "tools-public" || mcp.type === "all";
|
|
1033
1176
|
const isPublic = mcp.type === "tools-public";
|
|
1034
1177
|
if (isTools) {
|
|
1035
1178
|
const toolsPath = join3(mcpDir, "src", "tools.ts");
|
|
1036
|
-
if (!await
|
|
1037
|
-
await
|
|
1179
|
+
if (!await fs6.pathExists(toolsPath)) {
|
|
1180
|
+
await fs6.writeFile(toolsPath, isPublic ? TOOLS_PUBLIC_TEMPLATE : TOOLS_TEMPLATE, "utf8");
|
|
1038
1181
|
}
|
|
1039
1182
|
}
|
|
1040
1183
|
if (isPublic) {
|
|
1041
1184
|
const authPath = join3(mcpDir, "src", "auth.ts");
|
|
1042
|
-
if (!await
|
|
1043
|
-
await
|
|
1185
|
+
if (!await fs6.pathExists(authPath)) {
|
|
1186
|
+
await fs6.writeFile(authPath, AUTH_MIDDLEWARE_TEMPLATE, "utf8");
|
|
1044
1187
|
}
|
|
1045
1188
|
const rateLimitPath = join3(mcpDir, "src", "rate-limit.ts");
|
|
1046
|
-
if (!await
|
|
1047
|
-
await
|
|
1189
|
+
if (!await fs6.pathExists(rateLimitPath)) {
|
|
1190
|
+
await fs6.writeFile(rateLimitPath, RATE_LIMIT_TEMPLATE, "utf8");
|
|
1048
1191
|
}
|
|
1049
1192
|
const migDir = join3(ctx.cwd, "supabase", "migrations");
|
|
1050
|
-
await
|
|
1193
|
+
await fs6.ensureDir(migDir);
|
|
1051
1194
|
const migPath = join3(migDir, "20260101_mcp_keys_and_usage.sql");
|
|
1052
|
-
if (!await
|
|
1053
|
-
await
|
|
1195
|
+
if (!await fs6.pathExists(migPath)) {
|
|
1196
|
+
await fs6.writeFile(migPath, SUPABASE_MIGRATION, "utf8");
|
|
1054
1197
|
}
|
|
1055
1198
|
const dashDir = join3(ctx.cwd, "src", "app", "dashboard");
|
|
1056
|
-
await
|
|
1057
|
-
await
|
|
1199
|
+
await fs6.ensureDir(join3(dashDir, "keys"));
|
|
1200
|
+
await fs6.ensureDir(join3(dashDir, "usage"));
|
|
1058
1201
|
const dashLayoutPath = join3(dashDir, "layout.tsx");
|
|
1059
|
-
if (!await
|
|
1060
|
-
await
|
|
1202
|
+
if (!await fs6.pathExists(dashLayoutPath)) {
|
|
1203
|
+
await fs6.writeFile(dashLayoutPath, DASHBOARD_LAYOUT, "utf8");
|
|
1061
1204
|
}
|
|
1062
1205
|
const dashPagePath = join3(dashDir, "page.tsx");
|
|
1063
|
-
if (!await
|
|
1064
|
-
await
|
|
1206
|
+
if (!await fs6.pathExists(dashPagePath)) {
|
|
1207
|
+
await fs6.writeFile(dashPagePath, DASHBOARD_PAGE, "utf8");
|
|
1065
1208
|
}
|
|
1066
1209
|
const keysPagePath = join3(dashDir, "keys", "page.tsx");
|
|
1067
|
-
if (!await
|
|
1068
|
-
await
|
|
1210
|
+
if (!await fs6.pathExists(keysPagePath)) {
|
|
1211
|
+
await fs6.writeFile(keysPagePath, KEYS_PAGE, "utf8");
|
|
1069
1212
|
}
|
|
1070
1213
|
const usagePagePath = join3(dashDir, "usage", "page.tsx");
|
|
1071
|
-
if (!await
|
|
1072
|
-
await
|
|
1214
|
+
if (!await fs6.pathExists(usagePagePath)) {
|
|
1215
|
+
await fs6.writeFile(usagePagePath, USAGE_PAGE, "utf8");
|
|
1073
1216
|
}
|
|
1074
1217
|
const apiKeysDir = join3(ctx.cwd, "src", "app", "api", "keys");
|
|
1075
|
-
await
|
|
1218
|
+
await fs6.ensureDir(apiKeysDir);
|
|
1076
1219
|
const keysRoutePath = join3(apiKeysDir, "route.ts");
|
|
1077
|
-
if (!await
|
|
1078
|
-
await
|
|
1220
|
+
if (!await fs6.pathExists(keysRoutePath)) {
|
|
1221
|
+
await fs6.writeFile(keysRoutePath, KEYS_API_ROUTE, "utf8");
|
|
1079
1222
|
}
|
|
1080
1223
|
}
|
|
1081
1224
|
if (mcp.type === "resources" || mcp.type === "all") {
|
|
1082
1225
|
const resPath = join3(mcpDir, "src", "resources.ts");
|
|
1083
|
-
if (!await
|
|
1084
|
-
await
|
|
1226
|
+
if (!await fs6.pathExists(resPath)) {
|
|
1227
|
+
await fs6.writeFile(resPath, RESOURCES_TEMPLATE, "utf8");
|
|
1085
1228
|
}
|
|
1086
1229
|
}
|
|
1087
1230
|
if (mcp.type === "prompts" || mcp.type === "all") {
|
|
1088
1231
|
const promptsPath = join3(mcpDir, "src", "prompts.ts");
|
|
1089
|
-
if (!await
|
|
1090
|
-
await
|
|
1232
|
+
if (!await fs6.pathExists(promptsPath)) {
|
|
1233
|
+
await fs6.writeFile(promptsPath, PROMPTS_TEMPLATE, "utf8");
|
|
1091
1234
|
}
|
|
1092
1235
|
}
|
|
1093
1236
|
const testPath = join3(mcpDir, "tests", "server.test.ts");
|
|
1094
|
-
if (!await
|
|
1095
|
-
await
|
|
1237
|
+
if (!await fs6.pathExists(testPath)) {
|
|
1238
|
+
await fs6.writeFile(testPath, TEST_TEMPLATE, "utf8");
|
|
1096
1239
|
}
|
|
1097
1240
|
const readmePath = join3(mcpDir, "README.md");
|
|
1098
|
-
if (!await
|
|
1099
|
-
await
|
|
1241
|
+
if (!await fs6.pathExists(readmePath)) {
|
|
1242
|
+
await fs6.writeFile(readmePath, buildReadme(mcp), "utf8");
|
|
1100
1243
|
}
|
|
1101
1244
|
const openspecPath = join3(ctx.cwd, "docs", "openspec.md");
|
|
1102
|
-
if (await
|
|
1103
|
-
const existing = await
|
|
1245
|
+
if (await fs6.pathExists(openspecPath)) {
|
|
1246
|
+
const existing = await fs6.readFile(openspecPath, "utf8");
|
|
1104
1247
|
if (!existing.includes("## MCP \uC11C\uBC84")) {
|
|
1105
1248
|
const section2 = buildOpenSpecMcpSection(mcp);
|
|
1106
|
-
await
|
|
1249
|
+
await fs6.appendFile(openspecPath, `
|
|
1107
1250
|
|
|
1108
1251
|
${section2}
|
|
1109
1252
|
`);
|
|
1110
1253
|
}
|
|
1111
1254
|
}
|
|
1112
1255
|
const mcpJsonPath = join3(ctx.cwd, ".mcp.json");
|
|
1113
|
-
const mcpJson = await
|
|
1256
|
+
const mcpJson = await fs6.pathExists(mcpJsonPath) ? await fs6.readJson(mcpJsonPath) : { mcpServers: {} };
|
|
1114
1257
|
mcpJson.mcpServers[mcp.name] = {
|
|
1115
1258
|
command: "node",
|
|
1116
1259
|
args: ["./mcp-server/dist/index.js"]
|
|
1117
1260
|
};
|
|
1118
|
-
await
|
|
1261
|
+
await fs6.writeJson(mcpJsonPath, mcpJson, { spaces: 2 });
|
|
1119
1262
|
const gitignorePath = join3(mcpDir, ".gitignore");
|
|
1120
|
-
if (!await
|
|
1121
|
-
await
|
|
1263
|
+
if (!await fs6.pathExists(gitignorePath)) {
|
|
1264
|
+
await fs6.writeFile(gitignorePath, "node_modules/\ndist/\n*.log\n", "utf8");
|
|
1122
1265
|
}
|
|
1123
1266
|
}
|
|
1124
1267
|
function buildIndexTs(mcp) {
|
|
@@ -1805,11 +1948,11 @@ __export(registry_exports, {
|
|
|
1805
1948
|
runProvisioners: () => runProvisioners
|
|
1806
1949
|
});
|
|
1807
1950
|
import { join as join4 } from "path";
|
|
1808
|
-
import
|
|
1951
|
+
import fs7 from "fs-extra";
|
|
1809
1952
|
async function provisionGitHub(ctx) {
|
|
1810
1953
|
const gitDir = join4(ctx.cwd, ".git");
|
|
1811
|
-
if (!await
|
|
1812
|
-
await
|
|
1954
|
+
if (!await fs7.pathExists(gitDir)) {
|
|
1955
|
+
await fs7.ensureDir(join4(ctx.cwd, ".github", "workflows"));
|
|
1813
1956
|
try {
|
|
1814
1957
|
const { execa } = await import("execa");
|
|
1815
1958
|
await execa("git", ["init"], { cwd: ctx.cwd });
|
|
@@ -1818,11 +1961,11 @@ async function provisionGitHub(ctx) {
|
|
|
1818
1961
|
}
|
|
1819
1962
|
}
|
|
1820
1963
|
const dirs = ["src", "docs", "tests", "public", ".pai"];
|
|
1821
|
-
await Promise.all(dirs.map((d) =>
|
|
1964
|
+
await Promise.all(dirs.map((d) => fs7.ensureDir(join4(ctx.cwd, d))));
|
|
1822
1965
|
const handoffPath = join4(ctx.cwd, "handoff.md");
|
|
1823
|
-
if (!await
|
|
1966
|
+
if (!await fs7.pathExists(handoffPath)) {
|
|
1824
1967
|
const now = (/* @__PURE__ */ new Date()).toLocaleString("ko-KR");
|
|
1825
|
-
await
|
|
1968
|
+
await fs7.writeFile(handoffPath, [
|
|
1826
1969
|
`# Handoff \u2014 ${ctx.projectName}`,
|
|
1827
1970
|
"",
|
|
1828
1971
|
`> \uB9C8\uC9C0\uB9C9 \uC5C5\uB370\uC774\uD2B8: ${now}`,
|
|
@@ -1852,8 +1995,8 @@ async function provisionGitHub(ctx) {
|
|
|
1852
1995
|
].join("\n") + "\n");
|
|
1853
1996
|
}
|
|
1854
1997
|
const contribPath = join4(ctx.cwd, "CONTRIBUTING.md");
|
|
1855
|
-
if (!await
|
|
1856
|
-
await
|
|
1998
|
+
if (!await fs7.pathExists(contribPath)) {
|
|
1999
|
+
await fs7.writeFile(contribPath, [
|
|
1857
2000
|
`# Contributing to ${ctx.projectName}`,
|
|
1858
2001
|
"",
|
|
1859
2002
|
"\uC774 \uD504\uB85C\uC81D\uD2B8\uC5D0 \uAE30\uC5EC\uD574 \uC8FC\uC154\uC11C \uAC10\uC0AC\uD569\uB2C8\uB2E4.",
|
|
@@ -1898,10 +2041,10 @@ async function provisionGitHub(ctx) {
|
|
|
1898
2041
|
].join("\n") + "\n");
|
|
1899
2042
|
}
|
|
1900
2043
|
const contribSkillDir = join4(ctx.cwd, ".claude", "skills");
|
|
1901
|
-
await
|
|
2044
|
+
await fs7.ensureDir(contribSkillDir);
|
|
1902
2045
|
const contribSkillPath = join4(contribSkillDir, "contributing.md");
|
|
1903
|
-
if (!await
|
|
1904
|
-
await
|
|
2046
|
+
if (!await fs7.pathExists(contribSkillPath)) {
|
|
2047
|
+
await fs7.writeFile(contribSkillPath, [
|
|
1905
2048
|
"---",
|
|
1906
2049
|
"name: contributing",
|
|
1907
2050
|
'description: "\uAE30\uC5EC\uC790 \uAC00\uC774\uB4DC \u2014 \uBE0C\uB79C\uCE58 \uADDC\uCE59, \uCEE4\uBC0B \uBA54\uC2DC\uC9C0, PR \uD504\uB85C\uC138\uC2A4 \uC790\uB3D9 \uC801\uC6A9"',
|
|
@@ -1927,8 +2070,8 @@ async function provisionGitHub(ctx) {
|
|
|
1927
2070
|
].join("\n") + "\n");
|
|
1928
2071
|
}
|
|
1929
2072
|
const gitignorePath = join4(ctx.cwd, ".gitignore");
|
|
1930
|
-
if (!await
|
|
1931
|
-
await
|
|
2073
|
+
if (!await fs7.pathExists(gitignorePath)) {
|
|
2074
|
+
await fs7.writeFile(gitignorePath, [
|
|
1932
2075
|
"# Dependencies",
|
|
1933
2076
|
"node_modules/",
|
|
1934
2077
|
"",
|
|
@@ -1974,8 +2117,8 @@ async function provisionGitHub(ctx) {
|
|
|
1974
2117
|
}
|
|
1975
2118
|
async function provisionVercel(ctx) {
|
|
1976
2119
|
const vercelJson = join4(ctx.cwd, "vercel.json");
|
|
1977
|
-
if (!await
|
|
1978
|
-
await
|
|
2120
|
+
if (!await fs7.pathExists(vercelJson)) {
|
|
2121
|
+
await fs7.writeJson(vercelJson, {
|
|
1979
2122
|
version: 2,
|
|
1980
2123
|
name: ctx.projectName,
|
|
1981
2124
|
builds: [{ src: "src/**", use: "@vercel/static" }]
|
|
@@ -1984,19 +2127,19 @@ async function provisionVercel(ctx) {
|
|
|
1984
2127
|
}
|
|
1985
2128
|
async function provisionSupabase(ctx) {
|
|
1986
2129
|
const supabaseDir = join4(ctx.cwd, "supabase");
|
|
1987
|
-
await
|
|
2130
|
+
await fs7.ensureDir(supabaseDir);
|
|
1988
2131
|
const configToml = join4(supabaseDir, "config.toml");
|
|
1989
|
-
if (!await
|
|
1990
|
-
await
|
|
2132
|
+
if (!await fs7.pathExists(configToml)) {
|
|
2133
|
+
await fs7.writeFile(configToml, '[api]\nschemas = ["public"]\n[auth]\nsite_url = "http://localhost:3000"\n');
|
|
1991
2134
|
}
|
|
1992
2135
|
ctx.envEntries["NEXT_PUBLIC_SUPABASE_URL"] = "YOUR_SUPABASE_URL";
|
|
1993
2136
|
ctx.envEntries["NEXT_PUBLIC_SUPABASE_ANON_KEY"] = "YOUR_SUPABASE_ANON_KEY";
|
|
1994
2137
|
}
|
|
1995
2138
|
async function provisionOpenSpec(ctx) {
|
|
1996
|
-
await
|
|
2139
|
+
await fs7.ensureDir(join4(ctx.cwd, "docs"));
|
|
1997
2140
|
const openspecPath = join4(ctx.cwd, "docs", "openspec.md");
|
|
1998
|
-
if (!await
|
|
1999
|
-
await
|
|
2141
|
+
if (!await fs7.pathExists(openspecPath)) {
|
|
2142
|
+
await fs7.writeFile(openspecPath, [
|
|
2000
2143
|
`# OpenSpec \u2014 ${ctx.projectName}`,
|
|
2001
2144
|
"",
|
|
2002
2145
|
"## 1. \uBAA9\uC801 (Purpose)",
|
|
@@ -2023,10 +2166,10 @@ async function provisionOpenSpec(ctx) {
|
|
|
2023
2166
|
}
|
|
2024
2167
|
}
|
|
2025
2168
|
async function provisionOMC(ctx) {
|
|
2026
|
-
await
|
|
2169
|
+
await fs7.ensureDir(join4(ctx.cwd, ".pai"));
|
|
2027
2170
|
const omcPath = join4(ctx.cwd, ".pai", "omc.md");
|
|
2028
|
-
if (!await
|
|
2029
|
-
await
|
|
2171
|
+
if (!await fs7.pathExists(omcPath)) {
|
|
2172
|
+
await fs7.writeFile(omcPath, [
|
|
2030
2173
|
`# OMC \u2014 Object Model Context (${ctx.projectName})`,
|
|
2031
2174
|
"",
|
|
2032
2175
|
"> AI\uAC00 \uC774 \uD504\uB85C\uC81D\uD2B8\uC758 \uB3C4\uBA54\uC778\uC744 \uC774\uD574\uD558\uAE30 \uC704\uD55C \uD575\uC2EC \uAC1D\uCCB4 \uBAA8\uB378",
|
|
@@ -2046,8 +2189,8 @@ async function provisionOMC(ctx) {
|
|
|
2046
2189
|
}
|
|
2047
2190
|
}
|
|
2048
2191
|
async function provisionGstack(ctx) {
|
|
2049
|
-
await
|
|
2050
|
-
await
|
|
2192
|
+
await fs7.ensureDir(join4(ctx.cwd, ".pai"));
|
|
2193
|
+
await fs7.writeJson(join4(ctx.cwd, ".pai", "gstack.json"), {
|
|
2051
2194
|
version: "1.0",
|
|
2052
2195
|
testRunner: "jest",
|
|
2053
2196
|
coverageThreshold: { global: { lines: 80 } },
|
|
@@ -2055,10 +2198,10 @@ async function provisionGstack(ctx) {
|
|
|
2055
2198
|
}, { spaces: 2 });
|
|
2056
2199
|
}
|
|
2057
2200
|
async function provisionRoboco(ctx) {
|
|
2058
|
-
await
|
|
2201
|
+
await fs7.ensureDir(join4(ctx.cwd, ".pai"));
|
|
2059
2202
|
const robocoPath = join4(ctx.cwd, ".pai", "roboco.json");
|
|
2060
|
-
if (await
|
|
2061
|
-
await
|
|
2203
|
+
if (await fs7.pathExists(robocoPath)) return;
|
|
2204
|
+
await fs7.writeJson(robocoPath, {
|
|
2062
2205
|
version: "1.0",
|
|
2063
2206
|
checks: ["github", "vercel", "supabase", "openspec", "omc"],
|
|
2064
2207
|
reportOutput: "AI_READINESS_REPORT.md",
|
|
@@ -2066,8 +2209,8 @@ async function provisionRoboco(ctx) {
|
|
|
2066
2209
|
}, { spaces: 2 });
|
|
2067
2210
|
}
|
|
2068
2211
|
async function provisionHarness(ctx) {
|
|
2069
|
-
await
|
|
2070
|
-
await
|
|
2212
|
+
await fs7.ensureDir(join4(ctx.cwd, ".pai"));
|
|
2213
|
+
await fs7.writeJson(join4(ctx.cwd, ".pai", "harness.json"), {
|
|
2071
2214
|
version: "1.0",
|
|
2072
2215
|
specFile: "docs/openspec.md",
|
|
2073
2216
|
checkOn: ["pre-commit", "ci"],
|
|
@@ -2125,20 +2268,20 @@ __export(claude_commands_exports, {
|
|
|
2125
2268
|
upgradeClaudeCommands: () => upgradeClaudeCommands
|
|
2126
2269
|
});
|
|
2127
2270
|
import { join as join5 } from "path";
|
|
2128
|
-
import
|
|
2271
|
+
import fs8 from "fs-extra";
|
|
2129
2272
|
async function writeCommandFiles(cmdDir, entries, options) {
|
|
2130
|
-
await
|
|
2273
|
+
await fs8.ensureDir(cmdDir);
|
|
2131
2274
|
const written = [];
|
|
2132
2275
|
const skipped = [];
|
|
2133
2276
|
const errors = [];
|
|
2134
2277
|
for (const [filename, content] of Object.entries(entries)) {
|
|
2135
2278
|
const filePath = join5(cmdDir, filename);
|
|
2136
2279
|
try {
|
|
2137
|
-
if (options.skipIfExists && await
|
|
2280
|
+
if (options.skipIfExists && await fs8.pathExists(filePath)) {
|
|
2138
2281
|
skipped.push(filename);
|
|
2139
2282
|
continue;
|
|
2140
2283
|
}
|
|
2141
|
-
await
|
|
2284
|
+
await fs8.writeFile(filePath, content);
|
|
2142
2285
|
written.push(filename);
|
|
2143
2286
|
} catch (err) {
|
|
2144
2287
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -2149,10 +2292,10 @@ async function writeCommandFiles(cmdDir, entries, options) {
|
|
|
2149
2292
|
}
|
|
2150
2293
|
async function provisionClaudeCommands(cwd) {
|
|
2151
2294
|
const skillDir = join5(cwd, ".claude", "skills", "pai");
|
|
2152
|
-
await
|
|
2295
|
+
await fs8.ensureDir(skillDir);
|
|
2153
2296
|
const skillPath = join5(skillDir, "SKILL.md");
|
|
2154
|
-
if (!await
|
|
2155
|
-
await
|
|
2297
|
+
if (!await fs8.pathExists(skillPath)) {
|
|
2298
|
+
await fs8.writeFile(skillPath, SKILL_CONTENT);
|
|
2156
2299
|
}
|
|
2157
2300
|
const cmdDir = join5(cwd, ".claude", "commands", "pai");
|
|
2158
2301
|
await writeCommandFiles(cmdDir, COMMANDS, { skipIfExists: true });
|
|
@@ -2164,9 +2307,9 @@ async function upgradeClaudeCommands(cwd) {
|
|
|
2164
2307
|
commandErrors: []
|
|
2165
2308
|
};
|
|
2166
2309
|
const skillDir = join5(cwd, ".claude", "skills", "pai");
|
|
2167
|
-
await
|
|
2310
|
+
await fs8.ensureDir(skillDir);
|
|
2168
2311
|
try {
|
|
2169
|
-
await
|
|
2312
|
+
await fs8.writeFile(join5(skillDir, "SKILL.md"), SKILL_CONTENT);
|
|
2170
2313
|
result.skillUpdated = true;
|
|
2171
2314
|
} catch (err) {
|
|
2172
2315
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -2986,42 +3129,6 @@ description: "\uD50C\uB7EC\uADF8\uC778 \uCD94\uAC00 \uC124\uCE58 \u2014 Mockup\u
|
|
|
2986
3129
|
}
|
|
2987
3130
|
});
|
|
2988
3131
|
|
|
2989
|
-
// src/core/config.ts
|
|
2990
|
-
import path2 from "path";
|
|
2991
|
-
import { createRequire } from "module";
|
|
2992
|
-
import fs7 from "fs-extra";
|
|
2993
|
-
async function loadConfig(cwd) {
|
|
2994
|
-
const configPath = path2.join(cwd, CONFIG_DIR, CONFIG_FILE);
|
|
2995
|
-
if (await fs7.pathExists(configPath)) {
|
|
2996
|
-
return fs7.readJson(configPath);
|
|
2997
|
-
}
|
|
2998
|
-
return null;
|
|
2999
|
-
}
|
|
3000
|
-
async function saveConfig(cwd, config) {
|
|
3001
|
-
const configDir = path2.join(cwd, CONFIG_DIR);
|
|
3002
|
-
await fs7.ensureDir(configDir);
|
|
3003
|
-
await fs7.writeJson(path2.join(configDir, CONFIG_FILE), config, { spaces: 2 });
|
|
3004
|
-
}
|
|
3005
|
-
function createDefaultConfig(projectName, mode) {
|
|
3006
|
-
return {
|
|
3007
|
-
version: pkg.version,
|
|
3008
|
-
mode,
|
|
3009
|
-
projectName,
|
|
3010
|
-
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3011
|
-
plugins: []
|
|
3012
|
-
};
|
|
3013
|
-
}
|
|
3014
|
-
var require2, pkg, CONFIG_DIR, CONFIG_FILE;
|
|
3015
|
-
var init_config = __esm({
|
|
3016
|
-
"src/core/config.ts"() {
|
|
3017
|
-
"use strict";
|
|
3018
|
-
require2 = createRequire(import.meta.url);
|
|
3019
|
-
pkg = require2("../../package.json");
|
|
3020
|
-
CONFIG_DIR = ".pai";
|
|
3021
|
-
CONFIG_FILE = "config.json";
|
|
3022
|
-
}
|
|
3023
|
-
});
|
|
3024
|
-
|
|
3025
3132
|
// src/stages/environment/doctor.ts
|
|
3026
3133
|
var doctor_exports = {};
|
|
3027
3134
|
__export(doctor_exports, {
|
|
@@ -3029,7 +3136,7 @@ __export(doctor_exports, {
|
|
|
3029
3136
|
});
|
|
3030
3137
|
import { join as join6 } from "path";
|
|
3031
3138
|
import { homedir } from "os";
|
|
3032
|
-
import
|
|
3139
|
+
import fs9 from "fs-extra";
|
|
3033
3140
|
async function runDoctor() {
|
|
3034
3141
|
section("PAI Doctor \u2014 \uD658\uACBD \uC9C4\uB2E8");
|
|
3035
3142
|
const checks = [];
|
|
@@ -3049,7 +3156,7 @@ async function runDoctor() {
|
|
|
3049
3156
|
fix: claudeCheck.ok ? void 0 : "npm install -g @anthropic-ai/claude-code"
|
|
3050
3157
|
});
|
|
3051
3158
|
const globalConfigPath = join6(homedir(), ".pai", "config.json");
|
|
3052
|
-
const hasGlobalConfig = await
|
|
3159
|
+
const hasGlobalConfig = await fs9.pathExists(globalConfigPath);
|
|
3053
3160
|
checks.push({
|
|
3054
3161
|
label: "\uAE00\uB85C\uBC8C \uC124\uC815",
|
|
3055
3162
|
ok: true,
|
|
@@ -3162,8 +3269,8 @@ var init_environment = __esm({
|
|
|
3162
3269
|
return files;
|
|
3163
3270
|
});
|
|
3164
3271
|
artifacts.push(...generated);
|
|
3165
|
-
const basePlugins = ["github", "openspec", "
|
|
3166
|
-
const pluginKeys = [...basePlugins, ...interview.extraTools];
|
|
3272
|
+
const basePlugins = ["github", "openspec", "roboco"];
|
|
3273
|
+
const pluginKeys = [.../* @__PURE__ */ new Set([...basePlugins, ...interview.extraTools])];
|
|
3167
3274
|
const provCtx = {
|
|
3168
3275
|
cwd: input.cwd,
|
|
3169
3276
|
projectName: interview.projectName,
|
|
@@ -3257,11 +3364,14 @@ var detector_exports = {};
|
|
|
3257
3364
|
__export(detector_exports, {
|
|
3258
3365
|
PLUGIN_META: () => PLUGIN_META,
|
|
3259
3366
|
PLUGIN_SIGNATURES: () => PLUGIN_SIGNATURES,
|
|
3367
|
+
getBasePluginsForMode: () => getBasePluginsForMode,
|
|
3260
3368
|
getPluginsForMode: () => getPluginsForMode,
|
|
3369
|
+
nextMode: () => nextMode,
|
|
3370
|
+
pluginsAddedByPromotion: () => pluginsAddedByPromotion,
|
|
3261
3371
|
scanProjectState: () => scanProjectState
|
|
3262
3372
|
});
|
|
3263
|
-
import
|
|
3264
|
-
import
|
|
3373
|
+
import path4 from "path";
|
|
3374
|
+
import fs10 from "fs-extra";
|
|
3265
3375
|
async function scanProjectState(cwd) {
|
|
3266
3376
|
const result = {
|
|
3267
3377
|
isNewProject: true,
|
|
@@ -3271,19 +3381,19 @@ async function scanProjectState(cwd) {
|
|
|
3271
3381
|
missingPlugins: [],
|
|
3272
3382
|
details: {}
|
|
3273
3383
|
};
|
|
3274
|
-
const paiConfigPath =
|
|
3275
|
-
if (await
|
|
3384
|
+
const paiConfigPath = path4.join(cwd, ".pai", "config.json");
|
|
3385
|
+
if (await fs10.pathExists(paiConfigPath)) {
|
|
3276
3386
|
result.hasPaiConfig = true;
|
|
3277
3387
|
try {
|
|
3278
|
-
const config = await
|
|
3279
|
-
result.projectMode = config.mode
|
|
3388
|
+
const config = await fs10.readJson(paiConfigPath);
|
|
3389
|
+
result.projectMode = config.mode != null ? normalizeMode(config.mode) : null;
|
|
3280
3390
|
} catch {
|
|
3281
3391
|
}
|
|
3282
3392
|
}
|
|
3283
3393
|
for (const [key, signatures] of Object.entries(PLUGIN_SIGNATURES)) {
|
|
3284
3394
|
const installed = await Promise.any(
|
|
3285
3395
|
signatures.map(async (sig) => {
|
|
3286
|
-
if (await
|
|
3396
|
+
if (await fs10.pathExists(path4.join(cwd, sig))) return true;
|
|
3287
3397
|
throw new Error("not found");
|
|
3288
3398
|
})
|
|
3289
3399
|
).catch(() => false);
|
|
@@ -3294,17 +3404,30 @@ async function scanProjectState(cwd) {
|
|
|
3294
3404
|
result.missingPlugins.push(key);
|
|
3295
3405
|
}
|
|
3296
3406
|
}
|
|
3297
|
-
const hasAnyContent = result.installedPlugins.length > 0 || await
|
|
3407
|
+
const hasAnyContent = result.installedPlugins.length > 0 || await fs10.pathExists(path4.join(cwd, "package.json")) || await fs10.pathExists(path4.join(cwd, "src")) || await fs10.pathExists(path4.join(cwd, "README.md"));
|
|
3298
3408
|
result.isNewProject = !hasAnyContent;
|
|
3299
3409
|
return result;
|
|
3300
3410
|
}
|
|
3301
3411
|
function getPluginsForMode(mode) {
|
|
3302
3412
|
return Object.entries(PLUGIN_META).filter(([, meta]) => meta.modes.includes(mode)).map(([key, meta]) => ({ key, ...meta }));
|
|
3303
3413
|
}
|
|
3414
|
+
function getBasePluginsForMode(mode) {
|
|
3415
|
+
return Object.entries(PLUGIN_META).filter(([, meta]) => meta.modes.includes(mode) && meta.required).map(([key]) => key);
|
|
3416
|
+
}
|
|
3417
|
+
function nextMode(current) {
|
|
3418
|
+
if (current === "prototype") return "poc";
|
|
3419
|
+
if (current === "poc") return "production";
|
|
3420
|
+
return null;
|
|
3421
|
+
}
|
|
3422
|
+
function pluginsAddedByPromotion(from, to) {
|
|
3423
|
+
const fromSet = new Set(getPluginsForMode(from).map((p) => p.key));
|
|
3424
|
+
return getPluginsForMode(to).map((p) => p.key).filter((k) => !fromSet.has(k));
|
|
3425
|
+
}
|
|
3304
3426
|
var PLUGIN_SIGNATURES, PLUGIN_META;
|
|
3305
3427
|
var init_detector = __esm({
|
|
3306
3428
|
"src/core/detector.ts"() {
|
|
3307
3429
|
"use strict";
|
|
3430
|
+
init_config();
|
|
3308
3431
|
PLUGIN_SIGNATURES = {
|
|
3309
3432
|
github: [".git", ".github"],
|
|
3310
3433
|
vercel: [".vercel", "vercel.json"],
|
|
@@ -3319,32 +3442,32 @@ var init_detector = __esm({
|
|
|
3319
3442
|
github: {
|
|
3320
3443
|
label: "GitHub \uB808\uD3EC & \uD3F4\uB354 \uAD6C\uC870",
|
|
3321
3444
|
description: "\uB808\uD3EC \uCD08\uAE30\uD654, .gitignore, \uAE30\uBCF8 \uBE0C\uB79C\uCE58 \uC124\uC815",
|
|
3322
|
-
modes: ["
|
|
3445
|
+
modes: ["prototype", "poc", "production"],
|
|
3323
3446
|
required: true
|
|
3324
3447
|
},
|
|
3325
|
-
vercel: {
|
|
3326
|
-
label: "Vercel \uBC30\uD3EC \uC5F0\uB3D9",
|
|
3327
|
-
description: "\uC790\uB3D9 \uBC30\uD3EC \uD30C\uC774\uD504\uB77C\uC778 \uBC0F Preview URL \uC124\uC815",
|
|
3328
|
-
modes: ["mockup", "production"],
|
|
3329
|
-
required: false
|
|
3330
|
-
},
|
|
3331
|
-
supabase: {
|
|
3332
|
-
label: "Supabase (DB & Auth)",
|
|
3333
|
-
description: "\uB370\uC774\uD130\uBCA0\uC774\uC2A4, \uC778\uC99D, API \uD0A4 \uC790\uB3D9 \uC5F0\uB3D9",
|
|
3334
|
-
modes: ["production"],
|
|
3335
|
-
required: false
|
|
3336
|
-
},
|
|
3337
3448
|
openspec: {
|
|
3338
3449
|
label: "OpenSpec (PRD \uC124\uACC4)",
|
|
3339
3450
|
description: "AI \uAE30\uBC18 PRD \uC0DD\uC131 \uBC0F \uC2A4\uD399 \uBB38\uC11C\uD654",
|
|
3340
|
-
modes: ["
|
|
3451
|
+
modes: ["prototype", "poc", "production"],
|
|
3341
3452
|
required: true
|
|
3342
3453
|
},
|
|
3454
|
+
roboco: {
|
|
3455
|
+
label: "roboco (AI \uC9C4\uB2E8)",
|
|
3456
|
+
description: "\uC124\uCE58 \uC0C1\uD0DC \uD3C9\uAC00 \uBC0F AI \uC900\uBE44\uB3C4 \uB9AC\uD3EC\uD2B8 \uC0DD\uC131",
|
|
3457
|
+
modes: ["prototype", "poc", "production"],
|
|
3458
|
+
required: false
|
|
3459
|
+
},
|
|
3343
3460
|
omc: {
|
|
3344
3461
|
label: "OMC (Object Model Context)",
|
|
3345
3462
|
description: "\uAC1D\uCCB4 \uBAA8\uB378 \uCEE8\uD14D\uC2A4\uD2B8 \u2014 AI\uAC00 \uB3C4\uBA54\uC778\uC744 \uC774\uD574\uD558\uB294 \uAD6C\uC870",
|
|
3346
|
-
modes: ["
|
|
3347
|
-
required:
|
|
3463
|
+
modes: ["poc", "production"],
|
|
3464
|
+
required: false
|
|
3465
|
+
},
|
|
3466
|
+
vercel: {
|
|
3467
|
+
label: "Vercel \uBC30\uD3EC \uC5F0\uB3D9",
|
|
3468
|
+
description: "\uC790\uB3D9 \uBC30\uD3EC \uD30C\uC774\uD504\uB77C\uC778 \uBC0F Preview URL \uC124\uC815",
|
|
3469
|
+
modes: ["poc", "production"],
|
|
3470
|
+
required: false
|
|
3348
3471
|
},
|
|
3349
3472
|
gstack: {
|
|
3350
3473
|
label: "gstack (QA / \uD488\uC9C8\uAD00\uB9AC)",
|
|
@@ -3352,17 +3475,17 @@ var init_detector = __esm({
|
|
|
3352
3475
|
modes: ["production"],
|
|
3353
3476
|
required: false
|
|
3354
3477
|
},
|
|
3355
|
-
roboco: {
|
|
3356
|
-
label: "roboco (AI \uC9C4\uB2E8)",
|
|
3357
|
-
description: "\uC124\uCE58 \uC0C1\uD0DC \uD3C9\uAC00 \uBC0F AI \uC900\uBE44\uB3C4 \uB9AC\uD3EC\uD2B8 \uC0DD\uC131",
|
|
3358
|
-
modes: ["mockup", "production"],
|
|
3359
|
-
required: false
|
|
3360
|
-
},
|
|
3361
3478
|
harness: {
|
|
3362
3479
|
label: "Harness Engineering (\uAC80\uC99D \uC790\uB3D9\uD654)",
|
|
3363
3480
|
description: "\uC124\uACC4(OpenSpec)\uC640 \uAD6C\uD604 \uC77C\uCE58 \uC5EC\uBD80 \uC790\uB3D9 \uCCB4\uD06C",
|
|
3364
3481
|
modes: ["production"],
|
|
3365
3482
|
required: false
|
|
3483
|
+
},
|
|
3484
|
+
supabase: {
|
|
3485
|
+
label: "Supabase (DB & Auth)",
|
|
3486
|
+
description: "\uB370\uC774\uD130\uBCA0\uC774\uC2A4, \uC778\uC99D, API \uD0A4 \uC790\uB3D9 \uC5F0\uB3D9",
|
|
3487
|
+
modes: ["production"],
|
|
3488
|
+
required: false
|
|
3366
3489
|
}
|
|
3367
3490
|
};
|
|
3368
3491
|
}
|
|
@@ -3425,7 +3548,7 @@ __export(analyzer_exports2, {
|
|
|
3425
3548
|
analyzeRepository: () => analyzeRepository
|
|
3426
3549
|
});
|
|
3427
3550
|
import { join as join7 } from "path";
|
|
3428
|
-
import
|
|
3551
|
+
import fs11 from "fs-extra";
|
|
3429
3552
|
async function analyzeRepository(repoPath) {
|
|
3430
3553
|
try {
|
|
3431
3554
|
return await aiAnalysis(repoPath);
|
|
@@ -3486,14 +3609,14 @@ async function checkTestCoverage(repoPath) {
|
|
|
3486
3609
|
".nycrc"
|
|
3487
3610
|
];
|
|
3488
3611
|
for (const f of testConfigs) {
|
|
3489
|
-
const found = await
|
|
3612
|
+
const found = await fs11.pathExists(join7(repoPath, f));
|
|
3490
3613
|
findings.push({ item: f, found, details: found ? "\uC874\uC7AC" : "\uC5C6\uC74C" });
|
|
3491
3614
|
if (found) score += 20;
|
|
3492
3615
|
}
|
|
3493
3616
|
const testDirs = ["tests", "test", "__tests__", "spec"];
|
|
3494
3617
|
let hasTestDir = false;
|
|
3495
3618
|
for (const d of testDirs) {
|
|
3496
|
-
if (await
|
|
3619
|
+
if (await fs11.pathExists(join7(repoPath, d))) {
|
|
3497
3620
|
findings.push({ item: d, found: true, details: "\uD14C\uC2A4\uD2B8 \uB514\uB809\uD1A0\uB9AC \uC874\uC7AC" });
|
|
3498
3621
|
hasTestDir = true;
|
|
3499
3622
|
score += 30;
|
|
@@ -3516,8 +3639,8 @@ async function checkCiCd(repoPath) {
|
|
|
3516
3639
|
{ path: "Jenkinsfile", label: "Jenkins" },
|
|
3517
3640
|
{ path: ".circleci", label: "CircleCI" }
|
|
3518
3641
|
];
|
|
3519
|
-
for (const { path:
|
|
3520
|
-
const found = await
|
|
3642
|
+
for (const { path: path6, label } of ciConfigs) {
|
|
3643
|
+
const found = await fs11.pathExists(join7(repoPath, path6));
|
|
3521
3644
|
findings.push({ item: label, found, details: found ? "\uC874\uC7AC" : "\uC5C6\uC74C" });
|
|
3522
3645
|
if (found) score += 40;
|
|
3523
3646
|
}
|
|
@@ -3535,8 +3658,8 @@ async function checkHooks(repoPath) {
|
|
|
3535
3658
|
{ path: "commitlint.config.js", label: "commitlint" },
|
|
3536
3659
|
{ path: ".claude/settings.json", label: "Claude Code settings" }
|
|
3537
3660
|
];
|
|
3538
|
-
for (const { path:
|
|
3539
|
-
const found = await
|
|
3661
|
+
for (const { path: path6, label } of hookConfigs) {
|
|
3662
|
+
const found = await fs11.pathExists(join7(repoPath, path6));
|
|
3540
3663
|
findings.push({ item: label, found, details: found ? "\uC874\uC7AC" : "\uC5C6\uC74C" });
|
|
3541
3664
|
if (found) score += 20;
|
|
3542
3665
|
}
|
|
@@ -3553,8 +3676,8 @@ async function checkRepoStructure(repoPath) {
|
|
|
3553
3676
|
{ path: ".env.example", label: "\uD658\uACBD\uBCC0\uC218 \uC608\uC2DC" },
|
|
3554
3677
|
{ path: ".gitignore", label: ".gitignore" }
|
|
3555
3678
|
];
|
|
3556
|
-
for (const { path:
|
|
3557
|
-
const found = await
|
|
3679
|
+
for (const { path: path6, label } of structureChecks) {
|
|
3680
|
+
const found = await fs11.pathExists(join7(repoPath, path6));
|
|
3558
3681
|
findings.push({ item: label, found, details: found ? "\uC874\uC7AC" : "\uC5C6\uC74C" });
|
|
3559
3682
|
if (found) score += 25;
|
|
3560
3683
|
}
|
|
@@ -3570,8 +3693,8 @@ async function checkDocumentation(repoPath) {
|
|
|
3570
3693
|
{ path: "docs", label: "docs/ \uB514\uB809\uD1A0\uB9AC", points: 25 },
|
|
3571
3694
|
{ path: "docs/openspec.md", label: "OpenSpec PRD", points: 25 }
|
|
3572
3695
|
];
|
|
3573
|
-
for (const { path:
|
|
3574
|
-
const found = await
|
|
3696
|
+
for (const { path: path6, label, points } of docChecks) {
|
|
3697
|
+
const found = await fs11.pathExists(join7(repoPath, path6));
|
|
3575
3698
|
findings.push({ item: label, found, details: found ? "\uC874\uC7AC" : "\uC5C6\uC74C" });
|
|
3576
3699
|
if (found) score += points;
|
|
3577
3700
|
}
|
|
@@ -3589,8 +3712,8 @@ async function checkHarnessEngineering(repoPath) {
|
|
|
3589
3712
|
{ path: ".claude/commands", label: ".claude/commands/", points: 10 },
|
|
3590
3713
|
{ path: ".pai/config.json", label: "PAI config", points: 10 }
|
|
3591
3714
|
];
|
|
3592
|
-
for (const { path:
|
|
3593
|
-
const found = await
|
|
3715
|
+
for (const { path: path6, label, points } of harnessChecks) {
|
|
3716
|
+
const found = await fs11.pathExists(join7(repoPath, path6));
|
|
3594
3717
|
findings.push({ item: label, found, details: found ? "\uC874\uC7AC" : "\uC5C6\uC74C" });
|
|
3595
3718
|
if (found) score += points;
|
|
3596
3719
|
}
|
|
@@ -3975,54 +4098,54 @@ __export(shell_cd_exports, {
|
|
|
3975
4098
|
});
|
|
3976
4099
|
import { join as join8 } from "path";
|
|
3977
4100
|
import { homedir as homedir2 } from "os";
|
|
3978
|
-
import
|
|
4101
|
+
import fs12 from "fs-extra";
|
|
3979
4102
|
async function requestCdAfter(targetDir) {
|
|
3980
|
-
await
|
|
3981
|
-
await
|
|
4103
|
+
await fs12.ensureDir(PAI_DIR);
|
|
4104
|
+
await fs12.writeFile(CD_FILE, targetDir);
|
|
3982
4105
|
}
|
|
3983
4106
|
async function installShellHelper() {
|
|
3984
|
-
await
|
|
4107
|
+
await fs12.ensureDir(PAI_DIR);
|
|
3985
4108
|
if (isWindows) {
|
|
3986
4109
|
return installPowerShellHelper();
|
|
3987
4110
|
}
|
|
3988
4111
|
return installBashHelper();
|
|
3989
4112
|
}
|
|
3990
4113
|
async function installBashHelper() {
|
|
3991
|
-
await
|
|
4114
|
+
await fs12.writeFile(HELPER_FILE_SH, BASH_HELPER);
|
|
3992
4115
|
const rcFile = getShellRcPath();
|
|
3993
4116
|
const sourceLine = 'source "$HOME/.pai/shell-helper.sh"';
|
|
3994
|
-
if (await
|
|
3995
|
-
const content = await
|
|
4117
|
+
if (await fs12.pathExists(rcFile)) {
|
|
4118
|
+
const content = await fs12.readFile(rcFile, "utf8");
|
|
3996
4119
|
if (content.includes("shell-helper.sh")) {
|
|
3997
4120
|
return true;
|
|
3998
4121
|
}
|
|
3999
|
-
await
|
|
4122
|
+
await fs12.appendFile(rcFile, `
|
|
4000
4123
|
# PAI \u2014 \uC790\uB3D9 \uB514\uB809\uD1A0\uB9AC \uC774\uB3D9
|
|
4001
4124
|
${sourceLine}
|
|
4002
4125
|
`);
|
|
4003
4126
|
return false;
|
|
4004
4127
|
}
|
|
4005
|
-
await
|
|
4128
|
+
await fs12.writeFile(rcFile, `${sourceLine}
|
|
4006
4129
|
`);
|
|
4007
4130
|
return false;
|
|
4008
4131
|
}
|
|
4009
4132
|
async function installPowerShellHelper() {
|
|
4010
|
-
await
|
|
4133
|
+
await fs12.writeFile(HELPER_FILE_PS1, POWERSHELL_HELPER);
|
|
4011
4134
|
const rcFile = getShellRcPath();
|
|
4012
4135
|
const sourceLine = '. "$env:USERPROFILE\\.pai\\shell-helper.ps1"';
|
|
4013
|
-
await
|
|
4014
|
-
if (await
|
|
4015
|
-
const content = await
|
|
4136
|
+
await fs12.ensureDir(join8(rcFile, ".."));
|
|
4137
|
+
if (await fs12.pathExists(rcFile)) {
|
|
4138
|
+
const content = await fs12.readFile(rcFile, "utf8");
|
|
4016
4139
|
if (content.includes("shell-helper.ps1")) {
|
|
4017
4140
|
return true;
|
|
4018
4141
|
}
|
|
4019
|
-
await
|
|
4142
|
+
await fs12.appendFile(rcFile, `
|
|
4020
4143
|
# PAI \u2014 \uC790\uB3D9 \uB514\uB809\uD1A0\uB9AC \uC774\uB3D9
|
|
4021
4144
|
${sourceLine}
|
|
4022
4145
|
`);
|
|
4023
4146
|
return false;
|
|
4024
4147
|
}
|
|
4025
|
-
await
|
|
4148
|
+
await fs12.writeFile(rcFile, `${sourceLine}
|
|
4026
4149
|
`);
|
|
4027
4150
|
return false;
|
|
4028
4151
|
}
|
|
@@ -4085,10 +4208,10 @@ __export(claude_settings_exports, {
|
|
|
4085
4208
|
mergeOmcIntoSettings: () => mergeOmcIntoSettings
|
|
4086
4209
|
});
|
|
4087
4210
|
import os2 from "os";
|
|
4088
|
-
import
|
|
4089
|
-
import
|
|
4211
|
+
import path5 from "path";
|
|
4212
|
+
import fs13 from "fs-extra";
|
|
4090
4213
|
function getClaudeSettingsPath(homeDir = os2.homedir()) {
|
|
4091
|
-
return
|
|
4214
|
+
return path5.join(homeDir, ".claude", "settings.json");
|
|
4092
4215
|
}
|
|
4093
4216
|
function parseJsonWithBom(raw) {
|
|
4094
4217
|
const stripped = raw.charCodeAt(0) === 65279 ? raw.slice(1) : raw;
|
|
@@ -4103,13 +4226,13 @@ async function enableOmcPlugin(options = {}) {
|
|
|
4103
4226
|
const pluginId = options.pluginId ?? DEFAULT_PLUGIN_ID;
|
|
4104
4227
|
const wantBackup = options.backup ?? true;
|
|
4105
4228
|
const settingsPath = getClaudeSettingsPath();
|
|
4106
|
-
await
|
|
4107
|
-
if (!await
|
|
4229
|
+
await fs13.ensureDir(path5.dirname(settingsPath));
|
|
4230
|
+
if (!await fs13.pathExists(settingsPath)) {
|
|
4108
4231
|
const skeleton = buildSkeleton(marketplaceId, marketplaceUrl, pluginId);
|
|
4109
|
-
await
|
|
4232
|
+
await fs13.writeFile(settingsPath, JSON.stringify(skeleton, null, 2) + "\n", "utf8");
|
|
4110
4233
|
return { action: "created", settingsPath };
|
|
4111
4234
|
}
|
|
4112
|
-
const raw = await
|
|
4235
|
+
const raw = await fs13.readFile(settingsPath, "utf8");
|
|
4113
4236
|
let parsed;
|
|
4114
4237
|
try {
|
|
4115
4238
|
const value = parseJsonWithBom(raw);
|
|
@@ -4119,7 +4242,7 @@ async function enableOmcPlugin(options = {}) {
|
|
|
4119
4242
|
parsed = value;
|
|
4120
4243
|
} catch (err) {
|
|
4121
4244
|
const backupPath2 = `${settingsPath}.backup-${timestampSuffix()}`;
|
|
4122
|
-
await
|
|
4245
|
+
await fs13.copy(settingsPath, backupPath2);
|
|
4123
4246
|
throw new ClaudeSettingsError(
|
|
4124
4247
|
`settings.json \uD30C\uC2F1 \uC2E4\uD328: ${err.message}. \uBC31\uC5C5: ${backupPath2}`,
|
|
4125
4248
|
backupPath2
|
|
@@ -4131,10 +4254,10 @@ async function enableOmcPlugin(options = {}) {
|
|
|
4131
4254
|
let backupPath;
|
|
4132
4255
|
if (wantBackup) {
|
|
4133
4256
|
backupPath = `${settingsPath}.backup-${timestampSuffix()}`;
|
|
4134
|
-
await
|
|
4257
|
+
await fs13.copy(settingsPath, backupPath);
|
|
4135
4258
|
}
|
|
4136
4259
|
const merged = mergeOmcIntoSettings(parsed, marketplaceId, marketplaceUrl, pluginId);
|
|
4137
|
-
await
|
|
4260
|
+
await fs13.writeFile(settingsPath, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
4138
4261
|
return { action: "added", settingsPath, backupPath };
|
|
4139
4262
|
}
|
|
4140
4263
|
function buildSkeleton(marketplaceId, marketplaceUrl, pluginId) {
|
|
@@ -4276,7 +4399,7 @@ __export(evaluate_cmd_exports, {
|
|
|
4276
4399
|
evaluateCommand: () => evaluateCommand
|
|
4277
4400
|
});
|
|
4278
4401
|
import { join as join10, basename } from "path";
|
|
4279
|
-
import
|
|
4402
|
+
import fs14 from "fs-extra";
|
|
4280
4403
|
async function evaluateCommand(cwd, options) {
|
|
4281
4404
|
const useCache = options.cache !== false;
|
|
4282
4405
|
let llmOutput = useCache ? getCachedResult(cwd) : null;
|
|
@@ -4298,15 +4421,15 @@ async function evaluateCommand(cwd, options) {
|
|
|
4298
4421
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4299
4422
|
const reportDir = join10(cwd, "docs", "p-reports");
|
|
4300
4423
|
const reportPath = join10(reportDir, `${today}.md`);
|
|
4301
|
-
await
|
|
4424
|
+
await fs14.ensureDir(reportDir);
|
|
4302
4425
|
const detailedReport = buildDetailedReport(result, projectName);
|
|
4303
|
-
await
|
|
4426
|
+
await fs14.writeFile(reportPath, detailedReport, "utf8");
|
|
4304
4427
|
console.log("");
|
|
4305
4428
|
success(`\uB9AC\uD3EC\uD2B8 \uC800\uC7A5: docs/p-reports/${today}.md`);
|
|
4306
4429
|
console.log("");
|
|
4307
4430
|
console.log(detailedReport);
|
|
4308
4431
|
if (options.output) {
|
|
4309
|
-
await
|
|
4432
|
+
await fs14.writeFile(options.output, detailedReport, "utf8");
|
|
4310
4433
|
success(`\uCD94\uAC00 \uC800\uC7A5: ${options.output}`);
|
|
4311
4434
|
}
|
|
4312
4435
|
if (options.failUnder && result.totalScore < options.failUnder) {
|
|
@@ -4336,52 +4459,91 @@ __export(env_cmd_exports, {
|
|
|
4336
4459
|
async function envSetupCommand(cwd) {
|
|
4337
4460
|
const { default: inquirer } = await import("inquirer");
|
|
4338
4461
|
const { basename: basename5 } = await import("path");
|
|
4339
|
-
section("\
|
|
4462
|
+
section("\uD50C\uB7EC\uADF8\uC778 \uCD94\uAC00 \xB7 \uBAA8\uB4DC \uC2B9\uACA9");
|
|
4340
4463
|
const state = await scanProjectState(cwd);
|
|
4341
|
-
const
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4464
|
+
const existingConfig = await loadConfig(cwd);
|
|
4465
|
+
const currentMode = state.projectMode ?? existingConfig?.mode ?? "prototype";
|
|
4466
|
+
const upgradeTarget = nextMode(currentMode);
|
|
4467
|
+
let promotedMode = null;
|
|
4468
|
+
const autoPluginsFromPromotion = [];
|
|
4469
|
+
if (upgradeTarget) {
|
|
4470
|
+
const addedPlugins = pluginsAddedByPromotion(currentMode, upgradeTarget);
|
|
4471
|
+
const notYetInstalled = addedPlugins.filter((k) => !(state.details[k]?.installed ?? false));
|
|
4472
|
+
console.log("");
|
|
4473
|
+
console.log(colors.dim(` \uD604\uC7AC \uBAA8\uB4DC: ${colors.accent(currentMode)}`));
|
|
4474
|
+
console.log(colors.dim(` \uB2E4\uC74C \uB2E8\uACC4: ${colors.accent(upgradeTarget)}`));
|
|
4475
|
+
if (notYetInstalled.length > 0) {
|
|
4476
|
+
console.log(colors.dim(` \uC2B9\uACA9 \uC2DC \uCD94\uAC00\uB418\uB294 \uD50C\uB7EC\uADF8\uC778: ${notYetInstalled.join(", ")}`));
|
|
4477
|
+
}
|
|
4478
|
+
console.log("");
|
|
4479
|
+
const { promote } = await inquirer.prompt([{
|
|
4480
|
+
type: "confirm",
|
|
4481
|
+
name: "promote",
|
|
4482
|
+
message: `${upgradeTarget} \uC218\uC900\uC73C\uB85C \uC2B9\uACA9\uD558\uC2DC\uACA0\uC5B4\uC694?`,
|
|
4483
|
+
default: false
|
|
4484
|
+
}]);
|
|
4485
|
+
if (promote) {
|
|
4486
|
+
promotedMode = upgradeTarget;
|
|
4487
|
+
autoPluginsFromPromotion.push(...notYetInstalled);
|
|
4488
|
+
}
|
|
4489
|
+
} else {
|
|
4490
|
+
info(`\uC774\uBBF8 \uCD5C\uC0C1\uC704 \uBAA8\uB4DC(${currentMode})\uC785\uB2C8\uB2E4.`);
|
|
4351
4491
|
}
|
|
4352
|
-
const
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4492
|
+
const targetMode = promotedMode ?? currentMode;
|
|
4493
|
+
const availableForMode = getPluginsForMode(targetMode).map((p) => p.key);
|
|
4494
|
+
const remaining = availableForMode.filter(
|
|
4495
|
+
(k) => !(state.details[k]?.installed ?? false) && !autoPluginsFromPromotion.includes(k)
|
|
4496
|
+
);
|
|
4497
|
+
let selectedKeys = [];
|
|
4498
|
+
if (remaining.length > 0) {
|
|
4499
|
+
console.log("");
|
|
4500
|
+
const choices = remaining.map((k) => {
|
|
4501
|
+
const meta = PLUGIN_META[k];
|
|
4502
|
+
const tag = meta?.required ? "[\uD544\uC218]" : "[\uC120\uD0DD]";
|
|
4503
|
+
return {
|
|
4504
|
+
name: `${meta?.label ?? k} ${colors.dim(tag)}`,
|
|
4505
|
+
value: k,
|
|
4506
|
+
checked: meta?.required ?? false
|
|
4507
|
+
};
|
|
4508
|
+
});
|
|
4509
|
+
const answer = await inquirer.prompt([{
|
|
4510
|
+
type: "checkbox",
|
|
4511
|
+
name: "selectedKeys",
|
|
4512
|
+
message: autoPluginsFromPromotion.length > 0 ? "\uCD94\uAC00\uB85C \uC124\uCE58\uD560 \uD50C\uB7EC\uADF8\uC778 (\uC120\uD0DD):" : "\uC124\uCE58\uD560 \uD50C\uB7EC\uADF8\uC778\uC744 \uC120\uD0DD\uD558\uC138\uC694:",
|
|
4513
|
+
choices
|
|
4514
|
+
}]);
|
|
4515
|
+
selectedKeys = answer.selectedKeys;
|
|
4516
|
+
}
|
|
4517
|
+
const allToInstall = [.../* @__PURE__ */ new Set([...autoPluginsFromPromotion, ...selectedKeys])];
|
|
4518
|
+
if (allToInstall.length === 0) {
|
|
4363
4519
|
info("\uC120\uD0DD\uB41C \uD50C\uB7EC\uADF8\uC778\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
4520
|
+
if (promotedMode) {
|
|
4521
|
+
const config2 = existingConfig ?? createDefaultConfig(basename5(cwd), promotedMode);
|
|
4522
|
+
config2.mode = promotedMode;
|
|
4523
|
+
await saveConfig(cwd, config2);
|
|
4524
|
+
success(`\uBAA8\uB4DC: ${currentMode} \u2192 ${promotedMode}`);
|
|
4525
|
+
}
|
|
4364
4526
|
return;
|
|
4365
4527
|
}
|
|
4366
|
-
const
|
|
4367
|
-
type: "input",
|
|
4368
|
-
name: "projectName",
|
|
4369
|
-
message: "\uD504\uB85C\uC81D\uD2B8\uBA85:",
|
|
4370
|
-
default: basename5(cwd)
|
|
4371
|
-
}]);
|
|
4528
|
+
const projectName = existingConfig?.projectName ?? basename5(cwd);
|
|
4372
4529
|
const ctx = {
|
|
4373
4530
|
cwd,
|
|
4374
4531
|
projectName,
|
|
4375
|
-
mode:
|
|
4532
|
+
mode: targetMode,
|
|
4376
4533
|
envEntries: {}
|
|
4377
4534
|
};
|
|
4378
4535
|
section("\uD50C\uB7EC\uADF8\uC778 \uC124\uCE58 \uC911...");
|
|
4379
|
-
await runProvisioners(
|
|
4380
|
-
const config =
|
|
4381
|
-
config.
|
|
4536
|
+
await runProvisioners(allToInstall, ctx);
|
|
4537
|
+
const config = existingConfig ?? createDefaultConfig(projectName, targetMode);
|
|
4538
|
+
config.mode = targetMode;
|
|
4539
|
+
config.plugins = [.../* @__PURE__ */ new Set([...config.plugins, ...allToInstall])];
|
|
4382
4540
|
await saveConfig(cwd, config);
|
|
4383
|
-
success("\uC124\uCE58 \uC644\uB8CC
|
|
4384
|
-
|
|
4541
|
+
success("\uC124\uCE58 \uC644\uB8CC");
|
|
4542
|
+
if (promotedMode) {
|
|
4543
|
+
success(`\uBAA8\uB4DC: ${currentMode} \u2192 ${promotedMode}`);
|
|
4544
|
+
}
|
|
4545
|
+
console.log("");
|
|
4546
|
+
hint("\uB2E4\uC74C \uB2E8\uACC4: /pai status \uB610\uB294 /pai grade");
|
|
4385
4547
|
}
|
|
4386
4548
|
async function envDoctorCommand() {
|
|
4387
4549
|
await runDoctor();
|
|
@@ -4415,6 +4577,10 @@ async function envStatusCommand(cwd) {
|
|
|
4415
4577
|
if (state.projectMode) {
|
|
4416
4578
|
console.log("");
|
|
4417
4579
|
info(`\uBAA8\uB4DC: ${state.projectMode}`);
|
|
4580
|
+
const next = nextMode(state.projectMode);
|
|
4581
|
+
if (next) {
|
|
4582
|
+
hint(`\uC2B9\uACA9 \uACBD\uB85C: ${state.projectMode} \u2192 ${next} (pai add \uC5D0\uC11C \uC2B9\uACA9 \uAC00\uB2A5)`);
|
|
4583
|
+
}
|
|
4418
4584
|
}
|
|
4419
4585
|
}
|
|
4420
4586
|
var init_env_cmd = __esm({
|
|
@@ -4426,6 +4592,7 @@ var init_env_cmd = __esm({
|
|
|
4426
4592
|
init_registry();
|
|
4427
4593
|
init_doctor();
|
|
4428
4594
|
init_analyzer();
|
|
4595
|
+
init_logger();
|
|
4429
4596
|
}
|
|
4430
4597
|
});
|
|
4431
4598
|
|
|
@@ -4435,7 +4602,7 @@ __export(init_cmd_exports, {
|
|
|
4435
4602
|
initCommand: () => initCommand
|
|
4436
4603
|
});
|
|
4437
4604
|
import { join as join11, basename as basename2 } from "path";
|
|
4438
|
-
import
|
|
4605
|
+
import fs15 from "fs-extra";
|
|
4439
4606
|
async function initCommand(cwd, nameArg) {
|
|
4440
4607
|
printBanner();
|
|
4441
4608
|
const { isWindows: isWindows2, diagnoseWindowsEnv: diagnoseWindowsEnv2 } = await Promise.resolve().then(() => (init_platform(), platform_exports));
|
|
@@ -4494,10 +4661,10 @@ async function initCommand(cwd, nameArg) {
|
|
|
4494
4661
|
printReport2(evalResult);
|
|
4495
4662
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4496
4663
|
const reportDir = join11(cwd, "docs", "p-reports");
|
|
4497
|
-
await
|
|
4664
|
+
await fs15.ensureDir(reportDir);
|
|
4498
4665
|
const legacyName = basename2(cwd);
|
|
4499
4666
|
const detailedReport = buildDetailedReport3(evalResult, legacyName);
|
|
4500
|
-
await
|
|
4667
|
+
await fs15.writeFile(join11(reportDir, `${today}.md`), detailedReport, "utf8");
|
|
4501
4668
|
console.log("");
|
|
4502
4669
|
success(`\uB9AC\uD3EC\uD2B8 \uC800\uC7A5: docs/p-reports/${today}.md`);
|
|
4503
4670
|
} catch {
|
|
@@ -4543,7 +4710,7 @@ async function initCommand(cwd, nameArg) {
|
|
|
4543
4710
|
projectName = answer.name.trim();
|
|
4544
4711
|
}
|
|
4545
4712
|
const projectDir = join11(cwd, projectName);
|
|
4546
|
-
if (await
|
|
4713
|
+
if (await fs15.pathExists(projectDir)) {
|
|
4547
4714
|
const existingConfig = await loadConfig(projectDir);
|
|
4548
4715
|
if (existingConfig) {
|
|
4549
4716
|
console.log("");
|
|
@@ -4565,7 +4732,7 @@ async function initCommand(cwd, nameArg) {
|
|
|
4565
4732
|
return;
|
|
4566
4733
|
}
|
|
4567
4734
|
} else {
|
|
4568
|
-
await
|
|
4735
|
+
await fs15.ensureDir(projectDir);
|
|
4569
4736
|
success(`${projectName}/ \uD3F4\uB354 \uC0DD\uC131`);
|
|
4570
4737
|
}
|
|
4571
4738
|
await setupInDirectory(projectDir, projectName);
|
|
@@ -4579,7 +4746,7 @@ async function setupInDirectory(projectDir, projectName) {
|
|
|
4579
4746
|
console.log("");
|
|
4580
4747
|
}
|
|
4581
4748
|
step(2, 3, "\uD504\uB85C\uC81D\uD2B8 \uC124\uC815");
|
|
4582
|
-
const config = createDefaultConfig(projectName, "
|
|
4749
|
+
const config = createDefaultConfig(projectName, "prototype");
|
|
4583
4750
|
const input = {
|
|
4584
4751
|
cwd: projectDir,
|
|
4585
4752
|
config,
|
|
@@ -4646,7 +4813,7 @@ async function showCompletion(projectName, projectDir, extraTools, isCurrentDir)
|
|
|
4646
4813
|
{ label: "\uC2AC\uB798\uC2DC \uCEE4\uB9E8\uB4DC", path: ".claude/skills/pai/SKILL.md" }
|
|
4647
4814
|
];
|
|
4648
4815
|
for (const check of checks) {
|
|
4649
|
-
const exists = await
|
|
4816
|
+
const exists = await fs15.pathExists(join11(projectDir, check.path));
|
|
4650
4817
|
console.log(` ${exists ? colors.success("\u2713") : colors.err("\u2717")} ${check.label.padEnd(16)} ${colors.dim(check.path)}`);
|
|
4651
4818
|
}
|
|
4652
4819
|
console.log("");
|
|
@@ -4672,9 +4839,9 @@ async function showCompletion(projectName, projectDir, extraTools, isCurrentDir)
|
|
|
4672
4839
|
await sleep2(500);
|
|
4673
4840
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4674
4841
|
const reportDir = join11(projectDir, "docs", "p-reports");
|
|
4675
|
-
await
|
|
4842
|
+
await fs15.ensureDir(reportDir);
|
|
4676
4843
|
const detailedReport = buildDetailedReport3(evalResult, projectName);
|
|
4677
|
-
await
|
|
4844
|
+
await fs15.writeFile(join11(reportDir, `${today}.md`), detailedReport, "utf8");
|
|
4678
4845
|
await sleep2(500);
|
|
4679
4846
|
console.log("");
|
|
4680
4847
|
success(`\uB9AC\uD3EC\uD2B8 \uC800\uC7A5: docs/p-reports/${today}.md`);
|
|
@@ -4702,7 +4869,7 @@ async function showCompletion(projectName, projectDir, extraTools, isCurrentDir)
|
|
|
4702
4869
|
const shellRc = getShellRcPath2();
|
|
4703
4870
|
let hasYoloAliasSet = false;
|
|
4704
4871
|
try {
|
|
4705
|
-
const rcContent = await
|
|
4872
|
+
const rcContent = await fs15.readFile(shellRc, "utf8");
|
|
4706
4873
|
hasYoloAliasSet = checkYolo(rcContent);
|
|
4707
4874
|
} catch {
|
|
4708
4875
|
}
|
|
@@ -4723,10 +4890,10 @@ async function showCompletion(projectName, projectDir, extraTools, isCurrentDir)
|
|
|
4723
4890
|
const { getYoloAliasLine: getYoloAliasLine2 } = await Promise.resolve().then(() => (init_platform(), platform_exports));
|
|
4724
4891
|
const aliasLine = getYoloAliasLine2();
|
|
4725
4892
|
try {
|
|
4726
|
-
const rcContent = await
|
|
4893
|
+
const rcContent = await fs15.readFile(shellRc, "utf8").catch(() => "");
|
|
4727
4894
|
if (!rcContent.includes("claude-yolo")) {
|
|
4728
|
-
await
|
|
4729
|
-
await
|
|
4895
|
+
await fs15.ensureDir(join11(shellRc, ".."));
|
|
4896
|
+
await fs15.appendFile(shellRc, `
|
|
4730
4897
|
# PAI \u2014 claude-YOLO mode
|
|
4731
4898
|
${aliasLine}
|
|
4732
4899
|
`);
|
|
@@ -4830,16 +4997,30 @@ async function handleExistingProject(cwd, state) {
|
|
|
4830
4997
|
console.log(colors.dim(` \xB7 ${p.label} ${chalk8.gray("\uBBF8\uC124\uCE58")}`));
|
|
4831
4998
|
}
|
|
4832
4999
|
}
|
|
5000
|
+
const currentConfig = await loadConfig(cwd);
|
|
5001
|
+
if (currentConfig) {
|
|
5002
|
+
console.log("");
|
|
5003
|
+
console.log(colors.dim(` \uD604\uC7AC \uBAA8\uB4DC: ${colors.accent(currentConfig.mode)}`));
|
|
5004
|
+
}
|
|
4833
5005
|
console.log("");
|
|
4834
5006
|
const { action } = await inquirer.prompt([{
|
|
4835
5007
|
type: "list",
|
|
4836
5008
|
name: "action",
|
|
4837
|
-
message: "\uC5B4\
|
|
5009
|
+
message: "\uC5B4\uB5A4 \uC791\uC5C5\uC744 \uD560\uAE4C\uC694?",
|
|
4838
5010
|
choices: [
|
|
4839
|
-
{
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
5011
|
+
{
|
|
5012
|
+
name: `\u{1F4CA} AI \uAC1C\uBC1C \uC900\uBE44\uB3C4 \uD3C9\uAC00 ${colors.dim("(pai grade \u2014 6\uCE74\uD14C\uACE0\uB9AC \uC810\uC218)")}`,
|
|
5013
|
+
value: "evaluate"
|
|
5014
|
+
},
|
|
5015
|
+
{
|
|
5016
|
+
name: `\u2795 \uD50C\uB7EC\uADF8\uC778 \uCD94\uAC00\xB7\uBAA8\uB4DC \uC2B9\uACA9 ${colors.dim("(pai add \u2014 prototype \u2192 poc \u2192 production)")}`,
|
|
5017
|
+
value: "install"
|
|
5018
|
+
},
|
|
5019
|
+
{
|
|
5020
|
+
name: `\u{1FA7A} \uD658\uACBD \uC810\uAC80 ${colors.dim("(pai check \u2014 Node/Git/Claude/OMC)")}`,
|
|
5021
|
+
value: "doctor"
|
|
5022
|
+
},
|
|
5023
|
+
{ name: chalk8.gray("\u{1F6AA} \uC885\uB8CC"), value: "exit" }
|
|
4843
5024
|
]
|
|
4844
5025
|
}]);
|
|
4845
5026
|
switch (action) {
|
|
@@ -4900,7 +5081,7 @@ async function installOrchestratorOnly(projectDir, projectName) {
|
|
|
4900
5081
|
if (selectedPlugins.includes("gstack")) extraTools.push("gstack");
|
|
4901
5082
|
if (selectedPlugins.includes("harness")) extraTools.push("harness");
|
|
4902
5083
|
const autoInterview = {
|
|
4903
|
-
mode: "
|
|
5084
|
+
mode: "prototype",
|
|
4904
5085
|
projectName,
|
|
4905
5086
|
authMethods: [],
|
|
4906
5087
|
extraTools,
|
|
@@ -4925,8 +5106,8 @@ async function installOrchestratorOnly(projectDir, projectName) {
|
|
|
4925
5106
|
const provCtx = {
|
|
4926
5107
|
cwd: projectDir,
|
|
4927
5108
|
projectName,
|
|
4928
|
-
mode: "
|
|
4929
|
-
envEntries: { PAI_PROJECT_NAME: projectName, PAI_MODE: "
|
|
5109
|
+
mode: "prototype",
|
|
5110
|
+
envEntries: { PAI_PROJECT_NAME: projectName, PAI_MODE: "prototype" }
|
|
4930
5111
|
};
|
|
4931
5112
|
console.log("");
|
|
4932
5113
|
await withSpinner2("\uD50C\uB7EC\uADF8\uC778 \uC124\uCE58 \uC911...", async () => {
|
|
@@ -4940,7 +5121,7 @@ async function installOrchestratorOnly(projectDir, projectName) {
|
|
|
4940
5121
|
});
|
|
4941
5122
|
console.log("");
|
|
4942
5123
|
await withSpinner2("\uC124\uC815 \uC800\uC7A5 \uC911...", async () => {
|
|
4943
|
-
const config = createDefaultConfig(projectName, "
|
|
5124
|
+
const config = createDefaultConfig(projectName, "prototype");
|
|
4944
5125
|
config.plugins = allPluginKeys;
|
|
4945
5126
|
await saveConfig(projectDir, config);
|
|
4946
5127
|
await sleep2(300);
|
|
@@ -4957,8 +5138,8 @@ async function installOrchestratorOnly(projectDir, projectName) {
|
|
|
4957
5138
|
printReport2(evalResult);
|
|
4958
5139
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4959
5140
|
const reportDir = join11(projectDir, "docs", "p-reports");
|
|
4960
|
-
await
|
|
4961
|
-
await
|
|
5141
|
+
await fs15.ensureDir(reportDir);
|
|
5142
|
+
await fs15.writeFile(join11(reportDir, `${today}.md`), buildDetailedReport3(evalResult, projectName), "utf8");
|
|
4962
5143
|
console.log("");
|
|
4963
5144
|
hint(`\uC0C1\uC138 \uB9AC\uD3EC\uD2B8: docs/p-reports/${today}.md`);
|
|
4964
5145
|
} catch {
|
|
@@ -5008,7 +5189,7 @@ async function detectLegacyProject(cwd) {
|
|
|
5008
5189
|
".gitignore"
|
|
5009
5190
|
];
|
|
5010
5191
|
for (const signal of signals) {
|
|
5011
|
-
if (await
|
|
5192
|
+
if (await fs15.pathExists(join11(cwd, signal))) return true;
|
|
5012
5193
|
}
|
|
5013
5194
|
return false;
|
|
5014
5195
|
}
|
|
@@ -5100,16 +5281,16 @@ var init_help_cmd = __esm({
|
|
|
5100
5281
|
|
|
5101
5282
|
// src/stages/design/openspec.ts
|
|
5102
5283
|
import { join as join12 } from "path";
|
|
5103
|
-
import
|
|
5284
|
+
import fs16 from "fs-extra";
|
|
5104
5285
|
async function initOpenSpec(cwd, projectName) {
|
|
5105
5286
|
const docsDir = join12(cwd, "docs");
|
|
5106
|
-
await
|
|
5287
|
+
await fs16.ensureDir(docsDir);
|
|
5107
5288
|
const openspecPath = join12(docsDir, "openspec.md");
|
|
5108
|
-
if (await
|
|
5289
|
+
if (await fs16.pathExists(openspecPath)) {
|
|
5109
5290
|
info("docs/openspec.md \uC774\uBBF8 \uC874\uC7AC \u2014 \uAC74\uB108\uB700");
|
|
5110
5291
|
return;
|
|
5111
5292
|
}
|
|
5112
|
-
await
|
|
5293
|
+
await fs16.writeFile(openspecPath, [
|
|
5113
5294
|
`# OpenSpec \u2014 ${projectName}`,
|
|
5114
5295
|
"",
|
|
5115
5296
|
"## 1. \uBAA9\uC801 (Purpose)",
|
|
@@ -5143,7 +5324,7 @@ async function validateOpenSpec(cwd) {
|
|
|
5143
5324
|
];
|
|
5144
5325
|
let specPath = null;
|
|
5145
5326
|
for (const p of candidates) {
|
|
5146
|
-
if (await
|
|
5327
|
+
if (await fs16.pathExists(p)) {
|
|
5147
5328
|
specPath = p;
|
|
5148
5329
|
break;
|
|
5149
5330
|
}
|
|
@@ -5157,7 +5338,7 @@ async function validateOpenSpec(cwd) {
|
|
|
5157
5338
|
warnings: ["openspec.md \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. `pai design init` \uC744 \uC2E4\uD589\uD558\uC138\uC694."]
|
|
5158
5339
|
};
|
|
5159
5340
|
}
|
|
5160
|
-
const content = await
|
|
5341
|
+
const content = await fs16.readFile(specPath, "utf8");
|
|
5161
5342
|
const missing = [];
|
|
5162
5343
|
let filled = 0;
|
|
5163
5344
|
for (const section2 of REQUIRED_SECTIONS) {
|
|
@@ -5206,16 +5387,16 @@ var init_openspec = __esm({
|
|
|
5206
5387
|
|
|
5207
5388
|
// src/stages/design/omc.ts
|
|
5208
5389
|
import { join as join13 } from "path";
|
|
5209
|
-
import
|
|
5390
|
+
import fs17 from "fs-extra";
|
|
5210
5391
|
async function initOMC(cwd, projectName) {
|
|
5211
5392
|
const paiDir = join13(cwd, ".pai");
|
|
5212
|
-
await
|
|
5393
|
+
await fs17.ensureDir(paiDir);
|
|
5213
5394
|
const omcPath = join13(paiDir, "omc.md");
|
|
5214
|
-
if (await
|
|
5395
|
+
if (await fs17.pathExists(omcPath)) {
|
|
5215
5396
|
info(".pai/omc.md \uC774\uBBF8 \uC874\uC7AC \u2014 \uAC74\uB108\uB700");
|
|
5216
5397
|
return;
|
|
5217
5398
|
}
|
|
5218
|
-
await
|
|
5399
|
+
await fs17.writeFile(omcPath, [
|
|
5219
5400
|
`# OMC \u2014 Object Model Context (${projectName})`,
|
|
5220
5401
|
"",
|
|
5221
5402
|
"> AI\uAC00 \uC774 \uD504\uB85C\uC81D\uD2B8\uC758 \uB3C4\uBA54\uC778\uC744 \uC774\uD574\uD558\uAE30 \uC704\uD55C \uD575\uC2EC \uAC1D\uCCB4 \uBAA8\uB378",
|
|
@@ -5298,14 +5479,14 @@ var init_design_cmd = __esm({
|
|
|
5298
5479
|
|
|
5299
5480
|
// src/stages/validation/runner.ts
|
|
5300
5481
|
import { join as join14 } from "path";
|
|
5301
|
-
import
|
|
5482
|
+
import fs18 from "fs-extra";
|
|
5302
5483
|
async function runTests(cwd) {
|
|
5303
5484
|
const start = Date.now();
|
|
5304
5485
|
const gstackPath = join14(cwd, ".pai", "gstack.json");
|
|
5305
5486
|
let runner = "npm test";
|
|
5306
|
-
if (await
|
|
5487
|
+
if (await fs18.pathExists(gstackPath)) {
|
|
5307
5488
|
try {
|
|
5308
|
-
const config = await
|
|
5489
|
+
const config = await fs18.readJson(gstackPath);
|
|
5309
5490
|
if (config.testRunner === "vitest") runner = "npx vitest run";
|
|
5310
5491
|
else if (config.testRunner === "jest") runner = "npx jest";
|
|
5311
5492
|
else if (config.testRunner === "mocha") runner = "npx mocha";
|
|
@@ -5313,10 +5494,10 @@ async function runTests(cwd) {
|
|
|
5313
5494
|
}
|
|
5314
5495
|
}
|
|
5315
5496
|
const pkgPath = join14(cwd, "package.json");
|
|
5316
|
-
if (await
|
|
5497
|
+
if (await fs18.pathExists(pkgPath)) {
|
|
5317
5498
|
try {
|
|
5318
|
-
const
|
|
5319
|
-
if (!
|
|
5499
|
+
const pkg5 = await fs18.readJson(pkgPath);
|
|
5500
|
+
if (!pkg5.scripts?.test || pkg5.scripts.test.includes("no test specified")) {
|
|
5320
5501
|
return {
|
|
5321
5502
|
runner,
|
|
5322
5503
|
passed: false,
|
|
@@ -5358,15 +5539,15 @@ var init_runner = __esm({
|
|
|
5358
5539
|
|
|
5359
5540
|
// src/stages/validation/harness.ts
|
|
5360
5541
|
import { join as join15 } from "path";
|
|
5361
|
-
import
|
|
5542
|
+
import fs19 from "fs-extra";
|
|
5362
5543
|
async function runHarnessCheck(cwd) {
|
|
5363
5544
|
const harnessPath = join15(cwd, ".pai", "harness.json");
|
|
5364
|
-
if (!await
|
|
5545
|
+
if (!await fs19.pathExists(harnessPath)) {
|
|
5365
5546
|
return { enabled: false, specFile: null, rules: [], checks: [] };
|
|
5366
5547
|
}
|
|
5367
5548
|
let config;
|
|
5368
5549
|
try {
|
|
5369
|
-
config = await
|
|
5550
|
+
config = await fs19.readJson(harnessPath);
|
|
5370
5551
|
} catch {
|
|
5371
5552
|
return { enabled: false, specFile: null, rules: [], checks: [] };
|
|
5372
5553
|
}
|
|
@@ -5374,8 +5555,8 @@ async function runHarnessCheck(cwd) {
|
|
|
5374
5555
|
const rules = config.rules ?? [];
|
|
5375
5556
|
const checks = [];
|
|
5376
5557
|
if (rules.includes("spec-implementation-match")) {
|
|
5377
|
-
const specExists = await
|
|
5378
|
-
const srcExists = await
|
|
5558
|
+
const specExists = await fs19.pathExists(join15(cwd, specFile));
|
|
5559
|
+
const srcExists = await fs19.pathExists(join15(cwd, "src"));
|
|
5379
5560
|
checks.push({
|
|
5380
5561
|
rule: "spec-implementation-match",
|
|
5381
5562
|
passed: specExists && srcExists,
|
|
@@ -5383,8 +5564,8 @@ async function runHarnessCheck(cwd) {
|
|
|
5383
5564
|
});
|
|
5384
5565
|
}
|
|
5385
5566
|
if (rules.includes("api-contract-test")) {
|
|
5386
|
-
const testDir = await
|
|
5387
|
-
const testDir2 = await
|
|
5567
|
+
const testDir = await fs19.pathExists(join15(cwd, "tests"));
|
|
5568
|
+
const testDir2 = await fs19.pathExists(join15(cwd, "test"));
|
|
5388
5569
|
checks.push({
|
|
5389
5570
|
rule: "api-contract-test",
|
|
5390
5571
|
passed: testDir || testDir2,
|
|
@@ -5499,13 +5680,13 @@ var init_context = __esm({
|
|
|
5499
5680
|
|
|
5500
5681
|
// src/stages/design/index.ts
|
|
5501
5682
|
import { join as join16 } from "path";
|
|
5502
|
-
import
|
|
5683
|
+
import fs20 from "fs-extra";
|
|
5503
5684
|
async function autoInstallHarness(cwd) {
|
|
5504
5685
|
const harnessPath = join16(cwd, ".pai", "harness.json");
|
|
5505
|
-
if (await
|
|
5686
|
+
if (await fs20.pathExists(harnessPath)) return;
|
|
5506
5687
|
await withSpinner("Harness Engineering \uC790\uB3D9 \uC124\uC815 \uC911...", async () => {
|
|
5507
|
-
await
|
|
5508
|
-
await
|
|
5688
|
+
await fs20.ensureDir(join16(cwd, ".pai"));
|
|
5689
|
+
await fs20.writeJson(harnessPath, {
|
|
5509
5690
|
version: "1.0",
|
|
5510
5691
|
specFile: "docs/openspec.md",
|
|
5511
5692
|
checkOn: ["pre-commit", "ci"],
|
|
@@ -5862,7 +6043,7 @@ __export(remove_cmd_exports, {
|
|
|
5862
6043
|
removeCommand: () => removeCommand
|
|
5863
6044
|
});
|
|
5864
6045
|
import { basename as basename4, dirname } from "path";
|
|
5865
|
-
import
|
|
6046
|
+
import fs21 from "fs-extra";
|
|
5866
6047
|
async function removeCommand(cwd, options) {
|
|
5867
6048
|
section("\uD504\uB85C\uC81D\uD2B8 \uC0AD\uC81C");
|
|
5868
6049
|
const config = await loadConfig(cwd);
|
|
@@ -5880,7 +6061,7 @@ async function removeCommand(cwd, options) {
|
|
|
5880
6061
|
console.log(colors.err(` ${folderName}/ \uD3F4\uB354 \uC804\uCCB4\uAC00 \uC0AD\uC81C\uB429\uB2C8\uB2E4.`));
|
|
5881
6062
|
hint("\uC774 \uC791\uC5C5\uC740 \uB418\uB3CC\uB9B4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
5882
6063
|
console.log("");
|
|
5883
|
-
const items = await
|
|
6064
|
+
const items = await fs21.readdir(cwd);
|
|
5884
6065
|
const fileCount = items.filter((i) => !i.startsWith(".")).length;
|
|
5885
6066
|
const hiddenCount = items.filter((i) => i.startsWith(".")).length;
|
|
5886
6067
|
info(`\uD30C\uC77C/\uD3F4\uB354 ${fileCount}\uAC1C, \uC228\uAE40 \uD56D\uBAA9 ${hiddenCount}\uAC1C`);
|
|
@@ -5899,7 +6080,7 @@ async function removeCommand(cwd, options) {
|
|
|
5899
6080
|
}
|
|
5900
6081
|
process.chdir(parentDir);
|
|
5901
6082
|
try {
|
|
5902
|
-
await
|
|
6083
|
+
await fs21.remove(cwd);
|
|
5903
6084
|
console.log("");
|
|
5904
6085
|
success(`${folderName}/ \uD504\uB85C\uC81D\uD2B8\uAC00 \uC0AD\uC81C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`);
|
|
5905
6086
|
try {
|
|
@@ -5955,9 +6136,9 @@ var init_errors = __esm({
|
|
|
5955
6136
|
recoverable;
|
|
5956
6137
|
};
|
|
5957
6138
|
ConfigNotFoundError = class extends PaiError {
|
|
5958
|
-
constructor(
|
|
6139
|
+
constructor(path6) {
|
|
5959
6140
|
super(
|
|
5960
|
-
`.pai/config.json not found at ${
|
|
6141
|
+
`.pai/config.json not found at ${path6}. Run 'pai init' first.`,
|
|
5961
6142
|
"CONFIG_NOT_FOUND",
|
|
5962
6143
|
true
|
|
5963
6144
|
);
|
|
@@ -5972,7 +6153,7 @@ var upgrade_cmd_exports = {};
|
|
|
5972
6153
|
__export(upgrade_cmd_exports, {
|
|
5973
6154
|
upgradeCommand: () => upgradeCommand
|
|
5974
6155
|
});
|
|
5975
|
-
import { createRequire as
|
|
6156
|
+
import { createRequire as createRequire3 } from "module";
|
|
5976
6157
|
import chalk5 from "chalk";
|
|
5977
6158
|
function compareSemver(a, b) {
|
|
5978
6159
|
const pa = a.split(".").map(Number);
|
|
@@ -5991,7 +6172,7 @@ async function upgradeCommand(cwd, options) {
|
|
|
5991
6172
|
if (!config) {
|
|
5992
6173
|
throw new ConfigNotFoundError(cwd);
|
|
5993
6174
|
}
|
|
5994
|
-
const currentVersion =
|
|
6175
|
+
const currentVersion = pkg3.version;
|
|
5995
6176
|
const configVersion = config.version;
|
|
5996
6177
|
console.log("");
|
|
5997
6178
|
console.log(` \uD604\uC7AC \uBC84\uC804: ${chalk5.gray(`v${configVersion}`)}`);
|
|
@@ -6033,7 +6214,7 @@ async function upgradeCommand(cwd, options) {
|
|
|
6033
6214
|
success(`v${configVersion} \u2192 v${currentVersion} \uC5C5\uADF8\uB808\uC774\uB4DC \uC644\uB8CC!`);
|
|
6034
6215
|
console.log("");
|
|
6035
6216
|
}
|
|
6036
|
-
var
|
|
6217
|
+
var require4, pkg3;
|
|
6037
6218
|
var init_upgrade_cmd = __esm({
|
|
6038
6219
|
"src/cli/commands/upgrade.cmd.ts"() {
|
|
6039
6220
|
"use strict";
|
|
@@ -6042,8 +6223,8 @@ var init_upgrade_cmd = __esm({
|
|
|
6042
6223
|
init_claude_commands();
|
|
6043
6224
|
init_errors();
|
|
6044
6225
|
init_progress();
|
|
6045
|
-
|
|
6046
|
-
|
|
6226
|
+
require4 = createRequire3(import.meta.url);
|
|
6227
|
+
pkg3 = require4("../../package.json");
|
|
6047
6228
|
}
|
|
6048
6229
|
});
|
|
6049
6230
|
|
|
@@ -6053,7 +6234,7 @@ __export(savetoken_cmd_exports, {
|
|
|
6053
6234
|
savetokenCommand: () => savetokenCommand
|
|
6054
6235
|
});
|
|
6055
6236
|
import { join as join17, relative } from "path";
|
|
6056
|
-
import
|
|
6237
|
+
import fs22 from "fs-extra";
|
|
6057
6238
|
import chalk6 from "chalk";
|
|
6058
6239
|
async function savetokenCommand(cwd) {
|
|
6059
6240
|
const { createSpinner: createSpinner2 } = await Promise.resolve().then(() => (init_progress(), progress_exports));
|
|
@@ -6123,10 +6304,10 @@ async function savetokenCommand(cwd) {
|
|
|
6123
6304
|
console.log(` ${chalk6.red("\u25CF")} \uB192\uC74C \uCF54\uB4DC \uC0DD\uC131, \uBCF5\uC7A1\uD55C \uCD94\uB860, \uCC3D\uC758\uC801 \uC0DD\uC131`);
|
|
6124
6305
|
console.log(` \u2192 ${colors.dim("AI \uD544\uC218 \u2014 \uD504\uB86C\uD504\uD2B8 \uCD5C\uC801\uD654\uB85C \uD1A0\uD070 \uC808\uAC10")}`);
|
|
6125
6306
|
const reportDir = join17(cwd, ".pai");
|
|
6126
|
-
await
|
|
6307
|
+
await fs22.ensureDir(reportDir);
|
|
6127
6308
|
const report = buildReport(callSites, cwd);
|
|
6128
6309
|
const reportPath = join17(reportDir, "savetoken-report.md");
|
|
6129
|
-
await
|
|
6310
|
+
await fs22.writeFile(reportPath, report, "utf8");
|
|
6130
6311
|
console.log("");
|
|
6131
6312
|
success("\uC2A4\uCE94 \uB9AC\uD3EC\uD2B8 \uC800\uC7A5: .pai/savetoken-report.md");
|
|
6132
6313
|
console.log("");
|
|
@@ -6284,7 +6465,7 @@ __export(wakeup_cmd_exports, {
|
|
|
6284
6465
|
});
|
|
6285
6466
|
import { join as join18 } from "path";
|
|
6286
6467
|
import { homedir as homedir3, platform as osPlatform } from "os";
|
|
6287
|
-
import
|
|
6468
|
+
import fs23 from "fs-extra";
|
|
6288
6469
|
import chalk7 from "chalk";
|
|
6289
6470
|
async function wakeupCommand(timeOrAction, schedule = "\uD3C9\uC77C") {
|
|
6290
6471
|
if (timeOrAction === "off") {
|
|
@@ -6331,9 +6512,9 @@ async function wakeupCommand(timeOrAction, schedule = "\uD3C9\uC77C") {
|
|
|
6331
6512
|
projectDir,
|
|
6332
6513
|
launchMode
|
|
6333
6514
|
};
|
|
6334
|
-
await
|
|
6335
|
-
await
|
|
6336
|
-
await
|
|
6515
|
+
await fs23.ensureDir(PAI_DIR2);
|
|
6516
|
+
await fs23.writeJson(CONFIG_FILE2, config, { spaces: 2 });
|
|
6517
|
+
await fs23.writeJson(MESSAGES_FILE, MESSAGES);
|
|
6337
6518
|
await createWakeupScript(config);
|
|
6338
6519
|
if (osPlatform() === "darwin") {
|
|
6339
6520
|
await setupMacOS(config);
|
|
@@ -6364,7 +6545,7 @@ async function setupMacOS(config) {
|
|
|
6364
6545
|
const { execa } = await import("execa");
|
|
6365
6546
|
const [hour, minute] = config.time.split(":").map(Number);
|
|
6366
6547
|
const plistDir = join18(homedir3(), "Library", "LaunchAgents");
|
|
6367
|
-
await
|
|
6548
|
+
await fs23.ensureDir(plistDir);
|
|
6368
6549
|
const weekdays = scheduleToWeekdays(config.schedule);
|
|
6369
6550
|
let calendarEntries;
|
|
6370
6551
|
if (weekdays.length === 7) {
|
|
@@ -6400,7 +6581,7 @@ ${calendarEntries}
|
|
|
6400
6581
|
<string>${PAI_DIR2}/wakeup.log</string>
|
|
6401
6582
|
</dict>
|
|
6402
6583
|
</plist>`;
|
|
6403
|
-
await
|
|
6584
|
+
await fs23.writeFile(PLIST_PATH, plist);
|
|
6404
6585
|
await execa("launchctl", ["unload", PLIST_PATH]).catch(() => {
|
|
6405
6586
|
});
|
|
6406
6587
|
await execa("launchctl", ["load", PLIST_PATH]);
|
|
@@ -6423,7 +6604,7 @@ async function setupWindows(config) {
|
|
|
6423
6604
|
const { execa } = await import("execa");
|
|
6424
6605
|
const [hour, minute] = config.time.split(":").map(Number);
|
|
6425
6606
|
const psScriptDir = join18(homedir3(), ".pai");
|
|
6426
|
-
await
|
|
6607
|
+
await fs23.ensureDir(psScriptDir);
|
|
6427
6608
|
const psScriptPath = join18(psScriptDir, "wakeup.ps1");
|
|
6428
6609
|
const claudeCmd = config.launchMode === "yolo" ? "claude --dangerously-skip-permissions" : "claude";
|
|
6429
6610
|
const psScript = `# PAI Wakeup \u2014 Claude Code \uC138\uC158 \uC790\uB3D9 \uC2DC\uC791
|
|
@@ -6453,7 +6634,7 @@ $notifier.Show([Windows.UI.Notifications.ToastNotification]::new($xml))
|
|
|
6453
6634
|
# Open PowerShell with Claude Code
|
|
6454
6635
|
Start-Process powershell -ArgumentList "-NoExit", "-Command", "Get-Content '$todayFile'; Write-Host ''; Set-Location '${config.projectDir}'; ${claudeCmd}"
|
|
6455
6636
|
`;
|
|
6456
|
-
await
|
|
6637
|
+
await fs23.writeFile(psScriptPath, psScript, "utf8");
|
|
6457
6638
|
const daysMap = {
|
|
6458
6639
|
"\uD3C9\uC77C": "MON,TUE,WED,THU,FRI",
|
|
6459
6640
|
"\uB9E4\uC77C": "MON,TUE,WED,THU,FRI,SAT,SUN",
|
|
@@ -6501,7 +6682,7 @@ async function disableWakeup() {
|
|
|
6501
6682
|
if (osPlatform() === "darwin") {
|
|
6502
6683
|
await execa("launchctl", ["unload", PLIST_PATH]).catch(() => {
|
|
6503
6684
|
});
|
|
6504
|
-
await
|
|
6685
|
+
await fs23.remove(PLIST_PATH).catch(() => {
|
|
6505
6686
|
});
|
|
6506
6687
|
success("launchd \uC2A4\uCF00\uC904 \uC81C\uAC70");
|
|
6507
6688
|
console.log("");
|
|
@@ -6522,14 +6703,14 @@ async function disableWakeup() {
|
|
|
6522
6703
|
} else {
|
|
6523
6704
|
await removeCronEntry();
|
|
6524
6705
|
}
|
|
6525
|
-
await
|
|
6706
|
+
await fs23.remove(CONFIG_FILE2).catch(() => {
|
|
6526
6707
|
});
|
|
6527
6708
|
console.log("");
|
|
6528
6709
|
success("\u2600\uFE0F \uC6E8\uC774\uD06C\uC5C5 \uD574\uC81C \uC644\uB8CC");
|
|
6529
6710
|
}
|
|
6530
6711
|
async function showStatus() {
|
|
6531
|
-
if (await
|
|
6532
|
-
const config = await
|
|
6712
|
+
if (await fs23.pathExists(CONFIG_FILE2)) {
|
|
6713
|
+
const config = await fs23.readJson(CONFIG_FILE2);
|
|
6533
6714
|
console.log("");
|
|
6534
6715
|
success("\u2600\uFE0F \uC6E8\uC774\uD06C\uC5C5 \uD65C\uC131\uD654");
|
|
6535
6716
|
console.log(` \uC2DC\uAC04 ${chalk7.white(config.time)}`);
|
|
@@ -6537,7 +6718,7 @@ async function showStatus() {
|
|
|
6537
6718
|
console.log(` \uD504\uB85C\uC81D\uD2B8 ${chalk7.white(config.projectDir)}`);
|
|
6538
6719
|
console.log(` \uBAA8\uB4DC ${chalk7.white(config.launchMode === "yolo" ? "claude-YOLO mode" : "\uC77C\uBC18 \uBAA8\uB4DC")}`);
|
|
6539
6720
|
if (osPlatform() === "darwin") {
|
|
6540
|
-
const plistExists = await
|
|
6721
|
+
const plistExists = await fs23.pathExists(PLIST_PATH);
|
|
6541
6722
|
console.log(` launchd ${plistExists ? chalk7.green("\uD65C\uC131") : chalk7.red("\uBE44\uD65C\uC131")}`);
|
|
6542
6723
|
}
|
|
6543
6724
|
console.log("");
|
|
@@ -6690,7 +6871,7 @@ fi
|
|
|
6690
6871
|
|
|
6691
6872
|
echo "[$(date)] PAI Wakeup completed" >> "$LOG_FILE"
|
|
6692
6873
|
`;
|
|
6693
|
-
await
|
|
6874
|
+
await fs23.writeFile(SCRIPT_FILE, script, { mode: 493 });
|
|
6694
6875
|
}
|
|
6695
6876
|
var PAI_DIR2, CONFIG_FILE2, MESSAGES_FILE, SCRIPT_FILE, PLIST_NAME, PLIST_PATH, CRON_MARKER, MESSAGES;
|
|
6696
6877
|
var init_wakeup_cmd = __esm({
|
|
@@ -6764,7 +6945,7 @@ Good programmers write code that humans can understand."
|
|
|
6764
6945
|
|
|
6765
6946
|
// src/cli/index.ts
|
|
6766
6947
|
import { Command } from "commander";
|
|
6767
|
-
import { createRequire as
|
|
6948
|
+
import { createRequire as createRequire4 } from "module";
|
|
6768
6949
|
|
|
6769
6950
|
// src/cli/deprecation.ts
|
|
6770
6951
|
var warned = /* @__PURE__ */ new Set();
|
|
@@ -6778,11 +6959,14 @@ function warnDeprecated(oldCmd, newCmd) {
|
|
|
6778
6959
|
}
|
|
6779
6960
|
|
|
6780
6961
|
// src/cli/index.ts
|
|
6781
|
-
var
|
|
6782
|
-
var
|
|
6962
|
+
var require5 = createRequire4(import.meta.url);
|
|
6963
|
+
var pkg4 = require5("../../package.json");
|
|
6783
6964
|
function createProgram() {
|
|
6784
6965
|
const program2 = new Command();
|
|
6785
|
-
program2.name("pai").description("PAI Zero (Plugin AI for ProjectZero) \u2014 AI \uAC1C\uBC1C \uBE4C\uB4DC \uC624\uCF00\uC2A4\uD2B8\uB808\uC774\uD130").version(
|
|
6966
|
+
program2.name("pai").description("PAI Zero (Plugin AI for ProjectZero) \u2014 AI \uAC1C\uBC1C \uBE4C\uB4DC \uC624\uCF00\uC2A4\uD2B8\uB808\uC774\uD130").version(pkg4.version, "-v, --version").action(async () => {
|
|
6967
|
+
const { welcomeCommand: welcomeCommand2 } = await Promise.resolve().then(() => (init_welcome_cmd(), welcome_cmd_exports));
|
|
6968
|
+
await welcomeCommand2(process.cwd());
|
|
6969
|
+
});
|
|
6786
6970
|
program2.command("init [project-name]").description("\uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654 (\uC0C8 \uD504\uB85C\uC81D\uD2B8 / \uAE30\uC874 \uD504\uB85C\uC81D\uD2B8 \uC790\uB3D9 \uAC10\uC9C0)").action(async (projectName) => {
|
|
6787
6971
|
const { initCommand: initCommand2 } = await Promise.resolve().then(() => (init_init_cmd(), init_cmd_exports));
|
|
6788
6972
|
await initCommand2(process.cwd(), projectName);
|