@kira905/dsh-memory-toolkit 0.1.3 → 0.2.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/CHANGELOG.md +92 -0
- package/README.en.md +225 -2
- package/README.md +180 -2
- package/lib/deploy-guard.mjs +463 -275
- package/lib/guard-http.mjs +59 -62
- package/lib/pitfall-form-map.mjs +94 -84
- package/lib/pitfall-score.mjs +262 -185
- package/lib/session-file-name.mjs +116 -100
- package/lib/zstd-frames.mjs +88 -67
- package/memory-db-tools/README.md +29 -1
- package/memory-db-tools/audit-analyze.mjs +1 -1
- package/memory-db-tools/audit-export.mjs +60 -16
- package/memory-db-tools/audit-struct-probe.mjs +29 -8
- package/memory-db-tools/lib/known-devices.mjs +137 -0
- package/memory-engine/README.md +58 -4
- package/memory-engine/bench/bench.mjs +1 -1
- package/memory-engine/cli/band-sentinel.mjs +164 -0
- package/memory-engine/cli/distill-rollback.mjs +112 -44
- package/memory-engine/cli/distill-sessions.mjs +237 -0
- package/memory-engine/cli/distill.mjs +196 -95
- package/memory-engine/cli/doc-index-rebuild.mjs +142 -108
- package/memory-engine/cli/doc-index.mjs +47 -38
- package/memory-engine/cli/domain-tags.mjs +246 -162
- package/memory-engine/cli/layer-migrate.mjs +176 -0
- package/memory-engine/cli/layer-move.mjs +189 -0
- package/memory-engine/cli/pitfall-hook.mjs +136 -70
- package/memory-engine/cli/recall.mjs +243 -110
- package/memory-engine/cli/selfcheck.mjs +93 -44
- package/memory-engine/cli/serve-start.mjs +221 -140
- package/memory-engine/cli/sweep.mjs +83 -44
- package/memory-engine/cli/sync.mjs +93 -57
- package/memory-engine/config/audit-devices.json +6 -0
- package/memory-engine/config/bands.json +7 -0
- package/memory-engine/config/layers.json +7 -0
- package/memory-engine/dict/LICENSE-/350/257/215/345/205/270.md +53 -0
- package/memory-engine/dict/lexicon-config.json +11 -0
- package/memory-engine/dict//350/257/215/345/205/270.txt +109750 -0
- package/memory-engine/dict//350/257/215/351/242/221.txt +20000 -0
- package/memory-engine/lib/band-sentinel.mjs +417 -0
- package/memory-engine/lib/cli-strict.mjs +128 -0
- package/memory-engine/lib/cli-util.mjs +147 -125
- package/memory-engine/lib/config.mjs +83 -96
- package/memory-engine/lib/dirty-ledger.mjs +127 -94
- package/memory-engine/lib/distill-rollback.mjs +173 -133
- package/memory-engine/lib/distill.mjs +878 -585
- package/memory-engine/lib/doc-index-store.mjs +208 -235
- package/memory-engine/lib/doc-index.mjs +351 -350
- package/memory-engine/lib/doc-scan.mjs +178 -156
- package/memory-engine/lib/doc-summarize.mjs +220 -205
- package/memory-engine/lib/domain-tags.mjs +358 -277
- package/memory-engine/lib/embedder.mjs +175 -194
- package/memory-engine/lib/hashes.mjs +22 -7
- package/memory-engine/lib/layer-migrate.mjs +330 -0
- package/memory-engine/lib/layer-move.mjs +307 -0
- package/memory-engine/lib/layers.mjs +191 -0
- package/memory-engine/lib/lexicon-recall.mjs +473 -0
- package/memory-engine/lib/memory-source.mjs +78 -80
- package/memory-engine/lib/pitfall-source.mjs +115 -114
- package/memory-engine/lib/policy-source.mjs +279 -261
- package/memory-engine/lib/recall-log.mjs +285 -0
- package/memory-engine/lib/recall.mjs +565 -240
- package/memory-engine/lib/selfcheck.mjs +142 -106
- package/memory-engine/lib/session-distill.mjs +603 -0
- package/memory-engine/lib/session-source.mjs +421 -0
- package/memory-engine/lib/sweep.mjs +107 -130
- package/memory-engine/lib/sync.mjs +110 -140
- package/memory-engine/lib/tick-hook.mjs +123 -148
- package/memory-engine/lib/vectors-store.mjs +213 -188
- package/memory-engine/test/12-layering.test.mjs +539 -0
- package/memory-engine/test/13-session-distill.test.mjs +616 -0
- package/memory-engine/tools/bridge-smoke.mjs +94 -55
- package/memory-engine/tools/fetch-model.mjs +167 -87
- package/memory-engine/tools/smoke-recall.mjs +94 -38
- package/memory-engine/tools/verify-recall-chain.mjs +413 -0
- package/package.json +1 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
//
|
|
1
|
+
// 文档索引的「逃生舱」:库烂了 / 陈旧了,用它重建;重建前自动留快照,出事能一键盖回去。
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
3
|
+
// 支持的动作与开关:
|
|
4
|
+
// 无开关 一键全量刷新(范围内按 path 重跑,幂等)
|
|
5
|
+
// --purge 先清空范围内的条再重建(模拟"库损坏 / 陈旧")
|
|
6
|
+
// --no-snapshot 不留重建前快照(缺省会留)
|
|
7
|
+
// --restore <快照> 回滚:用快照覆盖当前库
|
|
8
|
+
// --list-snapshots 列出可用快照
|
|
9
|
+
// 路径注入:--docs-root / --dsh-root / --doc-index-db / --state-file / --home / --snapshot-dir
|
|
10
10
|
//
|
|
11
11
|
// 退出码:0 成功 / 1 有失败 / 2 用法错
|
|
12
12
|
import fs from 'node:fs';
|
|
@@ -16,140 +16,174 @@ import { isMainEntry, parseArgs, makeLogger } from '../lib/cli-util.mjs';
|
|
|
16
16
|
import { runDocIndexOnce } from '../lib/doc-index.mjs';
|
|
17
17
|
import { openDocIndexStore, snapshotDb } from '../lib/doc-index-store.mjs';
|
|
18
18
|
|
|
19
|
-
const
|
|
19
|
+
const RC = { ok: 0, fail: 1, usage: 2 };
|
|
20
|
+
const SNAP_HEAD = 'doc-index-';
|
|
21
|
+
const SNAP_TAIL = '.db';
|
|
20
22
|
|
|
23
|
+
/** 本地时间戳(快照文件名):YYYYMMDD-HHMMSS。 */
|
|
24
|
+
function stamp(when = new Date()) {
|
|
25
|
+
const two = (v) => `${v}`.padStart(2, '0');
|
|
26
|
+
const day = `${when.getFullYear()}${two(when.getMonth() + 1)}${two(when.getDate())}`;
|
|
27
|
+
const clock = [when.getHours(), when.getMinutes(), when.getSeconds()].map(two).join('');
|
|
28
|
+
return `${day}-${clock}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** 落点解析:home 一定,其余三项才有默认值。 */
|
|
21
32
|
function resolvePaths(flags, env = process.env) {
|
|
22
|
-
const
|
|
33
|
+
const fallbackHome = path.join(os.homedir(), '.dsh');
|
|
34
|
+
const home = path.resolve(String(flags.home || env.DSH_HOME || fallbackHome));
|
|
23
35
|
const vectorsDir = path.join(home, 'memory-vectors');
|
|
24
36
|
const dbPath = path.resolve(String(flags['doc-index-db'] || env.DOC_INDEX_DB || path.join(vectorsDir, 'doc-index.db')));
|
|
25
|
-
|
|
26
|
-
|
|
37
|
+
return {
|
|
38
|
+
home,
|
|
39
|
+
vectorsDir,
|
|
40
|
+
dbPath,
|
|
41
|
+
snapshotDir: path.resolve(String(flags['snapshot-dir'] || path.join(vectorsDir, 'doc-index-snapshots'))),
|
|
42
|
+
};
|
|
27
43
|
}
|
|
28
44
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const p = (n) => String(n).padStart(2, '0');
|
|
32
|
-
return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}-${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}`;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** 重建前快照(VACUUM INTO;库不存在则跳过——没有可备份的东西)。 */
|
|
36
|
-
export function takeSnapshot({ dbPath, snapshotDir, log = () => {} }) {
|
|
37
|
-
if (!fs.existsSync(dbPath)) return { ok: true, skipped: true, reason: '库不存在(首次建库无需快照)' };
|
|
38
|
-
const dest = path.join(snapshotDir, `doc-index-${ts()}.db`);
|
|
45
|
+
/** 开库 → 干活 → 无论成败都把库关掉(快照与清表都借这个壳)。 */
|
|
46
|
+
function withStore(dbPath, work) {
|
|
39
47
|
const store = openDocIndexStore(dbPath, { create: false });
|
|
40
48
|
try {
|
|
41
|
-
|
|
49
|
+
return work(store.db);
|
|
42
50
|
} finally {
|
|
43
|
-
try {
|
|
44
|
-
store.db.close();
|
|
45
|
-
} catch {
|
|
46
|
-
/* ignore */
|
|
47
|
-
}
|
|
51
|
+
try { store.db.close(); } catch { /* 关不掉不盖住真正的错 */ }
|
|
48
52
|
}
|
|
49
|
-
const size = fs.statSync(dest).size;
|
|
50
|
-
log(`[rebuild] 重建前快照:${dest}(${size} B)`);
|
|
51
|
-
return { ok: true, dest, size };
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
/**
|
|
55
|
+
/** 重建前快照(VACUUM INTO)。库还不存在 ⇒ 没有可备份的东西,跳过即可。 */
|
|
56
|
+
export function takeSnapshot({ dbPath, snapshotDir, log = () => {} }) {
|
|
57
|
+
const hasDb = fs.existsSync(dbPath);
|
|
58
|
+
if (!hasDb) return { ok: true, skipped: true, reason: '库不存在(首次建库无需快照)' };
|
|
59
|
+
const dest = path.join(snapshotDir, `${SNAP_HEAD}${stamp()}${SNAP_TAIL}`);
|
|
60
|
+
withStore(dbPath, (db) => snapshotDb(db, dest));
|
|
61
|
+
const { size } = fs.statSync(dest);
|
|
62
|
+
log(`[rebuild] 重建前快照已留:${dest}(${size} B)`);
|
|
63
|
+
return { ok: true, size, dest };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** 列快照(新→旧)。目录不在 = 没有快照,不是错误。 */
|
|
55
67
|
export function listSnapshots(snapshotDir) {
|
|
68
|
+
let entries;
|
|
56
69
|
try {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
70
|
+
entries = fs.readdirSync(snapshotDir);
|
|
71
|
+
} catch {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const picked = [];
|
|
76
|
+
for (const name of entries) {
|
|
77
|
+
const looksLikeSnap = name.startsWith(SNAP_HEAD) && name.endsWith(SNAP_TAIL);
|
|
78
|
+
if (!looksLikeSnap) continue;
|
|
79
|
+
const file = path.join(snapshotDir, name);
|
|
80
|
+
const info = fs.statSync(file);
|
|
81
|
+
picked.push({ name, file, size: info.size, mtime: info.mtimeMs });
|
|
82
|
+
}
|
|
83
|
+
picked.sort((a, b) => b.mtime - a.mtime);
|
|
84
|
+
return picked;
|
|
62
85
|
} catch {
|
|
63
86
|
return [];
|
|
64
87
|
}
|
|
65
88
|
}
|
|
66
89
|
|
|
90
|
+
function existenceProblem(file, label) {
|
|
91
|
+
return fs.existsSync(file) ? null : `${label}:${file}`;
|
|
92
|
+
}
|
|
93
|
+
|
|
67
94
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
95
|
+
* 回滚:快照盖回当前库。当前库先另存一份 `.before-restore-<ts>`,绝不静默丢东西。
|
|
96
|
+
* 注意覆盖前必须清 `-wal` / `-shm`,否则新库会被旧 WAL 污染。
|
|
70
97
|
*/
|
|
71
98
|
export function restoreFromSnapshot({ dbPath, snapshotFile, log = () => {} }) {
|
|
72
|
-
|
|
73
|
-
if (
|
|
74
|
-
const backup = `${dbPath}.before-restore-${
|
|
75
|
-
|
|
76
|
-
for (const
|
|
77
|
-
const f = `${dbPath}${
|
|
99
|
+
const blocker = existenceProblem(snapshotFile, '快照不存在') ?? existenceProblem(dbPath, '目标库不存在');
|
|
100
|
+
if (blocker) return { ok: false, error: blocker };
|
|
101
|
+
const backup = `${dbPath}.before-restore-${stamp()}`;
|
|
102
|
+
copyFile(dbPath, backup);
|
|
103
|
+
for (const sidecar of ['-wal', '-shm']) {
|
|
104
|
+
const f = `${dbPath}${sidecar}`;
|
|
78
105
|
if (fs.existsSync(f)) fs.rmSync(f, { force: true });
|
|
79
106
|
}
|
|
80
|
-
|
|
81
|
-
log(`[rebuild]
|
|
107
|
+
copyFile(snapshotFile, dbPath);
|
|
108
|
+
log(`[rebuild] 快照已回滚:${snapshotFile} → ${dbPath}(回滚前副本 ${backup})`);
|
|
82
109
|
return { ok: true, backup, from: snapshotFile };
|
|
83
110
|
}
|
|
84
111
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const log = makeLogger({ json, quiet: Boolean(flags.quiet) });
|
|
89
|
-
const { dbPath, snapshotDir, home } = resolvePaths(flags);
|
|
112
|
+
function copyFile(from, to) {
|
|
113
|
+
fs.copyFileSync(from, to);
|
|
114
|
+
}
|
|
90
115
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
116
|
+
/** 子命令:列快照。 */
|
|
117
|
+
function cmdList({ flags, json, log, paths }) {
|
|
118
|
+
const snaps = listSnapshots(paths.snapshotDir);
|
|
119
|
+
if (json) {
|
|
120
|
+
process.stdout.write(`${JSON.stringify({ ok: true, snapshotDir: paths.snapshotDir, snapshots: snaps }, null, 2)}\n`);
|
|
121
|
+
return RC.ok;
|
|
122
|
+
}
|
|
123
|
+
log(`快照目录:${paths.snapshotDir}`);
|
|
124
|
+
if (!snaps.length) log('(这个目录里还没有快照)');
|
|
125
|
+
for (const s of snaps) log(` ${new Date(s.mtime).toLocaleString('zh-CN')} ${s.size} B ${s.file}`);
|
|
126
|
+
return RC.ok;
|
|
127
|
+
}
|
|
102
128
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
129
|
+
/** 子命令:从快照回滚。 */
|
|
130
|
+
function cmdRestore({ flags, json, log, paths }) {
|
|
131
|
+
const r = restoreFromSnapshot({ dbPath: paths.dbPath, snapshotFile: path.resolve(flags.restore), log });
|
|
132
|
+
if (json) process.stdout.write(`${JSON.stringify({ ok: r.ok, ...r }, null, 2)}\n`);
|
|
133
|
+
return r.ok ? RC.ok : RC.fail;
|
|
134
|
+
}
|
|
108
135
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
136
|
+
/** 子命令:一键重建(缺省动作)。 */
|
|
137
|
+
async function cmdRebuild({ flags, json, log, paths }) {
|
|
138
|
+
// ① 先留退路(--no-snapshot / --dry-run 时不写)
|
|
139
|
+
let snapshot = { ok: true, skipped: true, reason: '--no-snapshot' };
|
|
140
|
+
const wantSnapshot = !flags['no-snapshot'] && !flags['dry-run'];
|
|
141
|
+
if (wantSnapshot) snapshot = takeSnapshot({ dbPath: paths.dbPath, snapshotDir: paths.snapshotDir, log });
|
|
114
142
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
143
|
+
// ② --purge:先把范围内的条清空,模拟"库烂了"从零重建
|
|
144
|
+
const canPurge = flags.purge && !flags['dry-run'] && fs.existsSync(paths.dbPath);
|
|
145
|
+
if (canPurge) {
|
|
146
|
+
const removed = withStore(paths.dbPath, (db) => db.prepare('DELETE FROM doc_index').run().changes);
|
|
147
|
+
log(`[rebuild] 清表完成:doc_index 删了 ${Number(removed) || 0} 条`);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ③ 全量刷新:ignore 差分、按 path 覆盖,所以重跑幂等
|
|
151
|
+
const r = await runDocIndexOnce({ flags: { ...flags, rebuild: true, home: paths.home, 'doc-index-db': paths.dbPath } });
|
|
152
|
+
for (const line of r.lines) log(line);
|
|
153
|
+
|
|
154
|
+
const payload = {
|
|
155
|
+
ok: r.status !== 'failed',
|
|
156
|
+
status: r.status,
|
|
157
|
+
dbPath: paths.dbPath,
|
|
158
|
+
snapshot,
|
|
159
|
+
stats: r.stats,
|
|
160
|
+
dailyLine: r.state.lastDailyLine,
|
|
161
|
+
};
|
|
162
|
+
if (json) process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
163
|
+
else log(`[rebuild] 收工:${r.state.lastDailyLine}`);
|
|
164
|
+
return r.status === 'failed' ? RC.fail : RC.ok;
|
|
165
|
+
}
|
|
129
166
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
};
|
|
144
|
-
if (json) process.stdout.write(JSON.stringify(out, null, 2) + '\n');
|
|
145
|
-
else log(`[rebuild] 完成:${r.state.lastDailyLine}`);
|
|
146
|
-
return r.status === 'failed' ? EXIT.FAIL : EXIT.OK;
|
|
167
|
+
const SUBCOMMANDS = [
|
|
168
|
+
{ pick: (flags) => Boolean(flags['list-snapshots']), run: cmdList },
|
|
169
|
+
{ pick: (flags) => typeof flags.restore === 'string', run: cmdRestore },
|
|
170
|
+
];
|
|
171
|
+
|
|
172
|
+
export async function main() {
|
|
173
|
+
const { flags } = parseArgs();
|
|
174
|
+
const asJson = Boolean(flags.json);
|
|
175
|
+
const log = makeLogger({ json: asJson, quiet: Boolean(flags.quiet) });
|
|
176
|
+
const paths = resolvePaths(flags);
|
|
177
|
+
const chosen = SUBCOMMANDS.find((c) => c.pick(flags));
|
|
178
|
+
try {
|
|
179
|
+
return await (chosen ? chosen.run({ flags, json: asJson, log, paths }) : cmdRebuild({ flags, json: asJson, log, paths }));
|
|
147
180
|
} catch (e) {
|
|
148
|
-
const msg = String(e
|
|
149
|
-
if (
|
|
181
|
+
const msg = String(e?.stack ?? e);
|
|
182
|
+
if (asJson) process.stdout.write(`${JSON.stringify({ ok: false, error: msg }, null, 2)}\n`);
|
|
150
183
|
else log(`❌ ${msg}`);
|
|
151
|
-
return
|
|
184
|
+
return RC.usage;
|
|
152
185
|
}
|
|
153
186
|
}
|
|
154
187
|
|
|
155
|
-
|
|
188
|
+
const launchedDirectly = isMainEntry(import.meta.url);
|
|
189
|
+
if (launchedDirectly) process.exitCode = await main();
|
|
@@ -1,48 +1,57 @@
|
|
|
1
|
-
//
|
|
1
|
+
// 文档索引 CLI(离线层):跑一轮「文档 → 索引库」的增量同步。
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
3
|
+
// 常见用法
|
|
4
|
+
// 什么都不给 增量跑一轮,范围是首期那 10 篇
|
|
5
|
+
// --all 扫描面全量(重活,别随手跑)
|
|
6
|
+
// --only a.md,b.md 只处理点名的几篇
|
|
7
|
+
// --rebuild 无视差分,范围内按 path 全跑(覆盖写,重跑幂等)
|
|
8
|
+
// --dry-run 只算不写:不建库、不动 state、不写日报
|
|
9
|
+
// --llm 摘要改走便宜模型(同样受成本闸约束)
|
|
10
|
+
// --json 机器可读;人话日志改走 stderr
|
|
11
|
+
// 路径都能改:--docs-root / --dsh-root / --doc-index-db / --state-file / --home
|
|
12
12
|
import { isMainEntry, parseArgs, makeLogger } from '../lib/cli-util.mjs';
|
|
13
13
|
import { runDocIndexOnce } from '../lib/doc-index.mjs';
|
|
14
14
|
|
|
15
|
+
/** 机器读 JSON,人读逐行 —— 两条路别混。 */
|
|
16
|
+
function narrate(run, { json, log }) {
|
|
17
|
+
if (!json) {
|
|
18
|
+
for (const line of run.lines) log(line);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const digest = {
|
|
22
|
+
ok: run.ok,
|
|
23
|
+
status: run.status,
|
|
24
|
+
exitCode: run.exitCode,
|
|
25
|
+
stats: run.stats,
|
|
26
|
+
dailyLine: run.state.lastDailyLine,
|
|
27
|
+
paths: run.state.paths,
|
|
28
|
+
};
|
|
29
|
+
process.stdout.write(`${JSON.stringify(digest, null, 2)}\n`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** 出错也要分两条路说清楚,然后按既定语义回 2。 */
|
|
33
|
+
function complain(e, { json, log }) {
|
|
34
|
+
const msg = String(e?.stack ?? e);
|
|
35
|
+
if (json) process.stdout.write(`${JSON.stringify({ ok: false, error: msg }, null, 2)}\n`);
|
|
36
|
+
else log(`❌ ${msg}`);
|
|
37
|
+
return 2;
|
|
38
|
+
}
|
|
39
|
+
|
|
15
40
|
export async function main() {
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
41
|
+
const parsed = parseArgs();
|
|
42
|
+
const flags = parsed.flags;
|
|
43
|
+
const asJson = Boolean(flags.json);
|
|
44
|
+
const log = makeLogger({ json: asJson, quiet: Boolean(flags.quiet) });
|
|
45
|
+
const channel = { json: asJson, log };
|
|
46
|
+
|
|
19
47
|
try {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
JSON.stringify(
|
|
24
|
-
{
|
|
25
|
-
ok: r.ok,
|
|
26
|
-
status: r.status,
|
|
27
|
-
exitCode: r.exitCode,
|
|
28
|
-
stats: r.stats,
|
|
29
|
-
dailyLine: r.state.lastDailyLine,
|
|
30
|
-
paths: r.state.paths,
|
|
31
|
-
},
|
|
32
|
-
null,
|
|
33
|
-
2,
|
|
34
|
-
) + '\n',
|
|
35
|
-
);
|
|
36
|
-
} else {
|
|
37
|
-
for (const l of r.lines) log(l);
|
|
38
|
-
}
|
|
39
|
-
process.exitCode = r.exitCode;
|
|
48
|
+
const run = await runDocIndexOnce({ flags });
|
|
49
|
+
narrate(run, channel);
|
|
50
|
+
process.exitCode = run.exitCode;
|
|
40
51
|
} catch (e) {
|
|
41
|
-
|
|
42
|
-
if (json) process.stdout.write(JSON.stringify({ ok: false, error: msg }, null, 2) + '\n');
|
|
43
|
-
else log(`❌ ${msg}`);
|
|
44
|
-
process.exitCode = 2;
|
|
52
|
+
process.exitCode = complain(e, channel);
|
|
45
53
|
}
|
|
46
54
|
}
|
|
47
55
|
|
|
48
|
-
|
|
56
|
+
const invokedDirectly = isMainEntry(import.meta.url);
|
|
57
|
+
if (invokedDirectly) await main();
|