@handsupmin/gc-tree 0.1.1
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/LICENSE +21 -0
- package/README.es.md +166 -0
- package/README.ja.md +166 -0
- package/README.ko.md +166 -0
- package/README.md +166 -0
- package/README.zh.md +166 -0
- package/dist/src/cli.js +360 -0
- package/dist/src/markdown.js +81 -0
- package/dist/src/onboard.js +36 -0
- package/dist/src/onboarding-protocol.js +38 -0
- package/dist/src/paths.js +28 -0
- package/dist/src/proposals.js +73 -0
- package/dist/src/provider.js +121 -0
- package/dist/src/repo-map.js +149 -0
- package/dist/src/resolve.js +38 -0
- package/dist/src/scaffold.js +199 -0
- package/dist/src/settings.js +30 -0
- package/dist/src/store.js +149 -0
- package/dist/src/types.js +1 -0
- package/dist/src/update.js +26 -0
- package/docs/concept.es.md +81 -0
- package/docs/concept.ja.md +81 -0
- package/docs/concept.ko.md +81 -0
- package/docs/concept.md +81 -0
- package/docs/concept.zh.md +81 -0
- package/docs/local-development.es.md +83 -0
- package/docs/local-development.ja.md +83 -0
- package/docs/local-development.ko.md +83 -0
- package/docs/local-development.md +83 -0
- package/docs/local-development.zh.md +83 -0
- package/docs/principles.es.md +49 -0
- package/docs/principles.ja.md +49 -0
- package/docs/principles.ko.md +49 -0
- package/docs/principles.md +50 -0
- package/docs/principles.zh.md +49 -0
- package/docs/usage.es.md +119 -0
- package/docs/usage.ja.md +119 -0
- package/docs/usage.ko.md +119 -0
- package/docs/usage.md +121 -0
- package/docs/usage.zh.md +119 -0
- package/package.json +32 -0
- package/skills/checkout/SKILL.md +17 -0
- package/skills/onboard/SKILL.md +74 -0
- package/skills/reset-gc-branch/SKILL.md +14 -0
- package/skills/resolve-context/SKILL.md +21 -0
- package/skills/update-global-context/SKILL.md +21 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { cp, mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { branchDir, branchDocsDir, branchIndexPath, branchMetaPath, branchesRoot, DEFAULT_BRANCH, headPath, INDEX_WARNING_CHARS, } from './paths.js';
|
|
5
|
+
import { renderIndexMarkdown } from './markdown.js';
|
|
6
|
+
export async function ensureHome(home) {
|
|
7
|
+
await mkdir(branchesRoot(home), { recursive: true });
|
|
8
|
+
}
|
|
9
|
+
export async function readHead(home) {
|
|
10
|
+
try {
|
|
11
|
+
return (await readFile(headPath(home), 'utf8')).trim() || null;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export async function writeHead(home, branch) {
|
|
18
|
+
await ensureHome(home);
|
|
19
|
+
await writeFile(headPath(home), `${branch}\n`, 'utf8');
|
|
20
|
+
}
|
|
21
|
+
export async function initHome(home, branch = DEFAULT_BRANCH) {
|
|
22
|
+
const already = existsSync(headPath(home));
|
|
23
|
+
await ensureHome(home);
|
|
24
|
+
await ensureBranch(home, branch, { copyFrom: null, summary: `Default gc-branch for ${branch}.` });
|
|
25
|
+
await writeHead(home, branch);
|
|
26
|
+
return { home, gc_branch: branch, created: !already };
|
|
27
|
+
}
|
|
28
|
+
export async function ensureBranch(home, branch, options) {
|
|
29
|
+
const dir = branchDir(home, branch);
|
|
30
|
+
if (existsSync(dir))
|
|
31
|
+
return;
|
|
32
|
+
await ensureHome(home);
|
|
33
|
+
if (options.copyFrom) {
|
|
34
|
+
await cp(branchDir(home, options.copyFrom), dir, { recursive: true });
|
|
35
|
+
const meta = await readBranchMeta(home, branch);
|
|
36
|
+
meta.branch = branch;
|
|
37
|
+
meta.updated_at = new Date().toISOString();
|
|
38
|
+
await writeFile(branchMetaPath(home, branch), `${JSON.stringify(meta, null, 2)}\n`, 'utf8');
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
await mkdir(branchDocsDir(home, branch), { recursive: true });
|
|
42
|
+
const now = new Date().toISOString();
|
|
43
|
+
const meta = {
|
|
44
|
+
version: 1,
|
|
45
|
+
branch,
|
|
46
|
+
created_at: now,
|
|
47
|
+
updated_at: now,
|
|
48
|
+
summary: options.summary,
|
|
49
|
+
};
|
|
50
|
+
await writeFile(branchMetaPath(home, branch), `${JSON.stringify(meta, null, 2)}\n`, 'utf8');
|
|
51
|
+
await writeFile(branchIndexPath(home, branch), renderIndexMarkdown({ branch, branchSummary: meta.summary, docs: [] }), 'utf8');
|
|
52
|
+
}
|
|
53
|
+
export async function readBranchMeta(home, branch) {
|
|
54
|
+
const raw = await readFile(branchMetaPath(home, branch), 'utf8');
|
|
55
|
+
return JSON.parse(raw);
|
|
56
|
+
}
|
|
57
|
+
export async function updateBranchMeta(home, branch, input) {
|
|
58
|
+
const current = await readBranchMeta(home, branch);
|
|
59
|
+
const next = {
|
|
60
|
+
...current,
|
|
61
|
+
...input,
|
|
62
|
+
updated_at: new Date().toISOString(),
|
|
63
|
+
};
|
|
64
|
+
await writeFile(branchMetaPath(home, branch), `${JSON.stringify(next, null, 2)}\n`, 'utf8');
|
|
65
|
+
return next;
|
|
66
|
+
}
|
|
67
|
+
export async function listBranches(home) {
|
|
68
|
+
await ensureHome(home);
|
|
69
|
+
const entries = await readdir(branchesRoot(home), { withFileTypes: true }).catch(() => []);
|
|
70
|
+
const gcBranches = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
|
|
71
|
+
return {
|
|
72
|
+
gc_branches: gcBranches,
|
|
73
|
+
current_gc_branch: await readHead(home),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export async function checkoutBranch(home, branch, create = false) {
|
|
77
|
+
const exists = existsSync(branchDir(home, branch));
|
|
78
|
+
if (!exists && !create) {
|
|
79
|
+
throw new Error(`gc-branch does not exist: ${branch}`);
|
|
80
|
+
}
|
|
81
|
+
if (!exists) {
|
|
82
|
+
await ensureBranch(home, branch, {
|
|
83
|
+
copyFrom: null,
|
|
84
|
+
summary: `Created gc-branch ${branch}.`,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
await writeHead(home, branch);
|
|
88
|
+
return {
|
|
89
|
+
gc_branch: branch,
|
|
90
|
+
created: !exists,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export async function writeIndexFromDocs(home, branch) {
|
|
94
|
+
const docsDir = branchDocsDir(home, branch);
|
|
95
|
+
await mkdir(docsDir, { recursive: true });
|
|
96
|
+
const files = (await readdir(docsDir)).filter((file) => file.endsWith('.md')).sort();
|
|
97
|
+
const docs = await Promise.all(files.map(async (file) => {
|
|
98
|
+
const raw = await readFile(join(docsDir, file), 'utf8');
|
|
99
|
+
const title = raw.match(/^#\s+(.+)$/m)?.[1]?.trim() || file.replace(/\.md$/i, '').replace(/-/g, ' ');
|
|
100
|
+
return { title, path: `docs/${file}` };
|
|
101
|
+
}));
|
|
102
|
+
const meta = await readBranchMeta(home, branch);
|
|
103
|
+
const index = renderIndexMarkdown({ branch, branchSummary: meta.summary, docs });
|
|
104
|
+
await writeFile(branchIndexPath(home, branch), index, 'utf8');
|
|
105
|
+
return { index_path: branchIndexPath(home, branch), doc_count: docs.length };
|
|
106
|
+
}
|
|
107
|
+
export async function isBranchContextEmpty(home, branch) {
|
|
108
|
+
const docs = (await readdir(branchDocsDir(home, branch)).catch(() => [])).filter((file) => file.endsWith('.md'));
|
|
109
|
+
return docs.length === 0;
|
|
110
|
+
}
|
|
111
|
+
export async function resetBranchContext(home, branch) {
|
|
112
|
+
await ensureBranchExists(home, branch);
|
|
113
|
+
await rm(branchDocsDir(home, branch), { recursive: true, force: true });
|
|
114
|
+
await mkdir(branchDocsDir(home, branch), { recursive: true });
|
|
115
|
+
await updateBranchMeta(home, branch, { summary: `Reset gc-branch ${branch}. Awaiting onboarding.` });
|
|
116
|
+
const index = await writeIndexFromDocs(home, branch);
|
|
117
|
+
return {
|
|
118
|
+
gc_branch: branch,
|
|
119
|
+
reset: true,
|
|
120
|
+
index_path: index.index_path,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
export async function statusForBranch(home, branch) {
|
|
124
|
+
const indexRaw = await readFile(branchIndexPath(home, branch), 'utf8');
|
|
125
|
+
const docs = (await readdir(branchDocsDir(home, branch)).catch(() => [])).filter((file) => file.endsWith('.md'));
|
|
126
|
+
const warnings = [];
|
|
127
|
+
if (indexRaw.length > INDEX_WARNING_CHARS) {
|
|
128
|
+
warnings.push(`index.md is ${indexRaw.length} chars; keep it closer to an index than a knowledge dump.`);
|
|
129
|
+
}
|
|
130
|
+
for (const doc of docs) {
|
|
131
|
+
const raw = await readFile(join(branchDocsDir(home, branch), doc), 'utf8');
|
|
132
|
+
if (!/^## Summary$/m.test(raw)) {
|
|
133
|
+
warnings.push(`source doc is missing a Summary section: docs/${doc}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
home,
|
|
138
|
+
gc_branch: branch,
|
|
139
|
+
index_path: branchIndexPath(home, branch),
|
|
140
|
+
index_chars: indexRaw.length,
|
|
141
|
+
doc_count: docs.length,
|
|
142
|
+
warnings,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
export async function ensureBranchExists(home, branch) {
|
|
146
|
+
if (!existsSync(branchDir(home, branch))) {
|
|
147
|
+
throw new Error(`gc-branch does not exist: ${branch}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { renderDocMarkdown, slugify } from './markdown.js';
|
|
4
|
+
import { branchDocsDir, DEFAULT_BRANCH } from './paths.js';
|
|
5
|
+
import { ensureBranchExists, updateBranchMeta, writeIndexFromDocs } from './store.js';
|
|
6
|
+
export async function updateBranchContext({ home, input, branch, }) {
|
|
7
|
+
const targetBranch = branch || input.branch || DEFAULT_BRANCH;
|
|
8
|
+
await ensureBranchExists(home, targetBranch);
|
|
9
|
+
await mkdir(branchDocsDir(home, targetBranch), { recursive: true });
|
|
10
|
+
const written = [];
|
|
11
|
+
for (const doc of input.docs) {
|
|
12
|
+
const fileName = `${slugify(doc.slug || doc.title)}.md`;
|
|
13
|
+
const fullPath = join(branchDocsDir(home, targetBranch), fileName);
|
|
14
|
+
await writeFile(fullPath, renderDocMarkdown(doc), 'utf8');
|
|
15
|
+
written.push(fullPath);
|
|
16
|
+
}
|
|
17
|
+
if (input.branchSummary?.trim()) {
|
|
18
|
+
await updateBranchMeta(home, targetBranch, { summary: input.branchSummary.trim() });
|
|
19
|
+
}
|
|
20
|
+
const index = await writeIndexFromDocs(home, targetBranch);
|
|
21
|
+
return {
|
|
22
|
+
gc_branch: targetBranch,
|
|
23
|
+
updated_docs: written,
|
|
24
|
+
index_path: index.index_path,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Concepto
|
|
2
|
+
|
|
3
|
+
[English](concept.md) | [한국어](concept.ko.md) | [简体中文](concept.zh.md) | [日本語](concept.ja.md) | [Español](concept.es.md)
|
|
4
|
+
|
|
5
|
+
## Summary
|
|
6
|
+
|
|
7
|
+
`gctree` es una capa de contexto global pequeña y clara para herramientas de programación con IA. Mantiene el contexto duradero en documentos markdown fuera de un único repositorio, permite cambiarlo y consultarlo por gc-branch, y además puede limitar cada gc-branch a los repositorios donde realmente aplica.
|
|
8
|
+
|
|
9
|
+
## Qué es `gctree`
|
|
10
|
+
|
|
11
|
+
`gctree` es una CLI ligera para gestionar contexto global reutilizable.
|
|
12
|
+
Está pensada para personas y equipos que necesitan conservar el mismo contexto duradero entre varios repositorios, sesiones y herramientas.
|
|
13
|
+
|
|
14
|
+
En lugar de dejar ese conocimiento repartido entre archivos de prompts o depender de memoria oculta, `gctree` le da un lugar claro, estable y basado en archivos.
|
|
15
|
+
|
|
16
|
+
## Qué problema resuelve
|
|
17
|
+
|
|
18
|
+
Muchos entornos de programación con IA empiezan con una de estas opciones:
|
|
19
|
+
|
|
20
|
+
- un solo `AGENTS.md`
|
|
21
|
+
- un solo `CLAUDE.md`
|
|
22
|
+
- un archivo de prompts dentro del repositorio
|
|
23
|
+
- un conjunto de notas copiadas manualmente en los prompts
|
|
24
|
+
|
|
25
|
+
Eso funciona al principio, pero con el tiempo aparecen necesidades como estas:
|
|
26
|
+
|
|
27
|
+
- separar el contexto por producto o cliente
|
|
28
|
+
- mantener contexto fuera de un único repositorio
|
|
29
|
+
- reutilizar la misma documentación duradera desde varias herramientas
|
|
30
|
+
- encontrar el contexto correcto de forma rápida y consistente
|
|
31
|
+
- actualizar el contexto duradero de una forma más segura
|
|
32
|
+
- trabajar en paralelo en muchos repositorios y sesiones a la vez
|
|
33
|
+
|
|
34
|
+
`gctree` se ocupa precisamente de esa capa.
|
|
35
|
+
|
|
36
|
+
## Límite de alcance
|
|
37
|
+
|
|
38
|
+
`gctree` intencionalmente no es:
|
|
39
|
+
|
|
40
|
+
- un orquestador de entrega request-to-commit
|
|
41
|
+
- un sistema de memoria oculta
|
|
42
|
+
- un runtime de colaboración en navegador
|
|
43
|
+
- un producto generalista de base de conocimiento
|
|
44
|
+
|
|
45
|
+
Se centra en ramas reutilizables de contexto global y en flujos de actualización explícitos.
|
|
46
|
+
|
|
47
|
+
## Estructura de archivos
|
|
48
|
+
|
|
49
|
+
Un directorio home típico se ve así:
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
~/.gctree/
|
|
53
|
+
HEAD
|
|
54
|
+
settings.json
|
|
55
|
+
branch-repo-map.json
|
|
56
|
+
branches/
|
|
57
|
+
main/
|
|
58
|
+
branch.json
|
|
59
|
+
index.md
|
|
60
|
+
docs/
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- `HEAD` indica el gc-branch activo de fallback.
|
|
64
|
+
- `settings.json` guarda el modo de provider, el provider real usado para iniciar el onboarding y el idioma preferido del flujo.
|
|
65
|
+
- `branch-repo-map.json` guarda las reglas include/exclude por gc-branch.
|
|
66
|
+
- `branch.json` guarda metadatos ligeros del gc-branch.
|
|
67
|
+
- `index.md` es el punto de entrada compacto para las herramientas.
|
|
68
|
+
- `docs/` guarda los documentos markdown source-of-truth.
|
|
69
|
+
|
|
70
|
+
## Comportamiento con alcance por repositorio
|
|
71
|
+
|
|
72
|
+
Un gc-branch no tiene por qué aplicarse a todos los repositorios.
|
|
73
|
+
Si la rama `A` solo es relevante para `B`, `C` y `D`, eso puede registrarse en `branch-repo-map.json`.
|
|
74
|
+
|
|
75
|
+
Entonces, si ejecutas `gctree resolve` desde `F`, puedes elegir entre:
|
|
76
|
+
|
|
77
|
+
- continuar solo esta vez
|
|
78
|
+
- usar siempre esa rama en ese repo
|
|
79
|
+
- ignorarla en ese repo
|
|
80
|
+
|
|
81
|
+
Eso vuelve a `gctree` mucho más seguro para usuarios intensivos que mantienen muchas sesiones paralelas abiertas sobre repositorios no relacionados.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# コンセプト
|
|
2
|
+
|
|
3
|
+
[English](concept.md) | [한국어](concept.ko.md) | [简体中文](concept.zh.md) | [日本語](concept.ja.md) | [Español](concept.es.md)
|
|
4
|
+
|
|
5
|
+
## Summary
|
|
6
|
+
|
|
7
|
+
`gctree` は AI コーディングツール向けの、小さく明確なグローバルコンテキストレイヤーです。長期コンテキストを単一リポジトリの外にある markdown 文書として管理し、gc-branch 単位で切り替え・参照・維持でき、さらに実際に関係するリポジトリだけに適用範囲を絞れます。
|
|
8
|
+
|
|
9
|
+
## `gctree` とは
|
|
10
|
+
|
|
11
|
+
`gctree` は再利用可能なグローバルコンテキストを管理するための軽量 CLI です。
|
|
12
|
+
複数のリポジトリ、セッション、ツールをまたいでも同じ長期コンテキストを使い続けたい個人やチームのために設計されています。
|
|
13
|
+
|
|
14
|
+
長期知識を隠れたメモリに任せたり、複数のプロンプトファイルへ散らしたりする代わりに、`gctree` はその知識に明確で安定したファイルベースの置き場所を与えます。
|
|
15
|
+
|
|
16
|
+
## 解決する課題
|
|
17
|
+
|
|
18
|
+
多くの AI コーディング環境は、次のいずれかから始まります。
|
|
19
|
+
|
|
20
|
+
- 1 つの `AGENTS.md`
|
|
21
|
+
- 1 つの `CLAUDE.md`
|
|
22
|
+
- リポジトリ内のローカルなプロンプトファイル
|
|
23
|
+
- プロンプトに都度貼り付けるメモ
|
|
24
|
+
|
|
25
|
+
最初はそれで十分でも、やがて次のような要件が出てきます。
|
|
26
|
+
|
|
27
|
+
- プロダクトやクライアントごとにコンテキストを分けたい
|
|
28
|
+
- 1 つのリポジトリの外にコンテキストを保ちたい
|
|
29
|
+
- 複数ツールが同じ長期文書を再利用できるようにしたい
|
|
30
|
+
- 必要なコンテキストを一貫した方法で素早く見つけたい
|
|
31
|
+
- 長期コンテキストをより安全に更新したい
|
|
32
|
+
- 同じユーザーが複数のリポジトリ・複数のセッションで並行作業する
|
|
33
|
+
|
|
34
|
+
`gctree` は、まさにその層を扱います。
|
|
35
|
+
|
|
36
|
+
## スコープ境界
|
|
37
|
+
|
|
38
|
+
`gctree` が意図的に担当しないものは次の通りです。
|
|
39
|
+
|
|
40
|
+
- request-to-commit 型のデリバリーオーケストレータ
|
|
41
|
+
- 隠れたメモリシステム
|
|
42
|
+
- ブラウザ協業ランタイム
|
|
43
|
+
- 汎用ナレッジベース製品
|
|
44
|
+
|
|
45
|
+
`gctree` は、再利用可能なグローバルコンテキストブランチと、明示的な更新フローに集中します。
|
|
46
|
+
|
|
47
|
+
## ファイル構成
|
|
48
|
+
|
|
49
|
+
典型的なホームディレクトリ構成は次の通りです。
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
~/.gctree/
|
|
53
|
+
HEAD
|
|
54
|
+
settings.json
|
|
55
|
+
branch-repo-map.json
|
|
56
|
+
branches/
|
|
57
|
+
main/
|
|
58
|
+
branch.json
|
|
59
|
+
index.md
|
|
60
|
+
docs/
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- `HEAD` は fallback のアクティブ gc-branch を指します。
|
|
64
|
+
- `settings.json` は provider モード、実際のオンボーディング起動 provider、優先ワークフロー言語を保持します。
|
|
65
|
+
- `branch-repo-map.json` は gc-branch ごとの include/exclude リポジトリ規則を保存します。
|
|
66
|
+
- `branch.json` は軽量な gc-branch メタデータを保存します。
|
|
67
|
+
- `index.md` はツール向けの小さな入口です。
|
|
68
|
+
- `docs/` には source-of-truth の markdown 文書を保存します。
|
|
69
|
+
|
|
70
|
+
## リポジトリ範囲の振る舞い
|
|
71
|
+
|
|
72
|
+
ある gc-branch がすべてのリポジトリに適用される必要はありません。
|
|
73
|
+
たとえば branch `A` が `B`、`C`、`D` にだけ関係するなら、その事実を `branch-repo-map.json` に記録できます。
|
|
74
|
+
|
|
75
|
+
その状態で `F` リポジトリから `gctree resolve` を実行すると、次を選べます。
|
|
76
|
+
|
|
77
|
+
- 今回だけ使う
|
|
78
|
+
- 今後もこのリポジトリで使う
|
|
79
|
+
- このリポジトリでは無視する
|
|
80
|
+
|
|
81
|
+
これにより、多数のセッションを開いて複数の無関係なリポジトリで並行作業する heavy ユーザーにも、より安全に使えるようになります。
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# 컨셉
|
|
2
|
+
|
|
3
|
+
[English](concept.md) | [한국어](concept.ko.md) | [简体中文](concept.zh.md) | [日本語](concept.ja.md) | [Español](concept.es.md)
|
|
4
|
+
|
|
5
|
+
## Summary
|
|
6
|
+
|
|
7
|
+
`gctree`는 AI 코딩 도구를 위한 작고 명확한 글로벌 컨텍스트 레이어입니다. 장기적으로 유지할 컨텍스트를 단일 저장소 바깥의 markdown 문서로 관리하고, gc-branch 단위로 전환·조회·유지할 수 있으며, 실제로 관련 있는 레포에만 적용되도록 범위를 제한할 수도 있습니다.
|
|
8
|
+
|
|
9
|
+
## `gctree`란
|
|
10
|
+
|
|
11
|
+
`gctree`는 재사용 가능한 글로벌 컨텍스트를 관리하기 위한 경량 CLI입니다.
|
|
12
|
+
여러 저장소, 세션, 도구를 오가더라도 같은 장기 컨텍스트를 일관되게 이어가야 하는 팀과 개인을 위해 만들어졌습니다.
|
|
13
|
+
|
|
14
|
+
장기 지식을 숨겨진 메모리에 맡기거나 여러 프롬프트 파일에 흩어 두는 대신, `gctree`는 그 지식이 머무를 안정적인 파일 기반 홈을 제공합니다.
|
|
15
|
+
|
|
16
|
+
## 해결하는 문제
|
|
17
|
+
|
|
18
|
+
많은 AI 코딩 환경은 보통 다음 중 하나로 시작합니다.
|
|
19
|
+
|
|
20
|
+
- 하나의 `AGENTS.md`
|
|
21
|
+
- 하나의 `CLAUDE.md`
|
|
22
|
+
- 저장소 내부의 프롬프트 파일
|
|
23
|
+
- 프롬프트에 복붙하는 임시 메모
|
|
24
|
+
|
|
25
|
+
처음에는 이 정도로도 충분하지만, 시간이 지나면 이런 요구가 생깁니다.
|
|
26
|
+
|
|
27
|
+
- 제품이나 고객사별로 컨텍스트를 분리하고 싶다
|
|
28
|
+
- 특정 저장소 바깥에서도 유지되는 컨텍스트가 필요하다
|
|
29
|
+
- 여러 도구가 함께 재사용할 수 있는 장기 문서가 필요하다
|
|
30
|
+
- 필요한 컨텍스트를 빠르게 찾는 일관된 방식이 필요하다
|
|
31
|
+
- 장기 컨텍스트를 더 안전하게 업데이트하고 싶다
|
|
32
|
+
- 한 사용자가 동시에 여러 레포/세션에서 병렬 작업을 한다
|
|
33
|
+
|
|
34
|
+
`gctree`는 바로 그 레이어를 다룹니다.
|
|
35
|
+
|
|
36
|
+
## 범위 경계
|
|
37
|
+
|
|
38
|
+
`gctree`는 의도적으로 다음 역할을 맡지 않습니다.
|
|
39
|
+
|
|
40
|
+
- request-to-commit 딜리버리 오케스트레이터
|
|
41
|
+
- 숨겨진 메모리 시스템
|
|
42
|
+
- 브라우저 기반 협업 런타임
|
|
43
|
+
- 범용 지식베이스 제품
|
|
44
|
+
|
|
45
|
+
`gctree`는 재사용 가능한 글로벌 컨텍스트 브랜치와 명시적인 업데이트 흐름에 집중합니다.
|
|
46
|
+
|
|
47
|
+
## 파일 구조
|
|
48
|
+
|
|
49
|
+
일반적인 홈 디렉터리 구조는 다음과 같습니다.
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
~/.gctree/
|
|
53
|
+
HEAD
|
|
54
|
+
settings.json
|
|
55
|
+
branch-repo-map.json
|
|
56
|
+
branches/
|
|
57
|
+
main/
|
|
58
|
+
branch.json
|
|
59
|
+
index.md
|
|
60
|
+
docs/
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- `HEAD`는 fallback 활성 gc-branch를 가리킵니다.
|
|
64
|
+
- `settings.json`은 provider 모드, 실제 온보딩에 사용할 provider, 선호 워크플로 언어를 저장합니다.
|
|
65
|
+
- `branch-repo-map.json`은 gc-branch별 include/exclude 레포 규칙을 저장합니다.
|
|
66
|
+
- `branch.json`은 가벼운 gc-branch 메타데이터를 저장합니다.
|
|
67
|
+
- `index.md`는 도구가 읽는 작은 진입점입니다.
|
|
68
|
+
- `docs/`는 source-of-truth markdown 문서를 보관합니다.
|
|
69
|
+
|
|
70
|
+
## 레포 범위 인식 동작
|
|
71
|
+
|
|
72
|
+
어떤 gc-branch가 모든 레포에 적용될 필요는 없습니다.
|
|
73
|
+
예를 들어 branch `A`가 `B`, `C`, `D` 레포에만 관련 있다면, 그 사실을 `branch-repo-map.json`에 기록할 수 있습니다.
|
|
74
|
+
|
|
75
|
+
그 상태에서 `F` 레포에서 `gctree resolve`가 호출되면 다음 중 하나를 고를 수 있습니다.
|
|
76
|
+
|
|
77
|
+
- 이번만 사용
|
|
78
|
+
- 이 레포에서 항상 사용
|
|
79
|
+
- 이 레포에서는 무시
|
|
80
|
+
|
|
81
|
+
이 구조 덕분에, 동시에 여러 세션을 열고 서로 다른 레포를 다루는 heavy 사용자에게도 더 안전해집니다.
|
package/docs/concept.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Concept
|
|
2
|
+
|
|
3
|
+
[English](concept.md) | [한국어](concept.ko.md) | [简体中文](concept.zh.md) | [日本語](concept.ja.md) | [Español](concept.es.md)
|
|
4
|
+
|
|
5
|
+
## Summary
|
|
6
|
+
|
|
7
|
+
`gctree` is a lightweight global-context layer for AI coding tools. It keeps durable context in explicit markdown documents outside any single repository, lets users switch between gc-branches, and can restrict each gc-branch to the repositories where it actually applies.
|
|
8
|
+
|
|
9
|
+
## What `gctree` is
|
|
10
|
+
|
|
11
|
+
`gctree` is a CLI for managing reusable global context.
|
|
12
|
+
It is designed for teams and individuals who want long-lived context to survive across repositories, sessions, and tools without turning that context into hidden memory.
|
|
13
|
+
|
|
14
|
+
Instead of scattering important knowledge across prompt files, repo-local notes, and ad hoc instructions, `gctree` gives that knowledge a stable, file-backed home.
|
|
15
|
+
|
|
16
|
+
## What problem it solves
|
|
17
|
+
|
|
18
|
+
Many AI coding setups start small:
|
|
19
|
+
|
|
20
|
+
- one `AGENTS.md`
|
|
21
|
+
- one `CLAUDE.md`
|
|
22
|
+
- one repo-local prompt file
|
|
23
|
+
- a handful of notes copied into prompts as needed
|
|
24
|
+
|
|
25
|
+
That works for a while. Then the same setup starts to break under real-world needs:
|
|
26
|
+
|
|
27
|
+
- different products need different context
|
|
28
|
+
- client work must stay isolated
|
|
29
|
+
- reusable guidance should live outside any single repository
|
|
30
|
+
- multiple tools should be able to read the same source of truth
|
|
31
|
+
- long-lived context should evolve through a safe, reviewable flow
|
|
32
|
+
- one user may run many sessions across many repositories at the same time
|
|
33
|
+
|
|
34
|
+
`gctree` exists to solve that layer cleanly.
|
|
35
|
+
|
|
36
|
+
## Scope boundary
|
|
37
|
+
|
|
38
|
+
`gctree` is intentionally not:
|
|
39
|
+
|
|
40
|
+
- a request-to-commit delivery orchestrator
|
|
41
|
+
- a hidden memory system
|
|
42
|
+
- a browser collaboration runtime
|
|
43
|
+
- a general-purpose knowledge base product
|
|
44
|
+
|
|
45
|
+
It focuses on one job: managing reusable global-context branches and explicit updates.
|
|
46
|
+
|
|
47
|
+
## File model
|
|
48
|
+
|
|
49
|
+
A typical home directory looks like this:
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
~/.gctree/
|
|
53
|
+
HEAD
|
|
54
|
+
settings.json
|
|
55
|
+
branch-repo-map.json
|
|
56
|
+
branches/
|
|
57
|
+
main/
|
|
58
|
+
branch.json
|
|
59
|
+
index.md
|
|
60
|
+
docs/
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- `HEAD` tracks the fallback active gc-branch.
|
|
64
|
+
- `settings.json` stores the provider mode, the onboarding provider chosen for runtime launch, and the preferred workflow language.
|
|
65
|
+
- `branch-repo-map.json` stores which repositories are included or excluded for each gc-branch.
|
|
66
|
+
- `branch.json` stores lightweight gc-branch metadata.
|
|
67
|
+
- `index.md` is the compact entry point for tools.
|
|
68
|
+
- `docs/` holds source-of-truth markdown documents.
|
|
69
|
+
|
|
70
|
+
## Repo-aware behavior
|
|
71
|
+
|
|
72
|
+
A gc-branch does not have to apply everywhere.
|
|
73
|
+
If branch `A` is only relevant to repositories `B`, `C`, and `D`, `gctree` can record that in `branch-repo-map.json`.
|
|
74
|
+
|
|
75
|
+
When `gctree resolve` runs in another repository such as `F`, it can:
|
|
76
|
+
|
|
77
|
+
- continue once
|
|
78
|
+
- always use that gc-branch in `F`
|
|
79
|
+
- ignore that gc-branch in `F`
|
|
80
|
+
|
|
81
|
+
This makes gc-tree much safer for heavy users who keep many parallel sessions open across unrelated repositories.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# 概念
|
|
2
|
+
|
|
3
|
+
[English](concept.md) | [한국어](concept.ko.md) | [简体中文](concept.zh.md) | [日本語](concept.ja.md) | [Español](concept.es.md)
|
|
4
|
+
|
|
5
|
+
## Summary
|
|
6
|
+
|
|
7
|
+
`gctree` 是一个小而明确的全局上下文层,面向 AI 编码工具。它把长期上下文放在单一仓库之外的 markdown 文档中,可以按 gc-branch 切换、检索和维护,也可以限制某个 gc-branch 只在真正相关的仓库中生效。
|
|
8
|
+
|
|
9
|
+
## `gctree` 是什么
|
|
10
|
+
|
|
11
|
+
`gctree` 是一个用于管理可复用全局上下文的轻量 CLI。
|
|
12
|
+
它面向那些需要在多个仓库、多个会话和多种工具之间持续复用长期上下文的个人与团队。
|
|
13
|
+
|
|
14
|
+
与其把长期知识交给隐藏记忆,或者散落在多个提示文件中,`gctree` 更像是为这些知识提供了一个清晰、稳定、基于文件的归档位置。
|
|
15
|
+
|
|
16
|
+
## 它解决什么问题
|
|
17
|
+
|
|
18
|
+
很多 AI 编码工作流最初都从下面这些方式开始:
|
|
19
|
+
|
|
20
|
+
- 一个 `AGENTS.md`
|
|
21
|
+
- 一个 `CLAUDE.md`
|
|
22
|
+
- 仓库里的本地提示文件
|
|
23
|
+
- 一组临时复制到提示词里的笔记
|
|
24
|
+
|
|
25
|
+
一开始这样可以工作,但随着项目变复杂,往往会出现这些需求:
|
|
26
|
+
|
|
27
|
+
- 希望按产品或客户隔离上下文
|
|
28
|
+
- 希望把上下文放在单个仓库之外长期维护
|
|
29
|
+
- 希望多种工具复用同一套长期文档
|
|
30
|
+
- 希望用一致的方式快速找到正确的上下文
|
|
31
|
+
- 希望以更安全的方式持续更新长期上下文
|
|
32
|
+
- 同一个用户会同时在多个仓库和多个会话中并行工作
|
|
33
|
+
|
|
34
|
+
`gctree` 解决的正是这一层问题。
|
|
35
|
+
|
|
36
|
+
## 范围边界
|
|
37
|
+
|
|
38
|
+
`gctree` 有意不做以下事情:
|
|
39
|
+
|
|
40
|
+
- request-to-commit 交付编排器
|
|
41
|
+
- 隐式记忆系统
|
|
42
|
+
- 浏览器协作运行时
|
|
43
|
+
- 通用知识库产品
|
|
44
|
+
|
|
45
|
+
它专注于可复用的全局上下文分支,以及显式的更新流程。
|
|
46
|
+
|
|
47
|
+
## 文件结构
|
|
48
|
+
|
|
49
|
+
一个典型的 home 目录大致如下:
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
~/.gctree/
|
|
53
|
+
HEAD
|
|
54
|
+
settings.json
|
|
55
|
+
branch-repo-map.json
|
|
56
|
+
branches/
|
|
57
|
+
main/
|
|
58
|
+
branch.json
|
|
59
|
+
index.md
|
|
60
|
+
docs/
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- `HEAD` 记录 fallback 的激活 gc-branch。
|
|
64
|
+
- `settings.json` 保存 provider 模式、实际用于启动 onboarding 的 provider,以及首选工作流语言。
|
|
65
|
+
- `branch-repo-map.json` 保存每个 gc-branch 的 include/exclude 仓库规则。
|
|
66
|
+
- `branch.json` 保存轻量级 gc-branch 元数据。
|
|
67
|
+
- `index.md` 是工具读取时的紧凑入口。
|
|
68
|
+
- `docs/` 存放 source-of-truth markdown 文档。
|
|
69
|
+
|
|
70
|
+
## 仓库范围行为
|
|
71
|
+
|
|
72
|
+
某个 gc-branch 不一定需要作用于所有仓库。
|
|
73
|
+
如果 branch `A` 只适用于 `B`、`C`、`D`,就可以把这个关系写进 `branch-repo-map.json`。
|
|
74
|
+
|
|
75
|
+
这样一来,当 `F` 仓库里运行 `gctree resolve` 时,可以选择:
|
|
76
|
+
|
|
77
|
+
- 这次先继续
|
|
78
|
+
- 以后这个仓库总是使用这个 gc-branch
|
|
79
|
+
- 在这个仓库里忽略这个 gc-branch
|
|
80
|
+
|
|
81
|
+
这让 `gctree` 更适合同时开很多会话、在多个不相关仓库里并行工作的 heavy 用户。
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Desarrollo local
|
|
2
|
+
|
|
3
|
+
[English](local-development.md) | [한국어](local-development.ko.md) | [简体中文](local-development.zh.md) | [日本語](local-development.ja.md) | [Español](local-development.es.md)
|
|
4
|
+
|
|
5
|
+
## Summary
|
|
6
|
+
|
|
7
|
+
El desarrollo local sigue un flujo estándar de Node.js 20+: instala dependencias, construye la CLI, ejecútala localmente y verifica con la suite de tests existente antes de enviar cambios.
|
|
8
|
+
|
|
9
|
+
## Estado del paquete
|
|
10
|
+
|
|
11
|
+
`@handsupmin/gc-tree` es el nombre del paquete npm publicado para este repositorio, mientras que el nombre del repositorio sigue siendo `gc-tree`.
|
|
12
|
+
Antes de cualquier release ejecuta `npm publish --dry-run` y, después de publicar de verdad, verifica el paquete desde un directorio limpio con `npx @handsupmin/gc-tree --help` o `npm install -g @handsupmin/gc-tree`.
|
|
13
|
+
|
|
14
|
+
## Requisitos previos
|
|
15
|
+
|
|
16
|
+
- Node.js 20+
|
|
17
|
+
- npm
|
|
18
|
+
- binarios locales de `codex` o `claude` si quieres validar manualmente el arranque del provider
|
|
19
|
+
|
|
20
|
+
## Configuración
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install
|
|
24
|
+
npm run build
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Ejecutar la CLI localmente
|
|
28
|
+
|
|
29
|
+
### Opción 1: ejecutar directamente la entrada construida
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
node dist/src/cli.js status
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Opción 2: enlazar la CLI a tu shell
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm link
|
|
39
|
+
gctree status
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Si cambias el código TypeScript, vuelve a construir antes de probar de nuevo la CLI.
|
|
43
|
+
|
|
44
|
+
## Verificación
|
|
45
|
+
|
|
46
|
+
Antes de enviar cambios, ejecuta:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm run build
|
|
50
|
+
npm test
|
|
51
|
+
npm publish --dry-run
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Tests de alcance por repositorio
|
|
55
|
+
|
|
56
|
+
La suite actual verifica:
|
|
57
|
+
|
|
58
|
+
- persistencia del modo de provider (`claude-code`, `codex`, `both`)
|
|
59
|
+
- persistencia del idioma preferido y refuerzo fuerte del idioma en el launch prompt
|
|
60
|
+
- selección de gc-branch según el repositorio
|
|
61
|
+
- interacciones include/exclude durante `resolve`
|
|
62
|
+
- actualización del branch repo map
|
|
63
|
+
- límites del flujo guiado de onboarding/update
|
|
64
|
+
|
|
65
|
+
## Verificación manual E2E del provider
|
|
66
|
+
|
|
67
|
+
Los tests automáticos desactivan el provider launch para validar el launch plan sin abrir sesiones reales de Codex o Claude Code.
|
|
68
|
+
Si quieres comprobar el camino real de arranque, usa un directorio temporal y ejecuta:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
gctree init --provider codex
|
|
72
|
+
gctree init --provider claude-code
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Si todo está bien, el provider se abrirá de verdad y recibirá inmediatamente `$gc-onboard` o `/gc-onboard`.
|
|
76
|
+
|
|
77
|
+
## Estructura del proyecto
|
|
78
|
+
|
|
79
|
+
- `src/` — CLI, almacenamiento de contexto, selección de provider, mapeo de alcance por repositorio, flujos guiados de onboarding/update y lógica de scaffolding
|
|
80
|
+
- `tests/` — tests de CLI y comportamiento
|
|
81
|
+
- `skills/` — skills de flujo de trabajo agnósticos a la herramienta
|
|
82
|
+
- `scaffolds/` — plantillas bootstrap específicas del host
|
|
83
|
+
- `docs/` — documentación de concept, principles, usage y development
|