@handsupmin/gc-tree 0.2.1 → 0.3.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.
- package/README.es.md +1 -1
- package/README.ja.md +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/README.zh.md +1 -1
- package/dist/src/cli.js +25 -0
- package/dist/src/hook.js +209 -0
- package/dist/src/paths.js +6 -0
- package/dist/src/scaffold.js +67 -7
- package/docs/usage.es.md +3 -1
- package/docs/usage.ja.md +3 -1
- package/docs/usage.ko.md +3 -1
- package/docs/usage.md +3 -1
- package/docs/usage.zh.md +3 -1
- package/package.json +1 -1
package/README.es.md
CHANGED
|
@@ -62,7 +62,7 @@ gctree init
|
|
|
62
62
|
2. Instalar los archivos de integración en el repositorio actual
|
|
63
63
|
3. Completar el onboarding guiado para el gc-branch `main`
|
|
64
64
|
|
|
65
|
-
Después, tu herramienta de IA
|
|
65
|
+
Después, tu herramienta de IA instala integración real de hooks SessionStart/UserPromptSubmit: revisa gc-tree automáticamente antes de trabajar y cachea resultados vacíos/no-match durante la sesión.
|
|
66
66
|
|
|
67
67
|
- **CLI:** `gctree`
|
|
68
68
|
- **Requisito:** Node.js 20+
|
package/README.ja.md
CHANGED
|
@@ -62,7 +62,7 @@ gctree init
|
|
|
62
62
|
2. 現在のリポジトリへの統合ファイルのインストール
|
|
63
63
|
3. `main` gc-branch のガイド付きオンボーディング実行
|
|
64
64
|
|
|
65
|
-
その後は、AI
|
|
65
|
+
その後は、AI ツールに実際の SessionStart / UserPromptSubmit フック統合が入り、作業前に gc-tree を自動確認し、空結果や no-match をセッション中キャッシュします。
|
|
66
66
|
|
|
67
67
|
- **CLI:** `gctree`
|
|
68
68
|
- **動作条件:** Node.js 20+
|
package/README.ko.md
CHANGED
|
@@ -62,7 +62,7 @@ gctree init
|
|
|
62
62
|
2. 현재 레포에 통합 파일 스캐폴딩
|
|
63
63
|
3. `main` gc-branch 가이드형 온보딩 실행
|
|
64
64
|
|
|
65
|
-
이후 AI
|
|
65
|
+
이후 AI 도구에 실제 SessionStart/UserPromptSubmit 훅 통합이 설치되어, 작업 전에 gc-tree를 자동 확인하고 세션 동안 빈 결과·no-match를 캐시합니다.
|
|
66
66
|
|
|
67
67
|
- **CLI:** `gctree`
|
|
68
68
|
- **요구 사항:** Node.js 20+
|
package/README.md
CHANGED
|
@@ -62,7 +62,7 @@ gctree init
|
|
|
62
62
|
2. Scaffold the integration files into your current repo
|
|
63
63
|
3. Run guided onboarding for the `main` gc-branch
|
|
64
64
|
|
|
65
|
-
After that, your AI tool
|
|
65
|
+
After that, your AI tool gets real SessionStart/UserPromptSubmit hook integration, so it auto-checks gc-tree before work and caches empty/no-match results for the session.
|
|
66
66
|
|
|
67
67
|
- **CLI:** `gctree`
|
|
68
68
|
- **Requires:** Node.js 20+
|
package/README.zh.md
CHANGED
|
@@ -49,7 +49,7 @@ gctree init
|
|
|
49
49
|
2. 在当前仓库安装集成文件
|
|
50
50
|
3. 为 `main` gc-branch 完成引导式 onboarding
|
|
51
51
|
|
|
52
|
-
之后,AI
|
|
52
|
+
之后,AI 工具会安装真正的 SessionStart / UserPromptSubmit hook 集成:在开始工作前自动检查 gc-tree,并在整个会话内缓存空结果和 no-match。
|
|
53
53
|
|
|
54
54
|
- **CLI:** `gctree`
|
|
55
55
|
- **要求:** Node.js 20+
|
package/dist/src/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import { stdin } from 'node:process';
|
|
4
|
+
import { dispatchGcTreeHook } from './hook.js';
|
|
4
5
|
import { onboardBranch } from './onboard.js';
|
|
5
6
|
import { buildProviderLaunchPlan, maybeLaunchProvider, promptLanguageSelection, promptLaunchProviderSelection, promptProviderSelection, } from './provider.js';
|
|
6
7
|
import { DEFAULT_BRANCH, resolveHome } from './paths.js';
|
|
@@ -37,12 +38,20 @@ function usage() {
|
|
|
37
38
|
Internal commands:
|
|
38
39
|
gctree __apply-onboarding --input FILE [--home DIR] [--branch NAME]
|
|
39
40
|
gctree __apply-update --input FILE [--home DIR] [--branch NAME]
|
|
41
|
+
gctree __hook --event <SessionStart|UserPromptSubmit> [--home DIR]
|
|
40
42
|
`);
|
|
41
43
|
process.exit(1);
|
|
42
44
|
}
|
|
43
45
|
async function readJsonFile(path) {
|
|
44
46
|
return JSON.parse(await readFile(path, 'utf8'));
|
|
45
47
|
}
|
|
48
|
+
async function readStdinText() {
|
|
49
|
+
const chunks = [];
|
|
50
|
+
for await (const chunk of process.stdin) {
|
|
51
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
|
|
52
|
+
}
|
|
53
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
54
|
+
}
|
|
46
55
|
function normalizeProvider(value) {
|
|
47
56
|
if (!value)
|
|
48
57
|
return undefined;
|
|
@@ -337,6 +346,22 @@ async function main() {
|
|
|
337
346
|
console.log(JSON.stringify(result, null, 2));
|
|
338
347
|
return;
|
|
339
348
|
}
|
|
349
|
+
case '__hook': {
|
|
350
|
+
const event = readArg('--event');
|
|
351
|
+
if (event !== 'SessionStart' && event !== 'UserPromptSubmit')
|
|
352
|
+
usage();
|
|
353
|
+
const raw = await readStdinText();
|
|
354
|
+
const payload = raw.trim() ? JSON.parse(raw) : {};
|
|
355
|
+
const result = await dispatchGcTreeHook({
|
|
356
|
+
event,
|
|
357
|
+
home,
|
|
358
|
+
payload,
|
|
359
|
+
});
|
|
360
|
+
if (result) {
|
|
361
|
+
console.log(JSON.stringify(result, null, 2));
|
|
362
|
+
}
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
340
365
|
case 'scaffold': {
|
|
341
366
|
const host = normalizeProviderMode(readArg('--host'));
|
|
342
367
|
if (!host)
|
package/dist/src/hook.js
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { dirname } from 'node:path';
|
|
4
|
+
import { DEFAULT_BRANCH } from './paths.js';
|
|
5
|
+
import { hookCachePath, } from './paths.js';
|
|
6
|
+
import { branchScopeStatus, readBranchRepoMap, resolveBranchForRepo } from './repo-map.js';
|
|
7
|
+
import { resolveContext } from './resolve.js';
|
|
8
|
+
import { readHead, statusForBranch } from './store.js';
|
|
9
|
+
function normalizeText(value) {
|
|
10
|
+
return value.trim().replace(/\s+/g, ' ');
|
|
11
|
+
}
|
|
12
|
+
function hashQuery(query) {
|
|
13
|
+
return createHash('sha1').update(normalizeText(query).toLowerCase()).digest('hex');
|
|
14
|
+
}
|
|
15
|
+
function limitMatches(matches, max = 3) {
|
|
16
|
+
return matches.slice(0, max);
|
|
17
|
+
}
|
|
18
|
+
function formatMatches(matches) {
|
|
19
|
+
return limitMatches(matches)
|
|
20
|
+
.map((match, index) => `${index + 1}. ${match.title}\n Summary: ${match.summary}\n Excerpt: ${match.excerpt}`)
|
|
21
|
+
.join('\n');
|
|
22
|
+
}
|
|
23
|
+
function buildSessionStartContext({ gcBranch, currentRepo, repoScopeStatus, }) {
|
|
24
|
+
return [
|
|
25
|
+
`gc-tree auto-resolve is active for this session.`,
|
|
26
|
+
`Active gc-branch: "${gcBranch}".`,
|
|
27
|
+
`Current repo: ${currentRepo || 'unscoped'}.`,
|
|
28
|
+
`Repo scope status: ${repoScopeStatus}.`,
|
|
29
|
+
`Before acting on new user prompts, use gc-tree hook context first. If the hook reports no reusable global context, avoid redundant resolve calls for the same session state unless the repo, gc-branch, or task changes materially.`,
|
|
30
|
+
].join(' ');
|
|
31
|
+
}
|
|
32
|
+
function buildEmptyBranchContext({ gcBranch, currentRepo, cached, }) {
|
|
33
|
+
return [
|
|
34
|
+
`gc-tree auto-resolve ${cached ? 'used cached state' : 'checked the active gc-branch'} and found no reusable global context for this session because gc-branch "${gcBranch}" currently has 0 docs.`,
|
|
35
|
+
`Repo: ${currentRepo || 'unscoped'}.`,
|
|
36
|
+
`Treat this as "no reusable global context yet" until the gc-branch content changes or a different repo/gc-branch is active.`,
|
|
37
|
+
].join(' ');
|
|
38
|
+
}
|
|
39
|
+
function buildExcludedContext({ gcBranch, currentRepo, cached, }) {
|
|
40
|
+
return [
|
|
41
|
+
`gc-tree auto-resolve ${cached ? 'used cached state' : 'checked the active gc-branch'} and found that repo "${currentRepo || 'unknown'}" is excluded from gc-branch "${gcBranch}".`,
|
|
42
|
+
`No reusable global context applies here unless the branch-repo mapping changes.`,
|
|
43
|
+
].join(' ');
|
|
44
|
+
}
|
|
45
|
+
function buildNoMatchContext({ gcBranch, currentRepo, query, cached, }) {
|
|
46
|
+
return [
|
|
47
|
+
`gc-tree auto-resolve ${cached ? 'skipped a redundant lookup using cached no-match state' : 'checked the active gc-branch'} and found no reusable global context for this prompt in gc-branch "${gcBranch}".`,
|
|
48
|
+
`Repo: ${currentRepo || 'unscoped'}.`,
|
|
49
|
+
`Query: "${query}".`,
|
|
50
|
+
`Only re-run resolve if the repo, gc-branch, or task changes materially.`,
|
|
51
|
+
].join(' ');
|
|
52
|
+
}
|
|
53
|
+
function buildMatchContext({ gcBranch, currentRepo, repoScopeStatus, query, matches, }) {
|
|
54
|
+
return [
|
|
55
|
+
`gc-tree auto-resolve checked gc-branch "${gcBranch}" for repo "${currentRepo || 'unscoped'}" (scope: ${repoScopeStatus}) before this prompt.`,
|
|
56
|
+
`Query: "${query}".`,
|
|
57
|
+
`Use these matching gc-tree summaries before planning or implementation:`,
|
|
58
|
+
formatMatches(matches),
|
|
59
|
+
`Read full docs only if the summaries are insufficient.`,
|
|
60
|
+
].join('\n');
|
|
61
|
+
}
|
|
62
|
+
async function readHookCache(home, sessionId) {
|
|
63
|
+
try {
|
|
64
|
+
const raw = await readFile(hookCachePath(home, sessionId), 'utf8');
|
|
65
|
+
return JSON.parse(raw);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async function writeHookCache(home, cache) {
|
|
72
|
+
const path = hookCachePath(home, cache.session_id);
|
|
73
|
+
await mkdir(dirname(path), { recursive: true });
|
|
74
|
+
await writeFile(path, `${JSON.stringify(cache, null, 2)}\n`, 'utf8');
|
|
75
|
+
}
|
|
76
|
+
function nextCacheState(previous, { sessionId, gcBranch, currentRepo, repoScopeStatus, }) {
|
|
77
|
+
const changed = !previous ||
|
|
78
|
+
previous.gc_branch !== gcBranch ||
|
|
79
|
+
previous.current_repo !== currentRepo ||
|
|
80
|
+
previous.repo_scope_status !== repoScopeStatus;
|
|
81
|
+
return {
|
|
82
|
+
version: 1,
|
|
83
|
+
session_id: sessionId,
|
|
84
|
+
gc_branch: gcBranch,
|
|
85
|
+
current_repo: currentRepo,
|
|
86
|
+
repo_scope_status: repoScopeStatus,
|
|
87
|
+
branch_empty: changed ? false : previous.branch_empty,
|
|
88
|
+
branch_excluded: changed ? false : previous.branch_excluded,
|
|
89
|
+
no_match_signatures: changed ? [] : previous.no_match_signatures,
|
|
90
|
+
updated_at: new Date().toISOString(),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function readSessionId(payload) {
|
|
94
|
+
const raw = normalizeText(payload.session_id || '');
|
|
95
|
+
return raw || 'default-session';
|
|
96
|
+
}
|
|
97
|
+
export async function dispatchGcTreeHook({ event, home, payload, }) {
|
|
98
|
+
const cwd = payload.cwd || process.cwd();
|
|
99
|
+
const head = (await readHead(home)) || DEFAULT_BRANCH;
|
|
100
|
+
const resolved = await resolveBranchForRepo({ home, head, cwd });
|
|
101
|
+
const gcBranch = resolved.gc_branch;
|
|
102
|
+
const currentRepo = resolved.current_repo;
|
|
103
|
+
const mapping = await readBranchRepoMap(home);
|
|
104
|
+
const repoScopeStatus = branchScopeStatus(mapping, gcBranch, currentRepo);
|
|
105
|
+
const sessionId = readSessionId(payload);
|
|
106
|
+
if (event === 'SessionStart') {
|
|
107
|
+
return {
|
|
108
|
+
hookSpecificOutput: {
|
|
109
|
+
hookEventName: event,
|
|
110
|
+
additionalContext: buildSessionStartContext({
|
|
111
|
+
gcBranch,
|
|
112
|
+
currentRepo,
|
|
113
|
+
repoScopeStatus,
|
|
114
|
+
}),
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const prompt = normalizeText(payload.user_prompt || '');
|
|
119
|
+
if (!prompt)
|
|
120
|
+
return null;
|
|
121
|
+
const branchStatus = await statusForBranch(home, gcBranch);
|
|
122
|
+
const previousCache = await readHookCache(home, sessionId);
|
|
123
|
+
const cache = nextCacheState(previousCache, {
|
|
124
|
+
sessionId,
|
|
125
|
+
gcBranch,
|
|
126
|
+
currentRepo,
|
|
127
|
+
repoScopeStatus,
|
|
128
|
+
});
|
|
129
|
+
if (repoScopeStatus === 'excluded') {
|
|
130
|
+
cache.branch_excluded = true;
|
|
131
|
+
cache.updated_at = new Date().toISOString();
|
|
132
|
+
await writeHookCache(home, cache);
|
|
133
|
+
return {
|
|
134
|
+
hookSpecificOutput: {
|
|
135
|
+
hookEventName: event,
|
|
136
|
+
additionalContext: buildExcludedContext({
|
|
137
|
+
gcBranch,
|
|
138
|
+
currentRepo,
|
|
139
|
+
cached: previousCache?.branch_excluded === true,
|
|
140
|
+
}),
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
if (branchStatus.doc_count === 0) {
|
|
145
|
+
const wasCached = cache.branch_empty;
|
|
146
|
+
cache.branch_empty = true;
|
|
147
|
+
cache.updated_at = new Date().toISOString();
|
|
148
|
+
await writeHookCache(home, cache);
|
|
149
|
+
return {
|
|
150
|
+
hookSpecificOutput: {
|
|
151
|
+
hookEventName: event,
|
|
152
|
+
additionalContext: buildEmptyBranchContext({
|
|
153
|
+
gcBranch,
|
|
154
|
+
currentRepo,
|
|
155
|
+
cached: wasCached,
|
|
156
|
+
}),
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
const query = currentRepo ? `${currentRepo} ${prompt}` : prompt;
|
|
161
|
+
const signature = hashQuery(query);
|
|
162
|
+
if (cache.no_match_signatures.includes(signature)) {
|
|
163
|
+
cache.updated_at = new Date().toISOString();
|
|
164
|
+
await writeHookCache(home, cache);
|
|
165
|
+
return {
|
|
166
|
+
hookSpecificOutput: {
|
|
167
|
+
hookEventName: event,
|
|
168
|
+
additionalContext: buildNoMatchContext({
|
|
169
|
+
gcBranch,
|
|
170
|
+
currentRepo,
|
|
171
|
+
query,
|
|
172
|
+
cached: true,
|
|
173
|
+
}),
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
const result = await resolveContext({ home, branch: gcBranch, query });
|
|
178
|
+
if (result.matches.length === 0) {
|
|
179
|
+
cache.no_match_signatures = [...new Set([...cache.no_match_signatures, signature])];
|
|
180
|
+
cache.updated_at = new Date().toISOString();
|
|
181
|
+
await writeHookCache(home, cache);
|
|
182
|
+
return {
|
|
183
|
+
hookSpecificOutput: {
|
|
184
|
+
hookEventName: event,
|
|
185
|
+
additionalContext: buildNoMatchContext({
|
|
186
|
+
gcBranch,
|
|
187
|
+
currentRepo,
|
|
188
|
+
query,
|
|
189
|
+
cached: false,
|
|
190
|
+
}),
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
cache.no_match_signatures = cache.no_match_signatures.filter((entry) => entry !== signature);
|
|
195
|
+
cache.updated_at = new Date().toISOString();
|
|
196
|
+
await writeHookCache(home, cache);
|
|
197
|
+
return {
|
|
198
|
+
hookSpecificOutput: {
|
|
199
|
+
hookEventName: event,
|
|
200
|
+
additionalContext: buildMatchContext({
|
|
201
|
+
gcBranch,
|
|
202
|
+
currentRepo,
|
|
203
|
+
repoScopeStatus,
|
|
204
|
+
query,
|
|
205
|
+
matches: result.matches,
|
|
206
|
+
}),
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
}
|
package/dist/src/paths.js
CHANGED
|
@@ -26,3 +26,9 @@ export function branchIndexPath(home, branch) {
|
|
|
26
26
|
export function branchDocsDir(home, branch) {
|
|
27
27
|
return join(branchDir(home, branch), 'docs');
|
|
28
28
|
}
|
|
29
|
+
export function hookCacheDir(home) {
|
|
30
|
+
return join(home, 'hook-cache');
|
|
31
|
+
}
|
|
32
|
+
export function hookCachePath(home, sessionId) {
|
|
33
|
+
return join(hookCacheDir(home), `${sessionId}.json`);
|
|
34
|
+
}
|
package/dist/src/scaffold.js
CHANGED
|
@@ -6,8 +6,8 @@ function renderCodexAgentsSnippet() {
|
|
|
6
6
|
'# gctree Codex integration snippet',
|
|
7
7
|
'',
|
|
8
8
|
'- Treat the active gctree branch as a **gc-branch** when you describe it to users.',
|
|
9
|
-
'-
|
|
10
|
-
'- Use `gctree resolve --query "<task>"`
|
|
9
|
+
'- gctree init installs SessionStart and UserPromptSubmit hooks that auto-check gc-tree before work.',
|
|
10
|
+
'- Use the hook-injected gc-tree context first. If hooks are unavailable or clearly stale, run `gctree status` and `gctree resolve --query "<task>"` yourself before planning or implementation.',
|
|
11
11
|
'- Use `$gc-onboard` only for an empty gc-branch.',
|
|
12
12
|
'- Use `$gc-update-global-context` when durable context in the active gc-branch should change.',
|
|
13
13
|
'',
|
|
@@ -18,12 +18,39 @@ function renderCodexBootstrapPrompt() {
|
|
|
18
18
|
'# gctree Bootstrap',
|
|
19
19
|
'',
|
|
20
20
|
'- Keep the active gc-branch explicit whenever global context matters.',
|
|
21
|
-
'-
|
|
21
|
+
'- Trust auto-resolved gc-tree hook context first; if it is missing, resolve reusable global context before planning or implementation.',
|
|
22
22
|
'- Read summaries first and only open full docs when needed.',
|
|
23
23
|
'- Treat gctree docs as explicit source-of-truth markdown, not hidden memory.',
|
|
24
24
|
'',
|
|
25
25
|
].join('\n');
|
|
26
26
|
}
|
|
27
|
+
function renderCodexHooksJson() {
|
|
28
|
+
return JSON.stringify({
|
|
29
|
+
hooks: {
|
|
30
|
+
SessionStart: [
|
|
31
|
+
{
|
|
32
|
+
matcher: 'startup|resume',
|
|
33
|
+
hooks: [
|
|
34
|
+
{
|
|
35
|
+
type: 'command',
|
|
36
|
+
command: 'gctree __hook --event SessionStart',
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
UserPromptSubmit: [
|
|
42
|
+
{
|
|
43
|
+
hooks: [
|
|
44
|
+
{
|
|
45
|
+
type: 'command',
|
|
46
|
+
command: 'gctree __hook --event UserPromptSubmit',
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
}, null, 2);
|
|
53
|
+
}
|
|
27
54
|
function renderCodexResolveSkill() {
|
|
28
55
|
return [
|
|
29
56
|
'---',
|
|
@@ -80,8 +107,8 @@ function renderClaudeSnippet() {
|
|
|
80
107
|
'# gctree Claude Code integration snippet',
|
|
81
108
|
'',
|
|
82
109
|
'- Treat the active gctree branch as a **gc-branch** in user-facing language.',
|
|
83
|
-
'-
|
|
84
|
-
'- Use `gctree resolve --query "<task>"`
|
|
110
|
+
'- gctree init installs SessionStart and UserPromptSubmit hooks that auto-check gc-tree before work.',
|
|
111
|
+
'- Use the hook-injected gc-tree context first. If hooks are unavailable or clearly stale, run `gctree status` and `gctree resolve --query "<task>"` yourself before planning or implementation.',
|
|
85
112
|
'- Use `/gc-onboard` only for an empty gc-branch.',
|
|
86
113
|
'- Use `/gc-update-global-context` when durable context in the active gc-branch should change.',
|
|
87
114
|
'',
|
|
@@ -91,12 +118,43 @@ function renderClaudeSessionStartHook() {
|
|
|
91
118
|
return [
|
|
92
119
|
'# gctree Claude Code SessionStart note',
|
|
93
120
|
'',
|
|
94
|
-
'-
|
|
121
|
+
'- gctree init installs real SessionStart/UserPromptSubmit hooks via `.claude/hooks/hooks.json`.',
|
|
122
|
+
'- At session start, use the injected hook context to confirm the active gc-branch.',
|
|
95
123
|
'- Refer to gctree branches as **gc-branches** in user-facing language.',
|
|
96
|
-
'-
|
|
124
|
+
'- If hook context is missing or stale, resolve summaries before planning or implementation when branch-level context may change the answer.',
|
|
97
125
|
'',
|
|
98
126
|
].join('\n');
|
|
99
127
|
}
|
|
128
|
+
function renderClaudeHooksJson() {
|
|
129
|
+
return JSON.stringify({
|
|
130
|
+
hooks: {
|
|
131
|
+
SessionStart: [
|
|
132
|
+
{
|
|
133
|
+
matcher: '*',
|
|
134
|
+
hooks: [
|
|
135
|
+
{
|
|
136
|
+
type: 'command',
|
|
137
|
+
command: 'gctree __hook --event SessionStart',
|
|
138
|
+
timeout: 10,
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
UserPromptSubmit: [
|
|
144
|
+
{
|
|
145
|
+
matcher: '*',
|
|
146
|
+
hooks: [
|
|
147
|
+
{
|
|
148
|
+
type: 'command',
|
|
149
|
+
command: 'gctree __hook --event UserPromptSubmit',
|
|
150
|
+
timeout: 10,
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
},
|
|
156
|
+
}, null, 2);
|
|
157
|
+
}
|
|
100
158
|
function renderClaudeResolveCommand() {
|
|
101
159
|
return [
|
|
102
160
|
'---',
|
|
@@ -150,6 +208,7 @@ function scaffoldFiles(host) {
|
|
|
150
208
|
if (host === 'codex') {
|
|
151
209
|
return [
|
|
152
210
|
{ path: 'AGENTS.md', content: renderCodexAgentsSnippet() },
|
|
211
|
+
{ path: '.codex/hooks.json', content: renderCodexHooksJson() },
|
|
153
212
|
{ path: '.codex/prompts/gctree-bootstrap.md', content: renderCodexBootstrapPrompt() },
|
|
154
213
|
{ path: '.codex/skills/gc-resolve-context/SKILL.md', content: renderCodexResolveSkill() },
|
|
155
214
|
{ path: '.codex/skills/gc-onboard/SKILL.md', content: renderCodexOnboardSkill() },
|
|
@@ -158,6 +217,7 @@ function scaffoldFiles(host) {
|
|
|
158
217
|
}
|
|
159
218
|
return [
|
|
160
219
|
{ path: 'CLAUDE.md', content: renderClaudeSnippet() },
|
|
220
|
+
{ path: '.claude/hooks/hooks.json', content: renderClaudeHooksJson() },
|
|
161
221
|
{ path: '.claude/hooks/gctree-session-start.md', content: renderClaudeSessionStartHook() },
|
|
162
222
|
{ path: '.claude/commands/gc-resolve-context.md', content: renderClaudeResolveCommand() },
|
|
163
223
|
{ path: '.claude/commands/gc-onboard.md', content: renderClaudeOnboardCommand() },
|
package/docs/usage.es.md
CHANGED
|
@@ -145,6 +145,7 @@ gctree scaffold --host both --target /path/to/repo
|
|
|
145
145
|
|
|
146
146
|
```
|
|
147
147
|
AGENTS.md ← fragmento de gctree añadido a las instrucciones del agente
|
|
148
|
+
.codex/hooks.json ← hooks de auto-resolve para SessionStart/UserPromptSubmit
|
|
148
149
|
.codex/prompts/gctree-bootstrap.md ← contexto de arranque para las sesiones de Codex
|
|
149
150
|
.codex/skills/gc-resolve-context/SKILL.md ← skill de resolve
|
|
150
151
|
.codex/skills/gc-onboard/SKILL.md ← skill de onboarding
|
|
@@ -155,7 +156,8 @@ AGENTS.md ← fragmento de gctree añadido a la
|
|
|
155
156
|
|
|
156
157
|
```
|
|
157
158
|
CLAUDE.md ← fragmento de gctree añadido
|
|
158
|
-
.claude/hooks/
|
|
159
|
+
.claude/hooks/hooks.json ← hooks de auto-resolve para SessionStart/UserPromptSubmit
|
|
160
|
+
.claude/hooks/gctree-session-start.md ← nota fallback de inicio de sesión
|
|
159
161
|
.claude/commands/gc-resolve-context.md ← comando slash de resolve
|
|
160
162
|
.claude/commands/gc-onboard.md ← comando slash de onboard
|
|
161
163
|
.claude/commands/gc-update-global-context.md ← comando slash de actualización
|
package/docs/usage.ja.md
CHANGED
|
@@ -145,6 +145,7 @@ gctree scaffold --host both --target /path/to/repo
|
|
|
145
145
|
|
|
146
146
|
```
|
|
147
147
|
AGENTS.md ← gctree のスニペットがエージェント指示に追記される
|
|
148
|
+
.codex/hooks.json ← SessionStart / UserPromptSubmit の自動 resolve フック
|
|
148
149
|
.codex/prompts/gctree-bootstrap.md ← Codex セッション向けのブートストラップコンテキスト
|
|
149
150
|
.codex/skills/gc-resolve-context/SKILL.md ← resolve スキル
|
|
150
151
|
.codex/skills/gc-onboard/SKILL.md ← オンボーディングスキル
|
|
@@ -155,7 +156,8 @@ AGENTS.md ← gctree のスニペットがエ
|
|
|
155
156
|
|
|
156
157
|
```
|
|
157
158
|
CLAUDE.md ← gctree のスニペットが追記される
|
|
158
|
-
.claude/hooks/
|
|
159
|
+
.claude/hooks/hooks.json ← SessionStart / UserPromptSubmit の自動 resolve フック
|
|
160
|
+
.claude/hooks/gctree-session-start.md ← セッション開始のフォールバックメモ
|
|
159
161
|
.claude/commands/gc-resolve-context.md ← resolve スラッシュコマンド
|
|
160
162
|
.claude/commands/gc-onboard.md ← onboard スラッシュコマンド
|
|
161
163
|
.claude/commands/gc-update-global-context.md ← 更新スラッシュコマンド
|
package/docs/usage.ko.md
CHANGED
|
@@ -145,6 +145,7 @@ gctree scaffold --host both --target /path/to/repo
|
|
|
145
145
|
|
|
146
146
|
```
|
|
147
147
|
AGENTS.md ← 에이전트 지시사항에 gctree 스니펫 추가
|
|
148
|
+
.codex/hooks.json ← SessionStart/UserPromptSubmit 자동 resolve 훅
|
|
148
149
|
.codex/prompts/gctree-bootstrap.md ← Codex 세션의 부트스트랩 컨텍스트
|
|
149
150
|
.codex/skills/gc-resolve-context/SKILL.md ← resolve 스킬
|
|
150
151
|
.codex/skills/gc-onboard/SKILL.md ← 온보딩 스킬
|
|
@@ -155,7 +156,8 @@ AGENTS.md ← 에이전트 지시사항에 gctr
|
|
|
155
156
|
|
|
156
157
|
```
|
|
157
158
|
CLAUDE.md ← gctree 스니펫 추가
|
|
158
|
-
.claude/hooks/
|
|
159
|
+
.claude/hooks/hooks.json ← SessionStart/UserPromptSubmit 자동 resolve 훅
|
|
160
|
+
.claude/hooks/gctree-session-start.md ← 세션 시작 fallback 메모
|
|
159
161
|
.claude/commands/gc-resolve-context.md ← resolve 슬래시 명령
|
|
160
162
|
.claude/commands/gc-onboard.md ← onboard 슬래시 명령
|
|
161
163
|
.claude/commands/gc-update-global-context.md ← 업데이트 슬래시 명령
|
package/docs/usage.md
CHANGED
|
@@ -145,6 +145,7 @@ gctree scaffold --host both --target /path/to/repo
|
|
|
145
145
|
|
|
146
146
|
```
|
|
147
147
|
AGENTS.md ← gctree snippet appended to agent instructions
|
|
148
|
+
.codex/hooks.json ← SessionStart/UserPromptSubmit auto-resolve hooks
|
|
148
149
|
.codex/prompts/gctree-bootstrap.md ← bootstrap context for Codex sessions
|
|
149
150
|
.codex/skills/gc-resolve-context/SKILL.md ← resolve skill
|
|
150
151
|
.codex/skills/gc-onboard/SKILL.md ← onboarding skill
|
|
@@ -155,7 +156,8 @@ AGENTS.md ← gctree snippet appended to agent
|
|
|
155
156
|
|
|
156
157
|
```
|
|
157
158
|
CLAUDE.md ← gctree snippet appended
|
|
158
|
-
.claude/hooks/
|
|
159
|
+
.claude/hooks/hooks.json ← SessionStart/UserPromptSubmit auto-resolve hooks
|
|
160
|
+
.claude/hooks/gctree-session-start.md ← session-start fallback note
|
|
159
161
|
.claude/commands/gc-resolve-context.md ← resolve slash command
|
|
160
162
|
.claude/commands/gc-onboard.md ← onboard slash command
|
|
161
163
|
.claude/commands/gc-update-global-context.md ← update slash command
|
package/docs/usage.zh.md
CHANGED
|
@@ -145,6 +145,7 @@ gctree scaffold --host both --target /path/to/repo
|
|
|
145
145
|
|
|
146
146
|
```
|
|
147
147
|
AGENTS.md ← gctree 代码片段追加到 agent 指令中
|
|
148
|
+
.codex/hooks.json ← SessionStart / UserPromptSubmit 自动 resolve hook
|
|
148
149
|
.codex/prompts/gctree-bootstrap.md ← Codex 会话的引导上下文
|
|
149
150
|
.codex/skills/gc-resolve-context/SKILL.md ← resolve 技能
|
|
150
151
|
.codex/skills/gc-onboard/SKILL.md ← onboarding 技能
|
|
@@ -155,7 +156,8 @@ AGENTS.md ← gctree 代码片段追加到 agen
|
|
|
155
156
|
|
|
156
157
|
```
|
|
157
158
|
CLAUDE.md ← gctree 代码片段追加
|
|
158
|
-
.claude/hooks/
|
|
159
|
+
.claude/hooks/hooks.json ← SessionStart / UserPromptSubmit 自动 resolve hook
|
|
160
|
+
.claude/hooks/gctree-session-start.md ← 会话启动 fallback 说明
|
|
159
161
|
.claude/commands/gc-resolve-context.md ← resolve 斜杠命令
|
|
160
162
|
.claude/commands/gc-onboard.md ← onboard 斜杠命令
|
|
161
163
|
.claude/commands/gc-update-global-context.md ← 更新斜杠命令
|