@rch4com/agent-setup 1.0.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.
Files changed (116) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +49 -0
  3. package/install.mjs +83 -0
  4. package/lib/args.mjs +266 -0
  5. package/lib/bootstrap/adapter.mjs +95 -0
  6. package/lib/bootstrap/apply.mjs +269 -0
  7. package/lib/bootstrap/flow.mjs +54 -0
  8. package/lib/bootstrap/manifest.mjs +74 -0
  9. package/lib/bootstrap/templates.mjs +148 -0
  10. package/lib/catalog.mjs +145 -0
  11. package/lib/claude-plugins.mjs +64 -0
  12. package/lib/clis.mjs +102 -0
  13. package/lib/context.mjs +65 -0
  14. package/lib/deps.mjs +19 -0
  15. package/lib/design-md/cache/awesome-design-md/airbnb/DESIGN.md +545 -0
  16. package/lib/design-md/cache/awesome-design-md/airtable/DESIGN.md +554 -0
  17. package/lib/design-md/cache/awesome-design-md/apple/DESIGN.md +562 -0
  18. package/lib/design-md/cache/awesome-design-md/binance/DESIGN.md +634 -0
  19. package/lib/design-md/cache/awesome-design-md/bmw/DESIGN.md +544 -0
  20. package/lib/design-md/cache/awesome-design-md/bmw-m/DESIGN.md +503 -0
  21. package/lib/design-md/cache/awesome-design-md/bugatti/DESIGN.md +454 -0
  22. package/lib/design-md/cache/awesome-design-md/cal/DESIGN.md +542 -0
  23. package/lib/design-md/cache/awesome-design-md/claude/DESIGN.md +589 -0
  24. package/lib/design-md/cache/awesome-design-md/clay/DESIGN.md +541 -0
  25. package/lib/design-md/cache/awesome-design-md/clickhouse/DESIGN.md +544 -0
  26. package/lib/design-md/cache/awesome-design-md/cohere/DESIGN.md +451 -0
  27. package/lib/design-md/cache/awesome-design-md/coinbase/DESIGN.md +570 -0
  28. package/lib/design-md/cache/awesome-design-md/composio/DESIGN.md +506 -0
  29. package/lib/design-md/cache/awesome-design-md/cursor/DESIGN.md +537 -0
  30. package/lib/design-md/cache/awesome-design-md/dell-1996/DESIGN.md +632 -0
  31. package/lib/design-md/cache/awesome-design-md/elevenlabs/DESIGN.md +504 -0
  32. package/lib/design-md/cache/awesome-design-md/expo/DESIGN.md +526 -0
  33. package/lib/design-md/cache/awesome-design-md/ferrari/DESIGN.md +531 -0
  34. package/lib/design-md/cache/awesome-design-md/figma/DESIGN.md +578 -0
  35. package/lib/design-md/cache/awesome-design-md/framer/DESIGN.md +544 -0
  36. package/lib/design-md/cache/awesome-design-md/hashicorp/DESIGN.md +575 -0
  37. package/lib/design-md/cache/awesome-design-md/hp/DESIGN.md +670 -0
  38. package/lib/design-md/cache/awesome-design-md/ibm/DESIGN.md +550 -0
  39. package/lib/design-md/cache/awesome-design-md/intercom/DESIGN.md +546 -0
  40. package/lib/design-md/cache/awesome-design-md/kraken/DESIGN.md +125 -0
  41. package/lib/design-md/cache/awesome-design-md/lamborghini/DESIGN.md +288 -0
  42. package/lib/design-md/cache/awesome-design-md/linear.app/DESIGN.md +548 -0
  43. package/lib/design-md/cache/awesome-design-md/lovable/DESIGN.md +298 -0
  44. package/lib/design-md/cache/awesome-design-md/mastercard/DESIGN.md +365 -0
  45. package/lib/design-md/cache/awesome-design-md/meta/DESIGN.md +683 -0
  46. package/lib/design-md/cache/awesome-design-md/minimax/DESIGN.md +746 -0
  47. package/lib/design-md/cache/awesome-design-md/mintlify/DESIGN.md +852 -0
  48. package/lib/design-md/cache/awesome-design-md/miro/DESIGN.md +825 -0
  49. package/lib/design-md/cache/awesome-design-md/mistral.ai/DESIGN.md +773 -0
  50. package/lib/design-md/cache/awesome-design-md/mongodb/DESIGN.md +767 -0
  51. package/lib/design-md/cache/awesome-design-md/nike/DESIGN.md +575 -0
  52. package/lib/design-md/cache/awesome-design-md/nintendo-2001/DESIGN.md +649 -0
  53. package/lib/design-md/cache/awesome-design-md/notion/DESIGN.md +821 -0
  54. package/lib/design-md/cache/awesome-design-md/nvidia/DESIGN.md +640 -0
  55. package/lib/design-md/cache/awesome-design-md/ollama/DESIGN.md +539 -0
  56. package/lib/design-md/cache/awesome-design-md/opencode.ai/DESIGN.md +521 -0
  57. package/lib/design-md/cache/awesome-design-md/pinterest/DESIGN.md +597 -0
  58. package/lib/design-md/cache/awesome-design-md/playstation/DESIGN.md +661 -0
  59. package/lib/design-md/cache/awesome-design-md/posthog/DESIGN.md +690 -0
  60. package/lib/design-md/cache/awesome-design-md/raycast/DESIGN.md +669 -0
  61. package/lib/design-md/cache/awesome-design-md/renault/DESIGN.md +589 -0
  62. package/lib/design-md/cache/awesome-design-md/replicate/DESIGN.md +616 -0
  63. package/lib/design-md/cache/awesome-design-md/resend/DESIGN.md +585 -0
  64. package/lib/design-md/cache/awesome-design-md/revolut/DESIGN.md +636 -0
  65. package/lib/design-md/cache/awesome-design-md/runwayml/DESIGN.md +244 -0
  66. package/lib/design-md/cache/awesome-design-md/sanity/DESIGN.md +357 -0
  67. package/lib/design-md/cache/awesome-design-md/sentry/DESIGN.md +551 -0
  68. package/lib/design-md/cache/awesome-design-md/shopify/DESIGN.md +516 -0
  69. package/lib/design-md/cache/awesome-design-md/slack/DESIGN.md +482 -0
  70. package/lib/design-md/cache/awesome-design-md/spacex/DESIGN.md +363 -0
  71. package/lib/design-md/cache/awesome-design-md/spotify/DESIGN.md +246 -0
  72. package/lib/design-md/cache/awesome-design-md/starbucks/DESIGN.md +580 -0
  73. package/lib/design-md/cache/awesome-design-md/stripe/DESIGN.md +487 -0
  74. package/lib/design-md/cache/awesome-design-md/supabase/DESIGN.md +462 -0
  75. package/lib/design-md/cache/awesome-design-md/superhuman/DESIGN.md +448 -0
  76. package/lib/design-md/cache/awesome-design-md/tesla/DESIGN.md +286 -0
  77. package/lib/design-md/cache/awesome-design-md/theverge/DESIGN.md +339 -0
  78. package/lib/design-md/cache/awesome-design-md/together.ai/DESIGN.md +633 -0
  79. package/lib/design-md/cache/awesome-design-md/uber/DESIGN.md +636 -0
  80. package/lib/design-md/cache/awesome-design-md/vercel/DESIGN.md +736 -0
  81. package/lib/design-md/cache/awesome-design-md/vodafone/DESIGN.md +538 -0
  82. package/lib/design-md/cache/awesome-design-md/voltagent/DESIGN.md +521 -0
  83. package/lib/design-md/cache/awesome-design-md/warp/DESIGN.md +526 -0
  84. package/lib/design-md/cache/awesome-design-md/webflow/DESIGN.md +588 -0
  85. package/lib/design-md/cache/awesome-design-md/wired/DESIGN.md +497 -0
  86. package/lib/design-md/cache/awesome-design-md/wise/DESIGN.md +544 -0
  87. package/lib/design-md/cache/awesome-design-md/x.ai/DESIGN.md +465 -0
  88. package/lib/design-md/cache/awesome-design-md/zapier/DESIGN.md +537 -0
  89. package/lib/design-md/cache/feelanet/faux/design.md +288 -0
  90. package/lib/design-md/cache/feelanet/faux-teams/design.md +382 -0
  91. package/lib/design-md/catalog.json +454 -0
  92. package/lib/design-md/catalog.mjs +268 -0
  93. package/lib/design-md/flow.mjs +166 -0
  94. package/lib/design-md/open.mjs +50 -0
  95. package/lib/design-md/providers/awesome-design-md.mjs +114 -0
  96. package/lib/design-md/providers/index.mjs +9 -0
  97. package/lib/design-md/scan.mjs +291 -0
  98. package/lib/engine.mjs +44 -0
  99. package/lib/gitignore.mjs +18 -0
  100. package/lib/items/.omc/state/sessions/a859aff7-59d9-4ff6-afc6-8cafe4471dc4/pre-tool-advisory-throttle.json +14 -0
  101. package/lib/items/mcp.codebase-memory.mjs +6 -0
  102. package/lib/items/mcp.notion.mjs +6 -0
  103. package/lib/items/mcp.supabase.mjs +6 -0
  104. package/lib/items/mcp.vercel.mjs +6 -0
  105. package/lib/items/plugin.bkit.mjs +7 -0
  106. package/lib/items/plugin.mattpocock-skills.mjs +8 -0
  107. package/lib/items/plugin.superpowers.mjs +7 -0
  108. package/lib/items/skill.gsd.mjs +24 -0
  109. package/lib/items/skill.gstack.mjs +39 -0
  110. package/lib/jsonfile.mjs +40 -0
  111. package/lib/tomlfile.mjs +60 -0
  112. package/lib/tui/render.mjs +192 -0
  113. package/lib/tui/rows.mjs +206 -0
  114. package/lib/tui/run.mjs +257 -0
  115. package/lib/tui/state.mjs +188 -0
  116. package/package.json +36 -0
@@ -0,0 +1,188 @@
1
+ // 순수 리듀서 — 아무것도 import 하지 않는다. 터미널도 파일시스템도 모른다.
2
+ // 모든 전이는 새 상태를 돌려준다. 키 시퀀스를 넣고 결과를 검증할 수 있게 하기 위해서다.
3
+
4
+ function clamp(n, lo, hi) {
5
+ return n < lo ? lo : n > hi ? hi : n
6
+ }
7
+
8
+ // 탭 = 섹션. 순서는 행 배열의 등장 순서를 그대로 따른다 —
9
+ // buildRows가 이미 SECTION_ORDER로 정렬해 주므로 여기서 순서를 다시 알 필요가 없다.
10
+ export function tabsOf(rows) {
11
+ const out = []
12
+ for (const row of rows) if (!out.includes(row.section)) out.push(row.section)
13
+ return out
14
+ }
15
+
16
+ // 포커스는 두 곳 중 하나에 있다: 'search'(검색 입력칸) 또는 'list'(항목 목록).
17
+ // 어느 쪽이 포커스인지가 Space·타이핑의 뜻을 가른다 — 검색칸에서는 글자가
18
+ // 검색어(스페이스 포함)로, 목록에서는 Space가 선택으로 동작한다.
19
+ // 흔한 TUI의 두-존(zone) 모델이다.
20
+ export function createState(rows, { selectedIds = [], query = '', tabIndex = 0, focus = 'list' } = {}) {
21
+ const tabs = tabsOf(rows)
22
+ const index = clamp(tabIndex, 0, Math.max(0, tabs.length - 1))
23
+ return {
24
+ rows,
25
+ tabs,
26
+ tabIndex: index,
27
+ focus,
28
+ query,
29
+ filtered: visibleRows(rows, query, tabs[index]),
30
+ selected: new Set(selectedIds),
31
+ cursor: 0,
32
+ offset: 0,
33
+ }
34
+ }
35
+
36
+ // 포커스를 검색칸/목록으로 옮긴다. 커서·선택·검색어는 건드리지 않는다.
37
+ export function setFocus(state, focus) {
38
+ return focus === state.focus ? state : { ...state, focus }
39
+ }
40
+
41
+ // 공백으로 나눈 토큰 AND 부분일치.
42
+ // 빈 검색어는 전체 통과다 — 여기서는 빈 검색어가 곧 초기 화면이다.
43
+ // 필터는 selected를 건드리지 않으므로, 빈 검색어가 전체 선택으로 새는 일이 없다.
44
+ export function filterRows(rows, query) {
45
+ const tokens = String(query ?? '').toLowerCase().split(/\s+/).filter(Boolean)
46
+ if (tokens.length === 0) return rows
47
+ return rows.filter((row) => tokens.every((tok) => row.searchText.includes(tok)))
48
+ }
49
+
50
+ // 화면에 실제로 보이는 행 = 활성 탭 ∩ 검색 결과.
51
+ // 검색은 탭 안으로 스코프하되, 다른 탭의 적중 수는 tabCounts로 함께 보여 준다 —
52
+ // 그래야 "어느 탭에 있는지" 를 잃지 않으면서도 Tab 키가 늘 의미를 갖는다.
53
+ function visibleRows(rows, query, tab) {
54
+ return filterRows(rows, query).filter((row) => row.section === tab)
55
+ }
56
+
57
+ export function activeTab(state) {
58
+ return state.tabs[state.tabIndex] ?? null
59
+ }
60
+
61
+ // 탭별 적중 수 — 검색 중에도 어느 탭에 결과가 있는지 한눈에 보이게 한다.
62
+ export function tabCounts(state) {
63
+ const hits = filterRows(state.rows, state.query)
64
+ return state.tabs.map((tab) => ({
65
+ tab,
66
+ shown: hits.filter((r) => r.section === tab).length,
67
+ total: state.rows.filter((r) => r.section === tab).length,
68
+ }))
69
+ }
70
+
71
+ export function currentRow(state) {
72
+ return state.filtered[state.cursor] ?? null
73
+ }
74
+
75
+ function refocus(state, patch) {
76
+ const next = { ...state, ...patch }
77
+ return { ...next, filtered: visibleRows(next.rows, next.query, activeTab(next)), cursor: 0, offset: 0 }
78
+ }
79
+
80
+ // 검색어를 바꾸면 커서는 첫 행으로 돌아간다.
81
+ // selected는 절대 건드리지 않는다 — 화면 밖 설치본이 조용히 사라지지 않게 하는 핵심 규칙이다.
82
+ export function setQuery(state, query) {
83
+ return refocus(state, { query })
84
+ }
85
+
86
+ // 탭 이동은 순환한다 — 탭은 대여섯 개뿐이라 끝에서 막히면 오히려 불편하다.
87
+ // 검색어는 유지한다: 같은 검색어로 탭을 훑는 것이 탭 UI의 본래 쓸모다.
88
+ export function moveTab(state, delta) {
89
+ if (state.tabs.length === 0) return state
90
+ const n = state.tabs.length
91
+ const tabIndex = (((state.tabIndex + delta) % n) + n) % n
92
+ return tabIndex === state.tabIndex ? state : refocus(state, { tabIndex })
93
+ }
94
+
95
+ export function setTab(state, index) {
96
+ if (state.tabs.length === 0) return state
97
+ const tabIndex = clamp(index, 0, state.tabs.length - 1)
98
+ return tabIndex === state.tabIndex ? state : refocus(state, { tabIndex })
99
+ }
100
+
101
+ // 양 끝에서 멈춘다(순환 없음) — 76개 목록에서 한 칸 지나쳤을 때 반대편으로 튀면 길을 잃는다.
102
+ export function move(state, delta) {
103
+ if (state.filtered.length === 0) return state
104
+ const cursor = clamp(state.cursor + delta, 0, state.filtered.length - 1)
105
+ return cursor === state.cursor ? state : { ...state, cursor }
106
+ }
107
+
108
+ // 커서가 항목 행일 때만 뒤집는다. 액션 행은 제거 개념이 없어 체크 대상이 아니다.
109
+ export function toggle(state) {
110
+ const row = currentRow(state)
111
+ if (row?.kind !== 'item') return state
112
+ const selected = new Set(state.selected)
113
+ if (selected.has(row.id)) selected.delete(row.id)
114
+ else selected.add(row.id)
115
+ return { ...state, selected }
116
+ }
117
+
118
+ // 지금 보이는 항목 행 전체를 켜거나 끈다.
119
+ // 보이는 것만 건드린다 — 화면 밖 설치본을 일괄 조작으로 날리지 않기 위해서다.
120
+ export function toggleVisible(state, on) {
121
+ const items = state.filtered.filter((r) => r.kind === 'item')
122
+ if (items.length === 0) return state
123
+ const selected = new Set(state.selected)
124
+ const turnOn = on ?? !items.every((r) => selected.has(r.id))
125
+ for (const row of items) {
126
+ if (turnOn) selected.add(row.id)
127
+ else selected.delete(row.id)
128
+ }
129
+ return { ...state, selected }
130
+ }
131
+
132
+ // 행을 갈아끼운다(적용·액션 실행 뒤 재스캔). 검색어·활성 탭은 유지하고
133
+ // 선택은 새 설치 상태로 재초기화한다.
134
+ export function replaceRows(state, rows, selectedIds) {
135
+ const tabs = tabsOf(rows)
136
+ const tabIndex = clamp(tabs.indexOf(activeTab(state)), 0, Math.max(0, tabs.length - 1))
137
+ const filtered = visibleRows(rows, state.query, tabs[tabIndex])
138
+ return {
139
+ ...state,
140
+ rows,
141
+ tabs,
142
+ tabIndex,
143
+ filtered,
144
+ selected: new Set(selectedIds),
145
+ cursor: clamp(state.cursor, 0, Math.max(0, filtered.length - 1)),
146
+ offset: 0,
147
+ }
148
+ }
149
+
150
+ // 활성 탭의 목록에 그룹 헤더를 끼워 넣는다.
151
+ // 그룹은 행의 group 필드다(design.md는 카테고리, 나머지는 없음) —
152
+ // 탭이 이미 섹션을 갈라 놓았으므로 섹션 헤더는 더 이상 필요 없다.
153
+ export function displayList(state) {
154
+ const tab = activeTab(state)
155
+ const totals = new Map()
156
+ for (const row of state.rows) {
157
+ if (row.section !== tab || !row.group) continue
158
+ totals.set(row.group, (totals.get(row.group) ?? 0) + 1)
159
+ }
160
+
161
+ const out = []
162
+ let header = null
163
+ state.filtered.forEach((row, index) => {
164
+ if (row.group && (!header || header.section !== row.group)) {
165
+ header = { type: 'header', section: row.group, shown: 0, total: totals.get(row.group) ?? 0 }
166
+ out.push(header)
167
+ }
168
+ if (!row.group) header = null
169
+ if (header) header.shown++
170
+ out.push({ type: 'row', row, index })
171
+ })
172
+ return out
173
+ }
174
+
175
+ // 커서가 창 밖으로 나가면 최소한으로 민다. 이미 보이면 그대로 둔다 — 목록이 덜 흔들린다.
176
+ export function scroll(state, height) {
177
+ const lines = displayList(state)
178
+ const line = lines.findIndex((e) => e.type === 'row' && e.index === state.cursor)
179
+ if (line < 0) return state.offset === 0 ? state : { ...state, offset: 0 }
180
+
181
+ let offset = state.offset
182
+ // 커서 바로 위 그룹 헤더까지 같이 보이게 한다 — 어느 그룹을 보고 있는지 잃지 않게.
183
+ const top = lines[line - 1]?.type === 'header' ? line - 1 : line
184
+ if (top < offset) offset = top
185
+ else if (line >= offset + height) offset = line - height + 1
186
+ offset = clamp(offset, 0, Math.max(0, lines.length - height))
187
+ return offset === state.offset ? state : { ...state, offset }
188
+ }
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@rch4com/agent-setup",
3
+ "version": "1.0.0",
4
+ "description": "여러 코딩 에이전트 CLI를 한 저장소에서 함께 쓰기 위한 저장소 범위 부트스트랩과 선택 항목 설치기",
5
+ "keywords": [
6
+ "agents-md",
7
+ "claude-code",
8
+ "codex",
9
+ "gemini-cli",
10
+ "copilot",
11
+ "mcp",
12
+ "agent-skills"
13
+ ],
14
+ "homepage": "https://github.com/rch4com/Agent-Setup#readme",
15
+ "bugs": "https://github.com/rch4com/Agent-Setup/issues",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/rch4com/Agent-Setup.git",
19
+ "directory": "agent-installer"
20
+ },
21
+ "license": "MIT",
22
+ "type": "module",
23
+ "engines": { "node": ">=20" },
24
+ "bin": { "agent-setup": "install.mjs" },
25
+ "files": ["install.mjs", "lib/", "README.md", "LICENSE"],
26
+ "publishConfig": { "access": "public" },
27
+ "scripts": {
28
+ "start": "node install.mjs",
29
+ "test": "node --test \"test/*.test.mjs\"",
30
+ "refresh-bundle": "node scripts/refresh-bundle.mjs"
31
+ },
32
+ "dependencies": {
33
+ "jsonc-parser": "^3.3.1",
34
+ "smol-toml": "^1.3.1"
35
+ }
36
+ }