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