gitnexushub 0.4.3 → 0.4.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/wiki/index.js
CHANGED
|
@@ -16,9 +16,8 @@ function reportError(err) {
|
|
|
16
16
|
process.exit(1);
|
|
17
17
|
}
|
|
18
18
|
export function registerWikiCommand(program) {
|
|
19
|
-
const wiki = program
|
|
20
|
-
|
|
21
|
-
.command('upload')
|
|
19
|
+
const wiki = program
|
|
20
|
+
.command('wiki')
|
|
22
21
|
.description('Generate the wiki locally with Claude Code and upload it to the Hub')
|
|
23
22
|
.option('--mode <mode>', 'full | incremental', 'full')
|
|
24
23
|
.option('--model <model>', 'Claude model to use', REAL_DEFAULT_MODEL)
|
|
@@ -28,14 +27,29 @@ export function registerWikiCommand(program) {
|
|
|
28
27
|
if (opts.model)
|
|
29
28
|
deps.model = opts.model;
|
|
30
29
|
const ac = new AbortController();
|
|
30
|
+
let sigCount = 0;
|
|
31
|
+
let forceExitTimer = null;
|
|
31
32
|
const onSig = () => {
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
sigCount++;
|
|
34
|
+
if (sigCount === 1) {
|
|
35
|
+
warn('interrupt received — cleaning up (Ctrl+C again to force quit)...');
|
|
36
|
+
ac.abort();
|
|
37
|
+
forceExitTimer = setTimeout(() => {
|
|
38
|
+
warn('cleanup timed out, forcing exit');
|
|
39
|
+
process.exit(130);
|
|
40
|
+
}, 3000);
|
|
41
|
+
forceExitTimer.unref();
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
if (forceExitTimer)
|
|
45
|
+
clearTimeout(forceExitTimer);
|
|
46
|
+
process.exit(130);
|
|
47
|
+
}
|
|
34
48
|
};
|
|
35
49
|
process.on('SIGINT', onSig);
|
|
36
50
|
process.on('SIGTERM', onSig);
|
|
37
51
|
try {
|
|
38
|
-
info(
|
|
52
|
+
info('Resolving repo context...');
|
|
39
53
|
const result = await runWikiUpload({ cwd, mode: opts.mode, model: opts.model, abortSignal: ac.signal }, deps);
|
|
40
54
|
ok(`Uploaded ${result.pagesPersisted} pages.`);
|
|
41
55
|
if (result.failedSlugs.length > 0) {
|
|
@@ -43,9 +57,15 @@ export function registerWikiCommand(program) {
|
|
|
43
57
|
}
|
|
44
58
|
}
|
|
45
59
|
catch (err) {
|
|
60
|
+
if (ac.signal.aborted) {
|
|
61
|
+
warn('aborted');
|
|
62
|
+
process.exit(130);
|
|
63
|
+
}
|
|
46
64
|
reportError(err);
|
|
47
65
|
}
|
|
48
66
|
finally {
|
|
67
|
+
if (forceExitTimer)
|
|
68
|
+
clearTimeout(forceExitTimer);
|
|
49
69
|
process.off('SIGINT', onSig);
|
|
50
70
|
process.off('SIGTERM', onSig);
|
|
51
71
|
}
|
|
@@ -4,7 +4,7 @@ export async function resolveWikiContext(deps, opts = {}) {
|
|
|
4
4
|
const repoRoot = deps.getGitRoot(deps.cwd);
|
|
5
5
|
if (!repoRoot) {
|
|
6
6
|
throw new GnxError(ErrorCode.NOT_GIT_REPO, 'not a git repository', {
|
|
7
|
-
hint: 'cd into your project, or run: gnx wiki
|
|
7
|
+
hint: 'cd into your project, or run: gnx wiki <path>',
|
|
8
8
|
});
|
|
9
9
|
}
|
|
10
10
|
const headCommit = deps.getGitHead(repoRoot);
|
package/dist/wiki/session.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ export interface RunSessionDeps {
|
|
|
21
21
|
modules: ModuleNode[];
|
|
22
22
|
moduleTree: unknown;
|
|
23
23
|
generatePage: GeneratePageFn;
|
|
24
|
+
onSessionStart?: (sessionId: string) => void;
|
|
24
25
|
onPageStart?: (slug: string) => void;
|
|
25
26
|
onPageDone?: (slug: string, bytes: number) => void;
|
|
26
27
|
onPageFail?: (slug: string, err: unknown) => void;
|
package/dist/wiki/session.js
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import { resolveWikiContext } from './resolve-context.js';
|
|
2
2
|
import { runWikiUploadSession } from './session.js';
|
|
3
3
|
import { GnxError, ErrorCode } from './errors.js';
|
|
4
|
+
import { info, warn } from '../cli-helpers.js';
|
|
5
|
+
function formatBytes(n) {
|
|
6
|
+
if (n < 1024)
|
|
7
|
+
return `${n} B`;
|
|
8
|
+
if (n < 1024 * 1024)
|
|
9
|
+
return `${(n / 1024).toFixed(1)} KB`;
|
|
10
|
+
return `${(n / (1024 * 1024)).toFixed(2)} MB`;
|
|
11
|
+
}
|
|
12
|
+
function formatDuration(ms) {
|
|
13
|
+
const s = Math.floor(ms / 1000);
|
|
14
|
+
if (s < 60)
|
|
15
|
+
return `${s}s`;
|
|
16
|
+
const m = Math.floor(s / 60);
|
|
17
|
+
const rem = s % 60;
|
|
18
|
+
return `${m}m${rem.toString().padStart(2, '0')}s`;
|
|
19
|
+
}
|
|
4
20
|
function slugify(name) {
|
|
5
21
|
return name
|
|
6
22
|
.toLowerCase()
|
|
@@ -115,11 +131,13 @@ export async function runWikiUpload(opts, deps) {
|
|
|
115
131
|
if (opts.abortSignal?.aborted)
|
|
116
132
|
throw new GnxError(ErrorCode.USER_ABORTED, 'aborted before session start');
|
|
117
133
|
const runner = deps.createClaudeRunner();
|
|
134
|
+
info(`Fetching graph context from Hub (${ctx.hubFullName})...`);
|
|
118
135
|
const [prompts, groupingCtx] = await Promise.all([
|
|
119
136
|
ctx.api.wikiPromptTemplates(ctx.hubRepoId),
|
|
120
137
|
ctx.api.wikiGroupingContext(ctx.hubRepoId),
|
|
121
138
|
]);
|
|
122
139
|
// Phase 1: Module tree
|
|
140
|
+
info('Phase 1/3: generating module tree with Claude Code...');
|
|
123
141
|
const groupingPrompt = fillTemplate(prompts.grouping.user, {
|
|
124
142
|
COMMUNITY_GROUPS: groupingCtx.communityGroups,
|
|
125
143
|
INTER_COMMUNITY_EDGES: groupingCtx.interCommunityEdges,
|
|
@@ -138,6 +156,7 @@ export async function runWikiUpload(opts, deps) {
|
|
|
138
156
|
const allPageNodes = [...leaves, ...parents];
|
|
139
157
|
const moduleRegistry = allPageNodes.map((m) => `- [${m.title}](${m.slug}.md)`).join('\n');
|
|
140
158
|
const generatedPages = new Map();
|
|
159
|
+
info(`Phase 2/3: generating ${leaves.length} leaf page(s) + ${parents.length} parent page(s)...`);
|
|
141
160
|
if (opts.abortSignal?.aborted)
|
|
142
161
|
throw new GnxError(ErrorCode.USER_ABORTED, 'aborted before page generation');
|
|
143
162
|
// Phase 2a: Leaf pages
|
|
@@ -279,6 +298,25 @@ export async function runWikiUpload(opts, deps) {
|
|
|
279
298
|
summary: m.summary,
|
|
280
299
|
files: m.files,
|
|
281
300
|
}));
|
|
301
|
+
info(`Phase 3/3: streaming ${orderedModules.length} page(s) to Hub...`);
|
|
302
|
+
let activeSessionId = null;
|
|
303
|
+
const onAbort = async () => {
|
|
304
|
+
if (!activeSessionId)
|
|
305
|
+
return;
|
|
306
|
+
try {
|
|
307
|
+
await ctx.api.wikiUploadAbort(ctx.hubRepoId, activeSessionId);
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
/* ignore secondary errors */
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
opts.abortSignal?.addEventListener('abort', onAbort, { once: true });
|
|
314
|
+
const total = orderedModules.length;
|
|
315
|
+
const titleBySlug = new Map(orderedModules.map((m) => [m.slug, m.title]));
|
|
316
|
+
const pageStartAt = new Map();
|
|
317
|
+
const runStartAt = Date.now();
|
|
318
|
+
let startedCount = 0;
|
|
319
|
+
let doneCount = 0;
|
|
282
320
|
try {
|
|
283
321
|
return await runWikiUploadSession({
|
|
284
322
|
api: ctx.api,
|
|
@@ -290,6 +328,29 @@ export async function runWikiUpload(opts, deps) {
|
|
|
290
328
|
modules: orderedModules,
|
|
291
329
|
moduleTree,
|
|
292
330
|
generatePage: generatePageByType,
|
|
331
|
+
onSessionStart: (id) => {
|
|
332
|
+
activeSessionId = id;
|
|
333
|
+
},
|
|
334
|
+
onPageStart: (slug) => {
|
|
335
|
+
startedCount += 1;
|
|
336
|
+
pageStartAt.set(slug, Date.now());
|
|
337
|
+
const title = titleBySlug.get(slug) ?? slug;
|
|
338
|
+
info(`[${startedCount}/${total}] ${title} — generating...`);
|
|
339
|
+
},
|
|
340
|
+
onPageDone: (slug, bytes) => {
|
|
341
|
+
doneCount += 1;
|
|
342
|
+
const startedAt = pageStartAt.get(slug) ?? Date.now();
|
|
343
|
+
const elapsed = formatDuration(Date.now() - startedAt);
|
|
344
|
+
const totalElapsed = formatDuration(Date.now() - runStartAt);
|
|
345
|
+
const pct = Math.round((doneCount / total) * 100);
|
|
346
|
+
const title = titleBySlug.get(slug) ?? slug;
|
|
347
|
+
info(`[${doneCount}/${total}] ${title} — uploaded (${formatBytes(bytes)}, ${elapsed}) · ${pct}% · total ${totalElapsed}`);
|
|
348
|
+
},
|
|
349
|
+
onPageFail: (slug, err) => {
|
|
350
|
+
const title = titleBySlug.get(slug) ?? slug;
|
|
351
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
352
|
+
warn(`[${startedCount}/${total}] ${title} — failed: ${msg}`);
|
|
353
|
+
},
|
|
293
354
|
});
|
|
294
355
|
}
|
|
295
356
|
catch (err) {
|
package/package.json
CHANGED