@evoclock/pi-agentic-driver 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +736 -0
- package/PROVENANCE.md +69 -0
- package/README.md +325 -0
- package/config/herdr-worker-repositories.v1.json +9 -0
- package/extensions/aidr.ts +5 -0
- package/extensions/code-phage.js +144 -0
- package/extensions/herdr-communication.ts +7 -0
- package/extensions/herdr-lifecycle.ts +7 -0
- package/extensions/linux-microvm.ts +10 -0
- package/lib/adapters/diff-scope.mjs +148 -0
- package/lib/adapters/evidence.mjs +151 -0
- package/lib/adapters/narrative.mjs +171 -0
- package/lib/adapters/review-feedback.mjs +77 -0
- package/lib/adapters/visualization.mjs +176 -0
- package/lib/code-phage-core.mjs +882 -0
- package/lib/python_ast_metrics.py +378 -0
- package/lib/typescript_ast_metrics.mjs +441 -0
- package/package.json +50 -0
- package/scripts/aidr_writing_review.js +468 -0
- package/scripts/enforcement/herdr_communication_pi.js +1198 -0
- package/scripts/enforcement/herdr_lifecycle_pi.js +902 -0
- package/scripts/enforcement/linux_microvm_cutover_pi.js +328 -0
- package/scripts/enforcement/linux_microvm_remote_fixture.sh +366 -0
- package/scripts/enforcement/native_tui_context.js +11 -0
- package/templates/AGENTS.md +72 -0
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 Julen Gamboa <j.a.r.gamboa@gmail.com>
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
|
|
4
|
+
import ts from "typescript";
|
|
5
|
+
|
|
6
|
+
const LOGICAL_KINDS = new Set([
|
|
7
|
+
ts.SyntaxKind.AmpersandAmpersandToken,
|
|
8
|
+
ts.SyntaxKind.BarBarToken,
|
|
9
|
+
ts.SyntaxKind.QuestionQuestionToken,
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
function isFunctionLike(node) {
|
|
13
|
+
return ts.isFunctionDeclaration(node)
|
|
14
|
+
|| ts.isMethodDeclaration(node)
|
|
15
|
+
|| ts.isConstructorDeclaration(node)
|
|
16
|
+
|| ts.isGetAccessorDeclaration(node)
|
|
17
|
+
|| ts.isSetAccessorDeclaration(node)
|
|
18
|
+
|| ts.isFunctionExpression(node)
|
|
19
|
+
|| ts.isArrowFunction(node);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function hasBody(node) {
|
|
23
|
+
return Boolean(node.body);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function lineOf(sourceFile, node) {
|
|
27
|
+
return sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function endLineOf(sourceFile, node) {
|
|
31
|
+
return sourceFile.getLineAndCharacterOfPosition(node.getEnd()).line + 1;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function callableName(node, parent, sourceFile) {
|
|
35
|
+
if (node.name) return node.name.getText(sourceFile);
|
|
36
|
+
if (parent && ts.isVariableDeclaration(parent) && parent.initializer === node) return parent.name.getText(sourceFile);
|
|
37
|
+
if (parent && ts.isPropertyAssignment(parent) && parent.initializer === node) return parent.name.getText(sourceFile);
|
|
38
|
+
if (parent && ts.isPropertyDeclaration(parent) && parent.initializer === node) return parent.name.getText(sourceFile);
|
|
39
|
+
return "<anonymous>";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function syntaxKindName(node) {
|
|
43
|
+
return ts.SyntaxKind[node.kind] || "unknown";
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function logicalOperator(node) {
|
|
47
|
+
return ts.tokenToString(node.operatorToken.kind) || syntaxKindName(node.operatorToken);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function isLogicalExpression(node) {
|
|
51
|
+
return Boolean(node) && ts.isBinaryExpression(node) && LOGICAL_KINDS.has(node.operatorToken.kind);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function logicalChain(node) {
|
|
55
|
+
const operators = [];
|
|
56
|
+
const collect = (current) => {
|
|
57
|
+
if (isLogicalExpression(current)) {
|
|
58
|
+
collect(current.left);
|
|
59
|
+
operators.push(logicalOperator(current));
|
|
60
|
+
collect(current.right);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
collect(node);
|
|
64
|
+
return operators;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function callableRecords(sourceFile) {
|
|
68
|
+
const records = [];
|
|
69
|
+
const collect = (node, parent) => {
|
|
70
|
+
if (isFunctionLike(node) && hasBody(node)) {
|
|
71
|
+
records.push({
|
|
72
|
+
node,
|
|
73
|
+
name: callableName(node, parent, sourceFile),
|
|
74
|
+
kind: syntaxKindName(node),
|
|
75
|
+
line: lineOf(sourceFile, node),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
ts.forEachChild(node, (child) => collect(child, node));
|
|
79
|
+
};
|
|
80
|
+
collect(sourceFile, undefined);
|
|
81
|
+
return records;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function newMetric(name, kind, line) {
|
|
85
|
+
return {
|
|
86
|
+
name,
|
|
87
|
+
kind,
|
|
88
|
+
line,
|
|
89
|
+
cyclomaticComplexity: 1,
|
|
90
|
+
cognitiveComplexity: 0,
|
|
91
|
+
decisionPoints: [],
|
|
92
|
+
logicalSequences: [],
|
|
93
|
+
recursiveCalls: 0,
|
|
94
|
+
maxNesting: 0,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function analyzeRegion(root, sourceFile, name, kind, callableRoot = false) {
|
|
99
|
+
const metric = newMetric(name, kind, lineOf(sourceFile, root));
|
|
100
|
+
const scoreDecision = (node, nesting, decisionKind, cognitiveNesting = nesting) => {
|
|
101
|
+
metric.cyclomaticComplexity += 1;
|
|
102
|
+
metric.cognitiveComplexity += 1 + cognitiveNesting;
|
|
103
|
+
metric.maxNesting = Math.max(metric.maxNesting, nesting);
|
|
104
|
+
metric.decisionPoints.push({ kind: decisionKind, line: lineOf(sourceFile, node), nesting });
|
|
105
|
+
};
|
|
106
|
+
const scoreIf = (node, nesting, chained = false) => {
|
|
107
|
+
scoreDecision(node, nesting, chained ? "else-if" : "if", chained ? 0 : nesting);
|
|
108
|
+
visit(node.expression, nesting, node);
|
|
109
|
+
visit(node.thenStatement, nesting + 1, node);
|
|
110
|
+
if (!node.elseStatement) return;
|
|
111
|
+
if (ts.isIfStatement(node.elseStatement)) {
|
|
112
|
+
scoreIf(node.elseStatement, nesting, true);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
metric.cognitiveComplexity += 1;
|
|
116
|
+
metric.decisionPoints.push({ kind: "else", line: lineOf(sourceFile, node.elseStatement), nesting });
|
|
117
|
+
visit(node.elseStatement, nesting + 1, node);
|
|
118
|
+
};
|
|
119
|
+
const visit = (node, nesting, parent) => {
|
|
120
|
+
if (!node) return;
|
|
121
|
+
if (node !== root && isFunctionLike(node)) return;
|
|
122
|
+
metric.maxNesting = Math.max(metric.maxNesting, nesting);
|
|
123
|
+
if (ts.isIfStatement(node)) {
|
|
124
|
+
scoreIf(node, nesting);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (ts.isForStatement(node) || ts.isForInStatement(node) || ts.isForOfStatement(node)) {
|
|
128
|
+
scoreDecision(node, nesting, syntaxKindName(node));
|
|
129
|
+
if (ts.isForStatement(node)) {
|
|
130
|
+
visit(node.initializer, nesting, node);
|
|
131
|
+
visit(node.condition, nesting, node);
|
|
132
|
+
visit(node.incrementor, nesting, node);
|
|
133
|
+
} else {
|
|
134
|
+
visit(node.initializer, nesting, node);
|
|
135
|
+
visit(node.expression, nesting, node);
|
|
136
|
+
}
|
|
137
|
+
visit(node.statement, nesting + 1, node);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (ts.isWhileStatement(node) || ts.isDoStatement(node)) {
|
|
141
|
+
scoreDecision(node, nesting, syntaxKindName(node));
|
|
142
|
+
visit(node.expression, nesting, node);
|
|
143
|
+
visit(node.statement, nesting + 1, node);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (ts.isSwitchStatement(node)) {
|
|
147
|
+
metric.cognitiveComplexity += 1 + nesting;
|
|
148
|
+
metric.maxNesting = Math.max(metric.maxNesting, nesting);
|
|
149
|
+
metric.decisionPoints.push({ kind: "switch", line: lineOf(sourceFile, node), nesting });
|
|
150
|
+
visit(node.expression, nesting, node);
|
|
151
|
+
for (const clause of node.caseBlock.clauses) {
|
|
152
|
+
if (ts.isCaseClause(clause)) {
|
|
153
|
+
metric.cyclomaticComplexity += 1;
|
|
154
|
+
metric.decisionPoints.push({ kind: "case", line: lineOf(sourceFile, clause), nesting: nesting + 1 });
|
|
155
|
+
visit(clause.expression, nesting + 1, clause);
|
|
156
|
+
}
|
|
157
|
+
for (const statement of clause.statements) visit(statement, nesting + 1, clause);
|
|
158
|
+
}
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (ts.isConditionalExpression(node)) {
|
|
162
|
+
scoreDecision(node, nesting, "conditional-expression");
|
|
163
|
+
visit(node.condition, nesting, node);
|
|
164
|
+
visit(node.whenTrue, nesting + 1, node);
|
|
165
|
+
visit(node.whenFalse, nesting + 1, node);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (ts.isCatchClause(node)) {
|
|
169
|
+
scoreDecision(node, nesting, "catch");
|
|
170
|
+
visit(node.variableDeclaration, nesting, node);
|
|
171
|
+
visit(node.block, nesting + 1, node);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (isLogicalExpression(node)) {
|
|
175
|
+
if (!isLogicalExpression(parent)) {
|
|
176
|
+
const operators = logicalChain(node);
|
|
177
|
+
const changes = operators.slice(1).filter((operator, index) => operator !== operators[index]).length;
|
|
178
|
+
metric.cyclomaticComplexity += operators.length;
|
|
179
|
+
metric.cognitiveComplexity += operators.length ? 1 + changes : 0;
|
|
180
|
+
metric.logicalSequences.push({
|
|
181
|
+
line: lineOf(sourceFile, node),
|
|
182
|
+
operators,
|
|
183
|
+
cognitiveIncrement: operators.length ? 1 + changes : 0,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (ts.isCallExpression(node) && name !== "<module>" && node.expression && ts.isIdentifier(node.expression)
|
|
188
|
+
&& node.expression.text === name) {
|
|
189
|
+
metric.cognitiveComplexity += 1;
|
|
190
|
+
metric.recursiveCalls += 1;
|
|
191
|
+
}
|
|
192
|
+
ts.forEachChild(node, (child) => visit(child, nesting, node));
|
|
193
|
+
};
|
|
194
|
+
visit(root, 0, undefined);
|
|
195
|
+
if (!callableRoot) metric.cyclomaticComplexity = Math.max(1, metric.cyclomaticComplexity);
|
|
196
|
+
return metric;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function lineCounts(source) {
|
|
200
|
+
const lines = source.split(/\r?\n/);
|
|
201
|
+
let codeLines = 0;
|
|
202
|
+
let commentLines = 0;
|
|
203
|
+
for (const line of lines) {
|
|
204
|
+
const trimmed = line.trim();
|
|
205
|
+
if (!trimmed) continue;
|
|
206
|
+
if (trimmed.startsWith("//") || trimmed.startsWith("/*") || trimmed.startsWith("*")) commentLines += 1;
|
|
207
|
+
else codeLines += 1;
|
|
208
|
+
}
|
|
209
|
+
return { lines: lines.length, codeLines, commentLines, blankLines: lines.length - codeLines - commentLines };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function parseKind(path) {
|
|
213
|
+
if (path.endsWith(".tsx") || path.endsWith(".jsx")) return ts.ScriptKind.TSX;
|
|
214
|
+
if (path.endsWith(".ts")) return ts.ScriptKind.TS;
|
|
215
|
+
return ts.ScriptKind.JS;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function hasModifier(node, kind) {
|
|
219
|
+
return Boolean(node?.modifiers?.some((modifier) => modifier.kind === kind));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function nodeName(node) {
|
|
223
|
+
return node?.name && ts.isIdentifier(node.name) ? node.name.text : undefined;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function stringLiteralValue(node) {
|
|
227
|
+
return node && (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node))
|
|
228
|
+
? node.text
|
|
229
|
+
: undefined;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function extractTypeScriptCodeFacts(sourceFile) {
|
|
233
|
+
const exportedSymbols = [];
|
|
234
|
+
const exportedFunctions = [];
|
|
235
|
+
const dependencies = new Set();
|
|
236
|
+
const declarations = new Map();
|
|
237
|
+
const functionDeclarations = new Map();
|
|
238
|
+
const functionKeys = new Set();
|
|
239
|
+
const addSymbol = (name) => {
|
|
240
|
+
if (typeof name === "string" && name && !exportedSymbols.includes(name)) exportedSymbols.push(name);
|
|
241
|
+
};
|
|
242
|
+
const addFunction = (name, node) => {
|
|
243
|
+
if (typeof name !== "string" || !name || !Array.isArray(node?.parameters)) return;
|
|
244
|
+
const parameterCount = node.parameters.length;
|
|
245
|
+
const key = `${name}/${parameterCount}`;
|
|
246
|
+
if (functionKeys.has(key)) return;
|
|
247
|
+
functionKeys.add(key);
|
|
248
|
+
exportedFunctions.push({ name, parameterCount });
|
|
249
|
+
};
|
|
250
|
+
const addDependency = (value) => {
|
|
251
|
+
const moduleName = stringLiteralValue(value) ?? (typeof value === "string" ? value : undefined);
|
|
252
|
+
if (moduleName) dependencies.add(moduleName);
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
for (const statement of sourceFile.statements) {
|
|
256
|
+
if (ts.isImportDeclaration(statement)) addDependency(statement.moduleSpecifier);
|
|
257
|
+
if (ts.isExportDeclaration(statement)) addDependency(statement.moduleSpecifier);
|
|
258
|
+
if (ts.isImportEqualsDeclaration(statement)) addDependency(statement.moduleReference);
|
|
259
|
+
|
|
260
|
+
if (ts.isFunctionDeclaration(statement)) {
|
|
261
|
+
const name = nodeName(statement);
|
|
262
|
+
if (name) {
|
|
263
|
+
declarations.set(name, statement);
|
|
264
|
+
functionDeclarations.set(name, statement);
|
|
265
|
+
}
|
|
266
|
+
if (hasModifier(statement, ts.SyntaxKind.ExportKeyword)) {
|
|
267
|
+
const exportedName = hasModifier(statement, ts.SyntaxKind.DefaultKeyword) ? (name || "default") : name;
|
|
268
|
+
addSymbol(exportedName);
|
|
269
|
+
addFunction(exportedName, statement);
|
|
270
|
+
}
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
if (ts.isVariableStatement(statement)) {
|
|
274
|
+
const exported = hasModifier(statement, ts.SyntaxKind.ExportKeyword);
|
|
275
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
276
|
+
const name = ts.isIdentifier(declaration.name) ? declaration.name.text : undefined;
|
|
277
|
+
if (!name) continue;
|
|
278
|
+
declarations.set(name, declaration);
|
|
279
|
+
if (exported) {
|
|
280
|
+
addSymbol(name);
|
|
281
|
+
if (declaration.initializer && isFunctionLike(declaration.initializer)) {
|
|
282
|
+
addFunction(name, declaration.initializer);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
if (ts.isClassDeclaration(statement) || ts.isInterfaceDeclaration(statement)
|
|
289
|
+
|| ts.isTypeAliasDeclaration(statement) || ts.isEnumDeclaration(statement)
|
|
290
|
+
|| ts.isModuleDeclaration(statement)) {
|
|
291
|
+
const name = nodeName(statement);
|
|
292
|
+
if (name) declarations.set(name, statement);
|
|
293
|
+
if (hasModifier(statement, ts.SyntaxKind.ExportKeyword)) {
|
|
294
|
+
addSymbol(hasModifier(statement, ts.SyntaxKind.DefaultKeyword) ? (name || "default") : name);
|
|
295
|
+
}
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
if (ts.isExportAssignment(statement)) {
|
|
299
|
+
if (statement.isExportEquals) {
|
|
300
|
+
if (ts.isIdentifier(statement.expression)) addSymbol(statement.expression.text);
|
|
301
|
+
} else {
|
|
302
|
+
addSymbol("default");
|
|
303
|
+
if (isFunctionLike(statement.expression)) addFunction("default", statement.expression);
|
|
304
|
+
if (ts.isIdentifier(statement.expression)) {
|
|
305
|
+
const declaration = functionDeclarations.get(statement.expression.text);
|
|
306
|
+
if (declaration) addFunction("default", declaration);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
for (const statement of sourceFile.statements) {
|
|
313
|
+
if (!ts.isExportDeclaration(statement) || !statement.exportClause || !ts.isNamedExports(statement.exportClause)) continue;
|
|
314
|
+
for (const element of statement.exportClause.elements) {
|
|
315
|
+
const exportedName = element.name.text;
|
|
316
|
+
const localName = element.propertyName?.text || exportedName;
|
|
317
|
+
addSymbol(exportedName);
|
|
318
|
+
const declaration = functionDeclarations.get(localName);
|
|
319
|
+
if (declaration) addFunction(exportedName, declaration);
|
|
320
|
+
else {
|
|
321
|
+
const variable = declarations.get(localName);
|
|
322
|
+
if (variable?.initializer && isFunctionLike(variable.initializer)) addFunction(exportedName, variable.initializer);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const collectCommonJsExports = (node) => {
|
|
328
|
+
if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "exports") {
|
|
329
|
+
addSymbol(node.name.text);
|
|
330
|
+
}
|
|
331
|
+
if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken
|
|
332
|
+
&& ts.isPropertyAccessExpression(node.left) && ts.isIdentifier(node.left.expression)
|
|
333
|
+
&& node.left.expression.text === "exports") {
|
|
334
|
+
addSymbol(node.left.name.text);
|
|
335
|
+
if (ts.isIdentifier(node.right)) {
|
|
336
|
+
const declaration = functionDeclarations.get(node.right.text);
|
|
337
|
+
if (declaration) addFunction(node.left.name.text, declaration);
|
|
338
|
+
}
|
|
339
|
+
if (isFunctionLike(node.right)) addFunction(node.left.name.text, node.right);
|
|
340
|
+
}
|
|
341
|
+
if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken
|
|
342
|
+
&& ts.isPropertyAccessExpression(node.left) && ts.isIdentifier(node.left.expression)
|
|
343
|
+
&& node.left.expression.text === "module" && node.left.name.text === "exports") {
|
|
344
|
+
if (ts.isIdentifier(node.right)) {
|
|
345
|
+
addSymbol(node.right.text);
|
|
346
|
+
const declaration = functionDeclarations.get(node.right.text);
|
|
347
|
+
if (declaration) addFunction(node.right.text, declaration);
|
|
348
|
+
}
|
|
349
|
+
if (ts.isObjectLiteralExpression(node.right)) {
|
|
350
|
+
for (const property of node.right.properties) {
|
|
351
|
+
if (ts.isPropertyAssignment(property) || ts.isShorthandPropertyAssignment(property)) {
|
|
352
|
+
const exportedName = property.name && ts.isIdentifier(property.name) ? property.name.text : undefined;
|
|
353
|
+
if (!exportedName) continue;
|
|
354
|
+
addSymbol(exportedName);
|
|
355
|
+
const localName = ts.isShorthandPropertyAssignment(property)
|
|
356
|
+
? property.name.text
|
|
357
|
+
: ts.isIdentifier(property.initializer) ? property.initializer.text : undefined;
|
|
358
|
+
const declaration = localName && functionDeclarations.get(localName);
|
|
359
|
+
if (declaration) addFunction(exportedName, declaration);
|
|
360
|
+
else if (ts.isFunctionLike(property.initializer)) addFunction(exportedName, property.initializer);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (ts.isCallExpression(node)) {
|
|
366
|
+
if (ts.isIdentifier(node.expression) && node.expression.text === "require") addDependency(node.arguments[0]);
|
|
367
|
+
if (node.expression.kind === ts.SyntaxKind.ImportKeyword) addDependency(node.arguments[0]);
|
|
368
|
+
}
|
|
369
|
+
ts.forEachChild(node, collectCommonJsExports);
|
|
370
|
+
};
|
|
371
|
+
collectCommonJsExports(sourceFile);
|
|
372
|
+
|
|
373
|
+
return {
|
|
374
|
+
exportedSymbols,
|
|
375
|
+
exportedFunctions,
|
|
376
|
+
dependencies: [...dependencies].sort(),
|
|
377
|
+
purpose: null,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
export function analyzeTypeScriptSource(source, path) {
|
|
382
|
+
const sourceFile = ts.createSourceFile(path, source, ts.ScriptTarget.Latest, true, parseKind(path));
|
|
383
|
+
const parseDiagnostics = sourceFile.parseDiagnostics || [];
|
|
384
|
+
if (parseDiagnostics.length) {
|
|
385
|
+
return {
|
|
386
|
+
status: "parse-error",
|
|
387
|
+
path,
|
|
388
|
+
language: "javascript-typescript",
|
|
389
|
+
method: "ast-v1",
|
|
390
|
+
parser: `typescript-compiler-api@${ts.version}`,
|
|
391
|
+
parseErrors: parseDiagnostics.length,
|
|
392
|
+
error: "Source contains syntax errors; complexity metrics are unavailable.",
|
|
393
|
+
codeFacts: {
|
|
394
|
+
exportedSymbols: [],
|
|
395
|
+
exportedFunctions: [],
|
|
396
|
+
dependencies: [],
|
|
397
|
+
purpose: null,
|
|
398
|
+
},
|
|
399
|
+
...lineCounts(source),
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
const moduleMetric = analyzeRegion(sourceFile, sourceFile, "<module>", "module");
|
|
403
|
+
const functions = callableRecords(sourceFile).map(({ node, name, kind, line }) => ({
|
|
404
|
+
...analyzeRegion(node.body, sourceFile, name, kind, true),
|
|
405
|
+
name,
|
|
406
|
+
kind,
|
|
407
|
+
line,
|
|
408
|
+
endLine: endLineOf(sourceFile, node),
|
|
409
|
+
}));
|
|
410
|
+
const all = [moduleMetric, ...functions];
|
|
411
|
+
const totalCyclomaticComplexity = all.reduce((sum, item) => sum + item.cyclomaticComplexity, 0);
|
|
412
|
+
const totalCognitiveComplexity = all.reduce((sum, item) => sum + item.cognitiveComplexity, 0);
|
|
413
|
+
const counts = lineCounts(source);
|
|
414
|
+
const dependencyCount = (() => {
|
|
415
|
+
let count = 0;
|
|
416
|
+
const visit = (node) => {
|
|
417
|
+
if (ts.isImportDeclaration(node) || ts.isImportEqualsDeclaration(node) || ts.isExportDeclaration(node)) count += 1;
|
|
418
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "require") count += 1;
|
|
419
|
+
ts.forEachChild(node, visit);
|
|
420
|
+
};
|
|
421
|
+
visit(sourceFile);
|
|
422
|
+
return count;
|
|
423
|
+
})();
|
|
424
|
+
return {
|
|
425
|
+
status: "parsed",
|
|
426
|
+
path,
|
|
427
|
+
language: "javascript-typescript",
|
|
428
|
+
method: "ast-v1",
|
|
429
|
+
parser: `typescript-compiler-api@${ts.version}`,
|
|
430
|
+
...counts,
|
|
431
|
+
module: moduleMetric,
|
|
432
|
+
callables: functions,
|
|
433
|
+
codeFacts: extractTypeScriptCodeFacts(sourceFile),
|
|
434
|
+
cyclomaticComplexity: Math.max(...all.map((item) => item.cyclomaticComplexity)),
|
|
435
|
+
cognitiveComplexity: Math.max(...all.map((item) => item.cognitiveComplexity)),
|
|
436
|
+
totalCyclomaticComplexity,
|
|
437
|
+
totalCognitiveComplexity,
|
|
438
|
+
dependencyCount,
|
|
439
|
+
uncertainty: "AST-derived for JavaScript/TypeScript syntax; metric semantics follow the documented code-phage rules and are not a universal quality gate.",
|
|
440
|
+
};
|
|
441
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@evoclock/pi-agentic-driver",
|
|
3
|
+
"version": "0.4.3",
|
|
4
|
+
"description": "Guardrail extensions for Agentic Driver: advisory review, bounded Herdr communication, and guarded worker lifecycle.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "AGPL-3.0-or-later",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"pi-package",
|
|
9
|
+
"pi-extension",
|
|
10
|
+
"agentic-driver"
|
|
11
|
+
],
|
|
12
|
+
"files": [
|
|
13
|
+
"extensions/code-phage.js",
|
|
14
|
+
"extensions/herdr-communication.ts",
|
|
15
|
+
"lib/adapters/diff-scope.mjs",
|
|
16
|
+
"lib/adapters/evidence.mjs",
|
|
17
|
+
"lib/adapters/narrative.mjs",
|
|
18
|
+
"lib/adapters/review-feedback.mjs",
|
|
19
|
+
"lib/adapters/visualization.mjs",
|
|
20
|
+
"lib/code-phage-core.mjs",
|
|
21
|
+
"lib/python_ast_metrics.py",
|
|
22
|
+
"lib/typescript_ast_metrics.mjs",
|
|
23
|
+
"scripts/enforcement/herdr_communication_pi.js",
|
|
24
|
+
"README.md",
|
|
25
|
+
"LICENSE",
|
|
26
|
+
"extensions/herdr-lifecycle.ts",
|
|
27
|
+
"scripts/enforcement/herdr_lifecycle_pi.js",
|
|
28
|
+
"config/herdr-worker-repositories.v1.json",
|
|
29
|
+
"extensions/linux-microvm.ts",
|
|
30
|
+
"scripts/enforcement/linux_microvm_cutover_pi.js",
|
|
31
|
+
"scripts/enforcement/native_tui_context.js",
|
|
32
|
+
"scripts/enforcement/linux_microvm_remote_fixture.sh",
|
|
33
|
+
"PROVENANCE.md",
|
|
34
|
+
"extensions/aidr.ts",
|
|
35
|
+
"scripts/aidr_writing_review.js",
|
|
36
|
+
"templates/AGENTS.md"
|
|
37
|
+
],
|
|
38
|
+
"pi": {
|
|
39
|
+
"extensions": [
|
|
40
|
+
"./extensions"
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"typescript": "5.9.2"
|
|
45
|
+
},
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "git+https://github.com/evoclock/pi-agentic-driver.git"
|
|
49
|
+
}
|
|
50
|
+
}
|