nexarch 0.9.3 → 0.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/init-agent.js +31 -18
- package/dist/commands/init-project.js +44 -8
- package/dist/index.js +1 -0
- package/package.json +1 -1
|
@@ -59,12 +59,12 @@ async function promptForValue(promptText, required = false) {
|
|
|
59
59
|
rl.close();
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
-
async function confirmInstructionWrite() {
|
|
62
|
+
async function confirmInstructionWrite(promptText = "Allow nexarch init-agent to write/update AGENTS.md/CLAUDE.md registration instructions? [y/N]: ") {
|
|
63
63
|
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
64
64
|
return false;
|
|
65
65
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
66
66
|
try {
|
|
67
|
-
const answer = (await rl.question(
|
|
67
|
+
const answer = (await rl.question(promptText)).trim().toLowerCase();
|
|
68
68
|
return answer === "y" || answer === "yes";
|
|
69
69
|
}
|
|
70
70
|
finally {
|
|
@@ -1084,20 +1084,25 @@ export async function initAgent(args) {
|
|
|
1084
1084
|
catch {
|
|
1085
1085
|
// non-fatal
|
|
1086
1086
|
}
|
|
1087
|
+
let existingInstructionTargets = injectAgentConfigs(registry);
|
|
1088
|
+
if (existingInstructionTargets.length === 0) {
|
|
1089
|
+
existingInstructionTargets = injectGenericAgentConfig(registry);
|
|
1090
|
+
}
|
|
1091
|
+
const alreadyConfigured = existingInstructionTargets.length > 0 && existingInstructionTargets.every((r) => r.status === "already_present");
|
|
1087
1092
|
if (denyInstructionWriteFlag) {
|
|
1088
1093
|
instructionsWriteAllowed = false;
|
|
1089
1094
|
}
|
|
1090
1095
|
else if (allowInstructionWriteFlag) {
|
|
1091
1096
|
instructionsWriteAllowed = true;
|
|
1092
1097
|
}
|
|
1098
|
+
else if (alreadyConfigured) {
|
|
1099
|
+
instructionsWriteAllowed = false;
|
|
1100
|
+
}
|
|
1093
1101
|
else if (!asJson) {
|
|
1094
1102
|
instructionsWriteAllowed = await confirmInstructionWrite();
|
|
1095
1103
|
}
|
|
1096
1104
|
if (instructionsWriteAllowed) {
|
|
1097
|
-
agentConfigResults =
|
|
1098
|
-
if (agentConfigResults.length === 0) {
|
|
1099
|
-
agentConfigResults = injectGenericAgentConfig(registry);
|
|
1100
|
-
}
|
|
1105
|
+
agentConfigResults = existingInstructionTargets;
|
|
1101
1106
|
if (agentConfigResults.length > 0) {
|
|
1102
1107
|
trustAttestationAttempted = true;
|
|
1103
1108
|
trustAttestation = await requestTrustAttestation(agentId);
|
|
@@ -1116,6 +1121,9 @@ export async function initAgent(args) {
|
|
|
1116
1121
|
}
|
|
1117
1122
|
}
|
|
1118
1123
|
}
|
|
1124
|
+
else if (alreadyConfigured) {
|
|
1125
|
+
agentConfigResults = existingInstructionTargets;
|
|
1126
|
+
}
|
|
1119
1127
|
}
|
|
1120
1128
|
checks.push({
|
|
1121
1129
|
name: "agent.registration",
|
|
@@ -1132,29 +1140,34 @@ export async function initAgent(args) {
|
|
|
1132
1140
|
? `awaiting identity input (${identityCapture.missingRequired.join(", ")})`
|
|
1133
1141
|
: identityCapture.detail,
|
|
1134
1142
|
});
|
|
1143
|
+
const instructionsAlreadyConfigured = agentConfigResults.length > 0 && agentConfigResults.every((r) => r.status === "already_present");
|
|
1135
1144
|
checks.push({
|
|
1136
1145
|
name: "agent.instructions.injection",
|
|
1137
1146
|
ok: !registration.ok || !instructionsWriteAllowed || agentConfigResults.length > 0,
|
|
1138
1147
|
detail: !registration.ok
|
|
1139
1148
|
? "skipped (registration failed)"
|
|
1140
|
-
:
|
|
1141
|
-
? "
|
|
1142
|
-
:
|
|
1143
|
-
?
|
|
1144
|
-
:
|
|
1149
|
+
: instructionsAlreadyConfigured
|
|
1150
|
+
? "already configured (no write needed)"
|
|
1151
|
+
: !instructionsWriteAllowed
|
|
1152
|
+
? "skipped (consent not granted)"
|
|
1153
|
+
: agentConfigResults.length > 0
|
|
1154
|
+
? `updated ${agentConfigResults.length} instruction target file(s)`
|
|
1155
|
+
: "no runtime instruction target matched this repository (non-fatal; create AGENTS.md/CLAUDE.md or configure a generic target)",
|
|
1145
1156
|
});
|
|
1146
1157
|
checks.push({
|
|
1147
1158
|
name: "agent.trust.attestation",
|
|
1148
1159
|
ok: !registration.ok || !instructionsWriteAllowed || !trustAttestationAttempted || Boolean(trustAttestation?.ok),
|
|
1149
1160
|
detail: !registration.ok
|
|
1150
1161
|
? "skipped (registration failed)"
|
|
1151
|
-
: !instructionsWriteAllowed
|
|
1152
|
-
? "skipped (
|
|
1153
|
-
: !
|
|
1154
|
-
? "skipped (
|
|
1155
|
-
:
|
|
1156
|
-
? "
|
|
1157
|
-
:
|
|
1162
|
+
: instructionsAlreadyConfigured && !instructionsWriteAllowed
|
|
1163
|
+
? "skipped (already configured)"
|
|
1164
|
+
: !instructionsWriteAllowed
|
|
1165
|
+
? "skipped (consent not granted)"
|
|
1166
|
+
: !trustAttestationAttempted
|
|
1167
|
+
? "skipped (no instruction target written)"
|
|
1168
|
+
: trustAttestation?.ok
|
|
1169
|
+
? "minted and injected into instruction file(s)"
|
|
1170
|
+
: `unavailable (${trustAttestation?.reason ?? "unknown"})`,
|
|
1158
1171
|
});
|
|
1159
1172
|
checks.push({
|
|
1160
1173
|
name: "technology.components",
|
|
@@ -28,6 +28,14 @@ function formatMs(ms) {
|
|
|
28
28
|
return `${ms}ms`;
|
|
29
29
|
return `${(ms / 1000).toFixed(2)}s`;
|
|
30
30
|
}
|
|
31
|
+
function chunkArray(items, size) {
|
|
32
|
+
if (size <= 0)
|
|
33
|
+
return [items];
|
|
34
|
+
const chunks = [];
|
|
35
|
+
for (let i = 0; i < items.length; i += size)
|
|
36
|
+
chunks.push(items.slice(i, i + size));
|
|
37
|
+
return chunks;
|
|
38
|
+
}
|
|
31
39
|
function slugify(name) {
|
|
32
40
|
return name.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
33
41
|
}
|
|
@@ -973,6 +981,7 @@ export async function initProject(args) {
|
|
|
973
981
|
const forceCreateApplication = parseFlag(args, "--create-application");
|
|
974
982
|
const autoMapApplication = parseFlag(args, "--auto-map-application");
|
|
975
983
|
const nonInteractive = parseFlag(args, "--non-interactive");
|
|
984
|
+
const upsertBatchSize = Number(parseOptionValue(args, "--batch-size") ?? "10") || 10;
|
|
976
985
|
const creds = requireCredentials();
|
|
977
986
|
const mcpOpts = { companyId: creds.companyId };
|
|
978
987
|
if (!asJson)
|
|
@@ -1312,17 +1321,44 @@ export async function initProject(args) {
|
|
|
1312
1321
|
}
|
|
1313
1322
|
if (!asJson)
|
|
1314
1323
|
console.log(`\nWriting to graph…`);
|
|
1315
|
-
// Upsert entities
|
|
1316
|
-
|
|
1317
|
-
const
|
|
1318
|
-
|
|
1324
|
+
// Upsert entities (chunked for progressive feedback)
|
|
1325
|
+
const entityChunks = chunkArray(entities, Math.max(1, upsertBatchSize));
|
|
1326
|
+
const entitiesResult = {
|
|
1327
|
+
summary: { requested: 0, succeeded: 0, failed: 0 },
|
|
1328
|
+
errors: [],
|
|
1329
|
+
};
|
|
1330
|
+
logProgress("upsert.entities.start", `count=${entities.length}, batches=${entityChunks.length}, batchSize=${Math.max(1, upsertBatchSize)}`);
|
|
1331
|
+
for (let i = 0; i < entityChunks.length; i += 1) {
|
|
1332
|
+
const chunk = entityChunks[i];
|
|
1333
|
+
logProgress("upsert.entities.batch.start", `${i + 1}/${entityChunks.length} size=${chunk.length}`);
|
|
1334
|
+
const entitiesRaw = await callMcpTool("nexarch_upsert_entities", { entities: chunk, agentContext, policyContext }, mcpOpts);
|
|
1335
|
+
const chunkResult = parseToolText(entitiesRaw);
|
|
1336
|
+
entitiesResult.summary.requested = Number(entitiesResult.summary.requested ?? 0) + Number(chunkResult.summary?.requested ?? chunk.length);
|
|
1337
|
+
entitiesResult.summary.succeeded = Number(entitiesResult.summary.succeeded ?? 0) + Number(chunkResult.summary?.succeeded ?? 0);
|
|
1338
|
+
entitiesResult.summary.failed = Number(entitiesResult.summary.failed ?? 0) + Number(chunkResult.summary?.failed ?? 0);
|
|
1339
|
+
if (chunkResult.errors?.length)
|
|
1340
|
+
entitiesResult.errors.push(...chunkResult.errors);
|
|
1341
|
+
logProgress("upsert.entities.batch.done", `${i + 1}/${entityChunks.length} succeeded=${chunkResult.summary?.succeeded ?? 0}, failed=${chunkResult.summary?.failed ?? 0}`);
|
|
1342
|
+
}
|
|
1319
1343
|
logProgress("upsert.entities.done", `succeeded=${entitiesResult.summary?.succeeded ?? 0}, failed=${entitiesResult.summary?.failed ?? 0}`);
|
|
1320
|
-
// Upsert relationships
|
|
1344
|
+
// Upsert relationships (chunked)
|
|
1321
1345
|
let relsResult = null;
|
|
1322
1346
|
if (relationships.length > 0) {
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1347
|
+
const relationshipChunks = chunkArray(relationships, Math.max(1, upsertBatchSize));
|
|
1348
|
+
relsResult = { summary: { requested: 0, succeeded: 0, failed: 0 }, errors: [] };
|
|
1349
|
+
logProgress("upsert.relationships.start", `count=${relationships.length}, batches=${relationshipChunks.length}, batchSize=${Math.max(1, upsertBatchSize)}`);
|
|
1350
|
+
for (let i = 0; i < relationshipChunks.length; i += 1) {
|
|
1351
|
+
const chunk = relationshipChunks[i];
|
|
1352
|
+
logProgress("upsert.relationships.batch.start", `${i + 1}/${relationshipChunks.length} size=${chunk.length}`);
|
|
1353
|
+
const relsRaw = await callMcpTool("nexarch_upsert_relationships", { relationships: chunk, agentContext, policyContext }, mcpOpts);
|
|
1354
|
+
const chunkResult = parseToolText(relsRaw);
|
|
1355
|
+
relsResult.summary.requested = Number(relsResult.summary.requested ?? 0) + Number(chunkResult.summary?.requested ?? chunk.length);
|
|
1356
|
+
relsResult.summary.succeeded = Number(relsResult.summary.succeeded ?? 0) + Number(chunkResult.summary?.succeeded ?? 0);
|
|
1357
|
+
relsResult.summary.failed = Number(relsResult.summary.failed ?? 0) + Number(chunkResult.summary?.failed ?? 0);
|
|
1358
|
+
if (chunkResult.errors?.length)
|
|
1359
|
+
relsResult.errors.push(...chunkResult.errors);
|
|
1360
|
+
logProgress("upsert.relationships.batch.done", `${i + 1}/${relationshipChunks.length} succeeded=${chunkResult.summary?.succeeded ?? 0}, failed=${chunkResult.summary?.failed ?? 0}`);
|
|
1361
|
+
}
|
|
1326
1362
|
logProgress("upsert.relationships.done", `succeeded=${relsResult.summary?.succeeded ?? 0}, failed=${relsResult.summary?.failed ?? 0}`);
|
|
1327
1363
|
}
|
|
1328
1364
|
// Build structured enrichment task (included in JSON output and printed in human mode)
|
package/dist/index.js
CHANGED
|
@@ -94,6 +94,7 @@ Usage:
|
|
|
94
94
|
--create-application force new application entity
|
|
95
95
|
--auto-map-application auto-map only when high confidence
|
|
96
96
|
--non-interactive fail on ambiguous mapping
|
|
97
|
+
--batch-size <n> upsert batch size (default: 10)
|
|
97
98
|
--dry-run preview without writing
|
|
98
99
|
--json
|
|
99
100
|
nexarch update-entity
|