nexarch 0.6.1 → 0.6.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.
@@ -138,8 +138,6 @@ export async function checkIn(args) {
138
138
  console.log(`Type : ${cmd.command_type}`);
139
139
  console.log(`Target : ${cmd.target_entity_key ?? "(any)"}`);
140
140
  console.log(`Priority : ${cmd.priority}`);
141
- if (cmd.resolved_execution_mode)
142
- console.log(`Mode : ${cmd.resolved_execution_mode}`);
143
141
  if (cmd.resolved_runtime_handler)
144
142
  console.log(`Runtime : ${cmd.resolved_runtime_handler}`);
145
143
  if (cmd.command_type_version != null)
@@ -0,0 +1,138 @@
1
+ import process from "process";
2
+ import { existsSync, readFileSync } from "fs";
3
+ import { join } from "path";
4
+ import { homedir } from "os";
5
+ import { requireCredentials } from "../lib/credentials.js";
6
+ import { callMcpTool } from "../lib/mcp.js";
7
+ function parseFlag(args, flag) {
8
+ return args.includes(flag);
9
+ }
10
+ function parseOptionValue(args, option) {
11
+ const idx = args.indexOf(option);
12
+ if (idx === -1)
13
+ return null;
14
+ const v = args[idx + 1];
15
+ if (!v || v.startsWith("--"))
16
+ return null;
17
+ return v;
18
+ }
19
+ function parseMultiOptionValues(args, option) {
20
+ const values = [];
21
+ for (let i = 0; i < args.length; i += 1) {
22
+ if (args[i] !== option)
23
+ continue;
24
+ const v = args[i + 1];
25
+ if (!v || v.startsWith("--"))
26
+ continue;
27
+ values.push(v);
28
+ }
29
+ return values;
30
+ }
31
+ function parseToolText(result) {
32
+ const text = result.content?.[0]?.text ?? "{}";
33
+ return JSON.parse(text);
34
+ }
35
+ function loadIdentityAgentKey() {
36
+ const identityPath = join(homedir(), ".nexarch", "identity.json");
37
+ if (!existsSync(identityPath))
38
+ return null;
39
+ try {
40
+ const data = JSON.parse(readFileSync(identityPath, "utf8"));
41
+ return data.agentKey ?? null;
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ function parseFindingToken(token) {
48
+ const [policyControlId, policyRuleId, resultRaw, rationaleRaw, missingRaw] = token.split("|");
49
+ const result = (resultRaw ?? "").trim().toLowerCase();
50
+ if (!policyControlId?.trim() || !policyRuleId?.trim() || !result) {
51
+ throw new Error("Each --finding must be: <policyControlId>|<policyRuleId>|<pass|partial|fail>|<rationale>|<missing1;missing2>");
52
+ }
53
+ if (result !== "pass" && result !== "partial" && result !== "fail") {
54
+ throw new Error(`Invalid finding result '${resultRaw}'. Use pass|partial|fail.`);
55
+ }
56
+ return {
57
+ policyControlId: policyControlId.trim(),
58
+ policyRuleId: policyRuleId.trim(),
59
+ result,
60
+ ...(rationaleRaw?.trim() ? { rationale: rationaleRaw.trim() } : {}),
61
+ ...(missingRaw?.trim() ? { missingRequirements: missingRaw.split(";").map((m) => m.trim()).filter(Boolean) } : {}),
62
+ };
63
+ }
64
+ function parseFindings(args) {
65
+ const findingsJson = parseOptionValue(args, "--findings-json");
66
+ if (findingsJson) {
67
+ let parsed;
68
+ try {
69
+ parsed = JSON.parse(findingsJson);
70
+ }
71
+ catch {
72
+ throw new Error("--findings-json must be valid JSON array");
73
+ }
74
+ if (!Array.isArray(parsed) || parsed.length === 0) {
75
+ throw new Error("--findings-json must be a non-empty JSON array");
76
+ }
77
+ return parsed.map((item) => {
78
+ const value = item;
79
+ const result = String(value.result ?? "").toLowerCase();
80
+ if (!value.policyControlId || !value.policyRuleId || !result) {
81
+ throw new Error("Each finding must include policyControlId, policyRuleId, result");
82
+ }
83
+ if (result !== "pass" && result !== "partial" && result !== "fail") {
84
+ throw new Error(`Invalid finding result '${String(value.result)}'. Use pass|partial|fail.`);
85
+ }
86
+ return {
87
+ policyControlId: String(value.policyControlId),
88
+ policyRuleId: String(value.policyRuleId),
89
+ result,
90
+ ...(value.rationale ? { rationale: String(value.rationale) } : {}),
91
+ ...(Array.isArray(value.missingRequirements) ? { missingRequirements: value.missingRequirements.map(String) } : {}),
92
+ };
93
+ });
94
+ }
95
+ const tokens = parseMultiOptionValues(args, "--finding");
96
+ if (tokens.length === 0) {
97
+ throw new Error("Provide findings via --finding (repeatable) or --findings-json '<json-array>'");
98
+ }
99
+ return tokens.map(parseFindingToken);
100
+ }
101
+ export async function policyAuditSubmit(args) {
102
+ const asJson = parseFlag(args, "--json");
103
+ const commandId = parseOptionValue(args, "--command-id") ?? parseOptionValue(args, "--id");
104
+ const applicationEntityKey = parseOptionValue(args, "--application-key") ?? parseOptionValue(args, "--entity");
105
+ const agentKey = parseOptionValue(args, "--agent-key") ?? loadIdentityAgentKey();
106
+ if (!commandId) {
107
+ console.error("error: --command-id <uuid> is required");
108
+ process.exit(1);
109
+ }
110
+ if (!applicationEntityKey) {
111
+ console.error("error: --application-key <externalKey> is required (e.g. application:bad-driving)");
112
+ process.exit(1);
113
+ }
114
+ const findings = parseFindings(args);
115
+ const creds = requireCredentials();
116
+ const raw = await callMcpTool("nexarch_submit_policy_audit", {
117
+ commandId,
118
+ applicationEntityKey,
119
+ ...(agentKey ? { agentKey } : {}),
120
+ findings,
121
+ companyId: creds.companyId,
122
+ }, { companyId: creds.companyId });
123
+ const result = parseToolText(raw);
124
+ if (asJson) {
125
+ process.stdout.write(JSON.stringify(result) + "\n");
126
+ return;
127
+ }
128
+ if (!result.ok) {
129
+ console.error(`Policy audit submit failed${result.error ? `: ${result.error}` : ""}`);
130
+ process.exit(1);
131
+ }
132
+ console.log(`Policy audit submitted for ${applicationEntityKey}.`);
133
+ if (result.runId)
134
+ console.log(`Run ID: ${result.runId}`);
135
+ if (result.summary) {
136
+ console.log(`Summary: ${result.summary.passCount ?? 0} pass, ${result.summary.partialCount ?? 0} partial, ${result.summary.failCount ?? 0} fail`);
137
+ }
138
+ }
@@ -0,0 +1,52 @@
1
+ import process from "process";
2
+ import { requireCredentials } from "../lib/credentials.js";
3
+ import { callMcpTool } from "../lib/mcp.js";
4
+ function parseFlag(args, flag) {
5
+ return args.includes(flag);
6
+ }
7
+ function parseOptionValue(args, option) {
8
+ const idx = args.indexOf(option);
9
+ if (idx === -1)
10
+ return null;
11
+ const v = args[idx + 1];
12
+ if (!v || v.startsWith("--"))
13
+ return null;
14
+ return v;
15
+ }
16
+ function parseToolText(result) {
17
+ const text = result.content?.[0]?.text ?? "{}";
18
+ return JSON.parse(text);
19
+ }
20
+ export async function policyControls(args) {
21
+ const asJson = parseFlag(args, "--json");
22
+ const entity = parseOptionValue(args, "--entity") ?? parseOptionValue(args, "--application-key");
23
+ if (!entity) {
24
+ console.error("error: --entity <externalKey> is required (e.g. application:bad-driving)");
25
+ process.exit(1);
26
+ }
27
+ const creds = requireCredentials();
28
+ const raw = await callMcpTool("nexarch_get_entity_policy_controls", { entityExternalKey: entity, companyId: creds.companyId }, { companyId: creds.companyId });
29
+ const result = parseToolText(raw);
30
+ if (asJson) {
31
+ process.stdout.write(JSON.stringify(result) + "\n");
32
+ return;
33
+ }
34
+ if (!result.found) {
35
+ console.log(`Entity not found: ${entity}`);
36
+ return;
37
+ }
38
+ console.log(`Policy controls for ${result.entityExternalKey ?? entity}`);
39
+ console.log(`Controls: ${result.controlCount ?? 0}`);
40
+ for (const control of result.controls ?? []) {
41
+ const rules = control.rules ?? [];
42
+ console.log(`\n- ${control.name} (${control.id})`);
43
+ if (rules.length === 0) {
44
+ console.log(" (no rules)");
45
+ continue;
46
+ }
47
+ for (const rule of rules) {
48
+ const level = rule.requirementLevel ? ` [${rule.requirementLevel}]` : "";
49
+ console.log(` • ${rule.name} (${rule.id})${level}`);
50
+ }
51
+ }
52
+ }
package/dist/index.js CHANGED
@@ -15,6 +15,8 @@ import { resolveNames } from "./commands/resolve-names.js";
15
15
  import { checkIn } from "./commands/check-in.js";
16
16
  import { commandDone } from "./commands/command-done.js";
17
17
  import { commandFail } from "./commands/command-fail.js";
18
+ import { policyControls } from "./commands/policy-controls.js";
19
+ import { policyAuditSubmit } from "./commands/policy-audit-submit.js";
18
20
  const [, , command, ...args] = process.argv;
19
21
  const commands = {
20
22
  login,
@@ -33,6 +35,8 @@ const commands = {
33
35
  "check-in": checkIn,
34
36
  "command-done": commandDone,
35
37
  "command-fail": commandFail,
38
+ "policy-controls": policyControls,
39
+ "policy-audit-submit": policyAuditSubmit,
36
40
  };
37
41
  async function main() {
38
42
  if (command === "agent") {
@@ -129,6 +133,18 @@ Usage:
129
133
  Options: --id <commandId> (required)
130
134
  --error <message> (required)
131
135
  --json
136
+ nexarch policy-controls
137
+ Fetch policy controls/rules assigned to an entity (for policy audits).
138
+ Options: --entity <externalKey> (required, e.g. application:bad-driving)
139
+ --json
140
+ nexarch policy-audit-submit
141
+ Submit structured policy findings (writes policy_audit_finding rows).
142
+ Options: --command-id <id> (required)
143
+ --application-key <key> (required)
144
+ --agent-key <key> (optional; defaults from identity)
145
+ --finding <controlId|ruleId|result|rationale|missing1;missing2> (repeatable)
146
+ --findings-json <json-array>
147
+ --json
132
148
  `);
133
149
  process.exit(command ? 1 : 0);
134
150
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexarch",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "description": "Your architecture workspace for AI delivery.",
5
5
  "keywords": [
6
6
  "nexarch",