pai-zero 0.7.15 → 0.9.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 CHANGED
@@ -1,6 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  var __defProp = Object.defineProperty;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
5
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
6
+ }) : x)(function(x) {
7
+ if (typeof require !== "undefined") return require.apply(this, arguments);
8
+ throw Error('Dynamic require of "' + x + '" is not supported');
9
+ });
4
10
  var __esm = (fn, res) => function __init() {
5
11
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
12
  };
@@ -614,6 +620,18 @@ This project uses PAI (Plugin-based AI) for structured AI development.
614
620
  - **Config**: \`.pai/config.json\`
615
621
 
616
622
  Run \`pai env status\` to check setup, \`pai evaluate\` for quality scoring.
623
+
624
+ ### Global Rules
625
+
626
+ - **\uC2EC\uCE35 \uC778\uD130\uBDF0 \uC790\uB3D9 \uC218\uD589**: \uCEE8\uD14D\uC2A4\uD2B8\uAC00 \uBD80\uC871\uD558\uAC70\uB098 \uBAA8\uD638\uD55C \uACBD\uC6B0, AskUserQuestion \uB3C4\uAD6C\uB97C \uC0AC\uC6A9\uD558\uC5EC \uC2EC\uCE35 \uC778\uD130\uBDF0\uB97C \uC790\uB3D9\uC73C\uB85C \uC9C4\uD589\uD569\uB2C8\uB2E4. \uCD94\uCE21\uD558\uC9C0 \uB9D0\uACE0 \uBC18\uB4DC\uC2DC \uC9C8\uBB38\uD558\uC138\uC694.
627
+ - **Ideation \u2192 PRD \uD30C\uC774\uD504\uB77C\uC778**: \`/pai design\` \uC2E4\uD589 \uC2DC ideation.md \u2192 openspec.md \uC21C\uC11C\uB85C \uC2EC\uCE35 \uC778\uD130\uBDF0\uB97C \uD1B5\uD574 \uC791\uC131\uD569\uB2C8\uB2E4.
628
+ - **\uAE30\uC220 \uC81C\uC57D \uD30C\uC545**: \uCF54\uB4DC \uC0DD\uC131 \uC804 \uAE30\uC220\uC801 \uC81C\uC57D \uC0AC\uD56D\uC744 \uC2EC\uCE35 \uC778\uD130\uBDF0\uB85C \uD655\uC778\uD569\uB2C8\uB2E4.
629
+ - **\uD558\uB124\uC2A4 \uC5D4\uC9C0\uB2C8\uC5B4\uB9C1**: AI \uC5D0\uC774\uC804\uD2B8\uAC00 \uC548\uC804\uD558\uAC8C \uC791\uC5C5\uD560 \uC218 \uC788\uB3C4\uB85D \uD14C\uC2A4\uD2B8/\uAC80\uC99D \uD658\uACBD\uC744 \uAD6C\uC131\uD569\uB2C8\uB2E4.
630
+ - **Git \uCEE4\uBC0B \uADDC\uCE59**: \uC791\uC5C5 \uB2E8\uC704\uBCC4\uB85C \uC758\uBBF8 \uC788\uB294 \uCEE4\uBC0B \uBA54\uC2DC\uC9C0\uB97C \uC791\uC131\uD569\uB2C8\uB2E4.
631
+
632
+ ### Contribution Guide
633
+
634
+ \uAE30\uC5EC\uC790\uB294 \`CONTRIBUTING.md\`\uB97C \uCC38\uACE0\uD558\uC138\uC694. \uC774 \uAC00\uC774\uB4DC\uB294 \`.claude/skills/\`\uC5D0 \uC2A4\uD0AC\uB85C \uB4F1\uB85D\uB418\uC5B4 \uC790\uB3D9 \uC801\uC6A9\uB429\uB2C8\uB2E4.
617
635
  </pai>
618
636
  `;
619
637
  return {
@@ -805,8 +823,12 @@ var platform_exports = {};
805
823
  __export(platform_exports, {
806
824
  diagnoseWindowsEnv: () => diagnoseWindowsEnv,
807
825
  getPlatformInfo: () => getPlatformInfo,
826
+ getShellRcPath: () => getShellRcPath,
827
+ getYoloAliasLine: () => getYoloAliasLine,
828
+ hasYoloAlias: () => hasYoloAlias,
808
829
  isMac: () => isMac,
809
830
  isWindows: () => isWindows,
831
+ spawnSubshell: () => spawnSubshell,
810
832
  writeEnvFile: () => writeEnvFile
811
833
  });
812
834
  import os from "os";
@@ -849,6 +871,41 @@ function getPlatformInfo() {
849
871
  nodeVersion: process.version
850
872
  };
851
873
  }
874
+ function getShellRcPath() {
875
+ const home = os.homedir();
876
+ if (isWindows) {
877
+ const ps7 = __require("path").join(home, "Documents", "PowerShell", "Microsoft.PowerShell_profile.ps1");
878
+ const ps5 = __require("path").join(home, "Documents", "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1");
879
+ if (fs3.existsSync(__require("path").dirname(ps7))) return ps7;
880
+ return ps5;
881
+ }
882
+ const shell = process.env["SHELL"] || "";
883
+ return shell.includes("zsh") ? __require("path").join(home, ".zshrc") : __require("path").join(home, ".bashrc");
884
+ }
885
+ function spawnSubshell(cwd) {
886
+ const { execFileSync } = __require("child_process");
887
+ try {
888
+ if (isWindows) {
889
+ execFileSync("powershell.exe", ["-NoExit", "-Command", `Set-Location '${cwd}'`], {
890
+ stdio: "inherit",
891
+ cwd
892
+ });
893
+ } else {
894
+ const shell = process.env["SHELL"] || "/bin/zsh";
895
+ execFileSync(shell, ["-l"], { stdio: "inherit", cwd });
896
+ }
897
+ } catch {
898
+ }
899
+ }
900
+ function getYoloAliasLine() {
901
+ if (isWindows) {
902
+ return "function claude-yolo { claude --dangerously-skip-permissions @args }";
903
+ }
904
+ return "alias claude-yolo='claude --dangerously-skip-permissions'";
905
+ }
906
+ function hasYoloAlias(rcContent) {
907
+ return rcContent.includes("claude-yolo") || rcContent.includes("dangerously-skip-permissions");
908
+ }
852
909
  var isWindows, isMac;
853
910
  var init_platform = __esm({
854
911
  "src/utils/platform.ts"() {
@@ -888,30 +945,147 @@ async function provisionGitHub(ctx) {
888
945
  `> \uB9C8\uC9C0\uB9C9 \uC5C5\uB370\uC774\uD2B8: ${now}`,
889
946
  "",
890
947
  "## \uC9C4\uD589 \uC911",
891
- `- [ ] PRD \uBB38\uC11C \uC791\uC131 \u2014 \`/pai design\` \uC2E4\uD589 \uB610\uB294 \`docs/openspec.md\` \uC9C1\uC811 \uD3B8\uC9D1 (\uB2F4\uB2F9: PAI > Design)`,
948
+ "- [ ] Ideation \uBB38\uC11C \uC791\uC131 \u2014 \uC2EC\uCE35 \uC778\uD130\uBDF0\uB97C \uD1B5\uD574 \uC544\uC774\uB514\uC5B4\uB97C \uAD6C\uCCB4\uD654 (\uB2F4\uB2F9: PAI > Design)",
892
949
  "",
893
950
  "## \uB2E4\uC74C \uB2E8\uACC4",
894
- "- [ ] PRD \uC644\uC131 \uD6C4 AI \uCF54\uB4DC \uC0DD\uC131 \uC2DC\uC791",
951
+ "- [ ] Ideation \uAE30\uBC18 PRD \uC791\uC131 \u2014 \uC2EC\uCE35 \uC778\uD130\uBDF0\uB85C \uB9E5\uB77D/\uAE30\uC220 \uC81C\uC57D \uBCF4\uAC15",
952
+ "- [ ] \uD558\uB124\uC2A4 \uC5D4\uC9C0\uB2C8\uC5B4\uB9C1 \uAD6C\uC131 \uD655\uC778 \u2014 \uC5D0\uC774\uC804\uD2B8 \uC791\uC5C5 \uD658\uACBD \uAC80\uC99D",
953
+ "- [ ] AI \uCF54\uB4DC \uC0DD\uC131 \uC2DC\uC791",
895
954
  "",
896
955
  "## \uC644\uB8CC",
897
956
  `- [x] \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654 (${now}) (\uB2F4\uB2F9: PAI > Environment)`,
898
957
  "",
958
+ "## \uC791\uC5C5 \uD30C\uC774\uD504\uB77C\uC778",
959
+ "```",
960
+ "1. /pai design \u2192 Ideation \uC2EC\uCE35 \uC778\uD130\uBDF0 \u2192 docs/ideation.md \uC0DD\uC131",
961
+ "2. /pai design \u2192 PRD \uC2EC\uCE35 \uC778\uD130\uBDF0 \u2192 docs/openspec.md \uC791\uC131",
962
+ "3. /pai design \u2192 \uAE30\uC220 \uC81C\uC57D \uC2EC\uCE35 \uC778\uD130\uBDF0 \u2192 \uD558\uB124\uC2A4 \uC5D4\uC9C0\uB2C8\uC5B4\uB9C1 \uD655\uC778",
963
+ "4. AI \uCF54\uB4DC \uC0DD\uC131 \u2192 \uAC80\uC99D \u2192 \uD3C9\uAC00",
964
+ "```",
965
+ "",
899
966
  "## \uBA54\uBAA8",
900
967
  `- \uBAA8\uB4DC: ${ctx.mode}`,
901
- "- Claude Code \uC2DC\uC791 \uD6C4 \uCCAB \uC791\uC5C5: `/pai design` \uC73C\uB85C PRD \uC791\uC131"
968
+ "- \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
+ ].join("\n") + "\n");
970
+ }
971
+ const contribPath = join3(ctx.cwd, "CONTRIBUTING.md");
972
+ if (!await fs4.pathExists(contribPath)) {
973
+ await fs4.writeFile(contribPath, [
974
+ `# Contributing to ${ctx.projectName}`,
975
+ "",
976
+ "\uC774 \uD504\uB85C\uC81D\uD2B8\uC5D0 \uAE30\uC5EC\uD574 \uC8FC\uC154\uC11C \uAC10\uC0AC\uD569\uB2C8\uB2E4.",
977
+ "",
978
+ "## \uAC1C\uBC1C \uD658\uACBD \uC124\uC815",
979
+ "",
980
+ "```bash",
981
+ "git clone <repo-url>",
982
+ "cd " + ctx.projectName,
983
+ "npm install",
984
+ "```",
985
+ "",
986
+ "## \uBE0C\uB79C\uCE58 \uADDC\uCE59",
987
+ "",
988
+ "- `main` \u2014 \uC548\uC815 \uBC84\uC804",
989
+ "- `feat/<\uAE30\uB2A5\uBA85>` \u2014 \uC0C8 \uAE30\uB2A5 \uAC1C\uBC1C",
990
+ "- `fix/<\uC774\uC288\uBC88\uD638>` \u2014 \uBC84\uADF8 \uC218\uC815",
991
+ "",
992
+ "## \uCEE4\uBC0B \uBA54\uC2DC\uC9C0",
993
+ "",
994
+ "```",
995
+ "feat: \uC0C8 \uAE30\uB2A5 \uCD94\uAC00",
996
+ "fix: \uBC84\uADF8 \uC218\uC815",
997
+ "docs: \uBB38\uC11C \uC218\uC815",
998
+ "refactor: \uB9AC\uD329\uD1A0\uB9C1",
999
+ "test: \uD14C\uC2A4\uD2B8 \uCD94\uAC00/\uC218\uC815",
1000
+ "```",
1001
+ "",
1002
+ "## PR \uD504\uB85C\uC138\uC2A4",
1003
+ "",
1004
+ "1. \uBE0C\uB79C\uCE58 \uC0DD\uC131 \u2192 \uC791\uC5C5 \u2192 \uCEE4\uBC0B",
1005
+ "2. `npm test` \uB85C \uD14C\uC2A4\uD2B8 \uD1B5\uACFC \uD655\uC778",
1006
+ "3. PR \uC0DD\uC131 \u2014 \uBCC0\uACBD \uC0AC\uD56D \uC694\uC57D \uC791\uC131",
1007
+ "4. \uB9AC\uBDF0 \uD6C4 \uBA38\uC9C0",
1008
+ "",
1009
+ "## AI \uD611\uC5C5 \uADDC\uCE59",
1010
+ "",
1011
+ "- `CLAUDE.md` \uB97C \uC77D\uACE0 \uD504\uB85C\uC81D\uD2B8 \uCEE8\uD14D\uC2A4\uD2B8\uB97C \uD30C\uC545\uD558\uC138\uC694",
1012
+ "- `/pai evaluate` \uB85C AI \uC900\uBE44\uB3C4\uB97C \uD655\uC778\uD558\uC138\uC694",
1013
+ "- \uCEE8\uD14D\uC2A4\uD2B8\uAC00 \uBD80\uC871\uD558\uBA74 \uCD94\uCE21\uD558\uC9C0 \uB9D0\uACE0 \uC9C8\uBB38\uD558\uC138\uC694",
1014
+ ""
1015
+ ].join("\n") + "\n");
1016
+ }
1017
+ const contribSkillDir = join3(ctx.cwd, ".claude", "skills");
1018
+ await fs4.ensureDir(contribSkillDir);
1019
+ const contribSkillPath = join3(contribSkillDir, "contributing.md");
1020
+ if (!await fs4.pathExists(contribSkillPath)) {
1021
+ await fs4.writeFile(contribSkillPath, [
1022
+ "---",
1023
+ "name: contributing",
1024
+ '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"',
1025
+ "---",
1026
+ "",
1027
+ "# Contributing Guide",
1028
+ "",
1029
+ "\uD504\uB85C\uC81D\uD2B8 \uAE30\uC5EC \uC2DC `CONTRIBUTING.md`\uC758 \uADDC\uCE59\uC744 \uC790\uB3D9\uC73C\uB85C \uC801\uC6A9\uD569\uB2C8\uB2E4.",
1030
+ "",
1031
+ "## \uC790\uB3D9 \uC801\uC6A9 \uADDC\uCE59",
1032
+ "",
1033
+ "1. **\uBE0C\uB79C\uCE58**: `feat/`, `fix/`, `docs/`, `refactor/`, `test/` \uC811\uB450\uC0AC \uC0AC\uC6A9",
1034
+ "2. **\uCEE4\uBC0B**: `feat:`, `fix:`, `docs:`, `refactor:`, `test:` \uD615\uC2DD",
1035
+ "3. **PR**: \uBCC0\uACBD \uC0AC\uD56D \uC694\uC57D \uD544\uC218",
1036
+ "4. **\uD14C\uC2A4\uD2B8**: PR \uC804 `npm test` \uD1B5\uACFC \uD544\uC218",
1037
+ "",
1038
+ "## \uC791\uC5C5 \uC2DC \uD655\uC778",
1039
+ "",
1040
+ "- `CONTRIBUTING.md` \uB97C \uC77D\uACE0 \uADDC\uCE59\uC744 \uB530\uB974\uC138\uC694",
1041
+ "- \uCEE4\uBC0B \uBA54\uC2DC\uC9C0\uAC00 \uADDC\uCE59\uC5D0 \uB9DE\uB294\uC9C0 \uD655\uC778\uD558\uC138\uC694",
1042
+ "- PR \uC0DD\uC131 \uC2DC \uBCC0\uACBD \uC0AC\uD56D\uC744 \uC694\uC57D\uD558\uC138\uC694",
1043
+ ""
902
1044
  ].join("\n") + "\n");
903
1045
  }
904
1046
  const gitignorePath = join3(ctx.cwd, ".gitignore");
905
1047
  if (!await fs4.pathExists(gitignorePath)) {
906
1048
  await fs4.writeFile(gitignorePath, [
1049
+ "# Dependencies",
907
1050
  "node_modules/",
1051
+ "",
1052
+ "# Environment",
1053
+ ".env",
908
1054
  ".env.local",
909
1055
  ".env*.local",
1056
+ "",
1057
+ "# Build",
1058
+ "dist/",
1059
+ "build/",
1060
+ ".next/",
1061
+ "out/",
1062
+ "",
1063
+ "# Services",
910
1064
  ".vercel",
911
1065
  ".supabase",
912
- "dist/",
1066
+ "",
1067
+ "# OS",
913
1068
  ".DS_Store",
914
- "Thumbs.db"
1069
+ "Thumbs.db",
1070
+ "",
1071
+ "# IDE",
1072
+ ".idea/",
1073
+ ".vscode/settings.json",
1074
+ "*.swp",
1075
+ "*.swo",
1076
+ "",
1077
+ "# PAI / OMC state",
1078
+ ".omc/state/",
1079
+ ".omc/sessions/",
1080
+ ".omc/logs/",
1081
+ "",
1082
+ "# Logs",
1083
+ "*.log",
1084
+ "npm-debug.log*",
1085
+ "",
1086
+ "# Windows",
1087
+ "desktop.ini",
1088
+ "$RECYCLE.BIN/"
915
1089
  ].join("\n") + "\n");
916
1090
  }
917
1091
  }
@@ -1332,30 +1506,74 @@ PAI Doctor \u2014 \uD658\uACBD \uC9C4\uB2E8
1332
1506
  `,
1333
1507
  "design.md": `---
1334
1508
  name: "PAI: Design"
1335
- description: "OpenSpec PRD / OMC \uB3C4\uBA54\uC778 \uBAA8\uB378 \uC0DD\uC131 \uBC0F \uAC80\uC99D"
1509
+ description: "Ideation \u2192 PRD \u2192 \uD558\uB124\uC2A4 \uAD6C\uC131\uAE4C\uC9C0 \uC2EC\uCE35 \uC778\uD130\uBDF0 \uAE30\uBC18 \uC124\uACC4"
1336
1510
  ---
1337
1511
 
1338
- # PAI \uC124\uACC4 \uAD00\uB9AC
1512
+ # PAI \uC124\uACC4 \u2014 \uC2EC\uCE35 \uC778\uD130\uBDF0 \uAE30\uBC18 \uD30C\uC774\uD504\uB77C\uC778
1339
1513
 
1340
1514
  ## \uC778\uC790: $ARGUMENTS
1341
- - \uC778\uC790 \uC5C6\uC74C \uB610\uB294 \`init\` \u2192 \uD15C\uD50C\uB9BF \uC0DD\uC131 + \uAC80\uC99D
1515
+ - \uC778\uC790 \uC5C6\uC74C \u2192 \uC804\uCCB4 \uD30C\uC774\uD504\uB77C\uC778 (Ideation \u2192 PRD \u2192 \uD558\uB124\uC2A4)
1516
+ - \`ideation\` \u2192 Ideation\uB9CC \uC218\uD589
1517
+ - \`prd\` \u2192 PRD\uB9CC \uC218\uD589
1342
1518
  - \`validate\` \u2192 \uAC80\uC99D\uB9CC \uC218\uD589
1343
1519
 
1344
- ## \uC218\uD589\uD560 \uC791\uC5C5
1520
+ ## Phase 1: Ideation (\uC544\uC774\uB514\uC5B4 \uAD6C\uCCB4\uD654)
1521
+
1522
+ **\uBAA9\uD45C**: \uC0AC\uC6A9\uC790\uC758 \uBA38\uB9BF\uC18D \uC544\uC774\uB514\uC5B4\uB97C \`docs/ideation.md\`\uB85C \uAD6C\uCCB4\uD654
1345
1523
 
1346
- ### \uD15C\uD50C\uB9BF \uC0DD\uC131 (init)
1347
- \`docs/openspec.md\`\uC640 \`.pai/omc.md\`\uAC00 \uC5C6\uC73C\uBA74 \uD15C\uD50C\uB9BF\uC744 \uC0DD\uC131\uD558\uC138\uC694.
1348
- \uC774\uBBF8 \uC874\uC7AC\uD558\uBA74 \uAC74\uB108\uB6F0\uC138\uC694.
1524
+ AskUserQuestion \uB3C4\uAD6C\uB85C \uC2EC\uCE35 \uC778\uD130\uBDF0\uB97C \uC9C4\uD589\uD558\uC138\uC694:
1525
+ 1. "\uC5B4\uB5A4 \uBB38\uC81C\uB97C \uD574\uACB0\uD558\uACE0 \uC2F6\uC73C\uC138\uC694?" \u2014 \uD575\uC2EC \uACFC\uC81C \uD30C\uC545
1526
+ 2. "\uC774 \uC11C\uBE44\uC2A4\uB97C \uC8FC\uB85C \uC0AC\uC6A9\uD560 \uC0AC\uB78C\uC740 \uB204\uAD6C\uC778\uAC00\uC694?" \u2014 \uB300\uC0C1 \uC0AC\uC6A9\uC790
1527
+ 3. "\uBE44\uC2B7\uD55C \uC11C\uBE44\uC2A4\uAC00 \uC788\uB2E4\uBA74 \uBB50\uAC00 \uB2E4\uB978\uAC00\uC694?" \u2014 \uCC28\uBCC4\uC810
1528
+ 4. "\uBC18\uB4DC\uC2DC \uC788\uC5B4\uC57C \uD560 \uAE30\uB2A5 3\uAC00\uC9C0\uB294?" \u2014 \uD575\uC2EC \uAE30\uB2A5
1529
+ 5. "\uC5B8\uC81C\uAE4C\uC9C0 \uB9CC\uB4E4\uACE0 \uC2F6\uC73C\uC138\uC694?" \u2014 \uC77C\uC815 \uC81C\uC57D
1349
1530
 
1350
- ### \uAC80\uC99D (validate)
1351
- \`docs/openspec.md\`\uB97C \uC77D\uACE0 5\uAC1C \uC139\uC158 \uC644\uC131\uB3C4\uB97C \uAC80\uC99D\uD558\uC138\uC694:
1352
- 1. \uBAA9\uC801 (Purpose) \u2014 \uAD6C\uCCB4\uC801 \uC124\uBA85 \uC788\uB294\uAC00?
1353
- 2. \uC0AC\uC6A9\uC790 (Users) \u2014 \uCD5C\uC18C 1\uAC1C \uC5ED\uD560 \uC815\uC758?
1354
- 3. \uD575\uC2EC \uAE30\uB2A5 (Features) \u2014 \uCD5C\uC18C 1\uAC1C \uAE30\uB2A5 \uAE30\uC220?
1355
- 4. \uAE30\uC220 \uC2A4\uD0DD (Stack) \u2014 1\uAC1C \uC774\uC0C1 \uC815\uC758?
1356
- 5. API \uC5D4\uB4DC\uD3EC\uC778\uD2B8 \u2014 \uCD5C\uC18C 1\uAC1C \uC815\uC758?
1531
+ \uB2F5\uBCC0\uC744 \uC885\uD569\uD558\uC5EC \`docs/ideation.md\`\uB97C \uC0DD\uC131\uD558\uC138\uC694.
1357
1532
 
1358
- \uBBF8\uC791\uC131 \uC139\uC158\uC740 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC548\uB0B4\uD558\uACE0, \uC6D0\uD558\uBA74 \uD568\uAED8 \uC791\uC131\uC744 \uB3C4\uC640\uC8FC\uC138\uC694.
1533
+ ## Phase 2: PRD \uC791\uC131 (\uC81C\uD488 \uC694\uAD6C\uC0AC\uD56D)
1534
+
1535
+ **\uBAA9\uD45C**: Ideation\uC744 \uAE30\uBC18\uC73C\uB85C \`docs/openspec.md\` PRD \uC791\uC131
1536
+
1537
+ \`docs/ideation.md\`\uB97C \uC77D\uACE0, \uBD80\uC871\uD55C \uB9E5\uB77D\uC740 AskUserQuestion\uC73C\uB85C \uBCF4\uAC15:
1538
+ 1. "\uAE30\uC220 \uC2A4\uD0DD \uC120\uD638\uAC00 \uC788\uC73C\uC138\uC694?" \u2014 \uD504\uB808\uC784\uC6CC\uD06C/\uC5B8\uC5B4 \uC81C\uC57D
1539
+ 2. "\uC678\uBD80 API \uC5F0\uB3D9\uC774 \uD544\uC694\uD55C\uAC00\uC694?" \u2014 \uC758\uC874\uC131 \uD30C\uC545
1540
+ 3. "\uB370\uC774\uD130\uB294 \uC5B4\uB5A4 \uAC83\uC744 \uC800\uC7A5\uD574\uC57C \uD558\uB098\uC694?" \u2014 DB \uC2A4\uD0A4\uB9C8 \uD78C\uD2B8
1541
+ 4. "\uB85C\uADF8\uC778/\uD68C\uC6D0\uAC00\uC785\uC774 \uD544\uC694\uD55C\uAC00\uC694?" \u2014 \uC778\uC99D \uBC94\uC704
1542
+
1543
+ \uB2F5\uBCC0\uC744 \uC885\uD569\uD558\uC5EC \`docs/openspec.md\` 5\uAC1C \uC139\uC158\uC744 \uC791\uC131:
1544
+ - \uBAA9\uC801 (Purpose)
1545
+ - \uC0AC\uC6A9\uC790 (Users)
1546
+ - \uD575\uC2EC \uAE30\uB2A5 (Features)
1547
+ - \uAE30\uC220 \uC2A4\uD0DD (Stack)
1548
+ - API \uC5D4\uB4DC\uD3EC\uC778\uD2B8
1549
+
1550
+ ## Phase 3: \uAE30\uC220 \uC81C\uC57D + \uD558\uB124\uC2A4 \uC5D4\uC9C0\uB2C8\uC5B4\uB9C1
1551
+
1552
+ **\uBAA9\uD45C**: AI \uC5D0\uC774\uC804\uD2B8\uAC00 \uC548\uC804\uD558\uAC8C \uC791\uC5C5\uD560 \uC218 \uC788\uB294 \uD658\uACBD \uD655\uC778
1553
+
1554
+ AskUserQuestion\uC73C\uB85C \uAE30\uC220\uC801 \uC81C\uC57D \uD30C\uC545:
1555
+ 1. "\uAE30\uC874\uC5D0 \uC0AC\uC6A9 \uC911\uC778 DB\uB098 \uC11C\uBC84\uAC00 \uC788\uB098\uC694?" \u2014 \uAE30\uC874 \uC778\uD504\uB77C
1556
+ 2. "\uBC30\uD3EC \uD658\uACBD\uC740 \uC5B4\uB514\uC778\uAC00\uC694?" \u2014 \uBC30\uD3EC \uC81C\uC57D
1557
+ 3. "\uD300\uC5D0\uC11C \uC0AC\uC6A9\uD558\uB294 \uCF54\uB529 \uADDC\uCE59\uC774 \uC788\uB098\uC694?" \u2014 \uC2A4\uD0C0\uC77C \uC81C\uC57D
1558
+
1559
+ \uD558\uB124\uC2A4 \uC5D4\uC9C0\uB2C8\uC5B4\uB9C1 \uD655\uC778:
1560
+ - \`CLAUDE.md\` \u2014 AI \uCEE8\uD14D\uC2A4\uD2B8 \uCDA9\uBD84\uD55C\uC9C0 \uAC80\uC99D
1561
+ - \`.claude/settings.json\` \u2014 \uAD8C\uD55C \uC124\uC815 \uC801\uC808\uD55C\uC9C0 \uD655\uC778
1562
+ - \uD14C\uC2A4\uD2B8 \uD658\uACBD \u2014 \`tests/\` \uB514\uB809\uD1A0\uB9AC + \uD14C\uC2A4\uD2B8 \uD504\uB808\uC784\uC6CC\uD06C \uC874\uC7AC \uD655\uC778
1563
+ - \uBD80\uC871\uD55C \uD56D\uBAA9\uC740 \uC790\uB3D9 \uC0DD\uC131 \uC81C\uC548
1564
+
1565
+ ## Phase 4: \uAC80\uC99D
1566
+
1567
+ \uBAA8\uB4E0 Phase \uC644\uB8CC \uD6C4:
1568
+ 1. \`docs/ideation.md\` \uC874\uC7AC + \uB0B4\uC6A9 \uD655\uC778
1569
+ 2. \`docs/openspec.md\` 5\uAC1C \uC139\uC158 \uC644\uC131\uB3C4 \uAC80\uC99D
1570
+ 3. \`handoff.md\` \uC5C5\uB370\uC774\uD2B8 \u2014 \uC644\uB8CC\uB41C \uD56D\uBAA9 \uCCB4\uD06C, \uB2E4\uC74C \uB2E8\uACC4 \uAC31\uC2E0
1571
+
1572
+ ## \uC911\uC694 \uC6D0\uCE59
1573
+
1574
+ - **\uCD94\uCE21 \uAE08\uC9C0**: \uCEE8\uD14D\uC2A4\uD2B8\uAC00 \uBD80\uC871\uD558\uBA74 \uBC18\uB4DC\uC2DC AskUserQuestion\uC73C\uB85C \uC9C8\uBB38
1575
+ - **\uC774\uBBF8 \uC874\uC7AC\uD558\uB294 \uD30C\uC77C \uB36E\uC5B4\uC4F0\uC9C0 \uC54A\uC74C** \u2014 \uBCF4\uAC15\uB9CC \uC81C\uC548
1576
+ - **\uAC01 Phase \uC644\uB8CC \uC2DC \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uACB0\uACFC \uC694\uC57D** \uBCF4\uACE0
1359
1577
  `,
1360
1578
  "validate.md": `---
1361
1579
  name: "PAI: Validate"
@@ -2678,9 +2896,14 @@ async function requestCdAfter(targetDir) {
2678
2896
  }
2679
2897
  async function installShellHelper() {
2680
2898
  await fs10.ensureDir(PAI_DIR);
2681
- await fs10.writeFile(HELPER_FILE, SHELL_HELPER);
2682
- const shellName = process.env.SHELL || "/bin/zsh";
2683
- const rcFile = shellName.includes("zsh") ? join7(homedir2(), ".zshrc") : join7(homedir2(), ".bashrc");
2899
+ if (isWindows) {
2900
+ return installPowerShellHelper();
2901
+ }
2902
+ return installBashHelper();
2903
+ }
2904
+ async function installBashHelper() {
2905
+ await fs10.writeFile(HELPER_FILE_SH, BASH_HELPER);
2906
+ const rcFile = getShellRcPath();
2684
2907
  const sourceLine = 'source "$HOME/.pai/shell-helper.sh"';
2685
2908
  if (await fs10.pathExists(rcFile)) {
2686
2909
  const content = await fs10.readFile(rcFile, "utf8");
@@ -2697,15 +2920,36 @@ ${sourceLine}
2697
2920
  `);
2698
2921
  return false;
2699
2922
  }
2700
- var PAI_DIR, CD_FILE, HELPER_FILE, SHELL_HELPER;
2923
+ async function installPowerShellHelper() {
2924
+ await fs10.writeFile(HELPER_FILE_PS1, POWERSHELL_HELPER);
2925
+ const rcFile = getShellRcPath();
2926
+ const sourceLine = '. "$env:USERPROFILE\\.pai\\shell-helper.ps1"';
2927
+ await fs10.ensureDir(join7(rcFile, ".."));
2928
+ if (await fs10.pathExists(rcFile)) {
2929
+ const content = await fs10.readFile(rcFile, "utf8");
2930
+ if (content.includes("shell-helper.ps1")) {
2931
+ return true;
2932
+ }
2933
+ await fs10.appendFile(rcFile, `
2934
+ # PAI \u2014 \uC790\uB3D9 \uB514\uB809\uD1A0\uB9AC \uC774\uB3D9
2935
+ ${sourceLine}
2936
+ `);
2937
+ return false;
2938
+ }
2939
+ await fs10.writeFile(rcFile, `${sourceLine}
2940
+ `);
2941
+ return false;
2942
+ }
2943
+ var PAI_DIR, CD_FILE, HELPER_FILE_SH, HELPER_FILE_PS1, BASH_HELPER, POWERSHELL_HELPER;
2701
2944
  var init_shell_cd = __esm({
2702
2945
  "src/utils/shell-cd.ts"() {
2703
2946
  "use strict";
2947
+ init_platform();
2704
2948
  PAI_DIR = join7(homedir2(), ".pai");
2705
2949
  CD_FILE = join7(PAI_DIR, ".cd-after");
2706
- HELPER_FILE = join7(PAI_DIR, "shell-helper.sh");
2707
- SHELL_HELPER = `# PAI shell helper \u2014 \uC790\uB3D9 \uB514\uB809\uD1A0\uB9AC \uC774\uB3D9 \uC9C0\uC6D0
2708
- # pai \uBA85\uB839 \uC2E4\uD589 \uD6C4 .cd-after \uD30C\uC77C\uC774 \uC788\uC73C\uBA74 \uC790\uB3D9\uC73C\uB85C cd
2950
+ HELPER_FILE_SH = join7(PAI_DIR, "shell-helper.sh");
2951
+ HELPER_FILE_PS1 = join7(PAI_DIR, "shell-helper.ps1");
2952
+ BASH_HELPER = `# PAI shell helper \u2014 \uC790\uB3D9 \uB514\uB809\uD1A0\uB9AC \uC774\uB3D9 \uC9C0\uC6D0
2709
2953
  pai() {
2710
2954
  local cd_target="$HOME/.pai/.cd-after"
2711
2955
  rm -f "$cd_target"
@@ -2722,6 +2966,24 @@ pai() {
2722
2966
  fi
2723
2967
  return $exit_code
2724
2968
  }
2969
+ `;
2970
+ POWERSHELL_HELPER = `# PAI shell helper \u2014 \uC790\uB3D9 \uB514\uB809\uD1A0\uB9AC \uC774\uB3D9 \uC9C0\uC6D0
2971
+ function pai {
2972
+ $cdTarget = Join-Path $env:USERPROFILE '.pai\\.cd-after'
2973
+ Remove-Item $cdTarget -ErrorAction SilentlyContinue
2974
+ $env:PAI_CD_AFTER = $cdTarget
2975
+ & npx pai-zero @args
2976
+ $exitCode = $LASTEXITCODE
2977
+ if (Test-Path $cdTarget) {
2978
+ $dir = Get-Content $cdTarget -Raw
2979
+ Remove-Item $cdTarget -ErrorAction SilentlyContinue
2980
+ if ($dir -and (Test-Path $dir)) {
2981
+ Set-Location $dir
2982
+ Write-Host " -> cd $dir"
2983
+ }
2984
+ }
2985
+ return $exitCode
2986
+ }
2725
2987
  `;
2726
2988
  }
2727
2989
  });
@@ -3234,16 +3496,16 @@ async function showCompletion(projectName, projectDir, extraTools, isCurrentDir)
3234
3496
  success("\uC774\uC81C Claude Code\uC640 \uD568\uAED8 PRD \uBB38\uC11C\uB97C \uC791\uC131\uD558\uC138\uC694.");
3235
3497
  console.log("");
3236
3498
  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"));
3237
- const { homedir: homedir4 } = await import("os");
3238
- const shellRc = join10(homedir4(), process.env.SHELL?.includes("zsh") ? ".zshrc" : ".bashrc");
3239
- let hasYoloAlias = false;
3499
+ const { getShellRcPath: getShellRcPath2, hasYoloAlias: checkYolo } = await Promise.resolve().then(() => (init_platform(), platform_exports));
3500
+ const shellRc = getShellRcPath2();
3501
+ let hasYoloAliasSet = false;
3240
3502
  try {
3241
3503
  const rcContent = await fs12.readFile(shellRc, "utf8");
3242
- hasYoloAlias = rcContent.includes("claude-yolo") || rcContent.includes("dangerously-skip-permissions");
3504
+ hasYoloAliasSet = checkYolo(rcContent);
3243
3505
  } catch {
3244
3506
  }
3245
3507
  let useYolo = false;
3246
- if (!hasYoloAlias) {
3508
+ if (!hasYoloAliasSet) {
3247
3509
  console.log("");
3248
3510
  const { mode } = await inquirer.prompt([{
3249
3511
  type: "list",
@@ -3256,10 +3518,12 @@ async function showCompletion(projectName, projectDir, extraTools, isCurrentDir)
3256
3518
  }]);
3257
3519
  if (mode === "yolo") {
3258
3520
  useYolo = true;
3259
- const aliasLine = "alias claude-yolo='claude --dangerously-skip-permissions'";
3521
+ const { getYoloAliasLine: getYoloAliasLine2 } = await Promise.resolve().then(() => (init_platform(), platform_exports));
3522
+ const aliasLine = getYoloAliasLine2();
3260
3523
  try {
3261
3524
  const rcContent = await fs12.readFile(shellRc, "utf8").catch(() => "");
3262
3525
  if (!rcContent.includes("claude-yolo")) {
3526
+ await fs12.ensureDir(join10(shellRc, ".."));
3263
3527
  await fs12.appendFile(shellRc, `
3264
3528
  # PAI \u2014 claude-YOLO mode
3265
3529
  ${aliasLine}
@@ -3291,12 +3555,8 @@ ${aliasLine}
3291
3555
  hint("claude \uB97C \uC785\uB825\uD558\uBA74 \uC2DC\uC791\uB429\uB2C8\uB2E4.");
3292
3556
  console.log("");
3293
3557
  if (!isCurrentDir) {
3294
- try {
3295
- const { execFileSync } = await import("child_process");
3296
- const shell = process.env.SHELL || "/bin/zsh";
3297
- execFileSync(shell, ["-l"], { stdio: "inherit", cwd: projectDir });
3298
- } catch {
3299
- }
3558
+ const { spawnSubshell: spawnSubshell2 } = await Promise.resolve().then(() => (init_platform(), platform_exports));
3559
+ spawnSubshell2(projectDir);
3300
3560
  }
3301
3561
  return;
3302
3562
  }
@@ -3345,12 +3605,8 @@ ${aliasLine}
3345
3605
  cwd: projectDir
3346
3606
  });
3347
3607
  if (!isCurrentDir) {
3348
- try {
3349
- const { execFileSync } = await import("child_process");
3350
- const shell = process.env.SHELL || "/bin/zsh";
3351
- execFileSync(shell, ["-l"], { stdio: "inherit", cwd: projectDir });
3352
- } catch {
3353
- }
3608
+ const { spawnSubshell: spawnSubshell2 } = await Promise.resolve().then(() => (init_platform(), platform_exports));
3609
+ spawnSubshell2(projectDir);
3354
3610
  }
3355
3611
  } catch {
3356
3612
  warn(`\uC2E4\uD589 \uC2E4\uD328. \uC9C1\uC811 \uC785\uB825\uD558\uC138\uC694: ${cmd}`);
@@ -4359,12 +4615,8 @@ async function removeCommand(cwd, options) {
4359
4615
  } else {
4360
4616
  console.log("");
4361
4617
  success(`\u2192 cd .. ${colors.dim("\uC0C1\uC704 \uD3F4\uB354\uB85C \uC774\uB3D9")}`);
4362
- try {
4363
- const { execFileSync } = await import("child_process");
4364
- const shell = process.env.SHELL || "/bin/zsh";
4365
- execFileSync(shell, ["-l"], { stdio: "inherit", cwd: parentDir });
4366
- } catch {
4367
- }
4618
+ const { spawnSubshell: spawnSubshell2 } = await Promise.resolve().then(() => (init_platform(), platform_exports));
4619
+ spawnSubshell2(parentDir);
4368
4620
  }
4369
4621
  }
4370
4622
  var init_remove_cmd = __esm({
@@ -4774,6 +5026,8 @@ async function wakeupCommand(timeOrAction, schedule = "\uD3C9\uC77C") {
4774
5026
  await createWakeupScript(config);
4775
5027
  if (osPlatform() === "darwin") {
4776
5028
  await setupMacOS(config);
5029
+ } else if (osPlatform() === "win32") {
5030
+ await setupWindows(config);
4777
5031
  } else {
4778
5032
  await setupLinux(config);
4779
5033
  }
@@ -4854,6 +5108,70 @@ ${calendarEntries}
4854
5108
  hint(`\uC218\uB3D9 \uC124\uC815: sudo pmset repeat wakeorpoweron ${pmsetDays} ${config.time}:00`);
4855
5109
  }
4856
5110
  }
5111
+ async function setupWindows(config) {
5112
+ const { execa } = await import("execa");
5113
+ const [hour, minute] = config.time.split(":").map(Number);
5114
+ const psScriptDir = join17(homedir3(), ".pai");
5115
+ await fs20.ensureDir(psScriptDir);
5116
+ const psScriptPath = join17(psScriptDir, "wakeup.ps1");
5117
+ const claudeCmd = config.launchMode === "yolo" ? "claude --dangerously-skip-permissions" : "claude";
5118
+ const psScript = `# PAI Wakeup \u2014 Claude Code \uC138\uC158 \uC790\uB3D9 \uC2DC\uC791
5119
+ $paiDir = "$env:USERPROFILE\\.pai"
5120
+ $msgFile = Join-Path $paiDir "wakeup-messages.json"
5121
+ $todayFile = Join-Path $paiDir "wakeup-today.txt"
5122
+
5123
+ # Pick random message
5124
+ try {
5125
+ $msgs = Get-Content $msgFile -Raw | ConvertFrom-Json
5126
+ $msg = $msgs[(Get-Random -Maximum $msgs.Count)]
5127
+ } catch {
5128
+ $msg = "Make it work, make it right, make it fast. \u2014 Kent Beck"
5129
+ }
5130
+ Set-Content -Path $todayFile -Value $msg
5131
+
5132
+ # Windows notification
5133
+ [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
5134
+ $template = [Windows.UI.Notifications.ToastTemplateType]::ToastText02
5135
+ $xml = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent($template)
5136
+ $text = $xml.GetElementsByTagName("text")
5137
+ $text[0].AppendChild($xml.CreateTextNode("PAI Wakeup")) | Out-Null
5138
+ $text[1].AppendChild($xml.CreateTextNode($msg.Substring(0, [Math]::Min(100, $msg.Length)))) | Out-Null
5139
+ $notifier = [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier("PAI")
5140
+ $notifier.Show([Windows.UI.Notifications.ToastNotification]::new($xml))
5141
+
5142
+ # Open PowerShell with Claude Code
5143
+ Start-Process powershell -ArgumentList "-NoExit", "-Command", "Get-Content '$todayFile'; Write-Host ''; Set-Location '${config.projectDir}'; ${claudeCmd}"
5144
+ `;
5145
+ await fs20.writeFile(psScriptPath, psScript, "utf8");
5146
+ const daysMap = {
5147
+ "\uD3C9\uC77C": "MON,TUE,WED,THU,FRI",
5148
+ "\uB9E4\uC77C": "MON,TUE,WED,THU,FRI,SAT,SUN",
5149
+ "\uC8FC\uB9D0": "SAT,SUN"
5150
+ };
5151
+ const days = daysMap[config.schedule] || daysMap["\uD3C9\uC77C"];
5152
+ await execa("schtasks", ["/delete", "/tn", "PAI-WAKEUP", "/f"]).catch(() => {
5153
+ });
5154
+ try {
5155
+ await execa("schtasks", [
5156
+ "/create",
5157
+ "/tn",
5158
+ "PAI-WAKEUP",
5159
+ "/tr",
5160
+ `powershell.exe -ExecutionPolicy Bypass -File "${psScriptPath}"`,
5161
+ "/sc",
5162
+ "WEEKLY",
5163
+ "/d",
5164
+ days,
5165
+ "/st",
5166
+ `${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}`,
5167
+ "/f"
5168
+ ]);
5169
+ success("Windows Task Scheduler \uB4F1\uB85D \uC644\uB8CC");
5170
+ } catch {
5171
+ warn("Task Scheduler \uB4F1\uB85D \uC2E4\uD328");
5172
+ hint("\uAD00\uB9AC\uC790 \uAD8C\uD55C\uC73C\uB85C \uC7AC\uC2DC\uB3C4\uD558\uAC70\uB098, \uC791\uC5C5 \uC2A4\uCF00\uC904\uB7EC\uC5D0\uC11C \uC9C1\uC811 \uB4F1\uB85D\uD558\uC138\uC694");
5173
+ }
5174
+ }
4857
5175
  async function setupLinux(config) {
4858
5176
  const { execa } = await import("execa");
4859
5177
  const cronExpr = scheduleToCron(config.time, config.schedule);
@@ -4883,6 +5201,13 @@ async function disableWakeup() {
4883
5201
  } catch {
4884
5202
  hint("\uC218\uB3D9 \uD574\uC81C: sudo pmset repeat cancel");
4885
5203
  }
5204
+ } else if (osPlatform() === "win32") {
5205
+ try {
5206
+ await execa("schtasks", ["/delete", "/tn", "PAI-WAKEUP", "/f"]);
5207
+ success("Windows Task Scheduler \uC81C\uAC70 \uC644\uB8CC");
5208
+ } catch {
5209
+ hint("\uC218\uB3D9 \uD574\uC81C: schtasks /delete /tn PAI-WAKEUP /f");
5210
+ }
4886
5211
  } else {
4887
5212
  await removeCronEntry();
4888
5213
  }