@rch4com/agent-setup 1.21.1 → 1.22.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.
@@ -0,0 +1,128 @@
1
+ // 오빠두엑셀 "디자인 시스템 갤러리" 프로바이더.
2
+ // https://www.oppadu.com/tools/design-systems-site/
3
+ //
4
+ // ⚠️ 아직 PROVIDERS(providers/index.mjs)에 등록하지 않는다. 사이트는 마크다운
5
+ // 다운로드·복사·원본 보기를 로그인 회원 전용으로 두고 바닥글이 "All rights
6
+ // reserved"다 — 재배포 허가(info@oppadu.com)가 오기 전에는 번들도, 카탈로그
7
+ // 항목도, 등록도 하지 않는다. design-md.oppadu.test.mjs가 이 상태를 못박는다.
8
+ // 허가가 오면: index.mjs에 등록 → `design --sync=catalog` → `npm run refresh-bundle`
9
+ // → cache/oppadu/LICENSE.md 고지 → README의 design.md 절 갱신 → 발행.
10
+ //
11
+ // 사이트 구조(2026-09-06 실측, schema_version 3):
12
+ // 카탈로그 data/brands-index.json — 브랜드 242개의 slug·이름·지역·한 줄 설명.
13
+ // 갤러리 그리드가 그대로 읽는 공개 파일이다.
14
+ // 파일 data/detail/<slug>.json — raw_markdown(라이트)·raw_markdown_dark.
15
+ // 사이트의 "가이드 다운로드"는 라이트 모드에서 raw_markdown의
16
+ // `[data-theme="dark"]` 규칙을 걷어낸 것을 <slug>-light.md로 저장한다
17
+ // (app.js currentDownloadMd·stripDarkBlock) — DESIGN.md도 그 판을 쓴다.
18
+ // 미리보기 brand/<slug>.html — 로그인 없이 보이는 공개 페이지.
19
+ import { existsSync, readFileSync } from 'node:fs'
20
+ import { join, dirname } from 'node:path'
21
+ import { fileURLToPath } from 'node:url'
22
+ import { LocalizedError } from '../../i18n/index.mjs'
23
+ import { isSafeSegment } from '../../untrusted.mjs'
24
+
25
+ const BUNDLE_DIR = join(dirname(fileURLToPath(import.meta.url)), '..', 'cache')
26
+
27
+ const BASE = 'https://www.oppadu.com/tools/design-systems-site'
28
+ const INDEX_URL = `${BASE}/data/brands-index.json`
29
+
30
+ // 카테고리는 사이트의 전체 목록 페이지(brand/)가 쓰는 지역 묶음과 같다 —
31
+ // 한국 48·아시아 14·해외 180. 색인의 `western`을 그 페이지는 "해외"로 적는다.
32
+ export const REGION_LABELS = { korea: '한국', asia: '아시아', western: '해외' }
33
+
34
+ // 사이트의 displayName과 같은 규칙 — 한국 브랜드만 괄호에 한글 이름을 붙인다.
35
+ function displayName(b) {
36
+ return b.region === 'korea' && b.brand_ko ? `${b.brand} (${b.brand_ko})` : String(b.brand ?? b.slug)
37
+ }
38
+
39
+ // brands-index.json → 카탈로그 엔트리. slug가 곧 이름이자 설치 경로 세그먼트다.
40
+ export function parseIndex(index) {
41
+ const brands = Array.isArray(index?.brands) ? index.brands : []
42
+ return brands
43
+ .filter((b) => typeof b?.slug === 'string' && isSafeSegment(b.slug))
44
+ .map((b) => ({
45
+ name: b.slug,
46
+ label: displayName(b),
47
+ category: REGION_LABELS[b.region] ?? String(b.region ?? ''),
48
+ description: String(b.signature_keyword ?? ''),
49
+ }))
50
+ .sort((a, b) => a.name.localeCompare(b.name))
51
+ }
52
+
53
+ // app.js의 stripDarkBlock을 그대로 옮겼다 — 사이트의 라이트 다운로드와 글자
54
+ // 단위로 같은 결과를 내야 한다. `[data-theme="dark"] { … }` 규칙을 중괄호
55
+ // 짝으로 찾아 제 줄까지 통째로 지운다(CSS 규칙 안에 중첩 중괄호는 없다).
56
+ export function stripDarkBlock(md) {
57
+ if (!md) return md
58
+ let out = md
59
+ let idx
60
+ while ((idx = out.indexOf('[data-theme="dark"]')) !== -1) {
61
+ const open = out.indexOf('{', idx)
62
+ if (open === -1) break
63
+ let depth = 1
64
+ let i = open + 1
65
+ for (; i < out.length && depth > 0; i++) {
66
+ if (out[i] === '{') depth++
67
+ else if (out[i] === '}') depth--
68
+ }
69
+ let start = idx
70
+ while (start > 0 && (out[start - 1] === ' ' || out[start - 1] === '\t')) start--
71
+ if (start > 0 && out[start - 1] === '\n') start--
72
+ out = out.slice(0, start) + out.slice(i)
73
+ }
74
+ return out
75
+ }
76
+
77
+ // app.js의 currentDownloadMd(mode='light')와 같다. 라이트·다크 겸용 브랜드는
78
+ // 다크 규칙을 걷어낸 라이트 판, 단일 모드 브랜드는 원문 그대로.
79
+ export function toDesignMd(detail) {
80
+ const md = detail?.raw_markdown
81
+ if (typeof md !== 'string' || md.length === 0) return null
82
+ const modes = Array.isArray(detail.theme_modes) ? detail.theme_modes : []
83
+ const dual = modes.includes('light') && modes.includes('dark')
84
+ const hasDark = dual && typeof detail.raw_markdown_dark === 'string' && detail.raw_markdown_dark.length > 0
85
+ return hasDark ? stripDarkBlock(md) : md
86
+ }
87
+
88
+ export const oppadu = {
89
+ id: 'oppadu',
90
+ label: 'Design Systems Gallery (오빠두엑셀)',
91
+ files: ['DESIGN.md'],
92
+ // 재배포 허가 전이다 — refresh-bundle과 번들 검사가 이 값을 보고 건너뛴다.
93
+ redistributable: false,
94
+
95
+ fileUrl(name) {
96
+ return `${BASE}/data/detail/${encodeURIComponent(name)}.json`
97
+ },
98
+
99
+ webUrl(name) {
100
+ return `${BASE}/brand/${encodeURIComponent(name)}.html`
101
+ },
102
+
103
+ bundlePath(name, file = 'DESIGN.md') {
104
+ return join(BUNDLE_DIR, this.id, name, file)
105
+ },
106
+
107
+ bundledText(name, file = 'DESIGN.md') {
108
+ if (/[\\/]/.test(name)) return null
109
+ const p = this.bundlePath(name, file)
110
+ return existsSync(p) ? readFileSync(p, 'utf8') : null
111
+ },
112
+
113
+ // 상세 JSON 하나가 곧 파일이다. 응답이 없거나 원문 필드가 비면 null —
114
+ // defineDesignMd가 그것을 "내려받지 못했다"로 보고한다.
115
+ async fetchFile(fetchImpl, name) {
116
+ const res = await fetchImpl(this.fileUrl(name))
117
+ if (!res.ok) return null
118
+ return toDesignMd(await res.json())
119
+ },
120
+
121
+ async fetchCatalog(fetchImpl) {
122
+ const res = await fetchImpl(INDEX_URL)
123
+ if (!res.ok) throw new LocalizedError('error.indexFetch', { url: INDEX_URL, status: res.status })
124
+ return parseIndex(await res.json())
125
+ },
126
+ }
127
+
128
+ export default oppadu
@@ -289,6 +289,7 @@ export default {
289
289
  'item.skill.karpathy.note': 'behavioral guidelines that curb overbuilding and vague success criteria',
290
290
  'item.skill.prompt-master.note': 'a skill that writes and refines prompts for AI tools. Activates only when explicitly asked to write or fix a prompt. Harness-neutral body shared by all 11 CLIs',
291
291
  'item.skill.strix.note': 'copies 9 security-testing skills (pentesting, OWASP Top 10, vulnerability discovery and fix flows) into the shared .agents/skills. The skills drive the Strix agent, so the strix binary is required on PATH — self-hosted needs pipx install strix-agent plus Docker and STRIX_LLM/LLM_API_KEY, managed needs strix cloud login. Use only against targets you are authorized to test',
292
+ 'item.skill.officecli.note': 'copies a skill for reading, editing and creating Word, Excel and PowerPoint documents (.docx, .xlsx, .pptx) into the shared .agents/skills. The skill drives the officecli binary, so officecli is required on PATH — npm install -g @officecli/officecli or the upstream install.sh/install.ps1. No Office installation needed',
292
293
  'item.skill.gstack.note': 'repo-local clone + setup (needs bash; Git Bash on Windows). Runtime state (~/.gstack) may be created globally. In a bootstrapped repository .claude/skills is a junction, so the files land in the shared .agents/skills — codex and opencode scan recursively and see the individual skills too',
293
294
  'item.skill.gsd.note': 'npx @opengsd/gsd-core, installed per project — wires five runtimes in one run: claude, codex, opencode, copilot, kilo (.claude/commands, .codex/skills, .opencode/skills, .github/skills, .kilo/skills). Each runtime writes roughly 700 files. gemini was dropped upstream and kimi still blocks project installs',
294
295
  // 커밋 템플릿은 CLI 배선이 아니라 저장소 규약이다 — note가 "무엇이 놓이고
@@ -489,4 +490,5 @@ export default {
489
490
  'error.ambiguousDesignId': 'ambiguous name \'{token}\' — pick a provider: {options}',
490
491
  'error.designDownload': '{provider}/{name}: DESIGN.md download failed',
491
492
  'error.readmeFetch': 'README fetch failed: HTTP {status}',
493
+ 'error.indexFetch': 'index fetch failed: HTTP {status} ({url})',
492
494
  }
@@ -282,6 +282,7 @@ export default {
282
282
  'item.skill.karpathy.note': '과설계와 모호한 완료 기준을 줄이는 행동 지침',
283
283
  'item.skill.prompt-master.note': 'AI 도구용 프롬프트를 만들고 다듬는 스킬. 프롬프트 작성·수정을 명시적으로 요청할 때만 활성화됩니다. 본문이 하네스 중립이라 11개 CLI가 함께 씁니다',
284
284
  'item.skill.strix.note': '보안 테스트 스킬 9종(침투 테스트·OWASP Top 10·취약점 탐지와 수정 흐름)을 공유 .agents/skills에 복사합니다. 스킬이 Strix 에이전트를 구동하므로 PATH에 strix 바이너리가 필요합니다 — 자체 호스팅은 pipx install strix-agent에 Docker와 STRIX_LLM·LLM_API_KEY, 관리형은 strix cloud login. 승인된 대상에만 쓰세요',
285
+ 'item.skill.officecli.note': 'Word·Excel·PowerPoint(.docx·.xlsx·.pptx) 문서를 읽고 고치고 만드는 스킬을 공유 .agents/skills에 복사합니다. 스킬이 officecli 바이너리를 구동하므로 PATH에 officecli가 필요합니다 — npm install -g @officecli/officecli 또는 상류 install.sh·install.ps1. Office 설치는 필요 없습니다',
285
286
  'item.skill.gstack.note': '저장소 로컬 clone + setup (bash 필요, Windows는 Git Bash). 런타임 상태(~/.gstack)는 전역에 생길 수 있음. 부트스트랩 저장소에서는 .claude/skills가 Junction이라 실물이 공유 .agents/skills에 앉습니다 — codex·opencode는 재귀 스캔이라 개별 스킬까지 함께 봅니다',
286
287
  'item.skill.gsd.note': 'npx @opengsd/gsd-core 프로젝트 로컬 설치 — claude·codex·opencode·copilot·kilo 다섯 런타임을 한 번에 배선합니다(.claude/commands, .codex/skills, .opencode/skills, .github/skills, .kilo/skills). 런타임마다 700개 안팎의 파일이 생깁니다. gemini는 상류가 제거했고 kimi는 프로젝트 설치를 아직 막습니다',
287
288
  // 커밋 템플릿은 CLI 배선이 아니라 저장소 규약이다 — en.mjs 쪽 주석 참고.
@@ -474,4 +475,5 @@ export default {
474
475
  'error.ambiguousDesignId': '중복된 이름 \'{token}\' — 제공자를 지정하세요: {options}',
475
476
  'error.designDownload': '{provider}/{name}: DESIGN.md 다운로드 실패',
476
477
  'error.readmeFetch': 'README 가져오기 실패: HTTP {status}',
478
+ 'error.indexFetch': '색인 가져오기 실패: HTTP {status} ({url})',
477
479
  }
@@ -0,0 +1,21 @@
1
+ import { defineRegistrySkill } from '../catalog.mjs'
2
+ // 상류는 루트 SKILL.md(공개 URL이 서빙하는 판)와 skills/officecli/SKILL.md
3
+ // (레지스트리가 발견하는 spec 준수 판)를 바이트 동일하게 유지한다(상류
4
+ // skill-parity 워크플로). 저장소 루트를 source로 주면 레지스트리가 루트
5
+ // SKILL.md를 스킬로 보고 **저장소 전체**(src·assets·워크플로, 94MB·1,208
6
+ // 파일)를 .agents/skills/officecli에 복사한다 — 2026-09-15 실측. 그래서
7
+ // skills/officecli 하위 경로를 준다: SKILL.md 하나(28K)만 들어온다.
8
+ // 잠금 파일의 source는 하위 경로 없이 iOfficeAI/OfficeCLI로 기록되는데,
9
+ // 단일 스킬 항목은 잠금이 아니라 이름으로 지우므로 영향이 없다.
10
+ //
11
+ // 스킬 본문은 officecli 바이너리를 구동하는 지침이라 바이너리가 사실상
12
+ // 전제다 — note가 알린다. 같은 폴더의 전문 스킬 10종(officecli-docx·pptx·
13
+ // xlsx, pitch-deck, morph-ppt 등)은 넣지 않는다 — 상류가 에이전트에 안내하는
14
+ // 공식 경로는 이 하나다(README "For AI Agents").
15
+ export default defineRegistrySkill({
16
+ id: 'skill.officecli', label: 'OfficeCLI', group: '__service',
17
+ source: 'https://github.com/iOfficeAI/OfficeCLI/tree/main/skills/officecli',
18
+ skill: 'officecli',
19
+ note: 'item.skill.officecli.note',
20
+ verified: '2026-09-15',
21
+ })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rch4com/agent-setup",
3
- "version": "1.21.1",
3
+ "version": "1.22.0",
4
4
  "description": "Repository-scoped bootstrap and optional-item installer for using multiple coding-agent CLIs in one repository | 여러 코딩 에이전트 CLI를 한 저장소에서 함께 쓰기 위한 저장소 범위 부트스트랩과 선택 항목 설치기",
5
5
  "keywords": [
6
6
  "agents-md",