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