@senticor/hive 1.49.1 → 1.50.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.md +8 -6
- package/chive.cjs +1472 -0
- package/hive.cjs +886 -11
- package/package.json +4 -2
package/chive.cjs
ADDED
|
@@ -0,0 +1,1472 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
|
|
30
|
+
// ../../node_modules/.pnpm/tsup@8.5.1_@swc+core@1.15.43_@swc+helpers@0.5.23__jiti@2.7.0_postcss@8.5.28_supports-co_ebdccb821406f648b54993c6aadaa9c1/node_modules/tsup/assets/cjs_shims.js
|
|
31
|
+
var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
|
|
32
|
+
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
33
|
+
|
|
34
|
+
// src/chive.mts
|
|
35
|
+
var import_node_fs = __toESM(require("fs"), 1);
|
|
36
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
37
|
+
|
|
38
|
+
// ../hive-kernel-code-context/src/index.ts
|
|
39
|
+
var src_exports = {};
|
|
40
|
+
__export(src_exports, {
|
|
41
|
+
BUILDER_VERSION: () => BUILDER_VERSION2,
|
|
42
|
+
EXT_LANG: () => EXT_LANG2,
|
|
43
|
+
buildContextPacket: () => buildContextPacket2,
|
|
44
|
+
buildDelta: () => buildDelta2,
|
|
45
|
+
buildGraph: () => buildGraph2,
|
|
46
|
+
parseFile: () => parseFile2,
|
|
47
|
+
projectContextPacket: () => projectContextPacket2,
|
|
48
|
+
projectDelta: () => projectDelta2,
|
|
49
|
+
projectGraph: () => projectGraph2,
|
|
50
|
+
scanRepository: () => scanRepository2
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// ../hive-kernel-code-context/src/scanner.ts
|
|
54
|
+
var scanner_exports = {};
|
|
55
|
+
__export(scanner_exports, {
|
|
56
|
+
DEFAULT_IGNORES: () => DEFAULT_IGNORES,
|
|
57
|
+
EXT_LANG: () => EXT_LANG,
|
|
58
|
+
scanRepository: () => scanRepository
|
|
59
|
+
});
|
|
60
|
+
var fs = __toESM(require("fs"), 1);
|
|
61
|
+
var path = __toESM(require("path"), 1);
|
|
62
|
+
var DEFAULT_IGNORES = /* @__PURE__ */ new Set([
|
|
63
|
+
"node_modules",
|
|
64
|
+
".git",
|
|
65
|
+
".pnpm-store",
|
|
66
|
+
"dist",
|
|
67
|
+
"build",
|
|
68
|
+
"out",
|
|
69
|
+
".next",
|
|
70
|
+
".turbo",
|
|
71
|
+
".cache",
|
|
72
|
+
"coverage",
|
|
73
|
+
".venv",
|
|
74
|
+
"venv",
|
|
75
|
+
"__pycache__",
|
|
76
|
+
".pytest_cache",
|
|
77
|
+
".mypy_cache",
|
|
78
|
+
".terraform"
|
|
79
|
+
]);
|
|
80
|
+
var EXT_LANG = {
|
|
81
|
+
".ts": "typescript",
|
|
82
|
+
".tsx": "typescript",
|
|
83
|
+
".mts": "typescript",
|
|
84
|
+
".cts": "typescript",
|
|
85
|
+
".js": "javascript",
|
|
86
|
+
".jsx": "javascript",
|
|
87
|
+
".mjs": "javascript",
|
|
88
|
+
".cjs": "javascript",
|
|
89
|
+
".py": "python",
|
|
90
|
+
".tf": "terraform",
|
|
91
|
+
".yaml": "yaml",
|
|
92
|
+
".yml": "yaml"
|
|
93
|
+
};
|
|
94
|
+
function readGitignore(repoRoot) {
|
|
95
|
+
const file = path.join(repoRoot, ".gitignore");
|
|
96
|
+
if (!fs.existsSync(file)) return [];
|
|
97
|
+
const text = fs.readFileSync(file, "utf8");
|
|
98
|
+
return text.split(/\r?\n/).map((l) => l.trim()).filter((l) => l && !l.startsWith("#")).map((l) => l.replace(/^\//, "").replace(/\/$/, ""));
|
|
99
|
+
}
|
|
100
|
+
function matchesIgnore(name, ignorePatterns) {
|
|
101
|
+
if (DEFAULT_IGNORES.has(name)) return true;
|
|
102
|
+
for (const pat of ignorePatterns) {
|
|
103
|
+
if (!pat.includes("*") && pat === name) return true;
|
|
104
|
+
if (pat.includes("*")) {
|
|
105
|
+
const re = new RegExp("^" + pat.replace(/\./g, "\\.").replace(/\*/g, ".*") + "$");
|
|
106
|
+
if (re.test(name)) return true;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
function scanRepository({ repositoryRoot, maxFiles = 5e3, extensions = null } = {}) {
|
|
112
|
+
if (!repositoryRoot || !fs.existsSync(repositoryRoot)) {
|
|
113
|
+
throw new Error(`repositoryRoot does not exist: ${repositoryRoot}`);
|
|
114
|
+
}
|
|
115
|
+
const absRoot = path.resolve(repositoryRoot);
|
|
116
|
+
const ignorePatterns = readGitignore(absRoot);
|
|
117
|
+
const wantExt = extensions ? new Set(extensions.map((e) => e.startsWith(".") ? e : "." + e)) : null;
|
|
118
|
+
const files = [];
|
|
119
|
+
let truncated = false;
|
|
120
|
+
const walk = (dir) => {
|
|
121
|
+
if (truncated) return;
|
|
122
|
+
let entries;
|
|
123
|
+
try {
|
|
124
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
125
|
+
} catch (_) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
for (const entry of entries) {
|
|
129
|
+
if (truncated) return;
|
|
130
|
+
const name = entry.name;
|
|
131
|
+
if (matchesIgnore(name, ignorePatterns)) continue;
|
|
132
|
+
const full = path.join(dir, name);
|
|
133
|
+
if (entry.isDirectory()) {
|
|
134
|
+
walk(full);
|
|
135
|
+
} else if (entry.isFile()) {
|
|
136
|
+
const ext = path.extname(name).toLowerCase();
|
|
137
|
+
const lang = EXT_LANG[ext];
|
|
138
|
+
if (!lang) continue;
|
|
139
|
+
if (wantExt && !wantExt.has(ext)) continue;
|
|
140
|
+
if (files.length >= maxFiles) {
|
|
141
|
+
truncated = true;
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
files.push({
|
|
145
|
+
filePath: path.relative(absRoot, full),
|
|
146
|
+
absPath: full,
|
|
147
|
+
language: lang,
|
|
148
|
+
ext
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
walk(absRoot);
|
|
154
|
+
return { files, truncated, repositoryRoot: absRoot };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ../hive-kernel-code-context/src/ts-parser.ts
|
|
158
|
+
var ts_parser_exports = {};
|
|
159
|
+
__export(ts_parser_exports, {
|
|
160
|
+
isTsLang: () => isTsLang,
|
|
161
|
+
moduleIdFor: () => moduleIdFor,
|
|
162
|
+
parseFile: () => parseFile
|
|
163
|
+
});
|
|
164
|
+
var fs2 = __toESM(require("fs"), 1);
|
|
165
|
+
var path2 = __toESM(require("path"), 1);
|
|
166
|
+
var import_node_module = require("module");
|
|
167
|
+
var _require = (0, import_node_module.createRequire)(importMetaUrl);
|
|
168
|
+
var _ts = null;
|
|
169
|
+
function ts() {
|
|
170
|
+
if (_ts) return _ts;
|
|
171
|
+
const mod = _require("typescript");
|
|
172
|
+
_ts = mod;
|
|
173
|
+
return mod;
|
|
174
|
+
}
|
|
175
|
+
function isTsLang(lang) {
|
|
176
|
+
return lang === "typescript" || lang === "javascript";
|
|
177
|
+
}
|
|
178
|
+
function scriptKindForExt(ext) {
|
|
179
|
+
const T = ts();
|
|
180
|
+
switch (ext) {
|
|
181
|
+
case ".ts":
|
|
182
|
+
case ".mts":
|
|
183
|
+
case ".cts":
|
|
184
|
+
return T.ScriptKind.TS;
|
|
185
|
+
case ".tsx":
|
|
186
|
+
return T.ScriptKind.TSX;
|
|
187
|
+
case ".jsx":
|
|
188
|
+
return T.ScriptKind.JSX;
|
|
189
|
+
case ".js":
|
|
190
|
+
case ".mjs":
|
|
191
|
+
case ".cjs":
|
|
192
|
+
default:
|
|
193
|
+
return T.ScriptKind.JS;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function nodeIdFor(filePath, kind, name, pos2) {
|
|
197
|
+
return `${kind}:${filePath}#${name || "_"}@${pos2}`;
|
|
198
|
+
}
|
|
199
|
+
function moduleIdFor(filePath) {
|
|
200
|
+
return `module:${filePath}`;
|
|
201
|
+
}
|
|
202
|
+
function parseFile({ filePath, absPath, ext = path2.extname(absPath).toLowerCase(), repositoryRoot }) {
|
|
203
|
+
const T = ts();
|
|
204
|
+
const source = fs2.readFileSync(absPath, "utf8");
|
|
205
|
+
const sf = T.createSourceFile(
|
|
206
|
+
absPath,
|
|
207
|
+
source,
|
|
208
|
+
T.ScriptTarget.Latest,
|
|
209
|
+
/*setParentNodes*/
|
|
210
|
+
true,
|
|
211
|
+
scriptKindForExt(ext)
|
|
212
|
+
);
|
|
213
|
+
const nodes = [];
|
|
214
|
+
const edges = [];
|
|
215
|
+
const moduleNodeId = moduleIdFor(filePath);
|
|
216
|
+
const language = EXT_LANG[ext] || (ext === ".ts" || ext === ".tsx" ? "typescript" : "javascript");
|
|
217
|
+
nodes.push({
|
|
218
|
+
nodeId: moduleNodeId,
|
|
219
|
+
kind: "module",
|
|
220
|
+
label: filePath,
|
|
221
|
+
filePath,
|
|
222
|
+
spanStart: 0,
|
|
223
|
+
spanEnd: source.length,
|
|
224
|
+
language
|
|
225
|
+
});
|
|
226
|
+
const definedSymbols = /* @__PURE__ */ new Map();
|
|
227
|
+
function recordDecl(kind, name, node) {
|
|
228
|
+
if (!name) return null;
|
|
229
|
+
const id = nodeIdFor(filePath, kind, name, node.pos);
|
|
230
|
+
nodes.push({
|
|
231
|
+
nodeId: id,
|
|
232
|
+
kind,
|
|
233
|
+
label: name,
|
|
234
|
+
filePath,
|
|
235
|
+
spanStart: node.getStart(sf),
|
|
236
|
+
spanEnd: node.getEnd(),
|
|
237
|
+
language
|
|
238
|
+
});
|
|
239
|
+
edges.push({
|
|
240
|
+
edgeId: `${moduleNodeId}|defines|${id}`,
|
|
241
|
+
from: moduleNodeId,
|
|
242
|
+
to: id,
|
|
243
|
+
predicate: "defines"
|
|
244
|
+
});
|
|
245
|
+
definedSymbols.set(name, id);
|
|
246
|
+
return id;
|
|
247
|
+
}
|
|
248
|
+
function resolveImportPath(specifier) {
|
|
249
|
+
if (!specifier) return null;
|
|
250
|
+
if (specifier.startsWith(".")) {
|
|
251
|
+
const baseDir = path2.dirname(filePath);
|
|
252
|
+
let resolved = path2.normalize(path2.join(baseDir, specifier));
|
|
253
|
+
if (resolved.startsWith("./")) resolved = resolved.slice(2);
|
|
254
|
+
return resolved;
|
|
255
|
+
}
|
|
256
|
+
return specifier;
|
|
257
|
+
}
|
|
258
|
+
function recordImport(specifier, importedNames, node) {
|
|
259
|
+
if (!specifier) return;
|
|
260
|
+
const resolved = resolveImportPath(specifier);
|
|
261
|
+
const isLocal = specifier.startsWith(".");
|
|
262
|
+
const targetId = isLocal ? `module:${resolved}` : `extmodule:${specifier}`;
|
|
263
|
+
edges.push({
|
|
264
|
+
edgeId: `${moduleNodeId}|imports|${targetId}@${node.pos}`,
|
|
265
|
+
from: moduleNodeId,
|
|
266
|
+
to: targetId,
|
|
267
|
+
predicate: "imports",
|
|
268
|
+
meta: {
|
|
269
|
+
specifier,
|
|
270
|
+
importedNames: importedNames || [],
|
|
271
|
+
external: !isLocal
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
if (!isLocal) {
|
|
275
|
+
nodes.push({
|
|
276
|
+
nodeId: targetId,
|
|
277
|
+
kind: "external_module",
|
|
278
|
+
label: specifier,
|
|
279
|
+
meta: { external: true }
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
function recordTopLevelCall(callee, node) {
|
|
284
|
+
if (!callee) return;
|
|
285
|
+
const targetSymbol = definedSymbols.get(callee);
|
|
286
|
+
const targetId = targetSymbol || `symbol:${callee}@external`;
|
|
287
|
+
edges.push({
|
|
288
|
+
edgeId: `${moduleNodeId}|calls|${targetId}@${node.pos}`,
|
|
289
|
+
from: moduleNodeId,
|
|
290
|
+
to: targetId,
|
|
291
|
+
predicate: "calls",
|
|
292
|
+
meta: { callee, external: !targetSymbol }
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
function visit(node) {
|
|
296
|
+
if (T.isFunctionDeclaration(node)) {
|
|
297
|
+
const name = node.name ? node.name.text : null;
|
|
298
|
+
recordDecl("function", name, node);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (T.isClassDeclaration(node)) {
|
|
302
|
+
const name = node.name ? node.name.text : null;
|
|
303
|
+
recordDecl("class", name, node);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
if (T.isInterfaceDeclaration(node)) {
|
|
307
|
+
recordDecl("interface", node.name.text, node);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if (T.isTypeAliasDeclaration(node)) {
|
|
311
|
+
recordDecl("type", node.name.text, node);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
if (T.isEnumDeclaration(node)) {
|
|
315
|
+
recordDecl("enum", node.name.text, node);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (T.isVariableStatement(node)) {
|
|
319
|
+
for (const decl of node.declarationList.declarations) {
|
|
320
|
+
if (T.isIdentifier(decl.name)) {
|
|
321
|
+
recordDecl("const", decl.name.text, decl);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (T.isImportDeclaration(node)) {
|
|
327
|
+
const moduleSpec = node.moduleSpecifier && T.isStringLiteral(node.moduleSpecifier) ? node.moduleSpecifier.text : null;
|
|
328
|
+
const names = [];
|
|
329
|
+
if (node.importClause) {
|
|
330
|
+
if (node.importClause.name) names.push(node.importClause.name.text);
|
|
331
|
+
const nb = node.importClause.namedBindings;
|
|
332
|
+
if (nb) {
|
|
333
|
+
if (T.isNamedImports(nb)) {
|
|
334
|
+
for (const e of nb.elements) names.push(e.name.text);
|
|
335
|
+
} else if (T.isNamespaceImport(nb)) {
|
|
336
|
+
names.push("* as " + nb.name.text);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
recordImport(moduleSpec, names, node);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
if (T.isExpressionStatement(node) && T.isCallExpression(node.expression)) {
|
|
344
|
+
const call = node.expression;
|
|
345
|
+
let callee = null;
|
|
346
|
+
if (T.isIdentifier(call.expression)) callee = call.expression.text;
|
|
347
|
+
else if (T.isPropertyAccessExpression(call.expression)) callee = call.expression.name.text;
|
|
348
|
+
recordTopLevelCall(callee, node);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
sf.forEachChild(visit);
|
|
353
|
+
return { nodes, edges };
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// ../hive-kernel-code-context/src/graph-builder.ts
|
|
357
|
+
var graph_builder_exports = {};
|
|
358
|
+
__export(graph_builder_exports, {
|
|
359
|
+
BUILDER_VERSION: () => BUILDER_VERSION,
|
|
360
|
+
buildGraph: () => buildGraph
|
|
361
|
+
});
|
|
362
|
+
var path4 = __toESM(require("path"), 1);
|
|
363
|
+
|
|
364
|
+
// ../hive-utils/dist/index.js
|
|
365
|
+
var import_node_crypto2 = require("crypto");
|
|
366
|
+
|
|
367
|
+
// ../hive-utils/dist/pagination.js
|
|
368
|
+
var import_node_crypto = require("crypto");
|
|
369
|
+
|
|
370
|
+
// ../hive-utils/dist/schema-org-records.js
|
|
371
|
+
var fs3 = __toESM(require("fs"), 1);
|
|
372
|
+
var path3 = __toESM(require("path"), 1);
|
|
373
|
+
|
|
374
|
+
// ../hive-utils/dist/ssrf.js
|
|
375
|
+
var import_node_net = __toESM(require("net"), 1);
|
|
376
|
+
var import_node_dns = __toESM(require("dns"), 1);
|
|
377
|
+
|
|
378
|
+
// ../hive-utils/dist/file-sniff.js
|
|
379
|
+
var PDF_SIG = Buffer.from("%PDF-", "latin1");
|
|
380
|
+
|
|
381
|
+
// ../hive-utils/dist/limits.js
|
|
382
|
+
var INGEST_LIMIT_SPEC = {
|
|
383
|
+
/**
|
|
384
|
+
* Max ids in a daily reconciliation manifest's job_application_ids[].
|
|
385
|
+
* `ceiling` is the hard wire-contract cap from the JSON schema's `maxItems`;
|
|
386
|
+
* an env override is clamped to it so the env-driven handler guard and the
|
|
387
|
+
* `/api/me/limits` advertisement can never exceed what the ajv validator
|
|
388
|
+
* accepts (otherwise a client following discovery would send a manifest the
|
|
389
|
+
* Kafka inline validator rejects as schema_mismatch — split behaviour).
|
|
390
|
+
*/
|
|
391
|
+
manifestMaxApplicationIds: { env: "HIVE_MANIFEST_MAX_APPLICATION_IDS", default: 1e5, ceiling: 1e5 },
|
|
392
|
+
/** Max attached documents per application. */
|
|
393
|
+
maxDocsPerApplication: { env: "HIVE_MAX_DOCS_PER_APPLICATION", default: 50 },
|
|
394
|
+
// NOTE: a per-jobposting application ceiling is intentionally NOT advertised
|
|
395
|
+
// here yet — enforcing it needs a durable per-jobposting counter at ingest,
|
|
396
|
+
// deferred to a follow-up. Advertising an unenforced limit would mislead
|
|
397
|
+
// clients (#1218 review), so it stays out of the discovery surface until wired.
|
|
398
|
+
/** Max bytes for a single ingested file (file-drop / upload). */
|
|
399
|
+
maxIngestFileBytes: { env: "HIVE_MAX_INGEST_FILE_BYTES", default: 25 * 1024 * 1024 },
|
|
400
|
+
/** Max pages rendered from a single PDF. */
|
|
401
|
+
maxPdfPages: { env: "HIVE_PDF_MARKDOWN_MAX_PAGES", default: 50 },
|
|
402
|
+
/** Max request body bytes accepted by ingest routes. */
|
|
403
|
+
maxBodyBytes: { env: "HIVE_MAX_BODY_BYTES", default: 10 * 1024 * 1024 },
|
|
404
|
+
// PDF semantic-enrichment caps (#1379) — folded into the SoT so they are
|
|
405
|
+
// advertised at /api/me/limits and read from one place instead of being
|
|
406
|
+
// hardcoded in the enrichment service. Breaching any of these flags the
|
|
407
|
+
// parent application (APPLICATION_PROCESSING_INCOMPLETE) instead of silently
|
|
408
|
+
// truncating. The `ceiling` is the hard cap above which an env override is
|
|
409
|
+
// clamped (a single oversized ingest must not OOM the worker — the #1326 root cause).
|
|
410
|
+
/** Max input bytes admitted into PDF semantic enrichment (skip+flag above). */
|
|
411
|
+
maxPdfEnrichmentInputBytes: { env: "HIVE_PDF_MAX_ENRICH_BYTES", default: 50 * 1024 * 1024, ceiling: 256 * 1024 * 1024 },
|
|
412
|
+
/** Max extracted-text chars fed to PDF semantic enrichment (abort+flag above). */
|
|
413
|
+
maxPdfEnrichmentTextChars: { env: "HIVE_PDF_MAX_ENRICH_TEXT_CHARS", default: 5e5, ceiling: 8e6 },
|
|
414
|
+
/** Max per-stream decompressed bytes when extracting PDF text (zip-bomb guard). */
|
|
415
|
+
maxPdfStreamDecompressionBytes: { env: "HIVE_PDF_MAX_DECOMPRESSION_BYTES", default: 64 * 1024 * 1024, ceiling: 256 * 1024 * 1024 },
|
|
416
|
+
/**
|
|
417
|
+
* Max UTF-8 bytes of a Kafka binding's broker CA bundle (`tls.caPem`, #83).
|
|
418
|
+
* The ceiling mirrors the wire-contract cap the api-contracts validator
|
|
419
|
+
* enforces (MISSION_KAFKA_TLS_CA_MAX_BYTES) — an env override can only
|
|
420
|
+
* LOWER the effective limit, so `/api/me/limits` never advertises more
|
|
421
|
+
* than the validator accepts (same split-behaviour guard as
|
|
422
|
+
* manifestMaxApplicationIds).
|
|
423
|
+
*/
|
|
424
|
+
maxKafkaTlsCaPemBytes: { env: "HIVE_MAX_KAFKA_TLS_CA_PEM_BYTES", default: 64 * 1024, ceiling: 64 * 1024 }
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
// ../hive-utils/dist/index.js
|
|
428
|
+
function sha256Hex(input) {
|
|
429
|
+
const h = (0, import_node_crypto2.createHash)("sha256");
|
|
430
|
+
h.update(input);
|
|
431
|
+
return h.digest("hex");
|
|
432
|
+
}
|
|
433
|
+
function nowIso() {
|
|
434
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// ../hive-kernel-code-context/src/graph-builder.ts
|
|
438
|
+
var BUILDER_VERSION = "0.1.0";
|
|
439
|
+
function buildGraph(params) {
|
|
440
|
+
const p = params || {};
|
|
441
|
+
const {
|
|
442
|
+
repositoryRoot,
|
|
443
|
+
repositoryRev = null,
|
|
444
|
+
graphId,
|
|
445
|
+
graphType = "source",
|
|
446
|
+
maxFiles = 5e3,
|
|
447
|
+
extensions = null
|
|
448
|
+
} = p;
|
|
449
|
+
if (!repositoryRoot) {
|
|
450
|
+
throw new Error("repositoryRoot is required");
|
|
451
|
+
}
|
|
452
|
+
const scan = scanRepository({ repositoryRoot, maxFiles, extensions });
|
|
453
|
+
const nodes = [];
|
|
454
|
+
const edges = [];
|
|
455
|
+
const seenNodes = /* @__PURE__ */ new Set();
|
|
456
|
+
const seenEdges = /* @__PURE__ */ new Set();
|
|
457
|
+
for (const file of scan.files) {
|
|
458
|
+
if (!isTsLang(file.language)) continue;
|
|
459
|
+
let result;
|
|
460
|
+
try {
|
|
461
|
+
result = parseFile({
|
|
462
|
+
filePath: file.filePath,
|
|
463
|
+
absPath: file.absPath,
|
|
464
|
+
ext: file.ext,
|
|
465
|
+
repositoryRoot: scan.repositoryRoot
|
|
466
|
+
});
|
|
467
|
+
} catch {
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
for (const n of result.nodes) {
|
|
471
|
+
if (seenNodes.has(n.nodeId)) continue;
|
|
472
|
+
seenNodes.add(n.nodeId);
|
|
473
|
+
nodes.push(n);
|
|
474
|
+
}
|
|
475
|
+
for (const e of result.edges) {
|
|
476
|
+
if (seenEdges.has(e.edgeId)) continue;
|
|
477
|
+
seenEdges.add(e.edgeId);
|
|
478
|
+
edges.push(e);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
const LOCAL_IMPORT_VARIANTS = [
|
|
482
|
+
"",
|
|
483
|
+
".ts",
|
|
484
|
+
".tsx",
|
|
485
|
+
".mts",
|
|
486
|
+
".cts",
|
|
487
|
+
".js",
|
|
488
|
+
".jsx",
|
|
489
|
+
".mjs",
|
|
490
|
+
".cjs",
|
|
491
|
+
"/index.ts",
|
|
492
|
+
"/index.tsx",
|
|
493
|
+
"/index.mts",
|
|
494
|
+
"/index.cts",
|
|
495
|
+
"/index.js",
|
|
496
|
+
"/index.jsx",
|
|
497
|
+
"/index.mjs",
|
|
498
|
+
"/index.cjs"
|
|
499
|
+
];
|
|
500
|
+
for (const edge of edges) {
|
|
501
|
+
if (edge.predicate !== "imports") continue;
|
|
502
|
+
if (edge.meta && edge.meta.external) continue;
|
|
503
|
+
if (seenNodes.has(edge.to)) continue;
|
|
504
|
+
const base = edge.to.startsWith("module:") ? edge.to.slice("module:".length) : edge.to;
|
|
505
|
+
for (const variant of LOCAL_IMPORT_VARIANTS) {
|
|
506
|
+
const candidate = `module:${base}${variant}`;
|
|
507
|
+
if (seenNodes.has(candidate)) {
|
|
508
|
+
edge.to = candidate;
|
|
509
|
+
if (edge.meta) edge.meta.resolvedExtension = variant || null;
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
const repoName = path4.basename(scan.repositoryRoot).toLowerCase().replace(/[^a-z0-9._-]/g, "-");
|
|
515
|
+
const finalGraphId = graphId || `cg.${repoName || "repo"}.v1`;
|
|
516
|
+
return {
|
|
517
|
+
schema: "hive.codeGraph.v1",
|
|
518
|
+
graphId: finalGraphId,
|
|
519
|
+
repositoryRoot: scan.repositoryRoot,
|
|
520
|
+
repositoryRev,
|
|
521
|
+
graphType,
|
|
522
|
+
builtAt: nowIso(),
|
|
523
|
+
builderVersion: BUILDER_VERSION,
|
|
524
|
+
nodes,
|
|
525
|
+
edges,
|
|
526
|
+
stats: {
|
|
527
|
+
nodeCount: nodes.length,
|
|
528
|
+
edgeCount: edges.length,
|
|
529
|
+
fileCount: scan.files.length,
|
|
530
|
+
truncated: scan.truncated
|
|
531
|
+
},
|
|
532
|
+
meta: {
|
|
533
|
+
builderLangs: ["typescript", "javascript"]
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// ../hive-kernel-code-context/src/context-builder.ts
|
|
539
|
+
var context_builder_exports = {};
|
|
540
|
+
__export(context_builder_exports, {
|
|
541
|
+
APPROX_CHARS_PER_TOKEN: () => APPROX_CHARS_PER_TOKEN,
|
|
542
|
+
buildContextPacket: () => buildContextPacket
|
|
543
|
+
});
|
|
544
|
+
var fs4 = __toESM(require("fs"), 1);
|
|
545
|
+
var path5 = __toESM(require("path"), 1);
|
|
546
|
+
var APPROX_CHARS_PER_TOKEN = 4;
|
|
547
|
+
function _matchScope(node, scope) {
|
|
548
|
+
if (!scope) return false;
|
|
549
|
+
if (Array.isArray(scope.paths) && node.filePath) {
|
|
550
|
+
for (const p of scope.paths) {
|
|
551
|
+
if (node.filePath === p || node.filePath.startsWith(p + path5.sep) || node.filePath.startsWith(p + "/")) {
|
|
552
|
+
return true;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
if (Array.isArray(scope.symbols) && node.label) {
|
|
557
|
+
if (scope.symbols.includes(node.label)) return true;
|
|
558
|
+
}
|
|
559
|
+
return false;
|
|
560
|
+
}
|
|
561
|
+
function _readSnippet(absRoot, node) {
|
|
562
|
+
if (!node.filePath) return null;
|
|
563
|
+
const abs = path5.isAbsolute(node.filePath) ? node.filePath : path5.join(absRoot || "", node.filePath);
|
|
564
|
+
let source;
|
|
565
|
+
try {
|
|
566
|
+
source = fs4.readFileSync(abs, "utf8");
|
|
567
|
+
} catch (_) {
|
|
568
|
+
return null;
|
|
569
|
+
}
|
|
570
|
+
const start = Math.max(0, node.spanStart || 0);
|
|
571
|
+
const end = Math.min(source.length, node.spanEnd || source.length);
|
|
572
|
+
return {
|
|
573
|
+
filePath: node.filePath,
|
|
574
|
+
spanStart: start,
|
|
575
|
+
spanEnd: end,
|
|
576
|
+
content: source.slice(start, end),
|
|
577
|
+
language: node.language || null,
|
|
578
|
+
reason: node.kind,
|
|
579
|
+
graphPath: [node.nodeId]
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
function buildContextPacket(params) {
|
|
583
|
+
const p = params || {};
|
|
584
|
+
const { graph, task, packetId, tokenBudgetHint = 4e3, repositoryRoot } = p;
|
|
585
|
+
if (!graph || graph.schema !== "hive.codeGraph.v1") {
|
|
586
|
+
throw new Error("graph must be a hive.codeGraph.v1 object");
|
|
587
|
+
}
|
|
588
|
+
if (!task || !task.objective) {
|
|
589
|
+
throw new Error("task.objective is required");
|
|
590
|
+
}
|
|
591
|
+
const absRoot = repositoryRoot || graph.repositoryRoot;
|
|
592
|
+
const nodesById = new Map(graph.nodes.map((n) => [n.nodeId, n]));
|
|
593
|
+
const seedIds = /* @__PURE__ */ new Set();
|
|
594
|
+
for (const n of graph.nodes) {
|
|
595
|
+
if (_matchScope(n, task.scope)) seedIds.add(n.nodeId);
|
|
596
|
+
}
|
|
597
|
+
const visited = new Set(seedIds);
|
|
598
|
+
for (const edge of graph.edges) {
|
|
599
|
+
if (seedIds.has(edge.from) || seedIds.has(edge.to)) {
|
|
600
|
+
visited.add(edge.from);
|
|
601
|
+
visited.add(edge.to);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
const charBudget = Math.max(0, tokenBudgetHint * APPROX_CHARS_PER_TOKEN);
|
|
605
|
+
let usedChars = 0;
|
|
606
|
+
const snippets = [];
|
|
607
|
+
const ordered = [
|
|
608
|
+
...[...seedIds].map((id) => nodesById.get(id)).filter((n) => Boolean(n)),
|
|
609
|
+
...[...visited].filter((id) => !seedIds.has(id)).map((id) => nodesById.get(id)).filter((n) => Boolean(n))
|
|
610
|
+
];
|
|
611
|
+
for (const node of ordered) {
|
|
612
|
+
if (node.kind === "external_module") continue;
|
|
613
|
+
const snip = _readSnippet(absRoot, node);
|
|
614
|
+
if (!snip) continue;
|
|
615
|
+
if (charBudget > 0 && usedChars + snip.content.length > charBudget && snippets.length > 0) {
|
|
616
|
+
break;
|
|
617
|
+
}
|
|
618
|
+
snippets.push(snip);
|
|
619
|
+
usedChars += snip.content.length;
|
|
620
|
+
}
|
|
621
|
+
const slug = (graph.graphId || "graph").replace(/^cg\./, "").replace(/\.v\d+$/, "");
|
|
622
|
+
const finalPacketId = packetId || `ccp.${slug || "task"}.v1`;
|
|
623
|
+
return {
|
|
624
|
+
schema: "hive.codeContextPacket.v1",
|
|
625
|
+
packetId: finalPacketId,
|
|
626
|
+
task: {
|
|
627
|
+
objective: task.objective,
|
|
628
|
+
kind: task.kind || "other",
|
|
629
|
+
scope: task.scope || {}
|
|
630
|
+
},
|
|
631
|
+
graphRefs: [
|
|
632
|
+
{
|
|
633
|
+
graphId: graph.graphId,
|
|
634
|
+
graphType: graph.graphType,
|
|
635
|
+
repositoryRev: graph.repositoryRev
|
|
636
|
+
}
|
|
637
|
+
],
|
|
638
|
+
snippets,
|
|
639
|
+
findings: [],
|
|
640
|
+
tokenBudgetHint,
|
|
641
|
+
builtAt: nowIso(),
|
|
642
|
+
meta: {
|
|
643
|
+
seedCount: seedIds.size,
|
|
644
|
+
expandedCount: visited.size,
|
|
645
|
+
usedChars,
|
|
646
|
+
truncated: snippets.length < ordered.length
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// ../hive-kernel-code-context/src/delta.ts
|
|
652
|
+
var delta_exports = {};
|
|
653
|
+
__export(delta_exports, {
|
|
654
|
+
buildDelta: () => buildDelta
|
|
655
|
+
});
|
|
656
|
+
function buildDelta({ baseGraph, headGraph, deltaId } = {}) {
|
|
657
|
+
if (!baseGraph || baseGraph.schema !== "hive.codeGraph.v1") {
|
|
658
|
+
throw new Error("baseGraph must be a hive.codeGraph.v1 object");
|
|
659
|
+
}
|
|
660
|
+
if (!headGraph || headGraph.schema !== "hive.codeGraph.v1") {
|
|
661
|
+
throw new Error("headGraph must be a hive.codeGraph.v1 object");
|
|
662
|
+
}
|
|
663
|
+
if (baseGraph.graphId !== headGraph.graphId) {
|
|
664
|
+
throw new Error(`graphId mismatch: ${baseGraph.graphId} vs ${headGraph.graphId}`);
|
|
665
|
+
}
|
|
666
|
+
const baseNodes = new Map(baseGraph.nodes.map((n) => [n.nodeId, n]));
|
|
667
|
+
const headNodes = new Map(headGraph.nodes.map((n) => [n.nodeId, n]));
|
|
668
|
+
const baseEdges = new Map(baseGraph.edges.map((e) => [e.edgeId, e]));
|
|
669
|
+
const headEdges = new Map(headGraph.edges.map((e) => [e.edgeId, e]));
|
|
670
|
+
const addedNodes = [];
|
|
671
|
+
const removedNodes = [];
|
|
672
|
+
for (const [id, n] of headNodes.entries()) {
|
|
673
|
+
if (!baseNodes.has(id)) addedNodes.push(n);
|
|
674
|
+
}
|
|
675
|
+
for (const id of baseNodes.keys()) {
|
|
676
|
+
if (!headNodes.has(id)) removedNodes.push(id);
|
|
677
|
+
}
|
|
678
|
+
const addedEdges = [];
|
|
679
|
+
const removedEdges = [];
|
|
680
|
+
for (const [id, e] of headEdges.entries()) {
|
|
681
|
+
if (!baseEdges.has(id)) addedEdges.push(e);
|
|
682
|
+
}
|
|
683
|
+
for (const id of baseEdges.keys()) {
|
|
684
|
+
if (!headEdges.has(id)) removedEdges.push(id);
|
|
685
|
+
}
|
|
686
|
+
const slug = (headGraph.graphId || "graph").replace(/^cg\./, "").replace(/\.v\d+$/, "");
|
|
687
|
+
const finalDeltaId = deltaId || `cgd.${slug || "graph"}.v1`;
|
|
688
|
+
return {
|
|
689
|
+
schema: "hive.codeGraphDelta.v1",
|
|
690
|
+
deltaId: finalDeltaId,
|
|
691
|
+
graphId: headGraph.graphId,
|
|
692
|
+
baseRev: baseGraph.repositoryRev || "unknown",
|
|
693
|
+
headRev: headGraph.repositoryRev || "unknown",
|
|
694
|
+
addedNodes,
|
|
695
|
+
removedNodes,
|
|
696
|
+
addedEdges,
|
|
697
|
+
removedEdges,
|
|
698
|
+
stats: {
|
|
699
|
+
addedNodes: addedNodes.length,
|
|
700
|
+
removedNodes: removedNodes.length,
|
|
701
|
+
addedEdges: addedEdges.length,
|
|
702
|
+
removedEdges: removedEdges.length
|
|
703
|
+
},
|
|
704
|
+
computedAt: nowIso()
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// ../hive-kernel-code-context/src/projection.ts
|
|
709
|
+
var projection_exports = {};
|
|
710
|
+
__export(projection_exports, {
|
|
711
|
+
projectContextPacket: () => projectContextPacket,
|
|
712
|
+
projectDelta: () => projectDelta,
|
|
713
|
+
projectGraph: () => projectGraph
|
|
714
|
+
});
|
|
715
|
+
function _missionSlug(missionId) {
|
|
716
|
+
return String(missionId || "default").replace(/[^a-z0-9._-]/gi, "-");
|
|
717
|
+
}
|
|
718
|
+
function projectGraph({ graph, missionId, tenantId = "default" } = {}) {
|
|
719
|
+
if (!graph || graph.schema !== "hive.codeGraph.v1") {
|
|
720
|
+
throw new Error("graph must be a hive.codeGraph.v1 object");
|
|
721
|
+
}
|
|
722
|
+
if (!missionId) throw new Error("missionId is required");
|
|
723
|
+
const slug = _missionSlug(missionId);
|
|
724
|
+
const nodes = graph.nodes.map((n) => ({
|
|
725
|
+
nodeId: n.nodeId,
|
|
726
|
+
kind: n.kind,
|
|
727
|
+
label: n.label || n.nodeId,
|
|
728
|
+
layer: "code",
|
|
729
|
+
missionId,
|
|
730
|
+
tenantId,
|
|
731
|
+
meta: {
|
|
732
|
+
filePath: n.filePath || null,
|
|
733
|
+
spanStart: n.spanStart || null,
|
|
734
|
+
spanEnd: n.spanEnd || null,
|
|
735
|
+
language: n.language || null,
|
|
736
|
+
graphId: graph.graphId,
|
|
737
|
+
...n.meta || {}
|
|
738
|
+
}
|
|
739
|
+
}));
|
|
740
|
+
const edges = graph.edges.map((e) => ({
|
|
741
|
+
edgeId: e.edgeId,
|
|
742
|
+
from: e.from,
|
|
743
|
+
predicate: e.predicate,
|
|
744
|
+
to: e.to,
|
|
745
|
+
layer: "code",
|
|
746
|
+
missionId,
|
|
747
|
+
weight: e.weight || null,
|
|
748
|
+
meta: {
|
|
749
|
+
graphId: graph.graphId,
|
|
750
|
+
...e.meta || {}
|
|
751
|
+
}
|
|
752
|
+
}));
|
|
753
|
+
const cellWrites = [
|
|
754
|
+
{
|
|
755
|
+
cellId: `kc.code.${slug}.graph`,
|
|
756
|
+
records: [
|
|
757
|
+
{
|
|
758
|
+
recordType: "CodeGraphSnapshot",
|
|
759
|
+
recordId: `${graph.graphId}@${graph.repositoryRev || "unknown"}`,
|
|
760
|
+
payload: {
|
|
761
|
+
graphId: graph.graphId,
|
|
762
|
+
graphType: graph.graphType,
|
|
763
|
+
repositoryRoot: graph.repositoryRoot,
|
|
764
|
+
repositoryRev: graph.repositoryRev,
|
|
765
|
+
stats: graph.stats,
|
|
766
|
+
builtAt: graph.builtAt
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
]
|
|
770
|
+
}
|
|
771
|
+
];
|
|
772
|
+
return { graphMutations: { nodes, edges }, cellWrites };
|
|
773
|
+
}
|
|
774
|
+
function projectContextPacket({ packet, missionId, tenantId = "default" } = {}) {
|
|
775
|
+
if (!packet || packet.schema !== "hive.codeContextPacket.v1") {
|
|
776
|
+
throw new Error("packet must be a hive.codeContextPacket.v1 object");
|
|
777
|
+
}
|
|
778
|
+
if (!missionId) throw new Error("missionId is required");
|
|
779
|
+
const slug = _missionSlug(missionId);
|
|
780
|
+
const packetHash = sha256Hex(JSON.stringify({ task: packet.task, snippets: packet.snippets }));
|
|
781
|
+
const cellWrites = [
|
|
782
|
+
{
|
|
783
|
+
cellId: `kc.code.${slug}.context-packets`,
|
|
784
|
+
records: [
|
|
785
|
+
{
|
|
786
|
+
recordType: "CodeContextPacket",
|
|
787
|
+
recordId: packet.packetId,
|
|
788
|
+
payload: {
|
|
789
|
+
packetId: packet.packetId,
|
|
790
|
+
task: packet.task,
|
|
791
|
+
graphRefs: packet.graphRefs,
|
|
792
|
+
snippetCount: (packet.snippets || []).length,
|
|
793
|
+
findingCount: (packet.findings || []).length,
|
|
794
|
+
tokenBudgetHint: packet.tokenBudgetHint,
|
|
795
|
+
builtAt: packet.builtAt,
|
|
796
|
+
packetHash
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
]
|
|
800
|
+
}
|
|
801
|
+
];
|
|
802
|
+
if (Array.isArray(packet.findings) && packet.findings.length > 0) {
|
|
803
|
+
cellWrites.push({
|
|
804
|
+
cellId: `kc.code.${slug}.findings`,
|
|
805
|
+
records: packet.findings.map((f) => ({
|
|
806
|
+
recordType: "CodeFinding",
|
|
807
|
+
recordId: f.findingId,
|
|
808
|
+
payload: { ...f, packetId: packet.packetId }
|
|
809
|
+
}))
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
const evidence = (packet.snippets || []).map((s, i) => ({
|
|
813
|
+
evidenceId: `${packet.packetId}#snippet-${i}`,
|
|
814
|
+
type: "code_snippet",
|
|
815
|
+
payload: {
|
|
816
|
+
filePath: s.filePath,
|
|
817
|
+
spanStart: s.spanStart,
|
|
818
|
+
spanEnd: s.spanEnd,
|
|
819
|
+
language: s.language,
|
|
820
|
+
reason: s.reason,
|
|
821
|
+
graphPath: s.graphPath || [],
|
|
822
|
+
contentHash: sha256Hex(s.content || "")
|
|
823
|
+
}
|
|
824
|
+
}));
|
|
825
|
+
return { cellWrites, evidence };
|
|
826
|
+
}
|
|
827
|
+
function projectDelta({ delta, missionId } = {}) {
|
|
828
|
+
if (!delta || delta.schema !== "hive.codeGraphDelta.v1") {
|
|
829
|
+
throw new Error("delta must be a hive.codeGraphDelta.v1 object");
|
|
830
|
+
}
|
|
831
|
+
if (!missionId) throw new Error("missionId is required");
|
|
832
|
+
const slug = _missionSlug(missionId);
|
|
833
|
+
return {
|
|
834
|
+
eventType: "CodeGraphDeltaComputed",
|
|
835
|
+
eventBody: {
|
|
836
|
+
missionId,
|
|
837
|
+
deltaId: delta.deltaId,
|
|
838
|
+
graphId: delta.graphId,
|
|
839
|
+
baseRev: delta.baseRev,
|
|
840
|
+
headRev: delta.headRev,
|
|
841
|
+
stats: delta.stats
|
|
842
|
+
},
|
|
843
|
+
cellWrite: {
|
|
844
|
+
cellId: `kc.code.${slug}.deltas`,
|
|
845
|
+
records: [
|
|
846
|
+
{
|
|
847
|
+
recordType: "CodeGraphDelta",
|
|
848
|
+
recordId: delta.deltaId,
|
|
849
|
+
payload: delta
|
|
850
|
+
}
|
|
851
|
+
]
|
|
852
|
+
}
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// ../hive-kernel-code-context/src/index.ts
|
|
857
|
+
var { scanRepository: scanRepository2, EXT_LANG: EXT_LANG2 } = scanner_exports;
|
|
858
|
+
var { buildGraph: buildGraph2, BUILDER_VERSION: BUILDER_VERSION2 } = graph_builder_exports;
|
|
859
|
+
var { buildContextPacket: buildContextPacket2 } = context_builder_exports;
|
|
860
|
+
var { buildDelta: buildDelta2 } = delta_exports;
|
|
861
|
+
var { projectGraph: projectGraph2, projectContextPacket: projectContextPacket2, projectDelta: projectDelta2 } = projection_exports;
|
|
862
|
+
var { parseFile: parseFile2 } = ts_parser_exports;
|
|
863
|
+
|
|
864
|
+
// src/chive-http.mts
|
|
865
|
+
var ChiveHttpError = class extends Error {
|
|
866
|
+
code;
|
|
867
|
+
status;
|
|
868
|
+
body;
|
|
869
|
+
constructor(message, opts = {}) {
|
|
870
|
+
super(message);
|
|
871
|
+
this.name = "ChiveHttpError";
|
|
872
|
+
this.code = opts.code || "http_error";
|
|
873
|
+
this.status = opts.status || null;
|
|
874
|
+
this.body = opts.body || null;
|
|
875
|
+
}
|
|
876
|
+
};
|
|
877
|
+
function assertFlagRecord(flags2) {
|
|
878
|
+
if (flags2 == null) return void 0;
|
|
879
|
+
if (typeof flags2 !== "object" || Array.isArray(flags2)) {
|
|
880
|
+
throw new ChiveHttpError("CLI flags must be an object", { code: "invalid_flags" });
|
|
881
|
+
}
|
|
882
|
+
return flags2;
|
|
883
|
+
}
|
|
884
|
+
function optionalStringFlag(flags2, name) {
|
|
885
|
+
if (!flags2) return void 0;
|
|
886
|
+
const value = flags2[name];
|
|
887
|
+
if (value == null || value === false || value === "") return void 0;
|
|
888
|
+
if (typeof value !== "string") {
|
|
889
|
+
throw new ChiveHttpError(`--${name} requires a value`, { code: `invalid_${name.replace(/[^a-z0-9]/gi, "_")}_flag` });
|
|
890
|
+
}
|
|
891
|
+
return value;
|
|
892
|
+
}
|
|
893
|
+
function optionalEnvString(name) {
|
|
894
|
+
const value = process.env[name];
|
|
895
|
+
return value && value.length > 0 ? value : void 0;
|
|
896
|
+
}
|
|
897
|
+
function errorMessage(error) {
|
|
898
|
+
return error instanceof Error ? error.message : String(error);
|
|
899
|
+
}
|
|
900
|
+
function extractResponseMessage(parsed) {
|
|
901
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
902
|
+
const obj = parsed;
|
|
903
|
+
if (typeof obj.error === "string" && obj.error) return obj.error;
|
|
904
|
+
if (typeof obj.message === "string" && obj.message) return obj.message;
|
|
905
|
+
return null;
|
|
906
|
+
}
|
|
907
|
+
function normalizeHeaders(headers) {
|
|
908
|
+
if (headers === void 0) return {};
|
|
909
|
+
if (!headers || typeof headers !== "object" || Array.isArray(headers)) {
|
|
910
|
+
throw new ChiveHttpError("headers must be an object", { code: "invalid_headers" });
|
|
911
|
+
}
|
|
912
|
+
return Object.fromEntries(
|
|
913
|
+
Object.entries(headers).map(([name, value]) => {
|
|
914
|
+
if (typeof value !== "string") {
|
|
915
|
+
throw new ChiveHttpError(`header ${name} must be a string`, { code: "invalid_headers" });
|
|
916
|
+
}
|
|
917
|
+
return [name, value];
|
|
918
|
+
})
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
function normalizeHttpOptions(options) {
|
|
922
|
+
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
923
|
+
throw new ChiveHttpError("httpJson options must be an object", { code: "invalid_http_options" });
|
|
924
|
+
}
|
|
925
|
+
const method = options.method ?? "GET";
|
|
926
|
+
if (typeof method !== "string" || method.length === 0) {
|
|
927
|
+
throw new ChiveHttpError("HTTP method must be a non-empty string", { code: "invalid_method" });
|
|
928
|
+
}
|
|
929
|
+
if (typeof options.url !== "string" || options.url.length === 0) {
|
|
930
|
+
throw new ChiveHttpError("HTTP URL must be a non-empty string", { code: "invalid_url" });
|
|
931
|
+
}
|
|
932
|
+
if (options.token != null && typeof options.token !== "string") {
|
|
933
|
+
throw new ChiveHttpError("token must be a string", { code: "invalid_token" });
|
|
934
|
+
}
|
|
935
|
+
const timeoutMs = options.timeoutMs ?? 3e4;
|
|
936
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
937
|
+
throw new ChiveHttpError("timeoutMs must be a positive number", { code: "invalid_timeout" });
|
|
938
|
+
}
|
|
939
|
+
return {
|
|
940
|
+
method,
|
|
941
|
+
url: options.url,
|
|
942
|
+
body: options.body,
|
|
943
|
+
token: options.token || null,
|
|
944
|
+
headers: normalizeHeaders(options.headers),
|
|
945
|
+
timeoutMs
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
function resolveApiBase(flags2) {
|
|
949
|
+
const flagRecord = assertFlagRecord(flags2);
|
|
950
|
+
const fromFlag = optionalStringFlag(flagRecord, "api") || optionalStringFlag(flagRecord, "api-base");
|
|
951
|
+
const fromEnv = optionalEnvString("HIVE_API_URL");
|
|
952
|
+
const base = (fromFlag || fromEnv || "").replace(/\/+$/, "");
|
|
953
|
+
if (!base) {
|
|
954
|
+
throw new ChiveHttpError(
|
|
955
|
+
"no API base URL \u2014 set HIVE_API_URL or pass --api <url>",
|
|
956
|
+
{ code: "no_api_url" }
|
|
957
|
+
);
|
|
958
|
+
}
|
|
959
|
+
return base;
|
|
960
|
+
}
|
|
961
|
+
function resolveToken(flags2) {
|
|
962
|
+
const flagRecord = assertFlagRecord(flags2);
|
|
963
|
+
return optionalStringFlag(flagRecord, "token") || optionalEnvString("HIVE_API_TOKEN") || null;
|
|
964
|
+
}
|
|
965
|
+
async function httpJson(options) {
|
|
966
|
+
const { method, url, body, token, headers, timeoutMs } = normalizeHttpOptions(options);
|
|
967
|
+
const requestInit = {
|
|
968
|
+
method,
|
|
969
|
+
headers: {
|
|
970
|
+
accept: "application/json",
|
|
971
|
+
...body !== void 0 ? { "content-type": "application/json" } : {},
|
|
972
|
+
...token ? { authorization: `Bearer ${token}` } : {},
|
|
973
|
+
...headers
|
|
974
|
+
}
|
|
975
|
+
};
|
|
976
|
+
if (body !== void 0) requestInit.body = JSON.stringify(body);
|
|
977
|
+
const controller = new AbortController();
|
|
978
|
+
const t = setTimeout(() => controller.abort(), timeoutMs);
|
|
979
|
+
requestInit.signal = controller.signal;
|
|
980
|
+
let res;
|
|
981
|
+
try {
|
|
982
|
+
res = await fetch(url, requestInit);
|
|
983
|
+
} catch (error) {
|
|
984
|
+
throw new ChiveHttpError(`network: ${errorMessage(error)}`, { code: "network" });
|
|
985
|
+
} finally {
|
|
986
|
+
clearTimeout(t);
|
|
987
|
+
}
|
|
988
|
+
const text = await res.text();
|
|
989
|
+
let parsed;
|
|
990
|
+
try {
|
|
991
|
+
parsed = text ? JSON.parse(text) : null;
|
|
992
|
+
} catch {
|
|
993
|
+
parsed = { raw: text };
|
|
994
|
+
}
|
|
995
|
+
if (!res.ok) {
|
|
996
|
+
const message = extractResponseMessage(parsed) || `HTTP ${res.status}`;
|
|
997
|
+
throw new ChiveHttpError(`${method} ${url} \u2192 ${res.status}: ${message}`, {
|
|
998
|
+
code: `http_${res.status}`,
|
|
999
|
+
status: res.status,
|
|
1000
|
+
body: parsed
|
|
1001
|
+
});
|
|
1002
|
+
}
|
|
1003
|
+
return parsed;
|
|
1004
|
+
}
|
|
1005
|
+
function mkRecordId(prefix) {
|
|
1006
|
+
if (typeof prefix !== "string" || prefix.length === 0) {
|
|
1007
|
+
throw new ChiveHttpError("record ID prefix must be a non-empty string", { code: "invalid_record_prefix" });
|
|
1008
|
+
}
|
|
1009
|
+
const ts2 = Date.now().toString(36);
|
|
1010
|
+
const rnd = Math.random().toString(36).slice(2, 8);
|
|
1011
|
+
return `${prefix}.${ts2}.${rnd}`;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
// src/chive.mts
|
|
1015
|
+
var VERSION = "0.2.0";
|
|
1016
|
+
var KNOWLEDGE_TOPICS = ["notes", "procedures", "examples", "post-mortems"];
|
|
1017
|
+
var KNOWLEDGE_RECORD_TYPES = {
|
|
1018
|
+
notes: "KnowledgeNote",
|
|
1019
|
+
procedures: "KnowledgeProcedure",
|
|
1020
|
+
examples: "KnowledgeExample",
|
|
1021
|
+
"post-mortems": "KnowledgePostMortem"
|
|
1022
|
+
};
|
|
1023
|
+
var KNOWLEDGE_TEMPLATE_ID = "mt.knowledge.base.v1";
|
|
1024
|
+
var codeContextKernel = src_exports;
|
|
1025
|
+
function parseArgs(argv) {
|
|
1026
|
+
const args = argv.slice(2);
|
|
1027
|
+
const positional = [];
|
|
1028
|
+
const flags2 = {};
|
|
1029
|
+
for (let i = 0; i < args.length; i++) {
|
|
1030
|
+
const a = args[i];
|
|
1031
|
+
if (a.startsWith("--")) {
|
|
1032
|
+
const eqIdx = a.indexOf("=");
|
|
1033
|
+
if (eqIdx > 0) {
|
|
1034
|
+
flags2[a.slice(2, eqIdx)] = a.slice(eqIdx + 1);
|
|
1035
|
+
} else if (i + 1 < args.length && !args[i + 1].startsWith("--")) {
|
|
1036
|
+
flags2[a.slice(2)] = args[++i];
|
|
1037
|
+
} else {
|
|
1038
|
+
flags2[a.slice(2)] = true;
|
|
1039
|
+
}
|
|
1040
|
+
} else {
|
|
1041
|
+
positional.push(a);
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
return { positional, flags: flags2 };
|
|
1045
|
+
}
|
|
1046
|
+
var { positional: pos, flags } = parseArgs(process.argv);
|
|
1047
|
+
function printHelp() {
|
|
1048
|
+
console.log(`chive v${VERSION} \u2014 Cognitive Hive OS code-context CLI
|
|
1049
|
+
|
|
1050
|
+
OFFLINE (kernel-only):
|
|
1051
|
+
chive graph build --repo <path> [--rev <rev>] [--graph-id <id>] [--max-files N] [--out <file>]
|
|
1052
|
+
chive graph update --repo <path> --base <graph.json> [--rev <rev>] [--graph-id <id>] [--out <file>]
|
|
1053
|
+
chive context build --graph <graph.json> --task "..." [--paths a,b] [--symbols x,y]
|
|
1054
|
+
[--budget <tokens>] [--repo <path>] [--out <file>]
|
|
1055
|
+
|
|
1056
|
+
ONLINE (talks to HIVE_API_URL or --api <url>; bearer via HIVE_API_TOKEN or --token):
|
|
1057
|
+
chive memory remember --task "..." --kind bugfix [--outcome success|failure]
|
|
1058
|
+
[--packet <packet.json>] [--summary "..."] [--domain code]
|
|
1059
|
+
chive memory recall [--task "..."] [--kind ...] [--domain code] [--limit N]
|
|
1060
|
+
chive arch decide --mission <missionId> --title "..." --because "..."
|
|
1061
|
+
[--files a,b] [--packet <packet.json>]
|
|
1062
|
+
chive arch list --mission <missionId>
|
|
1063
|
+
chive todo add "<title>" --mission <missionId> [--file path:line]
|
|
1064
|
+
[--priority high|med|low]
|
|
1065
|
+
chive todo list --mission <missionId> [--status open|done]
|
|
1066
|
+
chive todo done <todoId> --mission <missionId>
|
|
1067
|
+
chive knowledge mission create --intent "..." [--title "..."]
|
|
1068
|
+
chive knowledge mission list
|
|
1069
|
+
chive knowledge note add --mission <missionId> --topic notes|procedures|examples|post-mortems
|
|
1070
|
+
--title "..." [--body "..."] [--body-file <file>]
|
|
1071
|
+
[--tags a,b,c]
|
|
1072
|
+
chive knowledge note list --mission <missionId> [--topic ...]
|
|
1073
|
+
|
|
1074
|
+
chive version | help
|
|
1075
|
+
|
|
1076
|
+
Offline JSON shapes follow specs/schemas/hive.codeGraph.v1, hive.codeContextPacket.v1,
|
|
1077
|
+
and hive.codeGraphDelta.v1. Online commands write JSON to stdout (or --out).
|
|
1078
|
+
|
|
1079
|
+
Examples:
|
|
1080
|
+
chive graph build --repo . --rev "$(git rev-parse HEAD)" --out graph.json
|
|
1081
|
+
chive context build --graph graph.json --task "Fix auth bug" --symbols login --out packet.json
|
|
1082
|
+
chive memory remember --task "Fix auth race" --kind bugfix --packet packet.json --outcome success
|
|
1083
|
+
chive arch decide --mission m-1 --title "Redis sessions" --because "1h TTL fits..."
|
|
1084
|
+
chive todo add "Validate JWT exp claim" --mission m-1 --file src/auth.ts:42 --priority high
|
|
1085
|
+
chive knowledge mission create --intent "Security knowledge base" --title "Security"
|
|
1086
|
+
chive knowledge note add --mission m-2 --topic procedures --title "Rotate keys" --body "..."
|
|
1087
|
+
`);
|
|
1088
|
+
}
|
|
1089
|
+
if (hasFlag("version") || pos[0] === "version") {
|
|
1090
|
+
console.log(`chive v${VERSION}`);
|
|
1091
|
+
process.exit(0);
|
|
1092
|
+
}
|
|
1093
|
+
if (hasFlag("help") || hasFlag("h") || !pos[0] || pos[0] === "help") {
|
|
1094
|
+
printHelp();
|
|
1095
|
+
process.exit(0);
|
|
1096
|
+
}
|
|
1097
|
+
function dieUsage(msg) {
|
|
1098
|
+
console.error(`chive: ${msg}
|
|
1099
|
+
Run \`chive help\` for usage.`);
|
|
1100
|
+
process.exit(2);
|
|
1101
|
+
}
|
|
1102
|
+
function errorMessage2(error) {
|
|
1103
|
+
return error instanceof Error ? error.message : String(error);
|
|
1104
|
+
}
|
|
1105
|
+
function dieRuntime(error) {
|
|
1106
|
+
console.error(`chive: ${errorMessage2(error)}`);
|
|
1107
|
+
if (hasFlag("verbose") && error instanceof Error && error.stack) console.error(error.stack);
|
|
1108
|
+
process.exit(3);
|
|
1109
|
+
}
|
|
1110
|
+
function hasFlag(name) {
|
|
1111
|
+
return flags[name] !== void 0 && flags[name] !== false;
|
|
1112
|
+
}
|
|
1113
|
+
function stringFlag(name) {
|
|
1114
|
+
const value = flags[name];
|
|
1115
|
+
if (value === void 0 || value === false || value === "") return void 0;
|
|
1116
|
+
if (typeof value !== "string") dieUsage(`--${name} requires a value`);
|
|
1117
|
+
return value;
|
|
1118
|
+
}
|
|
1119
|
+
function requiredStringFlag(name, command) {
|
|
1120
|
+
const value = stringFlag(name);
|
|
1121
|
+
if (!value) dieUsage(`--${name} is required for \`${command}\``);
|
|
1122
|
+
return value;
|
|
1123
|
+
}
|
|
1124
|
+
function splitList(value) {
|
|
1125
|
+
if (!value) return [];
|
|
1126
|
+
return value.split(",").map((x) => x.trim()).filter(Boolean);
|
|
1127
|
+
}
|
|
1128
|
+
function stringListFlag(name) {
|
|
1129
|
+
return splitList(stringFlag(name));
|
|
1130
|
+
}
|
|
1131
|
+
function readJsonFile(p, label) {
|
|
1132
|
+
if (!import_node_fs.default.existsSync(p)) dieUsage(`${label} not found at ${p}`);
|
|
1133
|
+
try {
|
|
1134
|
+
return JSON.parse(import_node_fs.default.readFileSync(p, "utf8"));
|
|
1135
|
+
} catch (error) {
|
|
1136
|
+
dieRuntime(new Error(`${label} is not valid JSON: ${errorMessage2(error)}`));
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
function writeResult(obj) {
|
|
1140
|
+
const json = JSON.stringify(obj, null, 2);
|
|
1141
|
+
const out = stringFlag("out");
|
|
1142
|
+
if (out) {
|
|
1143
|
+
import_node_fs.default.writeFileSync(out, json + "\n");
|
|
1144
|
+
console.error(`chive: wrote ${import_node_path.default.resolve(out)}`);
|
|
1145
|
+
} else {
|
|
1146
|
+
process.stdout.write(json + "\n");
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
function parseIntFlag(name, value, { min = 1 } = {}) {
|
|
1150
|
+
if (value === void 0 || value === false || value === "") return void 0;
|
|
1151
|
+
if (typeof value !== "string") dieUsage(`--${name} requires a value`);
|
|
1152
|
+
const n = Number.parseInt(value, 10);
|
|
1153
|
+
if (!Number.isFinite(n)) dieUsage(`--${name} must be an integer`);
|
|
1154
|
+
if (n < min) dieUsage(`--${name} must be at least ${min}`);
|
|
1155
|
+
return n;
|
|
1156
|
+
}
|
|
1157
|
+
function isKnowledgeTopic(value) {
|
|
1158
|
+
return KNOWLEDGE_TOPICS.includes(value);
|
|
1159
|
+
}
|
|
1160
|
+
function includesString(value, needle) {
|
|
1161
|
+
return Array.isArray(value) && value.some((item) => item === needle);
|
|
1162
|
+
}
|
|
1163
|
+
async function apiCall(method, urlPath, body) {
|
|
1164
|
+
const base = resolveApiBase(flags);
|
|
1165
|
+
const token = resolveToken(flags);
|
|
1166
|
+
return await httpJson({ method, url: `${base}${urlPath}`, body, token });
|
|
1167
|
+
}
|
|
1168
|
+
async function createRecord({ recordType, missionId, cellId, data }) {
|
|
1169
|
+
const recordId = mkRecordId(recordType.toLowerCase().replace(/[^a-z0-9]/g, "-"));
|
|
1170
|
+
return await apiCall("POST", "/api/records", {
|
|
1171
|
+
recordId,
|
|
1172
|
+
recordType,
|
|
1173
|
+
missionId,
|
|
1174
|
+
cellId: cellId || null,
|
|
1175
|
+
data
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
async function listRecords({ recordType, missionId, extra = {} }) {
|
|
1179
|
+
const qs = new URLSearchParams({ recordType, ...missionId ? { missionId } : {}, ...extra });
|
|
1180
|
+
return await apiCall("GET", `/api/records?${qs.toString()}`, void 0);
|
|
1181
|
+
}
|
|
1182
|
+
async function patchRecord(recordId, patch) {
|
|
1183
|
+
return await apiCall("PATCH", `/api/records/${encodeURIComponent(recordId)}`, patch);
|
|
1184
|
+
}
|
|
1185
|
+
function readPacketIfSet() {
|
|
1186
|
+
const packetPath = stringFlag("packet");
|
|
1187
|
+
if (!packetPath) return null;
|
|
1188
|
+
if (!import_node_fs.default.existsSync(packetPath)) dieUsage(`packet file not found at ${packetPath}`);
|
|
1189
|
+
try {
|
|
1190
|
+
return JSON.parse(import_node_fs.default.readFileSync(packetPath, "utf8"));
|
|
1191
|
+
} catch (error) {
|
|
1192
|
+
dieRuntime(new Error(`packet is not valid JSON: ${errorMessage2(error)}`));
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
function readBodyIfSet() {
|
|
1196
|
+
const body = stringFlag("body");
|
|
1197
|
+
if (body) return body;
|
|
1198
|
+
const bodyFile = stringFlag("body-file");
|
|
1199
|
+
if (bodyFile) {
|
|
1200
|
+
if (!import_node_fs.default.existsSync(bodyFile)) dieUsage(`body-file not found at ${bodyFile}`);
|
|
1201
|
+
return import_node_fs.default.readFileSync(bodyFile, "utf8");
|
|
1202
|
+
}
|
|
1203
|
+
return null;
|
|
1204
|
+
}
|
|
1205
|
+
var group = pos[0];
|
|
1206
|
+
var sub = pos[1];
|
|
1207
|
+
(function dispatch() {
|
|
1208
|
+
try {
|
|
1209
|
+
if (group === "graph" && sub === "build") {
|
|
1210
|
+
const repo = requiredStringFlag("repo", "graph build");
|
|
1211
|
+
const graph = codeContextKernel.buildGraph({
|
|
1212
|
+
repositoryRoot: repo,
|
|
1213
|
+
repositoryRev: stringFlag("rev") || null,
|
|
1214
|
+
graphId: stringFlag("graph-id") || null,
|
|
1215
|
+
maxFiles: parseIntFlag("max-files", flags["max-files"])
|
|
1216
|
+
});
|
|
1217
|
+
writeResult(graph);
|
|
1218
|
+
process.exit(0);
|
|
1219
|
+
}
|
|
1220
|
+
if (group === "graph" && sub === "update") {
|
|
1221
|
+
const repo = requiredStringFlag("repo", "graph update");
|
|
1222
|
+
const basePath = requiredStringFlag("base", "graph update");
|
|
1223
|
+
const base = readJsonFile(basePath, "base graph");
|
|
1224
|
+
const head = codeContextKernel.buildGraph({
|
|
1225
|
+
repositoryRoot: repo,
|
|
1226
|
+
repositoryRev: stringFlag("rev") || null,
|
|
1227
|
+
graphId: stringFlag("graph-id") || base.graphId || null
|
|
1228
|
+
});
|
|
1229
|
+
const delta = codeContextKernel.buildDelta({ baseGraph: base, headGraph: head });
|
|
1230
|
+
writeResult(delta);
|
|
1231
|
+
process.exit(0);
|
|
1232
|
+
}
|
|
1233
|
+
if (group === "context" && sub === "build") {
|
|
1234
|
+
const graphPath = requiredStringFlag("graph", "context build");
|
|
1235
|
+
const taskObjective = requiredStringFlag("task", "context build");
|
|
1236
|
+
const graph = readJsonFile(graphPath, "graph");
|
|
1237
|
+
const packet = codeContextKernel.buildContextPacket({
|
|
1238
|
+
graph,
|
|
1239
|
+
task: {
|
|
1240
|
+
objective: taskObjective,
|
|
1241
|
+
kind: stringFlag("kind") || "other",
|
|
1242
|
+
scope: {
|
|
1243
|
+
paths: stringListFlag("paths"),
|
|
1244
|
+
symbols: stringListFlag("symbols")
|
|
1245
|
+
}
|
|
1246
|
+
},
|
|
1247
|
+
tokenBudgetHint: parseIntFlag("budget", flags.budget, { min: 0 }) ?? 4e3,
|
|
1248
|
+
repositoryRoot: stringFlag("repo")
|
|
1249
|
+
});
|
|
1250
|
+
writeResult(packet);
|
|
1251
|
+
process.exit(0);
|
|
1252
|
+
}
|
|
1253
|
+
if (group === "memory") {
|
|
1254
|
+
handleMemory().catch(dieRuntime);
|
|
1255
|
+
return;
|
|
1256
|
+
}
|
|
1257
|
+
if (group === "arch") {
|
|
1258
|
+
handleArch().catch(dieRuntime);
|
|
1259
|
+
return;
|
|
1260
|
+
}
|
|
1261
|
+
if (group === "todo") {
|
|
1262
|
+
handleTodo().catch(dieRuntime);
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1265
|
+
if (group === "knowledge") {
|
|
1266
|
+
handleKnowledge().catch(dieRuntime);
|
|
1267
|
+
return;
|
|
1268
|
+
}
|
|
1269
|
+
dieUsage(`unknown command: ${group}${sub ? " " + sub : ""}`);
|
|
1270
|
+
} catch (e) {
|
|
1271
|
+
dieRuntime(e);
|
|
1272
|
+
}
|
|
1273
|
+
})();
|
|
1274
|
+
async function handleMemory() {
|
|
1275
|
+
if (sub === "remember") {
|
|
1276
|
+
const task = requiredStringFlag("task", "memory remember");
|
|
1277
|
+
const kind = requiredStringFlag("kind", "memory remember");
|
|
1278
|
+
const outcome = stringFlag("outcome");
|
|
1279
|
+
const summary = stringFlag("summary");
|
|
1280
|
+
const packet = readPacketIfSet();
|
|
1281
|
+
const content = summary ? summary : `task: ${task}${outcome ? ` \u2014 outcome: ${outcome}` : ""}`;
|
|
1282
|
+
const meta = {
|
|
1283
|
+
taskKind: kind,
|
|
1284
|
+
outcome: outcome || null,
|
|
1285
|
+
packetId: packet ? packet.packetId : null,
|
|
1286
|
+
graphRefs: packet ? packet.graphRefs || [] : [],
|
|
1287
|
+
taskObjective: task
|
|
1288
|
+
};
|
|
1289
|
+
const tags = ["code", kind];
|
|
1290
|
+
if (packet && Array.isArray(packet.graphRefs)) {
|
|
1291
|
+
for (const ref of packet.graphRefs) if (ref.graphId) tags.push(`graph:${ref.graphId}`);
|
|
1292
|
+
}
|
|
1293
|
+
const r = await apiCall("POST", "/api/cortex/promote", {
|
|
1294
|
+
domain: stringFlag("domain") || "code",
|
|
1295
|
+
entries: [{ entryType: "outcome", content, tags, meta, confidence: 0.7 }],
|
|
1296
|
+
source: "chive"
|
|
1297
|
+
});
|
|
1298
|
+
writeResult(r);
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
if (sub === "recall") {
|
|
1302
|
+
const limit = parseIntFlag("limit", flags.limit) ?? 20;
|
|
1303
|
+
const kind = stringFlag("kind");
|
|
1304
|
+
const fetchLimit = kind ? Math.max(limit * 5, 100) : limit;
|
|
1305
|
+
const body = {
|
|
1306
|
+
domain: stringFlag("domain") || "code",
|
|
1307
|
+
query: stringFlag("task") || null,
|
|
1308
|
+
entryType: stringFlag("entryType") || "outcome",
|
|
1309
|
+
limit: fetchLimit
|
|
1310
|
+
};
|
|
1311
|
+
const r = await apiCall("POST", "/api/cortex/query", body);
|
|
1312
|
+
if (kind && r && Array.isArray(r.entries)) {
|
|
1313
|
+
r.entries = r.entries.filter((e) => e.meta?.taskKind === kind);
|
|
1314
|
+
r.entries = r.entries.slice(0, limit);
|
|
1315
|
+
r.count = r.entries.length;
|
|
1316
|
+
}
|
|
1317
|
+
writeResult(r);
|
|
1318
|
+
return;
|
|
1319
|
+
}
|
|
1320
|
+
dieUsage(`unknown memory subcommand: ${sub || ""}`);
|
|
1321
|
+
}
|
|
1322
|
+
async function handleArch() {
|
|
1323
|
+
if (sub === "decide") {
|
|
1324
|
+
const mission = requiredStringFlag("mission", "arch decide");
|
|
1325
|
+
const title = requiredStringFlag("title", "arch decide");
|
|
1326
|
+
const because = requiredStringFlag("because", "arch decide");
|
|
1327
|
+
const packet = readPacketIfSet();
|
|
1328
|
+
const data = {
|
|
1329
|
+
kind: "adr",
|
|
1330
|
+
title,
|
|
1331
|
+
because,
|
|
1332
|
+
files: stringListFlag("files"),
|
|
1333
|
+
packetId: packet ? packet.packetId : null,
|
|
1334
|
+
graphRefs: packet ? packet.graphRefs || [] : [],
|
|
1335
|
+
decidedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1336
|
+
status: "accepted"
|
|
1337
|
+
};
|
|
1338
|
+
const r = await createRecord({
|
|
1339
|
+
recordType: "CodeArchitectureDecision",
|
|
1340
|
+
missionId: mission,
|
|
1341
|
+
data
|
|
1342
|
+
});
|
|
1343
|
+
writeResult(r);
|
|
1344
|
+
return;
|
|
1345
|
+
}
|
|
1346
|
+
if (sub === "list") {
|
|
1347
|
+
const mission = requiredStringFlag("mission", "arch list");
|
|
1348
|
+
const r = await listRecords({
|
|
1349
|
+
recordType: "CodeArchitectureDecision",
|
|
1350
|
+
missionId: mission
|
|
1351
|
+
});
|
|
1352
|
+
writeResult(r);
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
dieUsage(`unknown arch subcommand: ${sub || ""}`);
|
|
1356
|
+
}
|
|
1357
|
+
async function handleTodo() {
|
|
1358
|
+
if (sub === "add") {
|
|
1359
|
+
const title = pos[2];
|
|
1360
|
+
if (!title) dieUsage('title is required: `chive todo add "<title>"`');
|
|
1361
|
+
const mission = requiredStringFlag("mission", "todo add");
|
|
1362
|
+
const data = {
|
|
1363
|
+
kind: "todo",
|
|
1364
|
+
title,
|
|
1365
|
+
file: stringFlag("file") || null,
|
|
1366
|
+
priority: stringFlag("priority") || "med",
|
|
1367
|
+
status: "open",
|
|
1368
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1369
|
+
};
|
|
1370
|
+
const r = await createRecord({
|
|
1371
|
+
recordType: "CodeTodo",
|
|
1372
|
+
missionId: mission,
|
|
1373
|
+
data
|
|
1374
|
+
});
|
|
1375
|
+
writeResult(r);
|
|
1376
|
+
return;
|
|
1377
|
+
}
|
|
1378
|
+
if (sub === "list") {
|
|
1379
|
+
const mission = requiredStringFlag("mission", "todo list");
|
|
1380
|
+
const r = await listRecords({
|
|
1381
|
+
recordType: "CodeTodo",
|
|
1382
|
+
missionId: mission
|
|
1383
|
+
});
|
|
1384
|
+
const status = stringFlag("status");
|
|
1385
|
+
if (status && r && Array.isArray(r.records)) {
|
|
1386
|
+
r.records = r.records.filter((rec) => rec.data?.status === status);
|
|
1387
|
+
}
|
|
1388
|
+
writeResult(r);
|
|
1389
|
+
return;
|
|
1390
|
+
}
|
|
1391
|
+
if (sub === "done") {
|
|
1392
|
+
const todoId = pos[2];
|
|
1393
|
+
if (!todoId) dieUsage("todoId is required: `chive todo done <todoId>`");
|
|
1394
|
+
const mission = requiredStringFlag("mission", "todo done");
|
|
1395
|
+
const r = await patchRecord(todoId, {
|
|
1396
|
+
missionId: mission,
|
|
1397
|
+
data: { status: "done", closedAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
1398
|
+
});
|
|
1399
|
+
writeResult(r);
|
|
1400
|
+
return;
|
|
1401
|
+
}
|
|
1402
|
+
dieUsage(`unknown todo subcommand: ${sub || ""}`);
|
|
1403
|
+
}
|
|
1404
|
+
async function handleKnowledge() {
|
|
1405
|
+
if (sub === "mission" && pos[2] === "create") {
|
|
1406
|
+
const intent = stringFlag("intent") || stringFlag("title");
|
|
1407
|
+
if (!intent) dieUsage("--intent (or --title) is required for `knowledge mission create`");
|
|
1408
|
+
const r = await apiCall("POST", `/api/mission-templates/${encodeURIComponent(KNOWLEDGE_TEMPLATE_ID)}/instantiate`, {
|
|
1409
|
+
userIntent: intent,
|
|
1410
|
+
instantiationConfig: {
|
|
1411
|
+
title: stringFlag("title") || intent
|
|
1412
|
+
}
|
|
1413
|
+
});
|
|
1414
|
+
writeResult(r);
|
|
1415
|
+
return;
|
|
1416
|
+
}
|
|
1417
|
+
if (sub === "mission" && pos[2] === "list") {
|
|
1418
|
+
const r = await apiCall("GET", "/api/missions", void 0);
|
|
1419
|
+
if (r && Array.isArray(r.missions)) {
|
|
1420
|
+
r.missions = r.missions.filter(
|
|
1421
|
+
(m) => (m.templateId || m.template_id) === KNOWLEDGE_TEMPLATE_ID || includesString(m.tags, "knowledge-base")
|
|
1422
|
+
);
|
|
1423
|
+
}
|
|
1424
|
+
writeResult(r);
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1427
|
+
if (sub === "note" && pos[2] === "add") {
|
|
1428
|
+
const mission = requiredStringFlag("mission", "knowledge note add");
|
|
1429
|
+
const topic = requiredStringFlag("topic", "knowledge note add");
|
|
1430
|
+
if (!isKnowledgeTopic(topic)) {
|
|
1431
|
+
dieUsage(`unknown topic "${topic}". Must be one of: ${KNOWLEDGE_TOPICS.join(", ")}`);
|
|
1432
|
+
}
|
|
1433
|
+
const title = requiredStringFlag("title", "knowledge note add");
|
|
1434
|
+
const recordType = KNOWLEDGE_RECORD_TYPES[topic];
|
|
1435
|
+
const body = readBodyIfSet();
|
|
1436
|
+
const data = {
|
|
1437
|
+
topic,
|
|
1438
|
+
title,
|
|
1439
|
+
body: body || "",
|
|
1440
|
+
tags: stringListFlag("tags"),
|
|
1441
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1442
|
+
};
|
|
1443
|
+
const r = await createRecord({
|
|
1444
|
+
recordType,
|
|
1445
|
+
missionId: mission,
|
|
1446
|
+
data
|
|
1447
|
+
});
|
|
1448
|
+
writeResult(r);
|
|
1449
|
+
return;
|
|
1450
|
+
}
|
|
1451
|
+
if (sub === "note" && pos[2] === "list") {
|
|
1452
|
+
const mission = requiredStringFlag("mission", "knowledge note list");
|
|
1453
|
+
const topic = stringFlag("topic");
|
|
1454
|
+
let topics = KNOWLEDGE_TOPICS;
|
|
1455
|
+
if (topic) {
|
|
1456
|
+
if (!isKnowledgeTopic(topic)) {
|
|
1457
|
+
dieUsage(`unknown topic "${topic}". Must be one of: ${KNOWLEDGE_TOPICS.join(", ")}`);
|
|
1458
|
+
}
|
|
1459
|
+
topics = [topic];
|
|
1460
|
+
}
|
|
1461
|
+
const combined = { ok: true, records: [] };
|
|
1462
|
+
for (const t of topics) {
|
|
1463
|
+
const recordType = KNOWLEDGE_RECORD_TYPES[t];
|
|
1464
|
+
const r = await listRecords({ recordType, missionId: mission });
|
|
1465
|
+
if (r && Array.isArray(r.records)) combined.records?.push(...r.records);
|
|
1466
|
+
}
|
|
1467
|
+
combined.count = combined.records?.length ?? 0;
|
|
1468
|
+
writeResult(combined);
|
|
1469
|
+
return;
|
|
1470
|
+
}
|
|
1471
|
+
dieUsage(`unknown knowledge subcommand: ${sub || ""}${pos[2] ? " " + pos[2] : ""}`);
|
|
1472
|
+
}
|