pattyeng 1.0.4 → 1.0.7

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.
Files changed (99) hide show
  1. package/README.md +103 -43
  2. package/bin/pattyeng.js +25 -14
  3. package/lib/skills.js +198 -0
  4. package/lib/upgrade.js +46 -0
  5. package/package.json +5 -3
  6. package/skills/.system/.codex-system-skills.marker +1 -0
  7. package/skills/.system/imagegen/LICENSE.txt +201 -0
  8. package/skills/.system/imagegen/SKILL.md +356 -0
  9. package/skills/.system/imagegen/agents/openai.yaml +6 -0
  10. package/skills/.system/imagegen/assets/imagegen-small.svg +5 -0
  11. package/skills/.system/imagegen/assets/imagegen.png +0 -0
  12. package/skills/.system/imagegen/references/cli.md +242 -0
  13. package/skills/.system/imagegen/references/codex-network.md +33 -0
  14. package/skills/.system/imagegen/references/image-api.md +90 -0
  15. package/skills/.system/imagegen/references/prompting.md +118 -0
  16. package/skills/.system/imagegen/references/sample-prompts.md +433 -0
  17. package/skills/.system/imagegen/scripts/image_gen.py +995 -0
  18. package/skills/.system/imagegen/scripts/remove_chroma_key.py +440 -0
  19. package/skills/.system/openai-docs/LICENSE.txt +201 -0
  20. package/skills/.system/openai-docs/SKILL.md +167 -0
  21. package/skills/.system/openai-docs/agents/openai.yaml +14 -0
  22. package/skills/.system/openai-docs/assets/openai-small.svg +3 -0
  23. package/skills/.system/openai-docs/assets/openai.png +0 -0
  24. package/skills/.system/openai-docs/references/latest-model.md +37 -0
  25. package/skills/.system/openai-docs/references/prompting-guide.md +244 -0
  26. package/skills/.system/openai-docs/references/upgrade-guide.md +181 -0
  27. package/skills/.system/openai-docs/scripts/fetch-codex-manual.mjs +598 -0
  28. package/skills/.system/openai-docs/scripts/resolve-latest-model-info.js +147 -0
  29. package/skills/.system/plugin-creator/SKILL.md +243 -0
  30. package/skills/.system/plugin-creator/agents/openai.yaml +6 -0
  31. package/skills/.system/plugin-creator/assets/plugin-creator-small.svg +3 -0
  32. package/skills/.system/plugin-creator/assets/plugin-creator.png +0 -0
  33. package/skills/.system/plugin-creator/references/installing-and-updating.md +143 -0
  34. package/skills/.system/plugin-creator/references/plugin-json-spec.md +194 -0
  35. package/skills/.system/plugin-creator/scripts/create_basic_plugin.py +324 -0
  36. package/skills/.system/plugin-creator/scripts/read_marketplace_name.py +48 -0
  37. package/skills/.system/plugin-creator/scripts/update_plugin_cachebuster.py +78 -0
  38. package/skills/.system/plugin-creator/scripts/validate_plugin.py +586 -0
  39. package/skills/.system/skill-creator/SKILL.md +416 -0
  40. package/skills/.system/skill-creator/agents/openai.yaml +5 -0
  41. package/skills/.system/skill-creator/assets/skill-creator-small.svg +3 -0
  42. package/skills/.system/skill-creator/assets/skill-creator.png +0 -0
  43. package/skills/.system/skill-creator/license.txt +202 -0
  44. package/skills/.system/skill-creator/references/openai_yaml.md +49 -0
  45. package/skills/.system/skill-creator/scripts/generate_openai_yaml.py +226 -0
  46. package/skills/.system/skill-creator/scripts/init_skill.py +400 -0
  47. package/skills/.system/skill-creator/scripts/quick_validate.py +101 -0
  48. package/skills/.system/skill-installer/LICENSE.txt +202 -0
  49. package/skills/.system/skill-installer/SKILL.md +58 -0
  50. package/skills/.system/skill-installer/agents/openai.yaml +5 -0
  51. package/skills/.system/skill-installer/assets/skill-installer-small.svg +3 -0
  52. package/skills/.system/skill-installer/assets/skill-installer.png +0 -0
  53. package/skills/.system/skill-installer/scripts/github_utils.py +21 -0
  54. package/skills/.system/skill-installer/scripts/install-skill-from-github.py +308 -0
  55. package/skills/.system/skill-installer/scripts/list-skills.py +107 -0
  56. package/skills/cap/SKILL.md +77 -0
  57. package/skills/caveman/SKILL.md +49 -0
  58. package/skills/code-review/SKILL.md +46 -0
  59. package/skills/codebook/SKILL.md +184 -0
  60. package/skills/doc-review/SKILL.md +147 -0
  61. package/skills/feature-research/SKILL.md +34 -0
  62. package/skills/file-op/SKILL.md +116 -0
  63. package/skills/grill-me/SKILL.md +10 -0
  64. package/skills/grill-with-docs/ADR-FORMAT.md +47 -0
  65. package/skills/grill-with-docs/CONTEXT-FORMAT.md +60 -0
  66. package/skills/grill-with-docs/SKILL.md +88 -0
  67. package/skills/handoff/SKILL.md +17 -0
  68. package/skills/improve-codebase/SKILL.md +79 -0
  69. package/skills/linear/SKILL.md +107 -0
  70. package/skills/next-step/SKILL.md +61 -0
  71. package/skills/no-reinvent/SKILL.md +131 -0
  72. package/skills/no-wall/SKILL.md +146 -0
  73. package/skills/online/SKILL.md +54 -0
  74. package/skills/plan-review/SKILL.md +55 -0
  75. package/skills/professional/SKILL.md +111 -0
  76. package/skills/promise-tracking/SKILL.md +131 -0
  77. package/skills/prove/SKILL.md +135 -0
  78. package/skills/read-before-write/SKILL.md +123 -0
  79. package/skills/review/SKILL.md +78 -0
  80. package/skills/review-mp/SKILL.md +78 -0
  81. package/skills/scope-boundary/SKILL.md +121 -0
  82. package/skills/semble-search/SKILL.md +40 -0
  83. package/skills/sitrep/SKILL.md +126 -0
  84. package/skills/structure-code/SKILL.md +116 -0
  85. package/skills/surface-assumptions/SKILL.md +139 -0
  86. package/skills/teach/GLOSSARY-FORMAT.md +35 -0
  87. package/skills/teach/LEARNING-RECORD-FORMAT.md +46 -0
  88. package/skills/teach/MISSION-FORMAT.md +31 -0
  89. package/skills/teach/RESOURCES-FORMAT.md +32 -0
  90. package/skills/teach/SKILL.md +131 -0
  91. package/skills/team-protocol/SKILL.md +172 -0
  92. package/skills/tech-lead/SKILL.md +332 -0
  93. package/skills/to-issues/SKILL.md +83 -0
  94. package/skills/to-prd/SKILL.md +74 -0
  95. package/skills/vectorbt-expert/SKILL.md +253 -0
  96. package/skills/verify-done/SKILL.md +128 -0
  97. package/skills/work-log/SKILL.md +141 -0
  98. package/skills/work-log/template.html +496 -0
  99. package/skills/zoom-out/SKILL.md +7 -0
package/README.md CHANGED
@@ -1,94 +1,154 @@
1
- # pattyeng 🐾
1
+ # pattyeng
2
2
 
3
- > Patty 엔지니어로 살아남기 위한 첫 번째 관문
3
+ Patty 엔지니어용 작업 환경 도구.
4
4
 
5
- 입사 첫날, 아무도 Codex 어떻게 설치하는지 알려줬죠?
6
- 이거 하나면 됩니다.
5
+ 노트북이든, WSL이든, 오래 방치한 개발환경이든 Patty에서 일하는 데 필요한 기본 세팅을 한 번에 맞춥니다.
6
+
7
+ 지금은 Codex 설정, 스킬 동기화, 업그레이드를 담당합니다. 앞으로는 MCP, hooks, 공통 환경설정까지 같은 방식으로 붙일 예정입니다.
7
8
 
8
9
  ---
9
10
 
10
- ## 뭐 하는 툴임?
11
+ ## 설치
12
+
13
+ ```bash
14
+ npm install -g pattyeng
15
+ ```
11
16
 
12
- 명령어 하나로:
17
+ 설치 후 아래 명령어로 시작합니다.
13
18
 
14
- - Codex 설치 + 최신 버전 업데이트
15
- - Patty SSO 로그인 (브라우저 자동 열림)
16
- - API 키 환경변수 자동 등록
17
- - `codex` 명령어에 Patty 설정 자동 연결
19
+ ```bash
20
+ pattyeng install codex
21
+ ```
18
22
 
19
- 손으로 해줌. 커피나 타세요.
23
+ 브라우저가 열리면 Patty 계정으로 로그인하세요. 로그인 후 필요한 값은 자동으로 설정됩니다.
20
24
 
21
25
  ---
22
26
 
23
- ## 사전 조건
27
+ ## 명령어
24
28
 
25
- - Node.js 18+
26
- - `@patty.io` 계정
27
- - `pattyeng` 그룹 멤버 (아직 아니면 관리자한테 Slack DM)
29
+ ### `pattyeng install codex`
28
30
 
29
- ---
31
+ Codex를 Patty 환경에 맞게 세팅합니다.
30
32
 
31
- ## 시작
33
+ 처리하는 일:
32
34
 
33
- **1. 설치**
35
+ - Codex 설치 확인
36
+ - Codex 최신 버전 업데이트
37
+ - Patty 설정 파일 복사
38
+ - Patty SSO 로그인
39
+ - `PATTY_AGENT_API_KEY` 등록
40
+ - `codex` 명령어가 Patty 프로필을 쓰도록 설정
41
+
42
+ 실행:
34
43
 
35
44
  ```bash
36
- npm install -g pattyeng
45
+ pattyeng install codex
37
46
  ```
38
47
 
39
- **2. 실행**
48
+ 마지막에 터미널만 다시 불러오면 됩니다.
49
+
50
+ macOS / Linux / WSL:
40
51
 
41
52
  ```bash
42
- pattyeng install codex
53
+ exec zsh # zsh 사용자
54
+ exec bash # bash 사용자
55
+ ```
56
+
57
+ Windows:
58
+
59
+ ```text
60
+ 터미널을 닫고 새로 열기
43
61
  ```
44
62
 
45
- 브라우저 열리면 Patty 계정으로 로그인하세요.
46
- 그게 끝임. 진짜로.
63
+ ---
47
64
 
48
- **3. 터미널 재시작**
65
+ ### `pattyeng upgrade`
66
+
67
+ 로컬 도구를 최신 상태로 맞춥니다.
49
68
 
50
69
  ```bash
51
- exec zsh # zsh
52
- exec bash # bash
70
+ pattyeng upgrade
53
71
  ```
54
72
 
55
- Windows면 그냥 터미널 껐다 켜세요.
73
+ 업데이트 대상:
74
+
75
+ - `pattyeng`
76
+ - Codex CLI
56
77
 
57
78
  ---
58
79
 
59
- ## 됐는지 확인
80
+ ### `pattyeng skills list`
81
+
82
+ 설치된 스킬 이름을 짧게 봅니다.
60
83
 
61
84
  ```bash
62
- codex "나 이제 Patty 엔지니어임?"
85
+ pattyeng skills list
63
86
  ```
64
87
 
65
- 뭔가 응답 오면 성공입니다 🎉
88
+ 설명까지 보고 싶으면:
66
89
 
67
- ---
90
+ ```bash
91
+ pattyeng skills list --long
92
+ ```
68
93
 
69
- ## 뭔가 잘못됨?
94
+ ---
70
95
 
71
- **브라우저가 열려요**
72
- 터미널에 출력된 `🔗 로그인 URL` 복사해서 브라우저에 그냥 붙여넣기
96
+ ### `pattyeng skills sync`
73
97
 
74
- **"pattyeng 그룹에 없다"고 함**
75
- 관리자한테 그룹 추가 요청하세요. 당신 잘못 아님.
98
+ Patty dotfiles에 있는 최신 스킬을 `~/.codex/skills`로 동기화합니다.
76
99
 
77
- **codex 명령어 없다고 함**
78
100
  ```bash
79
- npm install -g @openai/codex
101
+ pattyeng skills sync
80
102
  ```
81
103
 
82
- **Windows에서 뭔가 터짐**
83
- 터미널 관리자 권한으로 열고 다시 시도
104
+ 스킬이 바뀌었거나 새로 추가됐을 때 실행하면 됩니다.
84
105
 
85
106
  ---
86
107
 
87
108
  ## 지원 환경
88
109
 
89
- macOS, Linux, WSL2, Windows — 다 됩니다.
90
- IE는 지원 안 함 (당연히)
110
+ - macOS
111
+ - Linux
112
+ - WSL 2
113
+ - Windows PowerShell
114
+ - Windows CMD
115
+
116
+ Node.js 18 이상이 필요합니다.
117
+
118
+ ---
119
+
120
+ ## 자주 나는 문제
121
+
122
+ ### 브라우저가 자동으로 안 열림
123
+
124
+ 터미널에 출력된 로그인 URL을 복사해서 브라우저에 붙여넣으세요.
125
+
126
+ ### `pattyeng` 그룹이 아니라고 나옴
127
+
128
+ Patty 관리자에게 `pattyeng` 그룹 추가를 요청하세요.
129
+
130
+ ### 환경변수가 바로 안 잡힘
131
+
132
+ 새 터미널을 열거나 아래 명령어를 실행하세요.
133
+
134
+ ```bash
135
+ exec zsh
136
+ # 또는
137
+ exec bash
138
+ ```
139
+
140
+ Windows는 터미널을 닫고 새로 열면 됩니다.
141
+
142
+ ### Codex가 이상하게 동작함
143
+
144
+ 한 번 업데이트하세요.
145
+
146
+ ```bash
147
+ pattyeng upgrade
148
+ ```
91
149
 
92
150
  ---
93
151
 
94
- 문제 있으면 Slack으로. 이슈 올려도 됨.
152
+ ## 요약
153
+
154
+ Patty에서 쓰는 개발환경 세팅을 사람 손 덜 타게 만드는 도구입니다.
package/bin/pattyeng.js CHANGED
@@ -1,10 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
+ process.stdout.on('error', (err) => {
5
+ if (err.code === 'EPIPE') process.exit(0);
6
+ throw err;
7
+ });
8
+
4
9
  const { install } = require('../lib/install');
10
+ const { upgrade } = require('../lib/upgrade');
11
+ const { skills } = require('../lib/skills');
5
12
 
6
- const args = process.argv.slice(2);
7
- const cmd = args[0];
13
+ const args = process.argv.slice(2);
14
+ const cmd = args[0];
8
15
  const subcmd = args[1];
9
16
 
10
17
  async function main() {
@@ -16,6 +23,15 @@ async function main() {
16
23
  console.log('\n사용법: pattyeng install codex\n');
17
24
  }
18
25
  break;
26
+
27
+ case 'upgrade':
28
+ await upgrade();
29
+ break;
30
+
31
+ case 'skills':
32
+ await skills(args.slice(1));
33
+ break;
34
+
19
35
  default:
20
36
  printHelp();
21
37
  }
@@ -24,23 +40,18 @@ async function main() {
24
40
  function printHelp() {
25
41
  console.log(`
26
42
  ╔══════════════════════════════════════════╗
27
- ║ pattyeng CLI v1.0.0
43
+ ║ pattyeng CLI
28
44
  ╚══════════════════════════════════════════╝
29
45
 
30
- 사용법 (Usage):
31
- pattyeng install codex Codex 설치 SSO 로그인 설정
32
-
33
- 명령어 (Commands):
34
- install codex - Codex 설치, 최신 버전 업데이트, Patty SSO 로그인,
35
- API 키 환경변수 설정, alias 등록을 한번에 수행합니다.
36
- help - 이 도움말을 표시합니다.
37
-
38
- 예시 (Examples):
39
- pattyeng install codex
46
+ 명령어:
47
+ install codex Codex 설치 + SSO 로그인 + 환경설정
48
+ upgrade pattyeng, Codex 최신 버전으로 업데이트
49
+ skills list 설치된 스킬 목록
50
+ skills sync 스킬 최신 버전으로 동기화
40
51
  `);
41
52
  }
42
53
 
43
54
  main().catch((err) => {
44
- console.error('\n❌ 오류 발생:', err.message);
55
+ console.error('\n❌ 오류:', err.message);
45
56
  process.exit(1);
46
57
  });
package/lib/skills.js ADDED
@@ -0,0 +1,198 @@
1
+ 'use strict';
2
+
3
+ const { execSync } = require('child_process');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const os = require('os');
7
+
8
+ const HOME = os.homedir();
9
+ const DEST_DIR = path.join(HOME, '.codex', 'skills');
10
+
11
+ // Source: npm registry tarball for pattyeng — skills are bundled inside package
12
+ // Fallback: look for dotfiles repo next to package install location
13
+ function findSourceSkillsDir() {
14
+ const candidates = [
15
+ // bundled inside the npm package itself (skills/ at package root)
16
+ path.join(__dirname, '..', 'skills'),
17
+ // dotfiles repo sibling
18
+ path.join(__dirname, '..', '..', 'skills'),
19
+ path.join(__dirname, '..', '..', 'dotfiles', 'skills'),
20
+ ];
21
+ return candidates.find(d => fs.existsSync(d) && fs.statSync(d).isDirectory()) || null;
22
+ }
23
+
24
+ function log(msg) { process.stdout.write(msg + '\n'); }
25
+ function step(msg) { log(`\n🔧 ${msg}`); }
26
+ function ok(msg) { log(`✅ ${msg}`); }
27
+ function warn(msg) { log(`⚠️ ${msg}`); }
28
+ function info(msg) { log(` ${msg}`); }
29
+
30
+ // Read SKILL.md name/description
31
+ function readSkillMeta(skillDir) {
32
+ const mdPath = path.join(skillDir, 'SKILL.md');
33
+ if (!fs.existsSync(mdPath)) return { name: path.basename(skillDir), description: '' };
34
+ const content = fs.readFileSync(mdPath, 'utf8');
35
+ const nameMatch = content.match(/^name:\s*(.+)$/m);
36
+ const descMatch = content.match(/^description:\s*(.+)$/m);
37
+ return {
38
+ name: cleanYamlScalar(nameMatch ? nameMatch[1] : path.basename(skillDir)),
39
+ description: descMatch ? cleanYamlScalar(descMatch[1]) : '',
40
+ };
41
+ }
42
+
43
+ function cleanYamlScalar(value) {
44
+ return String(value || '')
45
+ .trim()
46
+ .replace(/^['\"]|['\"]$/g, '')
47
+ .replace(/^>\s*/, '')
48
+ .trim();
49
+ }
50
+
51
+ function cleanDescription(value) {
52
+ const cleaned = cleanYamlScalar(value).replace(/\s+/g, ' ');
53
+ return cleaned.length > 82 ? cleaned.slice(0, 79) + '...' : cleaned;
54
+ }
55
+
56
+ // Diff two SKILL.md files — returns true if different
57
+ function isDifferent(srcFile, destFile) {
58
+ if (!fs.existsSync(destFile)) return true;
59
+ return fs.readFileSync(srcFile, 'utf8') !== fs.readFileSync(destFile, 'utf8');
60
+ }
61
+
62
+ // Copy a skill folder recursively
63
+ function copySkill(srcDir, destDir) {
64
+ if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
65
+ for (const file of fs.readdirSync(srcDir)) {
66
+ const src = path.join(srcDir, file);
67
+ const dest = path.join(destDir, file);
68
+ if (fs.statSync(src).isDirectory()) {
69
+ copySkill(src, dest);
70
+ } else {
71
+ fs.copyFileSync(src, dest);
72
+ }
73
+ }
74
+ }
75
+
76
+ async function skills(args) {
77
+ const sub = args[0];
78
+
79
+ if (!sub || sub === 'list') {
80
+ return listSkills(args.includes('--long'));
81
+ }
82
+ if (sub === 'sync') {
83
+ return syncSkills();
84
+ }
85
+
86
+ log(`\n사용법:\n pattyeng skills list — 스킬 이름만 보기\n pattyeng skills list --long — 설명까지 보기\n pattyeng skills sync — 스킬 최신 버전으로 동기화\n`);
87
+ }
88
+
89
+ function listSkills(long = false) {
90
+ log(`\n📚 스킬 목록 (${DEST_DIR})\n`);
91
+
92
+ if (!fs.existsSync(DEST_DIR)) {
93
+ warn('~/.codex/skills 폴더가 없습니다. pattyeng skills sync 를 먼저 실행하세요.');
94
+ return;
95
+ }
96
+
97
+ const skills = fs.readdirSync(DEST_DIR).filter(f => {
98
+ try { return fs.statSync(path.join(DEST_DIR, f)).isDirectory(); }
99
+ catch { return false; } // broken symlink — skip
100
+ });
101
+
102
+ if (skills.length === 0) {
103
+ warn('스킬이 없습니다. pattyeng skills sync 를 실행하세요.');
104
+ return;
105
+ }
106
+
107
+ const names = skills
108
+ .sort()
109
+ .map(skill => readSkillMeta(path.join(DEST_DIR, skill)).name)
110
+ .filter(name => !name.startsWith('.'));
111
+
112
+ if (!long) {
113
+ const width = Math.max(18, ...names.map(n => n.length + 2));
114
+ for (let i = 0; i < names.length; i += 3) {
115
+ log(' ' + names.slice(i, i + 3).map(n => n.padEnd(width)).join(''));
116
+ }
117
+ log(`\n 총 ${names.length}개. 설명 보기: pattyeng skills list --long\n`);
118
+ return;
119
+ }
120
+
121
+ for (const skill of skills.sort()) {
122
+ const meta = readSkillMeta(path.join(DEST_DIR, skill));
123
+ if (meta.name.startsWith('.')) continue;
124
+ const desc = cleanDescription(meta.description);
125
+ log(` • ${meta.name.padEnd(20)} ${desc ? `— ${desc}` : ''}`);
126
+ }
127
+ log('');
128
+ }
129
+
130
+ function syncSkills() {
131
+ log(`
132
+ ╔══════════════════════════════════════════╗
133
+ ║ pattyeng skills sync 시작 ║
134
+ ╚══════════════════════════════════════════╝
135
+ `);
136
+
137
+ const srcDir = findSourceSkillsDir();
138
+ if (!srcDir) {
139
+ warn('스킬 소스 폴더를 찾을 수 없습니다.');
140
+ warn('dotfiles 저장소가 있어야 합니다: ~/projects/dotfiles/skills/');
141
+ process.exit(1);
142
+ }
143
+ log(` 소스: ${srcDir}`);
144
+ log(` 대상: ${DEST_DIR}\n`);
145
+
146
+ if (!fs.existsSync(DEST_DIR)) fs.mkdirSync(DEST_DIR, { recursive: true });
147
+
148
+ const srcSkills = fs.readdirSync(srcDir).filter(f =>
149
+ fs.statSync(path.join(srcDir, f)).isDirectory()
150
+ );
151
+
152
+ let added = 0;
153
+ let updated = 0;
154
+ let skipped = 0;
155
+
156
+ for (const skill of srcSkills.sort()) {
157
+ const src = path.join(srcDir, skill);
158
+ const dest = path.join(DEST_DIR, skill);
159
+ const meta = readSkillMeta(src);
160
+ const srcMd = path.join(src, 'SKILL.md');
161
+ const destMd = path.join(dest, 'SKILL.md');
162
+
163
+ const destExists = fs.existsSync(dest);
164
+ const destLstat = destExists ? null : null, lstat = (() => { try { return fs.lstatSync(dest); } catch { return null; } })();
165
+ const isSymlink = lstat && lstat.isSymbolicLink();
166
+ const alreadyPointsHere = isSymlink && fs.readlinkSync(dest) === src;
167
+
168
+ if (!lstat) {
169
+ // doesn’t exist at all
170
+ fs.symlinkSync(src, dest);
171
+ log(` ✨ 새로 추가: ${meta.name}`);
172
+ added++;
173
+ } else if (alreadyPointsHere) {
174
+ // already correct symlink
175
+ skipped++;
176
+ } else if (isSymlink) {
177
+ // symlink pointing somewhere else — update
178
+ fs.unlinkSync(dest);
179
+ fs.symlinkSync(src, dest);
180
+ log(` 🔄 업데이트: ${meta.name}`);
181
+ updated++;
182
+ } else if (isDifferent(srcMd, destMd)) {
183
+ // real dir with changed content — overwrite
184
+ copySkill(src, dest);
185
+ log(` 🔄 업데이트: ${meta.name}`);
186
+ updated++;
187
+ } else {
188
+ skipped++;
189
+ }
190
+ }
191
+
192
+ log(`
193
+ 추가: ${added}개 업데이트: ${updated}개 변경없음: ${skipped}개
194
+
195
+ ✅ 스킬 동기화 완료`);
196
+ }
197
+
198
+ module.exports = { skills };
package/lib/upgrade.js ADDED
@@ -0,0 +1,46 @@
1
+ 'use strict';
2
+
3
+ const { execSync } = require('child_process');
4
+
5
+ function log(msg) { process.stdout.write(msg + '\n'); }
6
+ function step(msg) { log(`\n🔧 ${msg}`); }
7
+ function ok(msg) { log(`✅ ${msg}`); }
8
+ function warn(msg) { log(`⚠️ ${msg}`); }
9
+
10
+ async function upgrade() {
11
+ log(`
12
+ ╔══════════════════════════════════════════╗
13
+ ║ pattyeng upgrade 시작 ║
14
+ ╚══════════════════════════════════════════╝
15
+ `);
16
+
17
+ // 1. pattyeng itself
18
+ step('pattyeng 최신 버전으로 업데이트 중...');
19
+ try {
20
+ const before = execSync('npm list -g pattyeng --depth=0 2>/dev/null', { encoding: 'utf8' }).trim();
21
+ execSync('npm install -g pattyeng@latest', { stdio: 'inherit' });
22
+ const after = execSync('npm list -g pattyeng --depth=0 2>/dev/null', { encoding: 'utf8' }).trim();
23
+ if (before !== after) {
24
+ ok('pattyeng 업데이트 완료');
25
+ } else {
26
+ ok('pattyeng 이미 최신 버전');
27
+ }
28
+ } catch (e) {
29
+ warn('pattyeng 업데이트 실패: ' + e.message);
30
+ }
31
+
32
+ // 2. codex
33
+ step('Codex 최신 버전으로 업데이트 중...');
34
+ try {
35
+ execSync('npm install -g @openai/codex@latest', { stdio: 'inherit' });
36
+ ok('Codex 업데이트 완료');
37
+ } catch (e) {
38
+ warn('Codex 업데이트 실패: ' + e.message);
39
+ }
40
+
41
+ log(`
42
+ ✨ 업그레이드 완료!
43
+ `);
44
+ }
45
+
46
+ module.exports = { upgrade };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pattyeng",
3
- "version": "1.0.4",
3
+ "version": "1.0.7",
4
4
  "description": "Patty Engineering CLI - Codex SSO setup tool",
5
5
  "bin": {
6
6
  "pattyeng": "./bin/pattyeng.js"
@@ -26,7 +26,9 @@
26
26
  "access": "public"
27
27
  },
28
28
  "files": [
29
- "bin/",
30
- "lib/"
29
+ "bin",
30
+ "lib",
31
+ "skills",
32
+ "README.md"
31
33
  ]
32
34
  }
@@ -0,0 +1 @@
1
+ 66eb33bbe0eb99ac