@handsupmin/gc-tree 1.1.1 → 1.1.2
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/src/integration-files.js +28 -13
- package/dist/src/scaffold.js +23 -9
- package/dist/src/uninstall.js +16 -6
- package/docs/usage.es.md +3 -2
- package/docs/usage.ja.md +3 -2
- package/docs/usage.ko.md +3 -2
- package/docs/usage.md +3 -2
- package/docs/usage.zh.md +3 -2
- package/package.json +1 -1
|
@@ -65,14 +65,15 @@ export async function removeManagedMarkdownBlock({ filePath, marker, }) {
|
|
|
65
65
|
await writeFile(filePath, next, 'utf8');
|
|
66
66
|
return 'removed';
|
|
67
67
|
}
|
|
68
|
-
function buildHookEntry(event) {
|
|
68
|
+
function buildHookEntry(event, target) {
|
|
69
69
|
return {
|
|
70
70
|
type: 'command',
|
|
71
71
|
command: `gctree __hook --event ${event}`,
|
|
72
72
|
metadata: {
|
|
73
73
|
owner: 'gctree',
|
|
74
|
+
managed_by: '@handsupmin/gc-tree',
|
|
74
75
|
},
|
|
75
|
-
...(event === 'UserPromptSubmit' ? { timeout: 10 } : {}),
|
|
76
|
+
...(target === 'claude-code' || event === 'UserPromptSubmit' ? { timeout: 10 } : {}),
|
|
76
77
|
};
|
|
77
78
|
}
|
|
78
79
|
function ensureObject(value) {
|
|
@@ -95,21 +96,29 @@ function mergeHookJson(raw, target) {
|
|
|
95
96
|
};
|
|
96
97
|
const upsertGroup = (event, matcher) => {
|
|
97
98
|
const groups = ensureEventArray(event);
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
hooks[event] = groups
|
|
100
|
+
.map((candidate) => {
|
|
101
|
+
const group = ensureObject(candidate);
|
|
102
|
+
const hooksArr = Array.isArray(group.hooks) ? group.hooks : [];
|
|
103
|
+
const nextHooks = hooksArr.filter((entry) => !isGcTreeHook(ensureObject(entry), event));
|
|
104
|
+
return nextHooks.length > 0 ? { ...group, hooks: nextHooks } : null;
|
|
105
|
+
})
|
|
106
|
+
.filter(Boolean);
|
|
107
|
+
let group = hooks[event].find((candidate) => {
|
|
108
|
+
if (matcher === undefined)
|
|
109
|
+
return candidate.matcher === undefined;
|
|
110
|
+
return String(candidate.matcher ?? '') === matcher;
|
|
101
111
|
});
|
|
102
112
|
if (!group) {
|
|
103
|
-
group = matcher ? { matcher, hooks: [] } : { hooks: [] };
|
|
104
|
-
|
|
113
|
+
group = matcher !== undefined ? { matcher, hooks: [] } : { hooks: [] };
|
|
114
|
+
hooks[event].push(group);
|
|
105
115
|
}
|
|
106
116
|
if (!Array.isArray(group.hooks))
|
|
107
117
|
group.hooks = [];
|
|
108
|
-
group.hooks
|
|
109
|
-
group.hooks.push(buildHookEntry(event));
|
|
118
|
+
group.hooks.push(buildHookEntry(event, target));
|
|
110
119
|
};
|
|
111
|
-
upsertGroup(sessionEvent, target === 'codex' ? 'startup|resume' : '
|
|
112
|
-
upsertGroup(promptEvent, target === 'codex' ? undefined : '
|
|
120
|
+
upsertGroup(sessionEvent, target === 'codex' ? 'startup|resume' : '');
|
|
121
|
+
upsertGroup(promptEvent, target === 'codex' ? undefined : '');
|
|
113
122
|
return `${JSON.stringify({ ...parsed, hooks }, null, 2)}\n`;
|
|
114
123
|
}
|
|
115
124
|
function unmergeHookJson(raw, events) {
|
|
@@ -166,7 +175,7 @@ export function gctreeManagedMarkdownTargets(targetDir) {
|
|
|
166
175
|
export function gctreeHookJsonTargets(targetDir) {
|
|
167
176
|
return {
|
|
168
177
|
codex: join(targetDir, '.codex', 'hooks.json'),
|
|
169
|
-
claude: join(targetDir, '.claude', '
|
|
178
|
+
claude: join(targetDir, '.claude', 'settings.json'),
|
|
170
179
|
};
|
|
171
180
|
}
|
|
172
181
|
export function gctreeGlobalRoot(host) {
|
|
@@ -177,5 +186,11 @@ export function gctreeGlobalRoot(host) {
|
|
|
177
186
|
}
|
|
178
187
|
export function gctreeGlobalHookJsonTarget(host) {
|
|
179
188
|
const root = gctreeGlobalRoot(host);
|
|
180
|
-
return host === 'codex' ? join(root, 'hooks.json') : join(root, '
|
|
189
|
+
return host === 'codex' ? join(root, 'hooks.json') : join(root, 'settings.json');
|
|
190
|
+
}
|
|
191
|
+
export function gctreeLegacyClaudeHooksJsonTarget(targetDir) {
|
|
192
|
+
return join(targetDir, 'hooks', 'hooks.json');
|
|
193
|
+
}
|
|
194
|
+
export function gctreeLegacyLocalClaudeHooksJsonTarget(targetDir) {
|
|
195
|
+
return join(targetDir, '.claude', 'hooks', 'hooks.json');
|
|
181
196
|
}
|
package/dist/src/scaffold.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { access, mkdir, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
|
-
import { gctreeGlobalHookJsonTarget, gctreeGlobalRoot, gctreeHookJsonTargets, gctreeManagedMarkdownTargets, mergeGcTreeHooksJson, unmergeGcTreeHooksJson, upsertManagedMarkdownBlock, } from './integration-files.js';
|
|
3
|
+
import { gctreeGlobalHookJsonTarget, gctreeGlobalRoot, gctreeHookJsonTargets, gctreeLegacyClaudeHooksJsonTarget, gctreeLegacyLocalClaudeHooksJsonTarget, gctreeManagedMarkdownTargets, mergeGcTreeHooksJson, unmergeGcTreeHooksJson, upsertManagedMarkdownBlock, } from './integration-files.js';
|
|
4
4
|
import { onboardingCompletionLines, onboardingProtocolLines } from './onboarding-protocol.js';
|
|
5
5
|
function renderCodexAgentsSnippet() {
|
|
6
6
|
return [
|
|
@@ -181,11 +181,15 @@ function renderClaudeHooksJson() {
|
|
|
181
181
|
hooks: {
|
|
182
182
|
SessionStart: [
|
|
183
183
|
{
|
|
184
|
-
matcher: '
|
|
184
|
+
matcher: '',
|
|
185
185
|
hooks: [
|
|
186
186
|
{
|
|
187
187
|
type: 'command',
|
|
188
188
|
command: 'gctree __hook --event SessionStart',
|
|
189
|
+
metadata: {
|
|
190
|
+
owner: 'gctree',
|
|
191
|
+
managed_by: '@handsupmin/gc-tree',
|
|
192
|
+
},
|
|
189
193
|
timeout: 10,
|
|
190
194
|
},
|
|
191
195
|
],
|
|
@@ -193,11 +197,15 @@ function renderClaudeHooksJson() {
|
|
|
193
197
|
],
|
|
194
198
|
UserPromptSubmit: [
|
|
195
199
|
{
|
|
196
|
-
matcher: '
|
|
200
|
+
matcher: '',
|
|
197
201
|
hooks: [
|
|
198
202
|
{
|
|
199
203
|
type: 'command',
|
|
200
204
|
command: 'gctree __hook --event UserPromptSubmit',
|
|
205
|
+
metadata: {
|
|
206
|
+
owner: 'gctree',
|
|
207
|
+
managed_by: '@handsupmin/gc-tree',
|
|
208
|
+
},
|
|
201
209
|
timeout: 10,
|
|
202
210
|
},
|
|
203
211
|
],
|
|
@@ -272,7 +280,7 @@ export function scaffoldFiles(host, scope = 'local') {
|
|
|
272
280
|
}
|
|
273
281
|
if (scope === 'global') {
|
|
274
282
|
return [
|
|
275
|
-
{ path: '
|
|
283
|
+
{ path: 'settings.json', content: renderClaudeHooksJson() },
|
|
276
284
|
{ path: 'hooks/gctree-session-start.md', content: renderClaudeSessionStartHook() },
|
|
277
285
|
{ path: 'commands/gc-resolve-context.md', content: renderClaudeResolveCommand() },
|
|
278
286
|
{ path: 'commands/gc-onboard.md', content: renderClaudeOnboardCommand() },
|
|
@@ -281,7 +289,7 @@ export function scaffoldFiles(host, scope = 'local') {
|
|
|
281
289
|
}
|
|
282
290
|
return [
|
|
283
291
|
{ path: 'CLAUDE.md', content: renderClaudeSnippet() },
|
|
284
|
-
{ path: '.claude/
|
|
292
|
+
{ path: '.claude/settings.json', content: renderClaudeHooksJson() },
|
|
285
293
|
{ path: '.claude/hooks/gctree-session-start.md', content: renderClaudeSessionStartHook() },
|
|
286
294
|
{ path: '.claude/commands/gc-resolve-context.md', content: renderClaudeResolveCommand() },
|
|
287
295
|
{ path: '.claude/commands/gc-onboard.md', content: renderClaudeOnboardCommand() },
|
|
@@ -309,15 +317,21 @@ export async function scaffoldHostIntegration({ host, targetDir, force = false,
|
|
|
309
317
|
written.push(managedMarkdownPath);
|
|
310
318
|
hookPath = isCodex ? hookTargets.codex : hookTargets.claude;
|
|
311
319
|
if (!isCodex) {
|
|
312
|
-
const
|
|
313
|
-
await unmergeGcTreeHooksJson(
|
|
320
|
+
const legacyHooksPath = gctreeLegacyLocalClaudeHooksJsonTarget(resolvedTargetDir);
|
|
321
|
+
const legacyStatus = await unmergeGcTreeHooksJson(legacyHooksPath);
|
|
322
|
+
if (legacyStatus !== 'missing') {
|
|
323
|
+
written.push(legacyHooksPath);
|
|
324
|
+
}
|
|
314
325
|
}
|
|
315
326
|
}
|
|
316
327
|
else {
|
|
317
328
|
hookPath = gctreeGlobalHookJsonTarget(host);
|
|
318
329
|
if (!isCodex) {
|
|
319
|
-
const
|
|
320
|
-
await unmergeGcTreeHooksJson(
|
|
330
|
+
const legacyHooksPath = gctreeLegacyClaudeHooksJsonTarget(resolvedTargetDir);
|
|
331
|
+
const legacyStatus = await unmergeGcTreeHooksJson(legacyHooksPath);
|
|
332
|
+
if (legacyStatus !== 'missing') {
|
|
333
|
+
written.push(legacyHooksPath);
|
|
334
|
+
}
|
|
321
335
|
}
|
|
322
336
|
}
|
|
323
337
|
if (scope === 'local') {
|
package/dist/src/uninstall.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readdir, rm } from 'node:fs/promises';
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
|
-
import { gctreeGlobalHookJsonTarget, gctreeGlobalRoot, gctreeHookJsonTargets, gctreeManagedMarkdownTargets, pathExists, removeManagedMarkdownBlock, unmergeGcTreeHooksJson, } from './integration-files.js';
|
|
3
|
+
import { gctreeGlobalHookJsonTarget, gctreeGlobalRoot, gctreeHookJsonTargets, gctreeLegacyClaudeHooksJsonTarget, gctreeLegacyLocalClaudeHooksJsonTarget, gctreeManagedMarkdownTargets, pathExists, removeManagedMarkdownBlock, unmergeGcTreeHooksJson, } from './integration-files.js';
|
|
4
4
|
import { scaffoldFiles } from './scaffold.js';
|
|
5
5
|
async function pathHasEntries(path) {
|
|
6
6
|
const entries = await readdir(path).catch(() => []);
|
|
@@ -26,6 +26,14 @@ async function uninstallHostScaffold({ host, scope, targetDir, removed, }) {
|
|
|
26
26
|
const hookPath = scope === 'local'
|
|
27
27
|
? (isCodex ? gctreeHookJsonTargets(targetDir).codex : gctreeHookJsonTargets(targetDir).claude)
|
|
28
28
|
: gctreeGlobalHookJsonTarget(host);
|
|
29
|
+
const hookPaths = isCodex
|
|
30
|
+
? [hookPath]
|
|
31
|
+
: [
|
|
32
|
+
hookPath,
|
|
33
|
+
scope === 'local'
|
|
34
|
+
? gctreeLegacyLocalClaudeHooksJsonTarget(targetDir)
|
|
35
|
+
: gctreeLegacyClaudeHooksJsonTarget(targetDir),
|
|
36
|
+
];
|
|
29
37
|
if (managedMarkdownPath) {
|
|
30
38
|
const markdownStatus = await removeManagedMarkdownBlock({
|
|
31
39
|
filePath: managedMarkdownPath,
|
|
@@ -36,14 +44,16 @@ async function uninstallHostScaffold({ host, scope, targetDir, removed, }) {
|
|
|
36
44
|
await pruneEmptyParents(managedMarkdownPath, targetDir);
|
|
37
45
|
}
|
|
38
46
|
}
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
for (const candidate of [...new Set(hookPaths)]) {
|
|
48
|
+
const hookStatus = await unmergeGcTreeHooksJson(candidate);
|
|
49
|
+
if (hookStatus !== 'missing') {
|
|
50
|
+
removed.push(candidate);
|
|
51
|
+
await pruneEmptyParents(candidate, targetDir);
|
|
52
|
+
}
|
|
43
53
|
}
|
|
44
54
|
const extraTargets = scaffoldFiles(host, scope)
|
|
45
55
|
.map((file) => join(targetDir, file.path))
|
|
46
|
-
.filter((path) => path
|
|
56
|
+
.filter((path) => !hookPaths.includes(path) && path !== managedMarkdownPath);
|
|
47
57
|
for (const target of [...new Set(extraTargets)]) {
|
|
48
58
|
if (!(await pathExists(target)))
|
|
49
59
|
continue;
|
package/docs/usage.es.md
CHANGED
|
@@ -181,7 +181,7 @@ AGENTS.md ← fragmento de gctree añadido a la
|
|
|
181
181
|
**Archivos globales de Claude Code (`gctree init`):**
|
|
182
182
|
|
|
183
183
|
```
|
|
184
|
-
~/.claude/
|
|
184
|
+
~/.claude/settings.json ← bloque de hooks de auto-resolve para SessionStart/UserPromptSubmit
|
|
185
185
|
~/.claude/hooks/gctree-session-start.md ← nota fallback de inicio de sesión
|
|
186
186
|
~/.claude/commands/gc-resolve-context.md ← comando slash de resolve
|
|
187
187
|
~/.claude/commands/gc-onboard.md ← comando slash de onboard
|
|
@@ -190,9 +190,10 @@ AGENTS.md ← fragmento de gctree añadido a la
|
|
|
190
190
|
|
|
191
191
|
**Archivos de override local para `gctree scaffold --host claude-code`:**
|
|
192
192
|
|
|
193
|
+
Los hooks de Claude Code permanecen en el `~/.claude/settings.json` global; el scaffold local no escribe un archivo de hooks duplicado.
|
|
194
|
+
|
|
193
195
|
```
|
|
194
196
|
CLAUDE.md ← fragmento de gctree añadido
|
|
195
|
-
.claude/hooks/hooks.json ← hooks de auto-resolve para SessionStart/UserPromptSubmit
|
|
196
197
|
.claude/hooks/gctree-session-start.md ← nota fallback de inicio de sesión
|
|
197
198
|
.claude/commands/gc-resolve-context.md ← comando slash de resolve
|
|
198
199
|
.claude/commands/gc-onboard.md ← comando slash de onboard
|
package/docs/usage.ja.md
CHANGED
|
@@ -181,7 +181,7 @@ AGENTS.md ← gctree のスニペットがエ
|
|
|
181
181
|
**Claude Code のグローバルファイル(`gctree init`):**
|
|
182
182
|
|
|
183
183
|
```
|
|
184
|
-
~/.claude/
|
|
184
|
+
~/.claude/settings.json ← SessionStart / UserPromptSubmit の自動 resolve フックブロック
|
|
185
185
|
~/.claude/hooks/gctree-session-start.md ← セッション開始のフォールバックメモ
|
|
186
186
|
~/.claude/commands/gc-resolve-context.md ← resolve スラッシュコマンド
|
|
187
187
|
~/.claude/commands/gc-onboard.md ← onboard スラッシュコマンド
|
|
@@ -190,9 +190,10 @@ AGENTS.md ← gctree のスニペットがエ
|
|
|
190
190
|
|
|
191
191
|
**`gctree scaffold --host claude-code` のローカル override ファイル:**
|
|
192
192
|
|
|
193
|
+
Claude Code のフックはグローバルの `~/.claude/settings.json` に残ります。ローカル scaffold は重複するフックファイルを書きません。
|
|
194
|
+
|
|
193
195
|
```
|
|
194
196
|
CLAUDE.md ← gctree のスニペットが追記される
|
|
195
|
-
.claude/hooks/hooks.json ← SessionStart / UserPromptSubmit の自動 resolve フック
|
|
196
197
|
.claude/hooks/gctree-session-start.md ← セッション開始のフォールバックメモ
|
|
197
198
|
.claude/commands/gc-resolve-context.md ← resolve スラッシュコマンド
|
|
198
199
|
.claude/commands/gc-onboard.md ← onboard スラッシュコマンド
|
package/docs/usage.ko.md
CHANGED
|
@@ -181,7 +181,7 @@ AGENTS.md ← 에이전트 지시사항에 gctr
|
|
|
181
181
|
**Claude Code 전역 파일 (`gctree init`):**
|
|
182
182
|
|
|
183
183
|
```
|
|
184
|
-
~/.claude/
|
|
184
|
+
~/.claude/settings.json ← SessionStart/UserPromptSubmit 자동 resolve 훅 블록
|
|
185
185
|
~/.claude/hooks/gctree-session-start.md ← 세션 시작 fallback 메모
|
|
186
186
|
~/.claude/commands/gc-resolve-context.md ← resolve 슬래시 명령
|
|
187
187
|
~/.claude/commands/gc-onboard.md ← onboard 슬래시 명령
|
|
@@ -190,9 +190,10 @@ AGENTS.md ← 에이전트 지시사항에 gctr
|
|
|
190
190
|
|
|
191
191
|
**`gctree scaffold --host claude-code` 로컬 override 파일:**
|
|
192
192
|
|
|
193
|
+
Claude Code 훅은 전역 `~/.claude/settings.json`에 유지됩니다. 로컬 scaffold는 중복 훅 파일을 쓰지 않습니다.
|
|
194
|
+
|
|
193
195
|
```
|
|
194
196
|
CLAUDE.md ← gctree 스니펫 추가
|
|
195
|
-
.claude/hooks/hooks.json ← SessionStart/UserPromptSubmit 자동 resolve 훅
|
|
196
197
|
.claude/hooks/gctree-session-start.md ← 세션 시작 fallback 메모
|
|
197
198
|
.claude/commands/gc-resolve-context.md ← resolve 슬래시 명령
|
|
198
199
|
.claude/commands/gc-onboard.md ← onboard 슬래시 명령
|
package/docs/usage.md
CHANGED
|
@@ -181,7 +181,7 @@ AGENTS.md ← gctree snippet appended to agent
|
|
|
181
181
|
**Global files for Claude Code (`gctree init`):**
|
|
182
182
|
|
|
183
183
|
```
|
|
184
|
-
~/.claude/
|
|
184
|
+
~/.claude/settings.json ← SessionStart/UserPromptSubmit auto-resolve hooks block
|
|
185
185
|
~/.claude/hooks/gctree-session-start.md ← session-start fallback note
|
|
186
186
|
~/.claude/commands/gc-resolve-context.md ← resolve slash command
|
|
187
187
|
~/.claude/commands/gc-onboard.md ← onboard slash command
|
|
@@ -190,9 +190,10 @@ AGENTS.md ← gctree snippet appended to agent
|
|
|
190
190
|
|
|
191
191
|
**Local override files for `gctree scaffold --host claude-code`:**
|
|
192
192
|
|
|
193
|
+
Claude Code hooks remain in the global `~/.claude/settings.json`; local scaffolding does not write a duplicate hook file.
|
|
194
|
+
|
|
193
195
|
```
|
|
194
196
|
CLAUDE.md ← gctree snippet appended
|
|
195
|
-
.claude/hooks/hooks.json ← SessionStart/UserPromptSubmit auto-resolve hooks
|
|
196
197
|
.claude/hooks/gctree-session-start.md ← session-start fallback note
|
|
197
198
|
.claude/commands/gc-resolve-context.md ← resolve slash command
|
|
198
199
|
.claude/commands/gc-onboard.md ← onboard slash command
|
package/docs/usage.zh.md
CHANGED
|
@@ -181,7 +181,7 @@ AGENTS.md ← gctree 代码片段追加到 agen
|
|
|
181
181
|
**Claude Code 全局文件(`gctree init`):**
|
|
182
182
|
|
|
183
183
|
```
|
|
184
|
-
~/.claude/
|
|
184
|
+
~/.claude/settings.json ← SessionStart / UserPromptSubmit 自动 resolve hook 块
|
|
185
185
|
~/.claude/hooks/gctree-session-start.md ← 会话启动 fallback 说明
|
|
186
186
|
~/.claude/commands/gc-resolve-context.md ← resolve 斜杠命令
|
|
187
187
|
~/.claude/commands/gc-onboard.md ← onboard 斜杠命令
|
|
@@ -190,9 +190,10 @@ AGENTS.md ← gctree 代码片段追加到 agen
|
|
|
190
190
|
|
|
191
191
|
**`gctree scaffold --host claude-code` 的本地 override 文件:**
|
|
192
192
|
|
|
193
|
+
Claude Code hook 保留在全局 `~/.claude/settings.json` 中;本地 scaffold 不写入重复的 hook 文件。
|
|
194
|
+
|
|
193
195
|
```
|
|
194
196
|
CLAUDE.md ← gctree 代码片段追加
|
|
195
|
-
.claude/hooks/hooks.json ← SessionStart / UserPromptSubmit 自动 resolve hook
|
|
196
197
|
.claude/hooks/gctree-session-start.md ← 会话启动 fallback 说明
|
|
197
198
|
.claude/commands/gc-resolve-context.md ← resolve 斜杠命令
|
|
198
199
|
.claude/commands/gc-onboard.md ← onboard 斜杠命令
|