@handsupmin/gc-tree 1.1.3 → 1.1.5

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/cli.js CHANGED
@@ -9,7 +9,7 @@ import { dispatchGcTreeHook } from './hook.js';
9
9
  import { onboardBranch } from './onboard.js';
10
10
  import { buildProviderLaunchPlan, maybeLaunchProvider, promptLanguageSelection, promptLaunchProviderSelection, promptProviderSelection, } from './provider.js';
11
11
  import { DEFAULT_BRANCH, branchDir, resolveHome } from './paths.js';
12
- import { branchRepoMapPath, branchScopeStatus, detectCurrentRepoId, promptResolveScopeDecision, readBranchRepoMap, resolveBranchForRepo, setRepoScopeForBranch, } from './repo-map.js';
12
+ import { branchRepoMapPath, detectCurrentRepoId, promptResolveScopeDecision, readBranchRepoMap, resolveBranchForRepo, setRepoScopeForBranch, } from './repo-map.js';
13
13
  import { findRelatedDocs, getDocById, resolveContext } from './resolve.js';
14
14
  import { scaffoldHostIntegration } from './scaffold.js';
15
15
  import { appendScaffoldedHost, requirePreferredProvider, writeSettings, readSettings } from './settings.js';
@@ -47,14 +47,14 @@ function usage() {
47
47
  gctree branches [--home DIR]
48
48
  gctree repo-map [--home DIR]
49
49
  gctree set-repo-scope --branch NAME [--repo NAME] [--cwd DIR] (--include|--exclude) [--home DIR]
50
- gctree status [--home DIR] [--cwd DIR]
50
+ gctree status [--home DIR] [--branch NAME] [--cwd DIR]
51
51
  gctree onboard [--home DIR] [--branch NAME] [--provider <codex|claude-code>] [--target DIR] [--no-launch]
52
52
  gctree verify-onboarding [--home DIR] [--branch NAME]
53
53
  gctree reset-gc-branch [--home DIR] [--branch NAME] --yes
54
54
  gctree uninstall [--home DIR] [--target DIR] [--host <codex|claude-code|both>] [--keep-home] --yes
55
55
  gctree resolve --query TEXT [--home DIR] [--branch NAME] [--cwd DIR]
56
- gctree show-doc --id ID [--home DIR] [--branch NAME]
57
- gctree related --id ID [--home DIR] [--branch NAME]
56
+ gctree show-doc --id ID [--home DIR] [--branch NAME] [--cwd DIR]
57
+ gctree related --id ID [--home DIR] [--branch NAME] [--cwd DIR]
58
58
  gctree update-global-context [--home DIR] [--branch NAME] [--provider <codex|claude-code>] [--target DIR] [--no-launch]
59
59
  gctree update-gc [--home DIR] [--branch NAME] [--provider <codex|claude-code>] [--target DIR] [--no-launch]
60
60
  gctree ugc [--home DIR] [--branch NAME] [--provider <codex|claude-code>] [--target DIR] [--no-launch]
@@ -78,6 +78,15 @@ async function readStdinText() {
78
78
  }
79
79
  return Buffer.concat(chunks).toString('utf8');
80
80
  }
81
+ async function resolveCommandBranch({ home, explicitBranch, cwd, }) {
82
+ const head = (await readHead(home)) || DEFAULT_BRANCH;
83
+ return resolveBranchForRepo({
84
+ home,
85
+ head,
86
+ explicitBranch,
87
+ cwd: cwd || process.cwd(),
88
+ });
89
+ }
81
90
  function compactMatchCommands(id, home, branch) {
82
91
  const homeArg = `--home ${JSON.stringify(home)}`;
83
92
  const branchArg = `--branch ${JSON.stringify(branch)}`;
@@ -276,22 +285,26 @@ async function main() {
276
285
  return;
277
286
  }
278
287
  case 'status': {
279
- const gcBranch = (await readHead(home)) || DEFAULT_BRANCH;
288
+ const resolved = await resolveCommandBranch({
289
+ home,
290
+ explicitBranch: readArg('--branch') || undefined,
291
+ cwd: readArg('--cwd') || process.cwd(),
292
+ });
293
+ const gcBranch = resolved.gc_branch;
280
294
  if (!existsSync(branchDir(home, gcBranch))) {
281
295
  throw new Error('gc-tree is not initialized. Run `gctree init` first.');
282
296
  }
283
297
  const result = await statusForBranch(home, gcBranch);
284
298
  const settings = await readSettings(home);
285
- const mapping = await readBranchRepoMap(home);
286
- const currentRepo = await detectCurrentRepoId(readArg('--cwd') || process.cwd());
287
299
  console.log(JSON.stringify({
288
300
  ...result,
289
301
  provider_mode: settings?.provider_mode || null,
290
302
  preferred_provider: settings?.preferred_provider || null,
291
303
  preferred_language: settings?.preferred_language || null,
292
- current_repo: currentRepo,
304
+ current_repo: resolved.current_repo,
305
+ source: resolved.source,
293
306
  branch_repo_map_path: branchRepoMapPath(home),
294
- repo_scope_status: branchScopeStatus(mapping, gcBranch, currentRepo),
307
+ repo_scope_status: resolved.scope_status,
295
308
  }, null, 2));
296
309
  return;
297
310
  }
@@ -365,10 +378,8 @@ async function main() {
365
378
  const query = readArg('--query');
366
379
  if (!query)
367
380
  usage();
368
- const head = (await readHead(home)) || DEFAULT_BRANCH;
369
- const resolved = await resolveBranchForRepo({
381
+ const resolved = await resolveCommandBranch({
370
382
  home,
371
- head,
372
383
  explicitBranch: readArg('--branch') || undefined,
373
384
  cwd: readArg('--cwd') || process.cwd(),
374
385
  });
@@ -491,10 +502,24 @@ async function main() {
491
502
  const id = readArg('--id');
492
503
  if (!id)
493
504
  usage();
494
- const gcBranch = readArg('--branch') || (await readHead(home)) || DEFAULT_BRANCH;
505
+ const resolved = await resolveCommandBranch({
506
+ home,
507
+ explicitBranch: readArg('--branch') || undefined,
508
+ cwd: readArg('--cwd') || process.cwd(),
509
+ });
510
+ const gcBranch = resolved.gc_branch;
495
511
  const branchStatus = await statusForBranch(home, gcBranch);
496
512
  if (branchStatus.doc_count === 0) {
497
- console.log(JSON.stringify({ status: 'empty_branch', gc_branch: gcBranch, id, message: `gc-branch "${gcBranch}" has no docs yet.`, doc: null }, null, 2));
513
+ console.log(JSON.stringify({
514
+ status: 'empty_branch',
515
+ gc_branch: gcBranch,
516
+ id,
517
+ current_repo: resolved.current_repo,
518
+ source: resolved.source,
519
+ repo_scope_status: resolved.scope_status,
520
+ message: `gc-branch "${gcBranch}" has no docs yet.`,
521
+ doc: null,
522
+ }, null, 2));
498
523
  return;
499
524
  }
500
525
  const doc = await getDocById({ home, branch: gcBranch, id });
@@ -502,6 +527,9 @@ async function main() {
502
527
  status: doc ? 'matched' : 'doc_not_found',
503
528
  gc_branch: gcBranch,
504
529
  id,
530
+ current_repo: resolved.current_repo,
531
+ source: resolved.source,
532
+ repo_scope_status: resolved.scope_status,
505
533
  message: doc ? `Loaded doc "${id}".` : `Doc "${id}" was not found in gc-branch "${gcBranch}".`,
506
534
  doc,
507
535
  }, null, 2));
@@ -511,12 +539,20 @@ async function main() {
511
539
  const id = readArg('--id');
512
540
  if (!id)
513
541
  usage();
514
- const gcBranch = readArg('--branch') || (await readHead(home)) || DEFAULT_BRANCH;
542
+ const resolved = await resolveCommandBranch({
543
+ home,
544
+ explicitBranch: readArg('--branch') || undefined,
545
+ cwd: readArg('--cwd') || process.cwd(),
546
+ });
547
+ const gcBranch = resolved.gc_branch;
515
548
  const result = await findRelatedDocs({ home, branch: gcBranch, id });
516
549
  console.log(JSON.stringify({
517
550
  status: result.status,
518
551
  gc_branch: gcBranch,
519
552
  id,
553
+ current_repo: resolved.current_repo,
554
+ source: resolved.source,
555
+ repo_scope_status: resolved.scope_status,
520
556
  message: result.status === 'matched'
521
557
  ? `Found ${result.matches.length} related docs for "${id}".`
522
558
  : result.status === 'no_related_docs'
package/dist/src/hook.js CHANGED
@@ -27,14 +27,14 @@ function limitMatches(matches, max = 3) {
27
27
  function displayKeyword(match) {
28
28
  return (match.label || match.title || match.id).trim();
29
29
  }
30
- function formatMatches(matches) {
30
+ function formatMatches(matches, gcBranch) {
31
31
  return limitMatches(matches)
32
32
  .map((match) => {
33
33
  const summary = match.summary?.trim() ?? '';
34
34
  const excerpt = match.excerpt?.trim() ?? '';
35
35
  const context = summary || excerpt;
36
36
  const shortContext = context.length > 180 ? `${context.slice(0, 177).trim()}...` : context;
37
- const showDoc = `gctree show-doc --id "${match.id}"`;
37
+ const showDoc = `gctree show-doc --id "${match.id}" --branch "${gcBranch}"`;
38
38
  return [
39
39
  `[${displayKeyword(match)}]`,
40
40
  shortContext,
@@ -59,7 +59,7 @@ function buildMatchContext({ gcBranch, currentRepo, repoScopeStatus, matches, })
59
59
  const lines = [
60
60
  `[gc-tree] USE FIRST: ${Math.min(matches.length, 3)} docs gc-branch="${gcBranch}" repo="${currentRepo || 'unscoped'}" scope=${repoScopeStatus}.`,
61
61
  '',
62
- formatMatches(matches),
62
+ formatMatches(matches, gcBranch),
63
63
  '',
64
64
  `Rule: 위 문서를 먼저 근거로 삼고, 부족하면 details 명령으로 세부 정보를 확인.`,
65
65
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@handsupmin/gc-tree",
3
- "version": "1.1.3",
3
+ "version": "1.1.5",
4
4
  "description": "Global Context Tree, a lightweight branch-aware global context orchestrator for AI coding tools",
5
5
  "type": "module",
6
6
  "private": false,
@@ -18,7 +18,7 @@
18
18
  "gctree": "dist/src/cli.js"
19
19
  },
20
20
  "scripts": {
21
- "build": "tsc -p tsconfig.json",
21
+ "build": "tsc -p tsconfig.json && node -e \"require('node:fs').chmodSync('dist/src/cli.js', 0o755)\"",
22
22
  "test": "node --import tsx --test tests/*.test.ts",
23
23
  "prepack": "npm run build",
24
24
  "eval": "node --import tsx tests/eval/index.ts",
@@ -1,73 +0,0 @@
1
- import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises';
2
- import { basename, join } from 'node:path';
3
- import { renderDocMarkdown, slugify } from './markdown.js';
4
- import { branchDir, branchDocsDir, branchProposalsDir, DEFAULT_BRANCH } from './paths.js';
5
- import { ensureBranchExists, updateBranchMeta, writeIndexFromDocs } from './store.js';
6
- export async function proposeUpdate({ home, input, branch, }) {
7
- const targetBranch = branch || input.branch || DEFAULT_BRANCH;
8
- await ensureBranchExists(home, targetBranch);
9
- await mkdir(branchProposalsDir(home, targetBranch), { recursive: true });
10
- const now = new Date().toISOString();
11
- const id = `${now.replace(/[:.]/g, '-')}-${slugify(input.title)}`;
12
- const proposal = {
13
- version: 1,
14
- id,
15
- status: 'proposed',
16
- branch: targetBranch,
17
- title: input.title.trim(),
18
- summary: input.summary.trim(),
19
- created_at: now,
20
- changes: input.docs.map((doc) => ({
21
- path: `docs/${slugify(doc.slug || doc.title)}.md`,
22
- title: doc.title.trim(),
23
- summary: doc.summary.trim(),
24
- body: doc.body.trim(),
25
- ...(doc.tags?.length ? { tags: doc.tags } : {}),
26
- })),
27
- };
28
- const proposalPath = join(branchProposalsDir(home, targetBranch), `${id}.json`);
29
- await writeFile(proposalPath, `${JSON.stringify(proposal, null, 2)}\n`, 'utf8');
30
- return { proposal_path: proposalPath, proposal };
31
- }
32
- export async function applyProposal({ home, proposalPath, }) {
33
- const raw = await readFile(proposalPath, 'utf8');
34
- const proposal = JSON.parse(raw);
35
- await ensureBranchExists(home, proposal.branch);
36
- await mkdir(branchDocsDir(home, proposal.branch), { recursive: true });
37
- const updatedDocs = [];
38
- for (const change of proposal.changes) {
39
- const fullPath = join(branchDir(home, proposal.branch), change.path);
40
- await writeFile(fullPath, renderDocMarkdown({
41
- title: change.title,
42
- summary: change.summary,
43
- body: change.body,
44
- tags: change.tags,
45
- }), 'utf8');
46
- updatedDocs.push(fullPath);
47
- }
48
- proposal.status = 'applied';
49
- proposal.applied_at = new Date().toISOString();
50
- await writeFile(proposalPath, `${JSON.stringify(proposal, null, 2)}\n`, 'utf8');
51
- await writeIndexFromDocs(home, proposal.branch);
52
- await updateBranchMeta(home, proposal.branch, {
53
- summary: proposal.summary || (await readBranchSummary(home, proposal.branch)),
54
- });
55
- return {
56
- branch: proposal.branch,
57
- updated_docs: updatedDocs,
58
- proposal_path: proposalPath,
59
- };
60
- }
61
- async function readBranchSummary(home, branch) {
62
- const branchJson = await readFile(join(branchDir(home, branch), 'branch.json'), 'utf8');
63
- return JSON.parse(branchJson).summary || '';
64
- }
65
- export async function listProposals(home, branch) {
66
- return (await readdir(branchProposalsDir(home, branch)).catch(() => []))
67
- .filter((file) => file.endsWith('.json'))
68
- .sort()
69
- .map((file) => join(branchProposalsDir(home, branch), file));
70
- }
71
- export function proposalBasename(path) {
72
- return basename(path);
73
- }