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