pai-zero 0.9.2 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/pai.js +586 -211
- package/dist/bin/pai.js.map +1 -1
- package/dist/cli/index.js +586 -211
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
package/dist/bin/pai.js
CHANGED
|
@@ -501,6 +501,37 @@ async function interactiveInterview(analysis, _cwd, projectName) {
|
|
|
501
501
|
if (database === "supabase") extraTools.push("supabase");
|
|
502
502
|
extraTools.push("gstack", "harness");
|
|
503
503
|
}
|
|
504
|
+
let mcp;
|
|
505
|
+
console.log("");
|
|
506
|
+
const { mcpDev } = await inquirer.prompt([{
|
|
507
|
+
type: "confirm",
|
|
508
|
+
name: "mcpDev",
|
|
509
|
+
message: "MCP(Model Context Protocol) \uC11C\uBC84\uB97C \uAC1C\uBC1C\uD558\uC2DC\uB098\uC694?",
|
|
510
|
+
default: false
|
|
511
|
+
}]);
|
|
512
|
+
if (mcpDev) {
|
|
513
|
+
console.log("");
|
|
514
|
+
const { mcpType } = await inquirer.prompt([{
|
|
515
|
+
type: "list",
|
|
516
|
+
name: "mcpType",
|
|
517
|
+
message: "MCP \uC11C\uBC84 \uC720\uD615:",
|
|
518
|
+
choices: [
|
|
519
|
+
{ name: `Tools \uC11C\uBC84 ${colors.dim("\u2500 AI\uAC00 \uD638\uCD9C\uD560 \uAE30\uB2A5 \uC81C\uACF5")}`, value: "tools" },
|
|
520
|
+
{ name: `Resources \uC11C\uBC84 ${colors.dim("\u2500 AI\uAC00 \uC77D\uC744 \uCEE8\uD14D\uC2A4\uD2B8 \uC81C\uACF5")}`, value: "resources" },
|
|
521
|
+
{ name: `Prompts \uC11C\uBC84 ${colors.dim("\u2500 \uC7AC\uC0AC\uC6A9 \uD504\uB86C\uD504\uD2B8 \uD15C\uD50C\uB9BF")}`, value: "prompts" },
|
|
522
|
+
{ name: `All-in-one ${colors.dim("\u2500 \uBAA8\uB450 \uD3EC\uD568")}`, value: "all" }
|
|
523
|
+
]
|
|
524
|
+
}]);
|
|
525
|
+
const { mcpName } = await inquirer.prompt([{
|
|
526
|
+
type: "input",
|
|
527
|
+
name: "mcpName",
|
|
528
|
+
message: "MCP \uC11C\uBC84 \uC774\uB984:",
|
|
529
|
+
default: `${projectName}-mcp`,
|
|
530
|
+
validate: (v) => /^[a-z0-9][a-z0-9-]*$/.test(v.trim()) ? true : "\uC601\uBB38 \uC18C\uBB38\uC790, \uC22B\uC790, \uD558\uC774\uD508(-)\uB9CC \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4."
|
|
531
|
+
}]);
|
|
532
|
+
mcp = { enabled: true, type: mcpType, name: mcpName.trim() };
|
|
533
|
+
extraTools.push("mcp");
|
|
534
|
+
}
|
|
504
535
|
step(3, 3, "\uC124\uCE58 \uD655\uC778");
|
|
505
536
|
console.log("");
|
|
506
537
|
console.log(colors.dim(" \uC124\uCE58\uB420 \uD56D\uBAA9"));
|
|
@@ -516,6 +547,9 @@ async function interactiveInterview(analysis, _cwd, projectName) {
|
|
|
516
547
|
if (extraTools.includes("supabase")) console.log(` ${colors.accent("+")} Supabase \uB370\uC774\uD130\uBCA0\uC774\uC2A4`);
|
|
517
548
|
if (extraTools.includes("gstack")) console.log(` ${colors.accent("+")} gstack \uD14C\uC2A4\uD2B8 \uC790\uB3D9\uD654`);
|
|
518
549
|
if (extraTools.includes("harness")) console.log(` ${colors.accent("+")} Harness \uD488\uC9C8 \uAC80\uC99D`);
|
|
550
|
+
if (extraTools.includes("mcp") && mcp) {
|
|
551
|
+
console.log(` ${colors.accent("+")} MCP \uC11C\uBC84 (${mcp.name}, ${mcp.type})`);
|
|
552
|
+
}
|
|
519
553
|
}
|
|
520
554
|
if (authMethods.length > 0) {
|
|
521
555
|
console.log("");
|
|
@@ -541,6 +575,7 @@ async function interactiveInterview(analysis, _cwd, projectName) {
|
|
|
541
575
|
authMethods,
|
|
542
576
|
customAuth,
|
|
543
577
|
extraTools,
|
|
578
|
+
mcp,
|
|
544
579
|
setupDomains: {
|
|
545
580
|
claudeEnv: true,
|
|
546
581
|
processDocs: true,
|
|
@@ -915,18 +950,348 @@ var init_platform = __esm({
|
|
|
915
950
|
}
|
|
916
951
|
});
|
|
917
952
|
|
|
953
|
+
// src/stages/environment/provisioners/mcp.ts
|
|
954
|
+
var mcp_exports = {};
|
|
955
|
+
__export(mcp_exports, {
|
|
956
|
+
provisionMcp: () => provisionMcp
|
|
957
|
+
});
|
|
958
|
+
import { join as join3 } from "path";
|
|
959
|
+
import fs4 from "fs-extra";
|
|
960
|
+
async function provisionMcp(ctx) {
|
|
961
|
+
const mcp = ctx.mcp;
|
|
962
|
+
if (!mcp?.enabled) return;
|
|
963
|
+
const mcpDir = join3(ctx.cwd, "mcp-server");
|
|
964
|
+
await fs4.ensureDir(mcpDir);
|
|
965
|
+
await fs4.ensureDir(join3(mcpDir, "src"));
|
|
966
|
+
await fs4.ensureDir(join3(mcpDir, "tests"));
|
|
967
|
+
const pkgJson = {
|
|
968
|
+
name: mcp.name,
|
|
969
|
+
version: "0.1.0",
|
|
970
|
+
description: `MCP server for ${ctx.projectName}`,
|
|
971
|
+
type: "module",
|
|
972
|
+
main: "dist/index.js",
|
|
973
|
+
bin: { [mcp.name]: "./dist/index.js" },
|
|
974
|
+
scripts: {
|
|
975
|
+
build: "tsc",
|
|
976
|
+
dev: "tsc --watch",
|
|
977
|
+
test: "vitest run",
|
|
978
|
+
start: "node dist/index.js"
|
|
979
|
+
},
|
|
980
|
+
dependencies: {
|
|
981
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
982
|
+
},
|
|
983
|
+
devDependencies: {
|
|
984
|
+
typescript: "^5.7.0",
|
|
985
|
+
"@types/node": "^20.17.0",
|
|
986
|
+
vitest: "^3.0.0"
|
|
987
|
+
}
|
|
988
|
+
};
|
|
989
|
+
const pkgPath = join3(mcpDir, "package.json");
|
|
990
|
+
if (!await fs4.pathExists(pkgPath)) {
|
|
991
|
+
await fs4.writeJson(pkgPath, pkgJson, { spaces: 2 });
|
|
992
|
+
}
|
|
993
|
+
const tsconfig = {
|
|
994
|
+
compilerOptions: {
|
|
995
|
+
target: "ES2022",
|
|
996
|
+
module: "ESNext",
|
|
997
|
+
moduleResolution: "bundler",
|
|
998
|
+
outDir: "./dist",
|
|
999
|
+
rootDir: "./src",
|
|
1000
|
+
strict: true,
|
|
1001
|
+
esModuleInterop: true,
|
|
1002
|
+
skipLibCheck: true,
|
|
1003
|
+
resolveJsonModule: true,
|
|
1004
|
+
declaration: true
|
|
1005
|
+
},
|
|
1006
|
+
include: ["src/**/*"],
|
|
1007
|
+
exclude: ["node_modules", "dist", "tests"]
|
|
1008
|
+
};
|
|
1009
|
+
const tsPath = join3(mcpDir, "tsconfig.json");
|
|
1010
|
+
if (!await fs4.pathExists(tsPath)) {
|
|
1011
|
+
await fs4.writeJson(tsPath, tsconfig, { spaces: 2 });
|
|
1012
|
+
}
|
|
1013
|
+
const indexPath = join3(mcpDir, "src", "index.ts");
|
|
1014
|
+
if (!await fs4.pathExists(indexPath)) {
|
|
1015
|
+
await fs4.writeFile(indexPath, buildIndexTs(mcp), "utf8");
|
|
1016
|
+
}
|
|
1017
|
+
if (mcp.type === "tools" || mcp.type === "all") {
|
|
1018
|
+
const toolsPath = join3(mcpDir, "src", "tools.ts");
|
|
1019
|
+
if (!await fs4.pathExists(toolsPath)) {
|
|
1020
|
+
await fs4.writeFile(toolsPath, TOOLS_TEMPLATE, "utf8");
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
if (mcp.type === "resources" || mcp.type === "all") {
|
|
1024
|
+
const resPath = join3(mcpDir, "src", "resources.ts");
|
|
1025
|
+
if (!await fs4.pathExists(resPath)) {
|
|
1026
|
+
await fs4.writeFile(resPath, RESOURCES_TEMPLATE, "utf8");
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
if (mcp.type === "prompts" || mcp.type === "all") {
|
|
1030
|
+
const promptsPath = join3(mcpDir, "src", "prompts.ts");
|
|
1031
|
+
if (!await fs4.pathExists(promptsPath)) {
|
|
1032
|
+
await fs4.writeFile(promptsPath, PROMPTS_TEMPLATE, "utf8");
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
const testPath = join3(mcpDir, "tests", "server.test.ts");
|
|
1036
|
+
if (!await fs4.pathExists(testPath)) {
|
|
1037
|
+
await fs4.writeFile(testPath, TEST_TEMPLATE, "utf8");
|
|
1038
|
+
}
|
|
1039
|
+
const readmePath = join3(mcpDir, "README.md");
|
|
1040
|
+
if (!await fs4.pathExists(readmePath)) {
|
|
1041
|
+
await fs4.writeFile(readmePath, buildReadme(mcp), "utf8");
|
|
1042
|
+
}
|
|
1043
|
+
const mcpJsonPath = join3(ctx.cwd, ".mcp.json");
|
|
1044
|
+
const mcpJson = await fs4.pathExists(mcpJsonPath) ? await fs4.readJson(mcpJsonPath) : { mcpServers: {} };
|
|
1045
|
+
mcpJson.mcpServers[mcp.name] = {
|
|
1046
|
+
command: "node",
|
|
1047
|
+
args: ["./mcp-server/dist/index.js"]
|
|
1048
|
+
};
|
|
1049
|
+
await fs4.writeJson(mcpJsonPath, mcpJson, { spaces: 2 });
|
|
1050
|
+
const gitignorePath = join3(mcpDir, ".gitignore");
|
|
1051
|
+
if (!await fs4.pathExists(gitignorePath)) {
|
|
1052
|
+
await fs4.writeFile(gitignorePath, "node_modules/\ndist/\n*.log\n", "utf8");
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
function buildIndexTs(mcp) {
|
|
1056
|
+
const imports = [];
|
|
1057
|
+
const registrations = [];
|
|
1058
|
+
if (mcp.type === "tools" || mcp.type === "all") {
|
|
1059
|
+
imports.push("import { registerTools } from './tools.js';");
|
|
1060
|
+
registrations.push(" registerTools(server);");
|
|
1061
|
+
}
|
|
1062
|
+
if (mcp.type === "resources" || mcp.type === "all") {
|
|
1063
|
+
imports.push("import { registerResources } from './resources.js';");
|
|
1064
|
+
registrations.push(" registerResources(server);");
|
|
1065
|
+
}
|
|
1066
|
+
if (mcp.type === "prompts" || mcp.type === "all") {
|
|
1067
|
+
imports.push("import { registerPrompts } from './prompts.js';");
|
|
1068
|
+
registrations.push(" registerPrompts(server);");
|
|
1069
|
+
}
|
|
1070
|
+
return `#!/usr/bin/env node
|
|
1071
|
+
/**
|
|
1072
|
+
* ${mcp.name} \u2014 MCP Server
|
|
1073
|
+
* Generated by PAI
|
|
1074
|
+
*/
|
|
1075
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
1076
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
1077
|
+
${imports.join("\n")}
|
|
1078
|
+
|
|
1079
|
+
async function main() {
|
|
1080
|
+
const server = new Server(
|
|
1081
|
+
{
|
|
1082
|
+
name: '${mcp.name}',
|
|
1083
|
+
version: '0.1.0',
|
|
1084
|
+
},
|
|
1085
|
+
{
|
|
1086
|
+
capabilities: {
|
|
1087
|
+
${mcp.type === "tools" || mcp.type === "all" ? " tools: {}," : ""}
|
|
1088
|
+
${mcp.type === "resources" || mcp.type === "all" ? " resources: {}," : ""}
|
|
1089
|
+
${mcp.type === "prompts" || mcp.type === "all" ? " prompts: {}," : ""}
|
|
1090
|
+
},
|
|
1091
|
+
},
|
|
1092
|
+
);
|
|
1093
|
+
|
|
1094
|
+
${registrations.join("\n")}
|
|
1095
|
+
|
|
1096
|
+
const transport = new StdioServerTransport();
|
|
1097
|
+
await server.connect(transport);
|
|
1098
|
+
console.error('${mcp.name} MCP server running on stdio');
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
main().catch((err) => {
|
|
1102
|
+
console.error('Fatal error:', err);
|
|
1103
|
+
process.exit(1);
|
|
1104
|
+
});
|
|
1105
|
+
`;
|
|
1106
|
+
}
|
|
1107
|
+
function buildReadme(mcp) {
|
|
1108
|
+
return `# ${mcp.name} \u2014 MCP Server
|
|
1109
|
+
|
|
1110
|
+
PAI\uAC00 \uC0DD\uC131\uD55C MCP(Model Context Protocol) \uC11C\uBC84\uC785\uB2C8\uB2E4.
|
|
1111
|
+
|
|
1112
|
+
## \uD0C0\uC785: ${mcp.type}
|
|
1113
|
+
|
|
1114
|
+
${mcp.type === "tools" || mcp.type === "all" ? "- **Tools**: AI\uAC00 \uD638\uCD9C\uD560 \uAE30\uB2A5 \uC81C\uACF5 (src/tools.ts)" : ""}
|
|
1115
|
+
${mcp.type === "resources" || mcp.type === "all" ? "- **Resources**: AI\uAC00 \uC77D\uC744 \uCEE8\uD14D\uC2A4\uD2B8 \uC81C\uACF5 (src/resources.ts)" : ""}
|
|
1116
|
+
${mcp.type === "prompts" || mcp.type === "all" ? "- **Prompts**: \uC7AC\uC0AC\uC6A9 \uD504\uB86C\uD504\uD2B8 \uD15C\uD50C\uB9BF (src/prompts.ts)" : ""}
|
|
1117
|
+
|
|
1118
|
+
## \uAC1C\uBC1C
|
|
1119
|
+
|
|
1120
|
+
\`\`\`bash
|
|
1121
|
+
cd mcp-server
|
|
1122
|
+
npm install
|
|
1123
|
+
npm run build
|
|
1124
|
+
npm test
|
|
1125
|
+
\`\`\`
|
|
1126
|
+
|
|
1127
|
+
## Claude Code \uC5F0\uACB0
|
|
1128
|
+
|
|
1129
|
+
\uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8\uC758 \`.mcp.json\` \uD30C\uC77C\uC5D0 \uC774\uBBF8 \uB4F1\uB85D\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4.
|
|
1130
|
+
Claude Code\uB97C \uC7AC\uC2DC\uC791\uD558\uBA74 \uC790\uB3D9\uC73C\uB85C MCP \uC11C\uBC84\uAC00 \uB85C\uB4DC\uB429\uB2C8\uB2E4.
|
|
1131
|
+
|
|
1132
|
+
\uC218\uB3D9 \uB4F1\uB85D:
|
|
1133
|
+
\`\`\`bash
|
|
1134
|
+
claude mcp add ${mcp.name} -- node ./mcp-server/dist/index.js
|
|
1135
|
+
\`\`\`
|
|
1136
|
+
|
|
1137
|
+
## \uB2E4\uC74C \uB2E8\uACC4
|
|
1138
|
+
|
|
1139
|
+
1. \`npm install\` \u2014 \uC758\uC874\uC131 \uC124\uCE58
|
|
1140
|
+
2. \`npm run build\` \u2014 TypeScript \uCEF4\uD30C\uC77C
|
|
1141
|
+
3. \`src/\` \uB514\uB809\uD1A0\uB9AC\uC758 \uD15C\uD50C\uB9BF\uC744 \uC2E4\uC81C \uB85C\uC9C1\uC73C\uB85C \uC218\uC815
|
|
1142
|
+
4. Claude Code \uC7AC\uC2DC\uC791 \u2192 MCP \uC11C\uBC84 \uC0AC\uC6A9
|
|
1143
|
+
|
|
1144
|
+
## \uCC38\uACE0 \uBB38\uC11C
|
|
1145
|
+
|
|
1146
|
+
- [MCP \uACF5\uC2DD \uBB38\uC11C](https://modelcontextprotocol.io/)
|
|
1147
|
+
- [SDK \uBB38\uC11C](https://github.com/modelcontextprotocol/sdk)
|
|
1148
|
+
`;
|
|
1149
|
+
}
|
|
1150
|
+
var TOOLS_TEMPLATE, RESOURCES_TEMPLATE, PROMPTS_TEMPLATE, TEST_TEMPLATE;
|
|
1151
|
+
var init_mcp = __esm({
|
|
1152
|
+
"src/stages/environment/provisioners/mcp.ts"() {
|
|
1153
|
+
"use strict";
|
|
1154
|
+
TOOLS_TEMPLATE = `import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
1155
|
+
import {
|
|
1156
|
+
CallToolRequestSchema,
|
|
1157
|
+
ListToolsRequestSchema,
|
|
1158
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
1159
|
+
|
|
1160
|
+
export function registerTools(server: Server): void {
|
|
1161
|
+
// Tool \uBAA9\uB85D \uC815\uC758
|
|
1162
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
1163
|
+
tools: [
|
|
1164
|
+
{
|
|
1165
|
+
name: 'hello',
|
|
1166
|
+
description: '\uD14C\uC2A4\uD2B8\uC6A9 \uC778\uC0AC \uB3C4\uAD6C \u2014 \uC774 \uD15C\uD50C\uB9BF\uC744 \uC218\uC815\uD574\uC11C \uC2E4\uC81C \uB3C4\uAD6C\uB97C \uAD6C\uD604\uD558\uC138\uC694',
|
|
1167
|
+
inputSchema: {
|
|
1168
|
+
type: 'object',
|
|
1169
|
+
properties: {
|
|
1170
|
+
name: { type: 'string', description: '\uC778\uC0AC\uD560 \uB300\uC0C1' },
|
|
1171
|
+
},
|
|
1172
|
+
required: ['name'],
|
|
1173
|
+
},
|
|
1174
|
+
},
|
|
1175
|
+
],
|
|
1176
|
+
}));
|
|
1177
|
+
|
|
1178
|
+
// Tool \uD638\uCD9C \uCC98\uB9AC
|
|
1179
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
1180
|
+
const { name, arguments: args } = request.params;
|
|
1181
|
+
|
|
1182
|
+
if (name === 'hello') {
|
|
1183
|
+
const target = (args as { name?: string })?.name ?? 'world';
|
|
1184
|
+
return {
|
|
1185
|
+
content: [{ type: 'text', text: \`Hello, \${target}!\` }],
|
|
1186
|
+
};
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
throw new Error(\`Unknown tool: \${name}\`);
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
`;
|
|
1193
|
+
RESOURCES_TEMPLATE = `import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
1194
|
+
import {
|
|
1195
|
+
ListResourcesRequestSchema,
|
|
1196
|
+
ReadResourceRequestSchema,
|
|
1197
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
1198
|
+
|
|
1199
|
+
export function registerResources(server: Server): void {
|
|
1200
|
+
// Resource \uBAA9\uB85D \uC815\uC758
|
|
1201
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
1202
|
+
resources: [
|
|
1203
|
+
{
|
|
1204
|
+
uri: 'example://sample',
|
|
1205
|
+
name: 'Sample Resource',
|
|
1206
|
+
description: '\uC608\uC81C \uB9AC\uC18C\uC2A4 \u2014 AI\uAC00 \uC77D\uC744 \uCEE8\uD14D\uC2A4\uD2B8',
|
|
1207
|
+
mimeType: 'text/plain',
|
|
1208
|
+
},
|
|
1209
|
+
],
|
|
1210
|
+
}));
|
|
1211
|
+
|
|
1212
|
+
// Resource \uC77D\uAE30
|
|
1213
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
1214
|
+
const { uri } = request.params;
|
|
1215
|
+
|
|
1216
|
+
if (uri === 'example://sample') {
|
|
1217
|
+
return {
|
|
1218
|
+
contents: [{
|
|
1219
|
+
uri,
|
|
1220
|
+
mimeType: 'text/plain',
|
|
1221
|
+
text: 'This is a sample resource content.',
|
|
1222
|
+
}],
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
throw new Error(\`Unknown resource: \${uri}\`);
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
1229
|
+
`;
|
|
1230
|
+
PROMPTS_TEMPLATE = `import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
1231
|
+
import {
|
|
1232
|
+
GetPromptRequestSchema,
|
|
1233
|
+
ListPromptsRequestSchema,
|
|
1234
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
1235
|
+
|
|
1236
|
+
export function registerPrompts(server: Server): void {
|
|
1237
|
+
// Prompt \uBAA9\uB85D \uC815\uC758
|
|
1238
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
1239
|
+
prompts: [
|
|
1240
|
+
{
|
|
1241
|
+
name: 'review-code',
|
|
1242
|
+
description: '\uCF54\uB4DC \uB9AC\uBDF0 \uC694\uCCAD \uD504\uB86C\uD504\uD2B8',
|
|
1243
|
+
arguments: [
|
|
1244
|
+
{ name: 'code', description: '\uB9AC\uBDF0\uD560 \uCF54\uB4DC', required: true },
|
|
1245
|
+
],
|
|
1246
|
+
},
|
|
1247
|
+
],
|
|
1248
|
+
}));
|
|
1249
|
+
|
|
1250
|
+
// Prompt \uAC00\uC838\uC624\uAE30
|
|
1251
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
1252
|
+
const { name, arguments: args } = request.params;
|
|
1253
|
+
|
|
1254
|
+
if (name === 'review-code') {
|
|
1255
|
+
const code = (args as { code?: string })?.code ?? '';
|
|
1256
|
+
return {
|
|
1257
|
+
messages: [{
|
|
1258
|
+
role: 'user',
|
|
1259
|
+
content: {
|
|
1260
|
+
type: 'text',
|
|
1261
|
+
text: \`\uB2E4\uC74C \uCF54\uB4DC\uB97C \uB9AC\uBDF0\uD574\uC8FC\uC138\uC694:\\n\\n\${code}\`,
|
|
1262
|
+
},
|
|
1263
|
+
}],
|
|
1264
|
+
};
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
throw new Error(\`Unknown prompt: \${name}\`);
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
`;
|
|
1271
|
+
TEST_TEMPLATE = `import { describe, it, expect } from 'vitest';
|
|
1272
|
+
|
|
1273
|
+
describe('MCP Server', () => {
|
|
1274
|
+
it('should be tested', () => {
|
|
1275
|
+
// TODO: MCP \uC11C\uBC84 \uD14C\uC2A4\uD2B8 \uC791\uC131
|
|
1276
|
+
expect(true).toBe(true);
|
|
1277
|
+
});
|
|
1278
|
+
});
|
|
1279
|
+
`;
|
|
1280
|
+
}
|
|
1281
|
+
});
|
|
1282
|
+
|
|
918
1283
|
// src/stages/environment/provisioners/registry.ts
|
|
919
1284
|
var registry_exports = {};
|
|
920
1285
|
__export(registry_exports, {
|
|
921
1286
|
PROVISIONERS: () => PROVISIONERS,
|
|
922
1287
|
runProvisioners: () => runProvisioners
|
|
923
1288
|
});
|
|
924
|
-
import { join as
|
|
925
|
-
import
|
|
1289
|
+
import { join as join4 } from "path";
|
|
1290
|
+
import fs5 from "fs-extra";
|
|
926
1291
|
async function provisionGitHub(ctx) {
|
|
927
|
-
const gitDir =
|
|
928
|
-
if (!await
|
|
929
|
-
await
|
|
1292
|
+
const gitDir = join4(ctx.cwd, ".git");
|
|
1293
|
+
if (!await fs5.pathExists(gitDir)) {
|
|
1294
|
+
await fs5.ensureDir(join4(ctx.cwd, ".github", "workflows"));
|
|
930
1295
|
try {
|
|
931
1296
|
const { execa } = await import("execa");
|
|
932
1297
|
await execa("git", ["init"], { cwd: ctx.cwd });
|
|
@@ -935,11 +1300,11 @@ async function provisionGitHub(ctx) {
|
|
|
935
1300
|
}
|
|
936
1301
|
}
|
|
937
1302
|
const dirs = ["src", "docs", "tests", "public", ".pai"];
|
|
938
|
-
await Promise.all(dirs.map((d) =>
|
|
939
|
-
const handoffPath =
|
|
940
|
-
if (!await
|
|
1303
|
+
await Promise.all(dirs.map((d) => fs5.ensureDir(join4(ctx.cwd, d))));
|
|
1304
|
+
const handoffPath = join4(ctx.cwd, "handoff.md");
|
|
1305
|
+
if (!await fs5.pathExists(handoffPath)) {
|
|
941
1306
|
const now = (/* @__PURE__ */ new Date()).toLocaleString("ko-KR");
|
|
942
|
-
await
|
|
1307
|
+
await fs5.writeFile(handoffPath, [
|
|
943
1308
|
`# Handoff \u2014 ${ctx.projectName}`,
|
|
944
1309
|
"",
|
|
945
1310
|
`> \uB9C8\uC9C0\uB9C9 \uC5C5\uB370\uC774\uD2B8: ${now}`,
|
|
@@ -968,9 +1333,9 @@ async function provisionGitHub(ctx) {
|
|
|
968
1333
|
"- \uCEE8\uD14D\uC2A4\uD2B8\uAC00 \uBD80\uC871\uD558\uBA74 AI\uAC00 \uC790\uB3D9\uC73C\uB85C \uC2EC\uCE35 \uC778\uD130\uBDF0\uB97C \uC9C4\uD589\uD569\uB2C8\uB2E4"
|
|
969
1334
|
].join("\n") + "\n");
|
|
970
1335
|
}
|
|
971
|
-
const contribPath =
|
|
972
|
-
if (!await
|
|
973
|
-
await
|
|
1336
|
+
const contribPath = join4(ctx.cwd, "CONTRIBUTING.md");
|
|
1337
|
+
if (!await fs5.pathExists(contribPath)) {
|
|
1338
|
+
await fs5.writeFile(contribPath, [
|
|
974
1339
|
`# Contributing to ${ctx.projectName}`,
|
|
975
1340
|
"",
|
|
976
1341
|
"\uC774 \uD504\uB85C\uC81D\uD2B8\uC5D0 \uAE30\uC5EC\uD574 \uC8FC\uC154\uC11C \uAC10\uC0AC\uD569\uB2C8\uB2E4.",
|
|
@@ -1014,11 +1379,11 @@ async function provisionGitHub(ctx) {
|
|
|
1014
1379
|
""
|
|
1015
1380
|
].join("\n") + "\n");
|
|
1016
1381
|
}
|
|
1017
|
-
const contribSkillDir =
|
|
1018
|
-
await
|
|
1019
|
-
const contribSkillPath =
|
|
1020
|
-
if (!await
|
|
1021
|
-
await
|
|
1382
|
+
const contribSkillDir = join4(ctx.cwd, ".claude", "skills");
|
|
1383
|
+
await fs5.ensureDir(contribSkillDir);
|
|
1384
|
+
const contribSkillPath = join4(contribSkillDir, "contributing.md");
|
|
1385
|
+
if (!await fs5.pathExists(contribSkillPath)) {
|
|
1386
|
+
await fs5.writeFile(contribSkillPath, [
|
|
1022
1387
|
"---",
|
|
1023
1388
|
"name: contributing",
|
|
1024
1389
|
'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"',
|
|
@@ -1043,9 +1408,9 @@ async function provisionGitHub(ctx) {
|
|
|
1043
1408
|
""
|
|
1044
1409
|
].join("\n") + "\n");
|
|
1045
1410
|
}
|
|
1046
|
-
const gitignorePath =
|
|
1047
|
-
if (!await
|
|
1048
|
-
await
|
|
1411
|
+
const gitignorePath = join4(ctx.cwd, ".gitignore");
|
|
1412
|
+
if (!await fs5.pathExists(gitignorePath)) {
|
|
1413
|
+
await fs5.writeFile(gitignorePath, [
|
|
1049
1414
|
"# Dependencies",
|
|
1050
1415
|
"node_modules/",
|
|
1051
1416
|
"",
|
|
@@ -1090,9 +1455,9 @@ async function provisionGitHub(ctx) {
|
|
|
1090
1455
|
}
|
|
1091
1456
|
}
|
|
1092
1457
|
async function provisionVercel(ctx) {
|
|
1093
|
-
const vercelJson =
|
|
1094
|
-
if (!await
|
|
1095
|
-
await
|
|
1458
|
+
const vercelJson = join4(ctx.cwd, "vercel.json");
|
|
1459
|
+
if (!await fs5.pathExists(vercelJson)) {
|
|
1460
|
+
await fs5.writeJson(vercelJson, {
|
|
1096
1461
|
version: 2,
|
|
1097
1462
|
name: ctx.projectName,
|
|
1098
1463
|
builds: [{ src: "src/**", use: "@vercel/static" }]
|
|
@@ -1100,20 +1465,20 @@ async function provisionVercel(ctx) {
|
|
|
1100
1465
|
}
|
|
1101
1466
|
}
|
|
1102
1467
|
async function provisionSupabase(ctx) {
|
|
1103
|
-
const supabaseDir =
|
|
1104
|
-
await
|
|
1105
|
-
const configToml =
|
|
1106
|
-
if (!await
|
|
1107
|
-
await
|
|
1468
|
+
const supabaseDir = join4(ctx.cwd, "supabase");
|
|
1469
|
+
await fs5.ensureDir(supabaseDir);
|
|
1470
|
+
const configToml = join4(supabaseDir, "config.toml");
|
|
1471
|
+
if (!await fs5.pathExists(configToml)) {
|
|
1472
|
+
await fs5.writeFile(configToml, '[api]\nschemas = ["public"]\n[auth]\nsite_url = "http://localhost:3000"\n');
|
|
1108
1473
|
}
|
|
1109
1474
|
ctx.envEntries["NEXT_PUBLIC_SUPABASE_URL"] = "YOUR_SUPABASE_URL";
|
|
1110
1475
|
ctx.envEntries["NEXT_PUBLIC_SUPABASE_ANON_KEY"] = "YOUR_SUPABASE_ANON_KEY";
|
|
1111
1476
|
}
|
|
1112
1477
|
async function provisionOpenSpec(ctx) {
|
|
1113
|
-
await
|
|
1114
|
-
const openspecPath =
|
|
1115
|
-
if (!await
|
|
1116
|
-
await
|
|
1478
|
+
await fs5.ensureDir(join4(ctx.cwd, "docs"));
|
|
1479
|
+
const openspecPath = join4(ctx.cwd, "docs", "openspec.md");
|
|
1480
|
+
if (!await fs5.pathExists(openspecPath)) {
|
|
1481
|
+
await fs5.writeFile(openspecPath, [
|
|
1117
1482
|
`# OpenSpec \u2014 ${ctx.projectName}`,
|
|
1118
1483
|
"",
|
|
1119
1484
|
"## 1. \uBAA9\uC801 (Purpose)",
|
|
@@ -1140,10 +1505,10 @@ async function provisionOpenSpec(ctx) {
|
|
|
1140
1505
|
}
|
|
1141
1506
|
}
|
|
1142
1507
|
async function provisionOMC(ctx) {
|
|
1143
|
-
await
|
|
1144
|
-
const omcPath =
|
|
1145
|
-
if (!await
|
|
1146
|
-
await
|
|
1508
|
+
await fs5.ensureDir(join4(ctx.cwd, ".pai"));
|
|
1509
|
+
const omcPath = join4(ctx.cwd, ".pai", "omc.md");
|
|
1510
|
+
if (!await fs5.pathExists(omcPath)) {
|
|
1511
|
+
await fs5.writeFile(omcPath, [
|
|
1147
1512
|
`# OMC \u2014 Object Model Context (${ctx.projectName})`,
|
|
1148
1513
|
"",
|
|
1149
1514
|
"> AI\uAC00 \uC774 \uD504\uB85C\uC81D\uD2B8\uC758 \uB3C4\uBA54\uC778\uC744 \uC774\uD574\uD558\uAE30 \uC704\uD55C \uD575\uC2EC \uAC1D\uCCB4 \uBAA8\uB378",
|
|
@@ -1163,8 +1528,8 @@ async function provisionOMC(ctx) {
|
|
|
1163
1528
|
}
|
|
1164
1529
|
}
|
|
1165
1530
|
async function provisionGstack(ctx) {
|
|
1166
|
-
await
|
|
1167
|
-
await
|
|
1531
|
+
await fs5.ensureDir(join4(ctx.cwd, ".pai"));
|
|
1532
|
+
await fs5.writeJson(join4(ctx.cwd, ".pai", "gstack.json"), {
|
|
1168
1533
|
version: "1.0",
|
|
1169
1534
|
testRunner: "jest",
|
|
1170
1535
|
coverageThreshold: { global: { lines: 80 } },
|
|
@@ -1172,10 +1537,10 @@ async function provisionGstack(ctx) {
|
|
|
1172
1537
|
}, { spaces: 2 });
|
|
1173
1538
|
}
|
|
1174
1539
|
async function provisionRoboco(ctx) {
|
|
1175
|
-
await
|
|
1176
|
-
const robocoPath =
|
|
1177
|
-
if (await
|
|
1178
|
-
await
|
|
1540
|
+
await fs5.ensureDir(join4(ctx.cwd, ".pai"));
|
|
1541
|
+
const robocoPath = join4(ctx.cwd, ".pai", "roboco.json");
|
|
1542
|
+
if (await fs5.pathExists(robocoPath)) return;
|
|
1543
|
+
await fs5.writeJson(robocoPath, {
|
|
1179
1544
|
version: "1.0",
|
|
1180
1545
|
checks: ["github", "vercel", "supabase", "openspec", "omc"],
|
|
1181
1546
|
reportOutput: "AI_READINESS_REPORT.md",
|
|
@@ -1183,14 +1548,18 @@ async function provisionRoboco(ctx) {
|
|
|
1183
1548
|
}, { spaces: 2 });
|
|
1184
1549
|
}
|
|
1185
1550
|
async function provisionHarness(ctx) {
|
|
1186
|
-
await
|
|
1187
|
-
await
|
|
1551
|
+
await fs5.ensureDir(join4(ctx.cwd, ".pai"));
|
|
1552
|
+
await fs5.writeJson(join4(ctx.cwd, ".pai", "harness.json"), {
|
|
1188
1553
|
version: "1.0",
|
|
1189
1554
|
specFile: "docs/openspec.md",
|
|
1190
1555
|
checkOn: ["pre-commit", "ci"],
|
|
1191
1556
|
rules: ["spec-implementation-match", "api-contract-test"]
|
|
1192
1557
|
}, { spaces: 2 });
|
|
1193
1558
|
}
|
|
1559
|
+
async function provisionMcpWrapper(ctx) {
|
|
1560
|
+
const { provisionMcp: provisionMcp2 } = await Promise.resolve().then(() => (init_mcp(), mcp_exports));
|
|
1561
|
+
await provisionMcp2(ctx);
|
|
1562
|
+
}
|
|
1194
1563
|
async function runProvisioners(keys, ctx) {
|
|
1195
1564
|
const results = [];
|
|
1196
1565
|
for (const key of keys) {
|
|
@@ -1208,7 +1577,7 @@ async function runProvisioners(keys, ctx) {
|
|
|
1208
1577
|
}
|
|
1209
1578
|
}
|
|
1210
1579
|
if (Object.keys(ctx.envEntries).length > 0) {
|
|
1211
|
-
writeEnvFile(
|
|
1580
|
+
writeEnvFile(join4(ctx.cwd, ".env.local"), ctx.envEntries);
|
|
1212
1581
|
}
|
|
1213
1582
|
return results;
|
|
1214
1583
|
}
|
|
@@ -1225,7 +1594,8 @@ var init_registry = __esm({
|
|
|
1225
1594
|
omc: provisionOMC,
|
|
1226
1595
|
gstack: provisionGstack,
|
|
1227
1596
|
roboco: provisionRoboco,
|
|
1228
|
-
harness: provisionHarness
|
|
1597
|
+
harness: provisionHarness,
|
|
1598
|
+
mcp: provisionMcpWrapper
|
|
1229
1599
|
};
|
|
1230
1600
|
}
|
|
1231
1601
|
});
|
|
@@ -1236,21 +1606,21 @@ __export(claude_commands_exports, {
|
|
|
1236
1606
|
provisionClaudeCommands: () => provisionClaudeCommands,
|
|
1237
1607
|
upgradeClaudeCommands: () => upgradeClaudeCommands
|
|
1238
1608
|
});
|
|
1239
|
-
import { join as
|
|
1240
|
-
import
|
|
1609
|
+
import { join as join5 } from "path";
|
|
1610
|
+
import fs6 from "fs-extra";
|
|
1241
1611
|
async function writeCommandFiles(cmdDir, entries, options) {
|
|
1242
|
-
await
|
|
1612
|
+
await fs6.ensureDir(cmdDir);
|
|
1243
1613
|
const written = [];
|
|
1244
1614
|
const skipped = [];
|
|
1245
1615
|
const errors = [];
|
|
1246
1616
|
for (const [filename, content] of Object.entries(entries)) {
|
|
1247
|
-
const filePath =
|
|
1617
|
+
const filePath = join5(cmdDir, filename);
|
|
1248
1618
|
try {
|
|
1249
|
-
if (options.skipIfExists && await
|
|
1619
|
+
if (options.skipIfExists && await fs6.pathExists(filePath)) {
|
|
1250
1620
|
skipped.push(filename);
|
|
1251
1621
|
continue;
|
|
1252
1622
|
}
|
|
1253
|
-
await
|
|
1623
|
+
await fs6.writeFile(filePath, content);
|
|
1254
1624
|
written.push(filename);
|
|
1255
1625
|
} catch (err) {
|
|
1256
1626
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -1260,13 +1630,13 @@ async function writeCommandFiles(cmdDir, entries, options) {
|
|
|
1260
1630
|
return { written, skipped, errors };
|
|
1261
1631
|
}
|
|
1262
1632
|
async function provisionClaudeCommands(cwd) {
|
|
1263
|
-
const skillDir =
|
|
1264
|
-
await
|
|
1265
|
-
const skillPath =
|
|
1266
|
-
if (!await
|
|
1267
|
-
await
|
|
1633
|
+
const skillDir = join5(cwd, ".claude", "skills", "pai");
|
|
1634
|
+
await fs6.ensureDir(skillDir);
|
|
1635
|
+
const skillPath = join5(skillDir, "SKILL.md");
|
|
1636
|
+
if (!await fs6.pathExists(skillPath)) {
|
|
1637
|
+
await fs6.writeFile(skillPath, SKILL_CONTENT);
|
|
1268
1638
|
}
|
|
1269
|
-
const cmdDir =
|
|
1639
|
+
const cmdDir = join5(cwd, ".claude", "commands", "pai");
|
|
1270
1640
|
await writeCommandFiles(cmdDir, COMMANDS, { skipIfExists: true });
|
|
1271
1641
|
}
|
|
1272
1642
|
async function upgradeClaudeCommands(cwd) {
|
|
@@ -1275,16 +1645,16 @@ async function upgradeClaudeCommands(cwd) {
|
|
|
1275
1645
|
commandsWritten: [],
|
|
1276
1646
|
commandErrors: []
|
|
1277
1647
|
};
|
|
1278
|
-
const skillDir =
|
|
1279
|
-
await
|
|
1648
|
+
const skillDir = join5(cwd, ".claude", "skills", "pai");
|
|
1649
|
+
await fs6.ensureDir(skillDir);
|
|
1280
1650
|
try {
|
|
1281
|
-
await
|
|
1651
|
+
await fs6.writeFile(join5(skillDir, "SKILL.md"), SKILL_CONTENT);
|
|
1282
1652
|
result.skillUpdated = true;
|
|
1283
1653
|
} catch (err) {
|
|
1284
1654
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1285
1655
|
result.commandErrors.push({ file: "SKILL.md", error: msg });
|
|
1286
1656
|
}
|
|
1287
|
-
const cmdDir =
|
|
1657
|
+
const cmdDir = join5(cwd, ".claude", "commands", "pai");
|
|
1288
1658
|
const { written, errors } = await writeCommandFiles(cmdDir, COMMANDS, { skipIfExists: false });
|
|
1289
1659
|
result.commandsWritten = written;
|
|
1290
1660
|
result.commandErrors.push(...errors);
|
|
@@ -1906,18 +2276,18 @@ npx pai-zero wakeup # \uC9C0\uAE08 \uB79C\uB364 \uBA54\uC2DC\uC9
|
|
|
1906
2276
|
// src/core/config.ts
|
|
1907
2277
|
import path from "path";
|
|
1908
2278
|
import { createRequire } from "module";
|
|
1909
|
-
import
|
|
2279
|
+
import fs7 from "fs-extra";
|
|
1910
2280
|
async function loadConfig(cwd) {
|
|
1911
2281
|
const configPath = path.join(cwd, CONFIG_DIR, CONFIG_FILE);
|
|
1912
|
-
if (await
|
|
1913
|
-
return
|
|
2282
|
+
if (await fs7.pathExists(configPath)) {
|
|
2283
|
+
return fs7.readJson(configPath);
|
|
1914
2284
|
}
|
|
1915
2285
|
return null;
|
|
1916
2286
|
}
|
|
1917
2287
|
async function saveConfig(cwd, config) {
|
|
1918
2288
|
const configDir = path.join(cwd, CONFIG_DIR);
|
|
1919
|
-
await
|
|
1920
|
-
await
|
|
2289
|
+
await fs7.ensureDir(configDir);
|
|
2290
|
+
await fs7.writeJson(path.join(configDir, CONFIG_FILE), config, { spaces: 2 });
|
|
1921
2291
|
}
|
|
1922
2292
|
function createDefaultConfig(projectName, mode) {
|
|
1923
2293
|
return {
|
|
@@ -1944,9 +2314,9 @@ var doctor_exports = {};
|
|
|
1944
2314
|
__export(doctor_exports, {
|
|
1945
2315
|
runDoctor: () => runDoctor
|
|
1946
2316
|
});
|
|
1947
|
-
import { join as
|
|
2317
|
+
import { join as join6 } from "path";
|
|
1948
2318
|
import { homedir } from "os";
|
|
1949
|
-
import
|
|
2319
|
+
import fs8 from "fs-extra";
|
|
1950
2320
|
async function runDoctor() {
|
|
1951
2321
|
section("PAI Doctor \u2014 \uD658\uACBD \uC9C4\uB2E8");
|
|
1952
2322
|
const checks = [];
|
|
@@ -1965,8 +2335,8 @@ async function runDoctor() {
|
|
|
1965
2335
|
detail: claudeCheck.detail,
|
|
1966
2336
|
fix: claudeCheck.ok ? void 0 : "npm install -g @anthropic-ai/claude-code"
|
|
1967
2337
|
});
|
|
1968
|
-
const globalConfigPath =
|
|
1969
|
-
const hasGlobalConfig = await
|
|
2338
|
+
const globalConfigPath = join6(homedir(), ".pai", "config.json");
|
|
2339
|
+
const hasGlobalConfig = await fs8.pathExists(globalConfigPath);
|
|
1970
2340
|
checks.push({
|
|
1971
2341
|
label: "\uAE00\uB85C\uBC8C \uC124\uC815",
|
|
1972
2342
|
ok: true,
|
|
@@ -2088,7 +2458,8 @@ var init_environment = __esm({
|
|
|
2088
2458
|
envEntries: {
|
|
2089
2459
|
PAI_PROJECT_NAME: interview.projectName,
|
|
2090
2460
|
PAI_MODE: interview.mode
|
|
2091
|
-
}
|
|
2461
|
+
},
|
|
2462
|
+
mcp: interview.mcp
|
|
2092
2463
|
};
|
|
2093
2464
|
if (interview.authMethods.includes("custom")) {
|
|
2094
2465
|
provCtx.envEntries["OAUTH_CLIENT_ID"] = interview.customAuth?.clientId || "YOUR_CLIENT_ID_HERE";
|
|
@@ -2108,6 +2479,7 @@ var init_environment = __esm({
|
|
|
2108
2479
|
...interview.extraTools.includes("supabase") ? ["supabase/config.toml"] : [],
|
|
2109
2480
|
...interview.extraTools.includes("gstack") ? [".pai/gstack.json"] : [],
|
|
2110
2481
|
...interview.extraTools.includes("harness") ? [".pai/harness.json"] : [],
|
|
2482
|
+
...interview.extraTools.includes("mcp") ? ["mcp-server/", ".mcp.json"] : [],
|
|
2111
2483
|
".env.local"
|
|
2112
2484
|
];
|
|
2113
2485
|
console.log("");
|
|
@@ -2175,7 +2547,7 @@ __export(detector_exports, {
|
|
|
2175
2547
|
scanProjectState: () => scanProjectState
|
|
2176
2548
|
});
|
|
2177
2549
|
import path2 from "path";
|
|
2178
|
-
import
|
|
2550
|
+
import fs9 from "fs-extra";
|
|
2179
2551
|
async function scanProjectState(cwd) {
|
|
2180
2552
|
const result = {
|
|
2181
2553
|
isNewProject: true,
|
|
@@ -2186,10 +2558,10 @@ async function scanProjectState(cwd) {
|
|
|
2186
2558
|
details: {}
|
|
2187
2559
|
};
|
|
2188
2560
|
const paiConfigPath = path2.join(cwd, ".pai", "config.json");
|
|
2189
|
-
if (await
|
|
2561
|
+
if (await fs9.pathExists(paiConfigPath)) {
|
|
2190
2562
|
result.hasPaiConfig = true;
|
|
2191
2563
|
try {
|
|
2192
|
-
const config = await
|
|
2564
|
+
const config = await fs9.readJson(paiConfigPath);
|
|
2193
2565
|
result.projectMode = config.mode ?? null;
|
|
2194
2566
|
} catch {
|
|
2195
2567
|
}
|
|
@@ -2197,7 +2569,7 @@ async function scanProjectState(cwd) {
|
|
|
2197
2569
|
for (const [key, signatures] of Object.entries(PLUGIN_SIGNATURES)) {
|
|
2198
2570
|
const installed = await Promise.any(
|
|
2199
2571
|
signatures.map(async (sig) => {
|
|
2200
|
-
if (await
|
|
2572
|
+
if (await fs9.pathExists(path2.join(cwd, sig))) return true;
|
|
2201
2573
|
throw new Error("not found");
|
|
2202
2574
|
})
|
|
2203
2575
|
).catch(() => false);
|
|
@@ -2208,7 +2580,7 @@ async function scanProjectState(cwd) {
|
|
|
2208
2580
|
result.missingPlugins.push(key);
|
|
2209
2581
|
}
|
|
2210
2582
|
}
|
|
2211
|
-
const hasAnyContent = result.installedPlugins.length > 0 || await
|
|
2583
|
+
const hasAnyContent = result.installedPlugins.length > 0 || await fs9.pathExists(path2.join(cwd, "package.json")) || await fs9.pathExists(path2.join(cwd, "src")) || await fs9.pathExists(path2.join(cwd, "README.md"));
|
|
2212
2584
|
result.isNewProject = !hasAnyContent;
|
|
2213
2585
|
return result;
|
|
2214
2586
|
}
|
|
@@ -2338,8 +2710,8 @@ var analyzer_exports2 = {};
|
|
|
2338
2710
|
__export(analyzer_exports2, {
|
|
2339
2711
|
analyzeRepository: () => analyzeRepository
|
|
2340
2712
|
});
|
|
2341
|
-
import { join as
|
|
2342
|
-
import
|
|
2713
|
+
import { join as join7 } from "path";
|
|
2714
|
+
import fs10 from "fs-extra";
|
|
2343
2715
|
async function analyzeRepository(repoPath) {
|
|
2344
2716
|
try {
|
|
2345
2717
|
return await aiAnalysis(repoPath);
|
|
@@ -2400,14 +2772,14 @@ async function checkTestCoverage(repoPath) {
|
|
|
2400
2772
|
".nycrc"
|
|
2401
2773
|
];
|
|
2402
2774
|
for (const f of testConfigs) {
|
|
2403
|
-
const found = await
|
|
2775
|
+
const found = await fs10.pathExists(join7(repoPath, f));
|
|
2404
2776
|
findings.push({ item: f, found, details: found ? "\uC874\uC7AC" : "\uC5C6\uC74C" });
|
|
2405
2777
|
if (found) score += 20;
|
|
2406
2778
|
}
|
|
2407
2779
|
const testDirs = ["tests", "test", "__tests__", "spec"];
|
|
2408
2780
|
let hasTestDir = false;
|
|
2409
2781
|
for (const d of testDirs) {
|
|
2410
|
-
if (await
|
|
2782
|
+
if (await fs10.pathExists(join7(repoPath, d))) {
|
|
2411
2783
|
findings.push({ item: d, found: true, details: "\uD14C\uC2A4\uD2B8 \uB514\uB809\uD1A0\uB9AC \uC874\uC7AC" });
|
|
2412
2784
|
hasTestDir = true;
|
|
2413
2785
|
score += 30;
|
|
@@ -2431,7 +2803,7 @@ async function checkCiCd(repoPath) {
|
|
|
2431
2803
|
{ path: ".circleci", label: "CircleCI" }
|
|
2432
2804
|
];
|
|
2433
2805
|
for (const { path: path3, label } of ciConfigs) {
|
|
2434
|
-
const found = await
|
|
2806
|
+
const found = await fs10.pathExists(join7(repoPath, path3));
|
|
2435
2807
|
findings.push({ item: label, found, details: found ? "\uC874\uC7AC" : "\uC5C6\uC74C" });
|
|
2436
2808
|
if (found) score += 40;
|
|
2437
2809
|
}
|
|
@@ -2450,7 +2822,7 @@ async function checkHooks(repoPath) {
|
|
|
2450
2822
|
{ path: ".claude/settings.json", label: "Claude Code settings" }
|
|
2451
2823
|
];
|
|
2452
2824
|
for (const { path: path3, label } of hookConfigs) {
|
|
2453
|
-
const found = await
|
|
2825
|
+
const found = await fs10.pathExists(join7(repoPath, path3));
|
|
2454
2826
|
findings.push({ item: label, found, details: found ? "\uC874\uC7AC" : "\uC5C6\uC74C" });
|
|
2455
2827
|
if (found) score += 20;
|
|
2456
2828
|
}
|
|
@@ -2468,7 +2840,7 @@ async function checkRepoStructure(repoPath) {
|
|
|
2468
2840
|
{ path: ".gitignore", label: ".gitignore" }
|
|
2469
2841
|
];
|
|
2470
2842
|
for (const { path: path3, label } of structureChecks) {
|
|
2471
|
-
const found = await
|
|
2843
|
+
const found = await fs10.pathExists(join7(repoPath, path3));
|
|
2472
2844
|
findings.push({ item: label, found, details: found ? "\uC874\uC7AC" : "\uC5C6\uC74C" });
|
|
2473
2845
|
if (found) score += 25;
|
|
2474
2846
|
}
|
|
@@ -2485,7 +2857,7 @@ async function checkDocumentation(repoPath) {
|
|
|
2485
2857
|
{ path: "docs/openspec.md", label: "OpenSpec PRD", points: 25 }
|
|
2486
2858
|
];
|
|
2487
2859
|
for (const { path: path3, label, points } of docChecks) {
|
|
2488
|
-
const found = await
|
|
2860
|
+
const found = await fs10.pathExists(join7(repoPath, path3));
|
|
2489
2861
|
findings.push({ item: label, found, details: found ? "\uC874\uC7AC" : "\uC5C6\uC74C" });
|
|
2490
2862
|
if (found) score += points;
|
|
2491
2863
|
}
|
|
@@ -2504,7 +2876,7 @@ async function checkHarnessEngineering(repoPath) {
|
|
|
2504
2876
|
{ path: ".pai/config.json", label: "PAI config", points: 10 }
|
|
2505
2877
|
];
|
|
2506
2878
|
for (const { path: path3, label, points } of harnessChecks) {
|
|
2507
|
-
const found = await
|
|
2879
|
+
const found = await fs10.pathExists(join7(repoPath, path3));
|
|
2508
2880
|
findings.push({ item: label, found, details: found ? "\uC874\uC7AC" : "\uC5C6\uC74C" });
|
|
2509
2881
|
if (found) score += points;
|
|
2510
2882
|
}
|
|
@@ -2887,56 +3259,56 @@ __export(shell_cd_exports, {
|
|
|
2887
3259
|
installShellHelper: () => installShellHelper,
|
|
2888
3260
|
requestCdAfter: () => requestCdAfter
|
|
2889
3261
|
});
|
|
2890
|
-
import { join as
|
|
3262
|
+
import { join as join8 } from "path";
|
|
2891
3263
|
import { homedir as homedir2 } from "os";
|
|
2892
|
-
import
|
|
3264
|
+
import fs11 from "fs-extra";
|
|
2893
3265
|
async function requestCdAfter(targetDir) {
|
|
2894
|
-
await
|
|
2895
|
-
await
|
|
3266
|
+
await fs11.ensureDir(PAI_DIR);
|
|
3267
|
+
await fs11.writeFile(CD_FILE, targetDir);
|
|
2896
3268
|
}
|
|
2897
3269
|
async function installShellHelper() {
|
|
2898
|
-
await
|
|
3270
|
+
await fs11.ensureDir(PAI_DIR);
|
|
2899
3271
|
if (isWindows) {
|
|
2900
3272
|
return installPowerShellHelper();
|
|
2901
3273
|
}
|
|
2902
3274
|
return installBashHelper();
|
|
2903
3275
|
}
|
|
2904
3276
|
async function installBashHelper() {
|
|
2905
|
-
await
|
|
3277
|
+
await fs11.writeFile(HELPER_FILE_SH, BASH_HELPER);
|
|
2906
3278
|
const rcFile = getShellRcPath();
|
|
2907
3279
|
const sourceLine = 'source "$HOME/.pai/shell-helper.sh"';
|
|
2908
|
-
if (await
|
|
2909
|
-
const content = await
|
|
3280
|
+
if (await fs11.pathExists(rcFile)) {
|
|
3281
|
+
const content = await fs11.readFile(rcFile, "utf8");
|
|
2910
3282
|
if (content.includes("shell-helper.sh")) {
|
|
2911
3283
|
return true;
|
|
2912
3284
|
}
|
|
2913
|
-
await
|
|
3285
|
+
await fs11.appendFile(rcFile, `
|
|
2914
3286
|
# PAI \u2014 \uC790\uB3D9 \uB514\uB809\uD1A0\uB9AC \uC774\uB3D9
|
|
2915
3287
|
${sourceLine}
|
|
2916
3288
|
`);
|
|
2917
3289
|
return false;
|
|
2918
3290
|
}
|
|
2919
|
-
await
|
|
3291
|
+
await fs11.writeFile(rcFile, `${sourceLine}
|
|
2920
3292
|
`);
|
|
2921
3293
|
return false;
|
|
2922
3294
|
}
|
|
2923
3295
|
async function installPowerShellHelper() {
|
|
2924
|
-
await
|
|
3296
|
+
await fs11.writeFile(HELPER_FILE_PS1, POWERSHELL_HELPER);
|
|
2925
3297
|
const rcFile = getShellRcPath();
|
|
2926
3298
|
const sourceLine = '. "$env:USERPROFILE\\.pai\\shell-helper.ps1"';
|
|
2927
|
-
await
|
|
2928
|
-
if (await
|
|
2929
|
-
const content = await
|
|
3299
|
+
await fs11.ensureDir(join8(rcFile, ".."));
|
|
3300
|
+
if (await fs11.pathExists(rcFile)) {
|
|
3301
|
+
const content = await fs11.readFile(rcFile, "utf8");
|
|
2930
3302
|
if (content.includes("shell-helper.ps1")) {
|
|
2931
3303
|
return true;
|
|
2932
3304
|
}
|
|
2933
|
-
await
|
|
3305
|
+
await fs11.appendFile(rcFile, `
|
|
2934
3306
|
# PAI \u2014 \uC790\uB3D9 \uB514\uB809\uD1A0\uB9AC \uC774\uB3D9
|
|
2935
3307
|
${sourceLine}
|
|
2936
3308
|
`);
|
|
2937
3309
|
return false;
|
|
2938
3310
|
}
|
|
2939
|
-
await
|
|
3311
|
+
await fs11.writeFile(rcFile, `${sourceLine}
|
|
2940
3312
|
`);
|
|
2941
3313
|
return false;
|
|
2942
3314
|
}
|
|
@@ -2945,10 +3317,10 @@ var init_shell_cd = __esm({
|
|
|
2945
3317
|
"src/utils/shell-cd.ts"() {
|
|
2946
3318
|
"use strict";
|
|
2947
3319
|
init_platform();
|
|
2948
|
-
PAI_DIR =
|
|
2949
|
-
CD_FILE =
|
|
2950
|
-
HELPER_FILE_SH =
|
|
2951
|
-
HELPER_FILE_PS1 =
|
|
3320
|
+
PAI_DIR = join8(homedir2(), ".pai");
|
|
3321
|
+
CD_FILE = join8(PAI_DIR, ".cd-after");
|
|
3322
|
+
HELPER_FILE_SH = join8(PAI_DIR, "shell-helper.sh");
|
|
3323
|
+
HELPER_FILE_PS1 = join8(PAI_DIR, "shell-helper.ps1");
|
|
2952
3324
|
BASH_HELPER = `# PAI shell helper \u2014 \uC790\uB3D9 \uB514\uB809\uD1A0\uB9AC \uC774\uB3D9 \uC9C0\uC6D0
|
|
2953
3325
|
pai() {
|
|
2954
3326
|
local cd_target="$HOME/.pai/.cd-after"
|
|
@@ -2990,12 +3362,12 @@ function pai {
|
|
|
2990
3362
|
|
|
2991
3363
|
// src/stages/evaluation/cache.ts
|
|
2992
3364
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
2993
|
-
import { join as
|
|
3365
|
+
import { join as join9 } from "path";
|
|
2994
3366
|
import { createHash } from "crypto";
|
|
2995
3367
|
function computeRepoHash(repoPath) {
|
|
2996
3368
|
const hash = createHash("sha256");
|
|
2997
3369
|
for (const file of FILES_TO_HASH) {
|
|
2998
|
-
const fullPath =
|
|
3370
|
+
const fullPath = join9(repoPath, file);
|
|
2999
3371
|
try {
|
|
3000
3372
|
const content = readFileSync(fullPath);
|
|
3001
3373
|
hash.update(`${file}:${content.length}`);
|
|
@@ -3006,7 +3378,7 @@ function computeRepoHash(repoPath) {
|
|
|
3006
3378
|
return hash.digest("hex").slice(0, 16);
|
|
3007
3379
|
}
|
|
3008
3380
|
function getCachePath(repoPath) {
|
|
3009
|
-
return
|
|
3381
|
+
return join9(repoPath, CACHE_DIR, CACHE_FILE);
|
|
3010
3382
|
}
|
|
3011
3383
|
function loadCache(repoPath) {
|
|
3012
3384
|
try {
|
|
@@ -3017,7 +3389,7 @@ function loadCache(repoPath) {
|
|
|
3017
3389
|
}
|
|
3018
3390
|
}
|
|
3019
3391
|
function saveCache(repoPath, store) {
|
|
3020
|
-
const cacheDir =
|
|
3392
|
+
const cacheDir = join9(repoPath, CACHE_DIR, "cache");
|
|
3021
3393
|
if (!existsSync(cacheDir)) {
|
|
3022
3394
|
mkdirSync(cacheDir, { recursive: true });
|
|
3023
3395
|
}
|
|
@@ -3076,8 +3448,8 @@ var evaluate_cmd_exports = {};
|
|
|
3076
3448
|
__export(evaluate_cmd_exports, {
|
|
3077
3449
|
evaluateCommand: () => evaluateCommand
|
|
3078
3450
|
});
|
|
3079
|
-
import { join as
|
|
3080
|
-
import
|
|
3451
|
+
import { join as join10, basename } from "path";
|
|
3452
|
+
import fs12 from "fs-extra";
|
|
3081
3453
|
async function evaluateCommand(cwd, options) {
|
|
3082
3454
|
const useCache = options.cache !== false;
|
|
3083
3455
|
let llmOutput = useCache ? getCachedResult(cwd) : null;
|
|
@@ -3097,17 +3469,17 @@ async function evaluateCommand(cwd, options) {
|
|
|
3097
3469
|
const config = await loadConfig(cwd);
|
|
3098
3470
|
const projectName = config?.projectName ?? basename(cwd);
|
|
3099
3471
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3100
|
-
const reportDir =
|
|
3101
|
-
const reportPath =
|
|
3102
|
-
await
|
|
3472
|
+
const reportDir = join10(cwd, "docs", "p-reports");
|
|
3473
|
+
const reportPath = join10(reportDir, `${today}.md`);
|
|
3474
|
+
await fs12.ensureDir(reportDir);
|
|
3103
3475
|
const detailedReport = buildDetailedReport(result, projectName);
|
|
3104
|
-
await
|
|
3476
|
+
await fs12.writeFile(reportPath, detailedReport, "utf8");
|
|
3105
3477
|
console.log("");
|
|
3106
3478
|
success(`\uB9AC\uD3EC\uD2B8 \uC800\uC7A5: docs/p-reports/${today}.md`);
|
|
3107
3479
|
console.log("");
|
|
3108
3480
|
console.log(detailedReport);
|
|
3109
3481
|
if (options.output) {
|
|
3110
|
-
await
|
|
3482
|
+
await fs12.writeFile(options.output, detailedReport, "utf8");
|
|
3111
3483
|
success(`\uCD94\uAC00 \uC800\uC7A5: ${options.output}`);
|
|
3112
3484
|
}
|
|
3113
3485
|
if (options.failUnder && result.totalScore < options.failUnder) {
|
|
@@ -3235,8 +3607,8 @@ var init_cmd_exports = {};
|
|
|
3235
3607
|
__export(init_cmd_exports, {
|
|
3236
3608
|
initCommand: () => initCommand
|
|
3237
3609
|
});
|
|
3238
|
-
import { join as
|
|
3239
|
-
import
|
|
3610
|
+
import { join as join11, basename as basename2 } from "path";
|
|
3611
|
+
import fs13 from "fs-extra";
|
|
3240
3612
|
async function initCommand(cwd, nameArg) {
|
|
3241
3613
|
printBanner();
|
|
3242
3614
|
const { isWindows: isWindows2, diagnoseWindowsEnv: diagnoseWindowsEnv2 } = await Promise.resolve().then(() => (init_platform(), platform_exports));
|
|
@@ -3294,11 +3666,11 @@ async function initCommand(cwd, nameArg) {
|
|
|
3294
3666
|
const evalResult = computeResult2(llmOutput);
|
|
3295
3667
|
printReport2(evalResult);
|
|
3296
3668
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3297
|
-
const reportDir =
|
|
3298
|
-
await
|
|
3669
|
+
const reportDir = join11(cwd, "docs", "p-reports");
|
|
3670
|
+
await fs13.ensureDir(reportDir);
|
|
3299
3671
|
const legacyName = basename2(cwd);
|
|
3300
3672
|
const detailedReport = buildDetailedReport3(evalResult, legacyName);
|
|
3301
|
-
await
|
|
3673
|
+
await fs13.writeFile(join11(reportDir, `${today}.md`), detailedReport, "utf8");
|
|
3302
3674
|
console.log("");
|
|
3303
3675
|
success(`\uB9AC\uD3EC\uD2B8 \uC800\uC7A5: docs/p-reports/${today}.md`);
|
|
3304
3676
|
} catch {
|
|
@@ -3343,8 +3715,8 @@ async function initCommand(cwd, nameArg) {
|
|
|
3343
3715
|
}]);
|
|
3344
3716
|
projectName = answer.name.trim();
|
|
3345
3717
|
}
|
|
3346
|
-
const projectDir =
|
|
3347
|
-
if (await
|
|
3718
|
+
const projectDir = join11(cwd, projectName);
|
|
3719
|
+
if (await fs13.pathExists(projectDir)) {
|
|
3348
3720
|
const existingConfig = await loadConfig(projectDir);
|
|
3349
3721
|
if (existingConfig) {
|
|
3350
3722
|
console.log("");
|
|
@@ -3366,7 +3738,7 @@ async function initCommand(cwd, nameArg) {
|
|
|
3366
3738
|
return;
|
|
3367
3739
|
}
|
|
3368
3740
|
} else {
|
|
3369
|
-
await
|
|
3741
|
+
await fs13.ensureDir(projectDir);
|
|
3370
3742
|
success(`${projectName}/ \uD3F4\uB354 \uC0DD\uC131`);
|
|
3371
3743
|
}
|
|
3372
3744
|
await setupInDirectory(projectDir, projectName);
|
|
@@ -3433,6 +3805,9 @@ async function showCompletion(projectName, projectDir, extraTools, isCurrentDir)
|
|
|
3433
3805
|
if (extraTools.includes("supabase")) {
|
|
3434
3806
|
console.log(` ${chalk8.cyan("Supabase")} DB + \uC778\uC99D + \uC2A4\uD1A0\uB9AC\uC9C0 (PostgreSQL \uAE30\uBC18)`);
|
|
3435
3807
|
}
|
|
3808
|
+
if (extraTools.includes("mcp")) {
|
|
3809
|
+
console.log(` ${chalk8.cyan("MCP \uC11C\uBC84")} AI \uB3C4\uAD6C \u2014 Claude\uAC00 \uD638\uCD9C\uD560 \uCEE4\uC2A4\uD140 \uAE30\uB2A5/\uB370\uC774\uD130`);
|
|
3810
|
+
}
|
|
3436
3811
|
console.log("");
|
|
3437
3812
|
console.log(colors.accent(" \uC124\uCE58 \uD655\uC778"));
|
|
3438
3813
|
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"));
|
|
@@ -3444,7 +3819,7 @@ async function showCompletion(projectName, projectDir, extraTools, isCurrentDir)
|
|
|
3444
3819
|
{ label: "\uC2AC\uB798\uC2DC \uCEE4\uB9E8\uB4DC", path: ".claude/skills/pai/SKILL.md" }
|
|
3445
3820
|
];
|
|
3446
3821
|
for (const check of checks) {
|
|
3447
|
-
const exists = await
|
|
3822
|
+
const exists = await fs13.pathExists(join11(projectDir, check.path));
|
|
3448
3823
|
console.log(` ${exists ? colors.success("\u2713") : colors.err("\u2717")} ${check.label.padEnd(16)} ${colors.dim(check.path)}`);
|
|
3449
3824
|
}
|
|
3450
3825
|
console.log("");
|
|
@@ -3469,10 +3844,10 @@ async function showCompletion(projectName, projectDir, extraTools, isCurrentDir)
|
|
|
3469
3844
|
printReport2(evalResult);
|
|
3470
3845
|
await sleep2(500);
|
|
3471
3846
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3472
|
-
const reportDir =
|
|
3473
|
-
await
|
|
3847
|
+
const reportDir = join11(projectDir, "docs", "p-reports");
|
|
3848
|
+
await fs13.ensureDir(reportDir);
|
|
3474
3849
|
const detailedReport = buildDetailedReport3(evalResult, projectName);
|
|
3475
|
-
await
|
|
3850
|
+
await fs13.writeFile(join11(reportDir, `${today}.md`), detailedReport, "utf8");
|
|
3476
3851
|
await sleep2(500);
|
|
3477
3852
|
console.log("");
|
|
3478
3853
|
success(`\uB9AC\uD3EC\uD2B8 \uC800\uC7A5: docs/p-reports/${today}.md`);
|
|
@@ -3500,7 +3875,7 @@ async function showCompletion(projectName, projectDir, extraTools, isCurrentDir)
|
|
|
3500
3875
|
const shellRc = getShellRcPath2();
|
|
3501
3876
|
let hasYoloAliasSet = false;
|
|
3502
3877
|
try {
|
|
3503
|
-
const rcContent = await
|
|
3878
|
+
const rcContent = await fs13.readFile(shellRc, "utf8");
|
|
3504
3879
|
hasYoloAliasSet = checkYolo(rcContent);
|
|
3505
3880
|
} catch {
|
|
3506
3881
|
}
|
|
@@ -3521,10 +3896,10 @@ async function showCompletion(projectName, projectDir, extraTools, isCurrentDir)
|
|
|
3521
3896
|
const { getYoloAliasLine: getYoloAliasLine2 } = await Promise.resolve().then(() => (init_platform(), platform_exports));
|
|
3522
3897
|
const aliasLine = getYoloAliasLine2();
|
|
3523
3898
|
try {
|
|
3524
|
-
const rcContent = await
|
|
3899
|
+
const rcContent = await fs13.readFile(shellRc, "utf8").catch(() => "");
|
|
3525
3900
|
if (!rcContent.includes("claude-yolo")) {
|
|
3526
|
-
await
|
|
3527
|
-
await
|
|
3901
|
+
await fs13.ensureDir(join11(shellRc, ".."));
|
|
3902
|
+
await fs13.appendFile(shellRc, `
|
|
3528
3903
|
# PAI \u2014 claude-YOLO mode
|
|
3529
3904
|
${aliasLine}
|
|
3530
3905
|
`);
|
|
@@ -3755,9 +4130,9 @@ async function installOrchestratorOnly(projectDir, projectName) {
|
|
|
3755
4130
|
const evalResult = computeResult2(llmOutput);
|
|
3756
4131
|
printReport2(evalResult);
|
|
3757
4132
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3758
|
-
const reportDir =
|
|
3759
|
-
await
|
|
3760
|
-
await
|
|
4133
|
+
const reportDir = join11(projectDir, "docs", "p-reports");
|
|
4134
|
+
await fs13.ensureDir(reportDir);
|
|
4135
|
+
await fs13.writeFile(join11(reportDir, `${today}.md`), buildDetailedReport3(evalResult, projectName), "utf8");
|
|
3761
4136
|
console.log("");
|
|
3762
4137
|
hint(`\uC0C1\uC138 \uB9AC\uD3EC\uD2B8: docs/p-reports/${today}.md`);
|
|
3763
4138
|
} catch {
|
|
@@ -3807,7 +4182,7 @@ async function detectLegacyProject(cwd) {
|
|
|
3807
4182
|
".gitignore"
|
|
3808
4183
|
];
|
|
3809
4184
|
for (const signal of signals) {
|
|
3810
|
-
if (await
|
|
4185
|
+
if (await fs13.pathExists(join11(cwd, signal))) return true;
|
|
3811
4186
|
}
|
|
3812
4187
|
return false;
|
|
3813
4188
|
}
|
|
@@ -3824,17 +4199,17 @@ var init_init_cmd = __esm({
|
|
|
3824
4199
|
});
|
|
3825
4200
|
|
|
3826
4201
|
// src/stages/design/openspec.ts
|
|
3827
|
-
import { join as
|
|
3828
|
-
import
|
|
4202
|
+
import { join as join12 } from "path";
|
|
4203
|
+
import fs14 from "fs-extra";
|
|
3829
4204
|
async function initOpenSpec(cwd, projectName) {
|
|
3830
|
-
const docsDir =
|
|
3831
|
-
await
|
|
3832
|
-
const openspecPath =
|
|
3833
|
-
if (await
|
|
4205
|
+
const docsDir = join12(cwd, "docs");
|
|
4206
|
+
await fs14.ensureDir(docsDir);
|
|
4207
|
+
const openspecPath = join12(docsDir, "openspec.md");
|
|
4208
|
+
if (await fs14.pathExists(openspecPath)) {
|
|
3834
4209
|
info("docs/openspec.md \uC774\uBBF8 \uC874\uC7AC \u2014 \uAC74\uB108\uB700");
|
|
3835
4210
|
return;
|
|
3836
4211
|
}
|
|
3837
|
-
await
|
|
4212
|
+
await fs14.writeFile(openspecPath, [
|
|
3838
4213
|
`# OpenSpec \u2014 ${projectName}`,
|
|
3839
4214
|
"",
|
|
3840
4215
|
"## 1. \uBAA9\uC801 (Purpose)",
|
|
@@ -3862,13 +4237,13 @@ async function initOpenSpec(cwd, projectName) {
|
|
|
3862
4237
|
}
|
|
3863
4238
|
async function validateOpenSpec(cwd) {
|
|
3864
4239
|
const candidates = [
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
4240
|
+
join12(cwd, "docs", "openspec.md"),
|
|
4241
|
+
join12(cwd, "openspec.md"),
|
|
4242
|
+
join12(cwd, ".pai", "openspec.md")
|
|
3868
4243
|
];
|
|
3869
4244
|
let specPath = null;
|
|
3870
4245
|
for (const p of candidates) {
|
|
3871
|
-
if (await
|
|
4246
|
+
if (await fs14.pathExists(p)) {
|
|
3872
4247
|
specPath = p;
|
|
3873
4248
|
break;
|
|
3874
4249
|
}
|
|
@@ -3882,7 +4257,7 @@ async function validateOpenSpec(cwd) {
|
|
|
3882
4257
|
warnings: ["openspec.md \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. `pai design init` \uC744 \uC2E4\uD589\uD558\uC138\uC694."]
|
|
3883
4258
|
};
|
|
3884
4259
|
}
|
|
3885
|
-
const content = await
|
|
4260
|
+
const content = await fs14.readFile(specPath, "utf8");
|
|
3886
4261
|
const missing = [];
|
|
3887
4262
|
let filled = 0;
|
|
3888
4263
|
for (const section2 of REQUIRED_SECTIONS) {
|
|
@@ -3930,17 +4305,17 @@ var init_openspec = __esm({
|
|
|
3930
4305
|
});
|
|
3931
4306
|
|
|
3932
4307
|
// src/stages/design/omc.ts
|
|
3933
|
-
import { join as
|
|
3934
|
-
import
|
|
4308
|
+
import { join as join13 } from "path";
|
|
4309
|
+
import fs15 from "fs-extra";
|
|
3935
4310
|
async function initOMC(cwd, projectName) {
|
|
3936
|
-
const paiDir =
|
|
3937
|
-
await
|
|
3938
|
-
const omcPath =
|
|
3939
|
-
if (await
|
|
4311
|
+
const paiDir = join13(cwd, ".pai");
|
|
4312
|
+
await fs15.ensureDir(paiDir);
|
|
4313
|
+
const omcPath = join13(paiDir, "omc.md");
|
|
4314
|
+
if (await fs15.pathExists(omcPath)) {
|
|
3940
4315
|
info(".pai/omc.md \uC774\uBBF8 \uC874\uC7AC \u2014 \uAC74\uB108\uB700");
|
|
3941
4316
|
return;
|
|
3942
4317
|
}
|
|
3943
|
-
await
|
|
4318
|
+
await fs15.writeFile(omcPath, [
|
|
3944
4319
|
`# OMC \u2014 Object Model Context (${projectName})`,
|
|
3945
4320
|
"",
|
|
3946
4321
|
"> AI\uAC00 \uC774 \uD504\uB85C\uC81D\uD2B8\uC758 \uB3C4\uBA54\uC778\uC744 \uC774\uD574\uD558\uAE30 \uC704\uD55C \uD575\uC2EC \uAC1D\uCCB4 \uBAA8\uB378",
|
|
@@ -4022,25 +4397,25 @@ var init_design_cmd = __esm({
|
|
|
4022
4397
|
});
|
|
4023
4398
|
|
|
4024
4399
|
// src/stages/validation/runner.ts
|
|
4025
|
-
import { join as
|
|
4026
|
-
import
|
|
4400
|
+
import { join as join14 } from "path";
|
|
4401
|
+
import fs16 from "fs-extra";
|
|
4027
4402
|
async function runTests(cwd) {
|
|
4028
4403
|
const start = Date.now();
|
|
4029
|
-
const gstackPath =
|
|
4404
|
+
const gstackPath = join14(cwd, ".pai", "gstack.json");
|
|
4030
4405
|
let runner = "npm test";
|
|
4031
|
-
if (await
|
|
4406
|
+
if (await fs16.pathExists(gstackPath)) {
|
|
4032
4407
|
try {
|
|
4033
|
-
const config = await
|
|
4408
|
+
const config = await fs16.readJson(gstackPath);
|
|
4034
4409
|
if (config.testRunner === "vitest") runner = "npx vitest run";
|
|
4035
4410
|
else if (config.testRunner === "jest") runner = "npx jest";
|
|
4036
4411
|
else if (config.testRunner === "mocha") runner = "npx mocha";
|
|
4037
4412
|
} catch {
|
|
4038
4413
|
}
|
|
4039
4414
|
}
|
|
4040
|
-
const pkgPath =
|
|
4041
|
-
if (await
|
|
4415
|
+
const pkgPath = join14(cwd, "package.json");
|
|
4416
|
+
if (await fs16.pathExists(pkgPath)) {
|
|
4042
4417
|
try {
|
|
4043
|
-
const pkg4 = await
|
|
4418
|
+
const pkg4 = await fs16.readJson(pkgPath);
|
|
4044
4419
|
if (!pkg4.scripts?.test || pkg4.scripts.test.includes("no test specified")) {
|
|
4045
4420
|
return {
|
|
4046
4421
|
runner,
|
|
@@ -4082,16 +4457,16 @@ var init_runner = __esm({
|
|
|
4082
4457
|
});
|
|
4083
4458
|
|
|
4084
4459
|
// src/stages/validation/harness.ts
|
|
4085
|
-
import { join as
|
|
4086
|
-
import
|
|
4460
|
+
import { join as join15 } from "path";
|
|
4461
|
+
import fs17 from "fs-extra";
|
|
4087
4462
|
async function runHarnessCheck(cwd) {
|
|
4088
|
-
const harnessPath =
|
|
4089
|
-
if (!await
|
|
4463
|
+
const harnessPath = join15(cwd, ".pai", "harness.json");
|
|
4464
|
+
if (!await fs17.pathExists(harnessPath)) {
|
|
4090
4465
|
return { enabled: false, specFile: null, rules: [], checks: [] };
|
|
4091
4466
|
}
|
|
4092
4467
|
let config;
|
|
4093
4468
|
try {
|
|
4094
|
-
config = await
|
|
4469
|
+
config = await fs17.readJson(harnessPath);
|
|
4095
4470
|
} catch {
|
|
4096
4471
|
return { enabled: false, specFile: null, rules: [], checks: [] };
|
|
4097
4472
|
}
|
|
@@ -4099,8 +4474,8 @@ async function runHarnessCheck(cwd) {
|
|
|
4099
4474
|
const rules = config.rules ?? [];
|
|
4100
4475
|
const checks = [];
|
|
4101
4476
|
if (rules.includes("spec-implementation-match")) {
|
|
4102
|
-
const specExists = await
|
|
4103
|
-
const srcExists = await
|
|
4477
|
+
const specExists = await fs17.pathExists(join15(cwd, specFile));
|
|
4478
|
+
const srcExists = await fs17.pathExists(join15(cwd, "src"));
|
|
4104
4479
|
checks.push({
|
|
4105
4480
|
rule: "spec-implementation-match",
|
|
4106
4481
|
passed: specExists && srcExists,
|
|
@@ -4108,8 +4483,8 @@ async function runHarnessCheck(cwd) {
|
|
|
4108
4483
|
});
|
|
4109
4484
|
}
|
|
4110
4485
|
if (rules.includes("api-contract-test")) {
|
|
4111
|
-
const testDir = await
|
|
4112
|
-
const testDir2 = await
|
|
4486
|
+
const testDir = await fs17.pathExists(join15(cwd, "tests"));
|
|
4487
|
+
const testDir2 = await fs17.pathExists(join15(cwd, "test"));
|
|
4113
4488
|
checks.push({
|
|
4114
4489
|
rule: "api-contract-test",
|
|
4115
4490
|
passed: testDir || testDir2,
|
|
@@ -4199,14 +4574,14 @@ var init_context = __esm({
|
|
|
4199
4574
|
});
|
|
4200
4575
|
|
|
4201
4576
|
// src/stages/design/index.ts
|
|
4202
|
-
import { join as
|
|
4203
|
-
import
|
|
4577
|
+
import { join as join16 } from "path";
|
|
4578
|
+
import fs18 from "fs-extra";
|
|
4204
4579
|
async function autoInstallHarness(cwd) {
|
|
4205
|
-
const harnessPath =
|
|
4206
|
-
if (await
|
|
4580
|
+
const harnessPath = join16(cwd, ".pai", "harness.json");
|
|
4581
|
+
if (await fs18.pathExists(harnessPath)) return;
|
|
4207
4582
|
await withSpinner("Harness Engineering \uC790\uB3D9 \uC124\uC815 \uC911...", async () => {
|
|
4208
|
-
await
|
|
4209
|
-
await
|
|
4583
|
+
await fs18.ensureDir(join16(cwd, ".pai"));
|
|
4584
|
+
await fs18.writeJson(harnessPath, {
|
|
4210
4585
|
version: "1.0",
|
|
4211
4586
|
specFile: "docs/openspec.md",
|
|
4212
4587
|
checkOn: ["pre-commit", "ci"],
|
|
@@ -4551,7 +4926,7 @@ __export(remove_cmd_exports, {
|
|
|
4551
4926
|
removeCommand: () => removeCommand
|
|
4552
4927
|
});
|
|
4553
4928
|
import { basename as basename4, dirname } from "path";
|
|
4554
|
-
import
|
|
4929
|
+
import fs19 from "fs-extra";
|
|
4555
4930
|
async function removeCommand(cwd, options) {
|
|
4556
4931
|
section("\uD504\uB85C\uC81D\uD2B8 \uC0AD\uC81C");
|
|
4557
4932
|
const config = await loadConfig(cwd);
|
|
@@ -4569,7 +4944,7 @@ async function removeCommand(cwd, options) {
|
|
|
4569
4944
|
console.log(colors.err(` ${folderName}/ \uD3F4\uB354 \uC804\uCCB4\uAC00 \uC0AD\uC81C\uB429\uB2C8\uB2E4.`));
|
|
4570
4945
|
hint("\uC774 \uC791\uC5C5\uC740 \uB418\uB3CC\uB9B4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
4571
4946
|
console.log("");
|
|
4572
|
-
const items = await
|
|
4947
|
+
const items = await fs19.readdir(cwd);
|
|
4573
4948
|
const fileCount = items.filter((i) => !i.startsWith(".")).length;
|
|
4574
4949
|
const hiddenCount = items.filter((i) => i.startsWith(".")).length;
|
|
4575
4950
|
info(`\uD30C\uC77C/\uD3F4\uB354 ${fileCount}\uAC1C, \uC228\uAE40 \uD56D\uBAA9 ${hiddenCount}\uAC1C`);
|
|
@@ -4588,7 +4963,7 @@ async function removeCommand(cwd, options) {
|
|
|
4588
4963
|
}
|
|
4589
4964
|
process.chdir(parentDir);
|
|
4590
4965
|
try {
|
|
4591
|
-
await
|
|
4966
|
+
await fs19.remove(cwd);
|
|
4592
4967
|
console.log("");
|
|
4593
4968
|
success(`${folderName}/ \uD504\uB85C\uC81D\uD2B8\uAC00 \uC0AD\uC81C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`);
|
|
4594
4969
|
try {
|
|
@@ -4741,8 +5116,8 @@ var savetoken_cmd_exports = {};
|
|
|
4741
5116
|
__export(savetoken_cmd_exports, {
|
|
4742
5117
|
savetokenCommand: () => savetokenCommand
|
|
4743
5118
|
});
|
|
4744
|
-
import { join as
|
|
4745
|
-
import
|
|
5119
|
+
import { join as join17, relative } from "path";
|
|
5120
|
+
import fs20 from "fs-extra";
|
|
4746
5121
|
import chalk6 from "chalk";
|
|
4747
5122
|
async function savetokenCommand(cwd) {
|
|
4748
5123
|
const { createSpinner: createSpinner2 } = await Promise.resolve().then(() => (init_progress(), progress_exports));
|
|
@@ -4811,11 +5186,11 @@ async function savetokenCommand(cwd) {
|
|
|
4811
5186
|
console.log(` \u2192 ${colors.dim("\uB8F0 \uAE30\uBC18 \uB85C\uC9C1, \uD0A4\uC6CC\uB4DC \uB9E4\uCE6D\uC73C\uB85C \uAC80\uD1A0 \uD6C4 \uB300\uCCB4")}`);
|
|
4812
5187
|
console.log(` ${chalk6.red("\u25CF")} \uB192\uC74C \uCF54\uB4DC \uC0DD\uC131, \uBCF5\uC7A1\uD55C \uCD94\uB860, \uCC3D\uC758\uC801 \uC0DD\uC131`);
|
|
4813
5188
|
console.log(` \u2192 ${colors.dim("AI \uD544\uC218 \u2014 \uD504\uB86C\uD504\uD2B8 \uCD5C\uC801\uD654\uB85C \uD1A0\uD070 \uC808\uAC10")}`);
|
|
4814
|
-
const reportDir =
|
|
4815
|
-
await
|
|
5189
|
+
const reportDir = join17(cwd, ".pai");
|
|
5190
|
+
await fs20.ensureDir(reportDir);
|
|
4816
5191
|
const report = buildReport(callSites, cwd);
|
|
4817
|
-
const reportPath =
|
|
4818
|
-
await
|
|
5192
|
+
const reportPath = join17(reportDir, "savetoken-report.md");
|
|
5193
|
+
await fs20.writeFile(reportPath, report, "utf8");
|
|
4819
5194
|
console.log("");
|
|
4820
5195
|
success("\uC2A4\uCE94 \uB9AC\uD3EC\uD2B8 \uC800\uC7A5: .pai/savetoken-report.md");
|
|
4821
5196
|
console.log("");
|
|
@@ -4971,9 +5346,9 @@ var wakeup_cmd_exports = {};
|
|
|
4971
5346
|
__export(wakeup_cmd_exports, {
|
|
4972
5347
|
wakeupCommand: () => wakeupCommand
|
|
4973
5348
|
});
|
|
4974
|
-
import { join as
|
|
5349
|
+
import { join as join18 } from "path";
|
|
4975
5350
|
import { homedir as homedir3, platform as osPlatform } from "os";
|
|
4976
|
-
import
|
|
5351
|
+
import fs21 from "fs-extra";
|
|
4977
5352
|
import chalk7 from "chalk";
|
|
4978
5353
|
async function wakeupCommand(timeOrAction, schedule = "\uD3C9\uC77C") {
|
|
4979
5354
|
if (timeOrAction === "off") {
|
|
@@ -5020,9 +5395,9 @@ async function wakeupCommand(timeOrAction, schedule = "\uD3C9\uC77C") {
|
|
|
5020
5395
|
projectDir,
|
|
5021
5396
|
launchMode
|
|
5022
5397
|
};
|
|
5023
|
-
await
|
|
5024
|
-
await
|
|
5025
|
-
await
|
|
5398
|
+
await fs21.ensureDir(PAI_DIR2);
|
|
5399
|
+
await fs21.writeJson(CONFIG_FILE2, config, { spaces: 2 });
|
|
5400
|
+
await fs21.writeJson(MESSAGES_FILE, MESSAGES);
|
|
5026
5401
|
await createWakeupScript(config);
|
|
5027
5402
|
if (osPlatform() === "darwin") {
|
|
5028
5403
|
await setupMacOS(config);
|
|
@@ -5052,8 +5427,8 @@ async function wakeupCommand(timeOrAction, schedule = "\uD3C9\uC77C") {
|
|
|
5052
5427
|
async function setupMacOS(config) {
|
|
5053
5428
|
const { execa } = await import("execa");
|
|
5054
5429
|
const [hour, minute] = config.time.split(":").map(Number);
|
|
5055
|
-
const plistDir =
|
|
5056
|
-
await
|
|
5430
|
+
const plistDir = join18(homedir3(), "Library", "LaunchAgents");
|
|
5431
|
+
await fs21.ensureDir(plistDir);
|
|
5057
5432
|
const weekdays = scheduleToWeekdays(config.schedule);
|
|
5058
5433
|
let calendarEntries;
|
|
5059
5434
|
if (weekdays.length === 7) {
|
|
@@ -5089,7 +5464,7 @@ ${calendarEntries}
|
|
|
5089
5464
|
<string>${PAI_DIR2}/wakeup.log</string>
|
|
5090
5465
|
</dict>
|
|
5091
5466
|
</plist>`;
|
|
5092
|
-
await
|
|
5467
|
+
await fs21.writeFile(PLIST_PATH, plist);
|
|
5093
5468
|
await execa("launchctl", ["unload", PLIST_PATH]).catch(() => {
|
|
5094
5469
|
});
|
|
5095
5470
|
await execa("launchctl", ["load", PLIST_PATH]);
|
|
@@ -5111,9 +5486,9 @@ ${calendarEntries}
|
|
|
5111
5486
|
async function setupWindows(config) {
|
|
5112
5487
|
const { execa } = await import("execa");
|
|
5113
5488
|
const [hour, minute] = config.time.split(":").map(Number);
|
|
5114
|
-
const psScriptDir =
|
|
5115
|
-
await
|
|
5116
|
-
const psScriptPath =
|
|
5489
|
+
const psScriptDir = join18(homedir3(), ".pai");
|
|
5490
|
+
await fs21.ensureDir(psScriptDir);
|
|
5491
|
+
const psScriptPath = join18(psScriptDir, "wakeup.ps1");
|
|
5117
5492
|
const claudeCmd = config.launchMode === "yolo" ? "claude --dangerously-skip-permissions" : "claude";
|
|
5118
5493
|
const psScript = `# PAI Wakeup \u2014 Claude Code \uC138\uC158 \uC790\uB3D9 \uC2DC\uC791
|
|
5119
5494
|
$paiDir = "$env:USERPROFILE\\.pai"
|
|
@@ -5142,7 +5517,7 @@ $notifier.Show([Windows.UI.Notifications.ToastNotification]::new($xml))
|
|
|
5142
5517
|
# Open PowerShell with Claude Code
|
|
5143
5518
|
Start-Process powershell -ArgumentList "-NoExit", "-Command", "Get-Content '$todayFile'; Write-Host ''; Set-Location '${config.projectDir}'; ${claudeCmd}"
|
|
5144
5519
|
`;
|
|
5145
|
-
await
|
|
5520
|
+
await fs21.writeFile(psScriptPath, psScript, "utf8");
|
|
5146
5521
|
const daysMap = {
|
|
5147
5522
|
"\uD3C9\uC77C": "MON,TUE,WED,THU,FRI",
|
|
5148
5523
|
"\uB9E4\uC77C": "MON,TUE,WED,THU,FRI,SAT,SUN",
|
|
@@ -5190,7 +5565,7 @@ async function disableWakeup() {
|
|
|
5190
5565
|
if (osPlatform() === "darwin") {
|
|
5191
5566
|
await execa("launchctl", ["unload", PLIST_PATH]).catch(() => {
|
|
5192
5567
|
});
|
|
5193
|
-
await
|
|
5568
|
+
await fs21.remove(PLIST_PATH).catch(() => {
|
|
5194
5569
|
});
|
|
5195
5570
|
success("launchd \uC2A4\uCF00\uC904 \uC81C\uAC70");
|
|
5196
5571
|
console.log("");
|
|
@@ -5211,14 +5586,14 @@ async function disableWakeup() {
|
|
|
5211
5586
|
} else {
|
|
5212
5587
|
await removeCronEntry();
|
|
5213
5588
|
}
|
|
5214
|
-
await
|
|
5589
|
+
await fs21.remove(CONFIG_FILE2).catch(() => {
|
|
5215
5590
|
});
|
|
5216
5591
|
console.log("");
|
|
5217
5592
|
success("\u2600\uFE0F \uC6E8\uC774\uD06C\uC5C5 \uD574\uC81C \uC644\uB8CC");
|
|
5218
5593
|
}
|
|
5219
5594
|
async function showStatus() {
|
|
5220
|
-
if (await
|
|
5221
|
-
const config = await
|
|
5595
|
+
if (await fs21.pathExists(CONFIG_FILE2)) {
|
|
5596
|
+
const config = await fs21.readJson(CONFIG_FILE2);
|
|
5222
5597
|
console.log("");
|
|
5223
5598
|
success("\u2600\uFE0F \uC6E8\uC774\uD06C\uC5C5 \uD65C\uC131\uD654");
|
|
5224
5599
|
console.log(` \uC2DC\uAC04 ${chalk7.white(config.time)}`);
|
|
@@ -5226,7 +5601,7 @@ async function showStatus() {
|
|
|
5226
5601
|
console.log(` \uD504\uB85C\uC81D\uD2B8 ${chalk7.white(config.projectDir)}`);
|
|
5227
5602
|
console.log(` \uBAA8\uB4DC ${chalk7.white(config.launchMode === "yolo" ? "claude-YOLO mode" : "\uC77C\uBC18 \uBAA8\uB4DC")}`);
|
|
5228
5603
|
if (osPlatform() === "darwin") {
|
|
5229
|
-
const plistExists = await
|
|
5604
|
+
const plistExists = await fs21.pathExists(PLIST_PATH);
|
|
5230
5605
|
console.log(` launchd ${plistExists ? chalk7.green("\uD65C\uC131") : chalk7.red("\uBE44\uD65C\uC131")}`);
|
|
5231
5606
|
}
|
|
5232
5607
|
console.log("");
|
|
@@ -5379,7 +5754,7 @@ fi
|
|
|
5379
5754
|
|
|
5380
5755
|
echo "[$(date)] PAI Wakeup completed" >> "$LOG_FILE"
|
|
5381
5756
|
`;
|
|
5382
|
-
await
|
|
5757
|
+
await fs21.writeFile(SCRIPT_FILE, script, { mode: 493 });
|
|
5383
5758
|
}
|
|
5384
5759
|
var PAI_DIR2, CONFIG_FILE2, MESSAGES_FILE, SCRIPT_FILE, PLIST_NAME, PLIST_PATH, CRON_MARKER, MESSAGES;
|
|
5385
5760
|
var init_wakeup_cmd = __esm({
|
|
@@ -5387,12 +5762,12 @@ var init_wakeup_cmd = __esm({
|
|
|
5387
5762
|
"use strict";
|
|
5388
5763
|
init_ui();
|
|
5389
5764
|
init_logger();
|
|
5390
|
-
PAI_DIR2 =
|
|
5391
|
-
CONFIG_FILE2 =
|
|
5392
|
-
MESSAGES_FILE =
|
|
5393
|
-
SCRIPT_FILE =
|
|
5765
|
+
PAI_DIR2 = join18(homedir3(), ".pai");
|
|
5766
|
+
CONFIG_FILE2 = join18(PAI_DIR2, "wakeup-config.json");
|
|
5767
|
+
MESSAGES_FILE = join18(PAI_DIR2, "wakeup-messages.json");
|
|
5768
|
+
SCRIPT_FILE = join18(PAI_DIR2, "wakeup.sh");
|
|
5394
5769
|
PLIST_NAME = "com.pai.wakeup";
|
|
5395
|
-
PLIST_PATH =
|
|
5770
|
+
PLIST_PATH = join18(homedir3(), "Library", "LaunchAgents", `${PLIST_NAME}.plist`);
|
|
5396
5771
|
CRON_MARKER = "# PAI-WAKEUP";
|
|
5397
5772
|
MESSAGES = [
|
|
5398
5773
|
`Here's to the crazy ones. The misfits. The rebels. The troublemakers.
|