nexarch 0.8.11 → 0.8.12
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 +164 -23
- package/package.json +1 -1
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { arch, homedir, hostname, platform, release, type as osType, userInfo } from "os";
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
3
3
|
import { join } from "path";
|
|
4
|
+
import * as readline from "node:readline/promises";
|
|
4
5
|
import process from "process";
|
|
5
6
|
import { requireCredentials } from "../lib/credentials.js";
|
|
6
7
|
import { fetchAgentRegistryOrThrow } from "../lib/agent-registry.js";
|
|
7
8
|
import { callMcpTool, mcpInitialize, mcpListTools } from "../lib/mcp.js";
|
|
8
9
|
import { buildVersionAttributes } from "../lib/version-normalization.js";
|
|
9
|
-
const CLI_VERSION = "0.8.
|
|
10
|
+
const CLI_VERSION = "0.8.12";
|
|
10
11
|
const AGENT_ENTITY_TYPE = "agent";
|
|
11
12
|
const TECH_COMPONENT_ENTITY_TYPE = "technology_component";
|
|
12
13
|
function parseFlag(args, flag) {
|
|
@@ -25,6 +26,42 @@ function parseToolText(result) {
|
|
|
25
26
|
const text = result.content?.[0]?.text ?? "{}";
|
|
26
27
|
return JSON.parse(text);
|
|
27
28
|
}
|
|
29
|
+
function parseCsv(value) {
|
|
30
|
+
if (!value)
|
|
31
|
+
return [];
|
|
32
|
+
return value.split(",").map((v) => v.trim()).filter(Boolean);
|
|
33
|
+
}
|
|
34
|
+
async function promptForValue(promptText, required = false) {
|
|
35
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
36
|
+
return null;
|
|
37
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
38
|
+
try {
|
|
39
|
+
// eslint-disable-next-line no-constant-condition
|
|
40
|
+
while (true) {
|
|
41
|
+
const value = (await rl.question(promptText)).trim();
|
|
42
|
+
if (value)
|
|
43
|
+
return value;
|
|
44
|
+
if (!required)
|
|
45
|
+
return null;
|
|
46
|
+
console.log("A value is required.");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
rl.close();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function confirmInstructionWrite() {
|
|
54
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
55
|
+
return false;
|
|
56
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
57
|
+
try {
|
|
58
|
+
const answer = (await rl.question("Allow nexarch init-agent to write/update AGENTS.md/CLAUDE.md registration instructions? [y/N]: ")).trim().toLowerCase();
|
|
59
|
+
return answer === "y" || answer === "yes";
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
rl.close();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
28
65
|
function renderChecksTable(checks) {
|
|
29
66
|
const headers = ["Status", "Check", "Details"];
|
|
30
67
|
const rows = checks.map((check) => [
|
|
@@ -360,6 +397,16 @@ export async function initAgent(args) {
|
|
|
360
397
|
const explicitAgentId = parseOptionValue(args, "--agent-id");
|
|
361
398
|
const bindToExternalKey = parseOptionValue(args, "--bind-to-external-key");
|
|
362
399
|
const bindRelationshipType = parseOptionValue(args, "--bind-relationship-type") ?? "depends_on";
|
|
400
|
+
const allowInstructionWriteFlag = parseFlag(args, "--allow-instruction-write");
|
|
401
|
+
const denyInstructionWriteFlag = parseFlag(args, "--deny-instruction-write");
|
|
402
|
+
const providerArg = parseOptionValue(args, "--provider");
|
|
403
|
+
const modelArg = parseOptionValue(args, "--model");
|
|
404
|
+
const clientArg = parseOptionValue(args, "--client");
|
|
405
|
+
const frameworkArg = parseOptionValue(args, "--framework");
|
|
406
|
+
const sessionIdArg = parseOptionValue(args, "--session-id");
|
|
407
|
+
const toolVersionArg = parseOptionValue(args, "--tool-version");
|
|
408
|
+
const capabilitiesArg = parseCsv(parseOptionValue(args, "--capabilities"));
|
|
409
|
+
const notesArg = parseOptionValue(args, "--notes");
|
|
363
410
|
const agentId = explicitAgentId ?? getDefaultAgentId();
|
|
364
411
|
const runtime = {
|
|
365
412
|
osPlatform: platform(),
|
|
@@ -813,7 +860,93 @@ export async function initAgent(args) {
|
|
|
813
860
|
}
|
|
814
861
|
}
|
|
815
862
|
}
|
|
863
|
+
let identityCapture = {
|
|
864
|
+
attempted: false,
|
|
865
|
+
ok: false,
|
|
866
|
+
detail: "skipped",
|
|
867
|
+
missingRequired: [],
|
|
868
|
+
};
|
|
869
|
+
if (registration.ok) {
|
|
870
|
+
let provider = providerArg;
|
|
871
|
+
let model = modelArg;
|
|
872
|
+
let client = clientArg;
|
|
873
|
+
if (!asJson) {
|
|
874
|
+
provider = provider ?? await promptForValue("Provider (e.g. anthropic/openai/google): ", true);
|
|
875
|
+
model = model ?? await promptForValue("Model id (e.g. claude-sonnet-4-6): ", true);
|
|
876
|
+
client = client ?? await promptForValue("Client (e.g. claude-code/cursor/codex-cli): ", true);
|
|
877
|
+
}
|
|
878
|
+
const missingRequired = [
|
|
879
|
+
!provider ? "provider" : null,
|
|
880
|
+
!model ? "model" : null,
|
|
881
|
+
!client ? "client" : null,
|
|
882
|
+
].filter(Boolean);
|
|
883
|
+
if (missingRequired.length > 0) {
|
|
884
|
+
identityCapture = {
|
|
885
|
+
attempted: false,
|
|
886
|
+
ok: false,
|
|
887
|
+
detail: `missing required identity fields: ${missingRequired.join(", ")}`,
|
|
888
|
+
missingRequired,
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
else {
|
|
892
|
+
const nowIso = new Date().toISOString();
|
|
893
|
+
identityCapture.attempted = true;
|
|
894
|
+
try {
|
|
895
|
+
const identityRaw = await callMcpTool("nexarch_upsert_entities", {
|
|
896
|
+
entities: [
|
|
897
|
+
{
|
|
898
|
+
externalKey: `agent:${agentId}`,
|
|
899
|
+
entityTypeCode: "agent",
|
|
900
|
+
name: `Agent ${agentId}`,
|
|
901
|
+
confidence: 1,
|
|
902
|
+
attributes: {
|
|
903
|
+
identity: {
|
|
904
|
+
source: "nexarch init-agent",
|
|
905
|
+
capturedAt: nowIso,
|
|
906
|
+
provider,
|
|
907
|
+
model,
|
|
908
|
+
client,
|
|
909
|
+
framework: frameworkArg,
|
|
910
|
+
sessionId: sessionIdArg,
|
|
911
|
+
toolVersion: toolVersionArg,
|
|
912
|
+
capabilities: capabilitiesArg,
|
|
913
|
+
notes: notesArg,
|
|
914
|
+
},
|
|
915
|
+
},
|
|
916
|
+
},
|
|
917
|
+
],
|
|
918
|
+
agentContext: {
|
|
919
|
+
agentId,
|
|
920
|
+
agentRunId: `init-agent-identify-${Date.now()}`,
|
|
921
|
+
repoRef: "nexarch-cli/init-agent",
|
|
922
|
+
observedAt: nowIso,
|
|
923
|
+
source: "nexarch-cli",
|
|
924
|
+
model,
|
|
925
|
+
provider,
|
|
926
|
+
},
|
|
927
|
+
policyContext: policies.policyBundleHash
|
|
928
|
+
? {
|
|
929
|
+
policyBundleHash: policies.policyBundleHash,
|
|
930
|
+
alignmentSummary: { score: 1, violations: [], waivers: [] },
|
|
931
|
+
}
|
|
932
|
+
: undefined,
|
|
933
|
+
dryRun: false,
|
|
934
|
+
}, { companyId: selectedCompanyId });
|
|
935
|
+
const identity = parseToolText(identityRaw);
|
|
936
|
+
const failed = Number(identity.summary?.failed ?? 0) > 0;
|
|
937
|
+
identityCapture.ok = !failed;
|
|
938
|
+
identityCapture.detail = failed
|
|
939
|
+
? `identity capture failed (${identity.errors?.[0]?.error ?? "unknown"})`
|
|
940
|
+
: "identity captured";
|
|
941
|
+
}
|
|
942
|
+
catch (error) {
|
|
943
|
+
identityCapture.ok = false;
|
|
944
|
+
identityCapture.detail = error instanceof Error ? error.message : "identity capture failed";
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
}
|
|
816
948
|
let agentConfigResults = [];
|
|
949
|
+
let instructionsWriteAllowed = false;
|
|
817
950
|
if (registration.ok) {
|
|
818
951
|
try {
|
|
819
952
|
// Save identity so check-in can find the agent key
|
|
@@ -824,9 +957,20 @@ export async function initAgent(args) {
|
|
|
824
957
|
catch {
|
|
825
958
|
// non-fatal
|
|
826
959
|
}
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
960
|
+
if (denyInstructionWriteFlag) {
|
|
961
|
+
instructionsWriteAllowed = false;
|
|
962
|
+
}
|
|
963
|
+
else if (allowInstructionWriteFlag) {
|
|
964
|
+
instructionsWriteAllowed = true;
|
|
965
|
+
}
|
|
966
|
+
else if (!asJson) {
|
|
967
|
+
instructionsWriteAllowed = await confirmInstructionWrite();
|
|
968
|
+
}
|
|
969
|
+
if (instructionsWriteAllowed) {
|
|
970
|
+
agentConfigResults = injectAgentConfigs(registry);
|
|
971
|
+
if (agentConfigResults.length === 0) {
|
|
972
|
+
agentConfigResults = injectGenericAgentConfig(registry);
|
|
973
|
+
}
|
|
830
974
|
}
|
|
831
975
|
}
|
|
832
976
|
checks.push({
|
|
@@ -834,14 +978,21 @@ export async function initAgent(args) {
|
|
|
834
978
|
ok: registration.ok,
|
|
835
979
|
detail: registration.detail,
|
|
836
980
|
});
|
|
981
|
+
checks.push({
|
|
982
|
+
name: "agent.identity.capture",
|
|
983
|
+
ok: !registration.ok || identityCapture.ok,
|
|
984
|
+
detail: !registration.ok ? "skipped (registration failed)" : identityCapture.detail,
|
|
985
|
+
});
|
|
837
986
|
checks.push({
|
|
838
987
|
name: "agent.instructions.injection",
|
|
839
|
-
ok: !registration.ok || agentConfigResults.length > 0,
|
|
988
|
+
ok: !registration.ok || !instructionsWriteAllowed || agentConfigResults.length > 0,
|
|
840
989
|
detail: !registration.ok
|
|
841
990
|
? "skipped (registration failed)"
|
|
842
|
-
:
|
|
843
|
-
?
|
|
844
|
-
:
|
|
991
|
+
: !instructionsWriteAllowed
|
|
992
|
+
? "skipped (consent not granted)"
|
|
993
|
+
: agentConfigResults.length > 0
|
|
994
|
+
? `updated ${agentConfigResults.length} instruction target file(s)`
|
|
995
|
+
: "no runtime instruction target matched this repository (non-fatal; create AGENTS.md/CLAUDE.md or configure a generic target)",
|
|
845
996
|
});
|
|
846
997
|
checks.push({
|
|
847
998
|
name: "technology.components",
|
|
@@ -862,17 +1013,12 @@ export async function initAgent(args) {
|
|
|
862
1013
|
}
|
|
863
1014
|
const allPassed = checks.every((c) => c.ok);
|
|
864
1015
|
const appDetection = detectLikelyApplicationInCwd();
|
|
865
|
-
const identifyPrompt = [
|
|
866
|
-
"Please identify your runtime so the workspace can register richer metadata.",
|
|
867
|
-
"Return ONLY the completed command below with real values (no markdown):",
|
|
868
|
-
`nexarch agent identify --agent-id \"${agentId}\" --provider \"<provider>\" --model \"<model>\" --client \"<client>\" --framework \"<openclaw|n8n|m365-agent-framework|other>\" --session-id \"<session-id>\" --tool-version \"<tool-version>\" --capabilities \"<capability1,capability2>\" --notes \"<optional notes>\" --json`,
|
|
869
|
-
].join("\n");
|
|
870
1016
|
if (asJson) {
|
|
871
1017
|
const output = {
|
|
872
1018
|
ok: strict ? allPassed : true,
|
|
873
1019
|
passed: allPassed,
|
|
874
1020
|
strict,
|
|
875
|
-
status: allPassed ? "
|
|
1021
|
+
status: allPassed ? "completed" : "completed_with_issues",
|
|
876
1022
|
checks,
|
|
877
1023
|
summary: {
|
|
878
1024
|
total: checks.length,
|
|
@@ -890,11 +1036,9 @@ export async function initAgent(args) {
|
|
|
890
1036
|
},
|
|
891
1037
|
binding,
|
|
892
1038
|
followUp: {
|
|
893
|
-
required:
|
|
894
|
-
type: "
|
|
895
|
-
detail: "
|
|
896
|
-
prompt: identifyPrompt,
|
|
897
|
-
submitCommandTemplate: `nexarch agent identify --agent-id \"${agentId}\" --provider \"<provider>\" --model \"<model>\" --client \"<client>\" --framework \"<openclaw|n8n|m365-agent-framework|other>\" --session-id \"<session-id>\" --tool-version \"<tool-version>\" --capabilities \"<capability1,capability2>\" --notes \"<optional notes>\" --json`,
|
|
1039
|
+
required: appDetection.detected,
|
|
1040
|
+
type: "init_project_recommendation",
|
|
1041
|
+
detail: appDetection.detected ? "Project detected; request consent before running init-project" : "No project detected",
|
|
898
1042
|
initProjectSuggestion: appDetection.detected
|
|
899
1043
|
? {
|
|
900
1044
|
detected: true,
|
|
@@ -940,11 +1084,8 @@ export async function initAgent(args) {
|
|
|
940
1084
|
}
|
|
941
1085
|
}
|
|
942
1086
|
const hasInjectedAgentInstructions = agentConfigResults.some((r) => r.status === "injected" || r.status === "updated");
|
|
943
|
-
console.log("\n➡ Next step (required): complete agent identity in your coding agent");
|
|
944
|
-
console.log(" Paste this and fill in real values:");
|
|
945
|
-
console.log(`\nrun npx nexarch@latest agent identify --agent-id \"${agentId}\" --provider \"<provider>\" --model \"<model>\" --client \"<client>\" --framework \"<openclaw|n8n|m365-agent-framework|other>\" --tool-version \"<tool-version>\" --capabilities \"<capability1,capability2>\" --json\n`);
|
|
946
1087
|
if (hasInjectedAgentInstructions) {
|
|
947
|
-
console.log(" (Registration instructions were
|
|
1088
|
+
console.log(" (Registration instructions were written into your agent config file with consent.)");
|
|
948
1089
|
}
|
|
949
1090
|
if (!fromSetup && appDetection.detected) {
|
|
950
1091
|
console.log("\n➡ Optional next step: likely application detected in current directory.");
|