@neuroverseos/governance 0.1.6 → 0.2.2

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.
Files changed (82) hide show
  1. package/README.md +279 -423
  2. package/dist/adapters/express.cjs +242 -2
  3. package/dist/adapters/express.d.cts +1 -1
  4. package/dist/adapters/express.d.ts +1 -1
  5. package/dist/adapters/express.js +5 -3
  6. package/dist/adapters/index.cjs +337 -5
  7. package/dist/adapters/index.d.cts +1 -1
  8. package/dist/adapters/index.d.ts +1 -1
  9. package/dist/adapters/index.js +8 -6
  10. package/dist/adapters/langchain.cjs +297 -3
  11. package/dist/adapters/langchain.d.cts +8 -1
  12. package/dist/adapters/langchain.d.ts +8 -1
  13. package/dist/adapters/langchain.js +5 -3
  14. package/dist/adapters/openai.cjs +297 -3
  15. package/dist/adapters/openai.d.cts +8 -1
  16. package/dist/adapters/openai.d.ts +8 -1
  17. package/dist/adapters/openai.js +5 -3
  18. package/dist/adapters/openclaw.cjs +297 -3
  19. package/dist/adapters/openclaw.d.cts +8 -1
  20. package/dist/adapters/openclaw.d.ts +8 -1
  21. package/dist/adapters/openclaw.js +5 -3
  22. package/dist/{bootstrap-H4HHKQ5G.js → bootstrap-GXVDZNF7.js} +2 -1
  23. package/dist/{build-73KAVHEY.js → build-P42YFKQV.js} +34 -3
  24. package/dist/{chunk-Z2S2HIV5.js → chunk-2NICNKOM.js} +2 -2
  25. package/dist/{chunk-B4NF3OLW.js → chunk-4JRYGIO7.js} +56 -2
  26. package/dist/chunk-4QXB6PEO.js +232 -0
  27. package/dist/chunk-6CZSKEY5.js +164 -0
  28. package/dist/{chunk-O5OMJMIE.js → chunk-7P3S7MAY.js} +502 -2
  29. package/dist/chunk-A5W4GNQO.js +130 -0
  30. package/dist/chunk-AKW5YVCE.js +96 -0
  31. package/dist/chunk-DPVS43ZT.js +608 -0
  32. package/dist/{chunk-EIUHJXBB.js → chunk-GR6DGCZ2.js} +1 -1
  33. package/dist/chunk-KEST3MWO.js +324 -0
  34. package/dist/{chunk-D7BGWV2J.js → chunk-NF5POFCI.js} +5 -3
  35. package/dist/{chunk-FZQCRGUU.js → chunk-OHAC6HJE.js} +27 -3
  36. package/dist/chunk-OT6PXH54.js +61 -0
  37. package/dist/{chunk-ITJ3LCPG.js → chunk-PDOZHZWL.js} +1 -1
  38. package/dist/{chunk-T4X42QXC.js → chunk-Q6O7ZLO2.js} +0 -59
  39. package/dist/{chunk-FYPYZFV5.js → chunk-QPASI2BR.js} +1 -1
  40. package/dist/{chunk-EQXFOKH2.js → chunk-RWXVAH6P.js} +27 -3
  41. package/dist/{chunk-CROPZ75A.js → chunk-SKU3GAPD.js} +27 -3
  42. package/dist/chunk-YZFATT7X.js +9 -0
  43. package/dist/cli/neuroverse.cjs +5343 -732
  44. package/dist/cli/neuroverse.js +69 -13
  45. package/dist/cli/plan.cjs +1599 -0
  46. package/dist/cli/plan.d.cts +20 -0
  47. package/dist/cli/plan.d.ts +20 -0
  48. package/dist/cli/plan.js +361 -0
  49. package/dist/cli/run.cjs +1746 -0
  50. package/dist/cli/run.d.cts +20 -0
  51. package/dist/cli/run.d.ts +20 -0
  52. package/dist/cli/run.js +143 -0
  53. package/dist/{configure-ai-46JVG56I.js → configure-ai-TK67ZWZL.js} +5 -2
  54. package/dist/{derive-6NAEWLM5.js → derive-TLIV4OOU.js} +6 -4
  55. package/dist/doctor-QV6HELS5.js +170 -0
  56. package/dist/{explain-3B3VB6TL.js → explain-IDCRWMPX.js} +2 -1
  57. package/dist/{guard-67Y66P3I.js → guard-GFLQZY6U.js} +20 -6
  58. package/dist/{guard-contract-D_RQz9kt.d.ts → guard-contract-Cm91Kp4j.d.cts} +182 -2
  59. package/dist/{guard-contract-D_RQz9kt.d.cts → guard-contract-Cm91Kp4j.d.ts} +182 -2
  60. package/dist/guard-engine-JLTUARGU.js +10 -0
  61. package/dist/{impact-CHERK3O6.js → impact-XPECYRLH.js} +5 -3
  62. package/dist/{improve-YG6I6ERG.js → improve-GPUBKTEA.js} +4 -3
  63. package/dist/index.cjs +2135 -89
  64. package/dist/index.d.cts +481 -12
  65. package/dist/index.d.ts +481 -12
  66. package/dist/index.js +70 -20
  67. package/dist/{init-Z66T6TDI.js → init-PKPIYHYE.js} +2 -0
  68. package/dist/mcp-server-LZVJHBT5.js +13 -0
  69. package/dist/model-adapter-BB7G4MFI.js +11 -0
  70. package/dist/playground-FGOMASHN.js +550 -0
  71. package/dist/redteam-SK7AMIG3.js +357 -0
  72. package/dist/session-VISISNWJ.js +14 -0
  73. package/dist/{simulate-ETHHINZ4.js → simulate-VDOYQFRO.js} +2 -1
  74. package/dist/test-75AVHC3R.js +217 -0
  75. package/dist/{trace-3YODSSIP.js → trace-JVF67VR3.js} +4 -2
  76. package/dist/{validate-UVE6GKQU.js → validate-LLBWVPGV.js} +15 -6
  77. package/dist/validate-engine-UIABSIHD.js +7 -0
  78. package/dist/{world-WLNHL5XC.js → world-LAXO6DOX.js} +87 -7
  79. package/dist/world-loader-HMPTOEA2.js +9 -0
  80. package/package.json +19 -5
  81. package/dist/validate-engine-657D75OG.js +0 -6
  82. /package/dist/{chunk-M3TZFGHO.js → chunk-JZPQGIKR.js} +0 -0
@@ -0,0 +1,20 @@
1
+ /**
2
+ * neuroverse run — Governed Runtime
3
+ *
4
+ * Modes:
5
+ * --pipe Pipe mode: JSON lines in → verdicts out (default if stdin is piped)
6
+ * --interactive Interactive chat session with a model
7
+ *
8
+ * Usage:
9
+ * # Pipe mode — works with any language/framework
10
+ * my_agent | neuroverse run --world ./world/ --plan plan.json
11
+ *
12
+ * # Interactive mode — governed chat session
13
+ * neuroverse run --world ./world/ --plan plan.json --provider openai
14
+ *
15
+ * # Quick start — auto-detect world and plan
16
+ * neuroverse run
17
+ */
18
+ declare function main(args: string[]): Promise<void>;
19
+
20
+ export { main };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * neuroverse run — Governed Runtime
3
+ *
4
+ * Modes:
5
+ * --pipe Pipe mode: JSON lines in → verdicts out (default if stdin is piped)
6
+ * --interactive Interactive chat session with a model
7
+ *
8
+ * Usage:
9
+ * # Pipe mode — works with any language/framework
10
+ * my_agent | neuroverse run --world ./world/ --plan plan.json
11
+ *
12
+ * # Interactive mode — governed chat session
13
+ * neuroverse run --world ./world/ --plan plan.json --provider openai
14
+ *
15
+ * # Quick start — auto-detect world and plan
16
+ * neuroverse run
17
+ */
18
+ declare function main(args: string[]): Promise<void>;
19
+
20
+ export { main };
@@ -0,0 +1,143 @@
1
+ import {
2
+ describeActiveWorld,
3
+ resolveWorldPath
4
+ } from "../chunk-AKW5YVCE.js";
5
+ import "../chunk-YZFATT7X.js";
6
+
7
+ // src/cli/run.ts
8
+ import { readFileSync, readdirSync, existsSync } from "fs";
9
+ import { join } from "path";
10
+ function parseArg(args, flag) {
11
+ const idx = args.indexOf(flag);
12
+ return idx >= 0 && idx + 1 < args.length ? args[idx + 1] : void 0;
13
+ }
14
+ function hasFlag(args, flag) {
15
+ return args.includes(flag);
16
+ }
17
+ function autoDetectPlan() {
18
+ const nvDir = ".neuroverse/plans";
19
+ if (!existsSync(nvDir)) return void 0;
20
+ const entries = readdirSync(nvDir).filter((e) => e.endsWith(".json"));
21
+ if (entries.length === 1) {
22
+ try {
23
+ return JSON.parse(readFileSync(join(nvDir, entries[0]), "utf-8"));
24
+ } catch {
25
+ return void 0;
26
+ }
27
+ }
28
+ return void 0;
29
+ }
30
+ function loadPlan(path) {
31
+ return JSON.parse(readFileSync(path, "utf-8"));
32
+ }
33
+ var RUN_USAGE = `
34
+ neuroverse run \u2014 Governed runtime for AI agents.
35
+
36
+ Modes:
37
+ --pipe JSON lines in \u2192 verdicts out (default if stdin is piped)
38
+ --interactive Chat session with model + governance
39
+
40
+ Options:
41
+ --world <path> Path to world directory
42
+ --plan <path> Path to plan.json
43
+ --level <level> Enforcement level (basic|standard|strict)
44
+ --trace Include evaluation trace in verdicts
45
+ --provider <name> Model provider (openai|anthropic|ollama)
46
+ --model <name> Model name override
47
+ --api-key <key> API key (or set via env var)
48
+
49
+ Usage:
50
+ # Pipe mode \u2014 works with any agent
51
+ my_agent | neuroverse run --world ./world/ --plan plan.json
52
+
53
+ # Interactive mode \u2014 governed chat session
54
+ neuroverse run --interactive --world ./world/ --provider openai
55
+
56
+ # Auto-detect world and plan
57
+ neuroverse run
58
+ `.trim();
59
+ async function main(args) {
60
+ if (hasFlag(args, "--help") || hasFlag(args, "-h")) {
61
+ process.stdout.write(RUN_USAGE + "\n");
62
+ process.exit(0);
63
+ return;
64
+ }
65
+ const worldPath = resolveWorldPath(parseArg(args, "--world"));
66
+ if (!worldPath) {
67
+ process.stderr.write(
68
+ "Error: No world found.\nUse --world <path>, set NEUROVERSE_WORLD, or run `neuroverse world use <name>`\n"
69
+ );
70
+ process.exit(1);
71
+ return;
72
+ }
73
+ const explicitWorld = parseArg(args, "--world");
74
+ const worldInfo = describeActiveWorld(explicitWorld);
75
+ if (worldInfo) {
76
+ process.stderr.write(`Using world: ${worldInfo.name}
77
+ `);
78
+ }
79
+ const planPath = parseArg(args, "--plan");
80
+ const plan = planPath ? loadPlan(planPath) : autoDetectPlan();
81
+ const level = parseArg(args, "--level");
82
+ const trace = hasFlag(args, "--trace");
83
+ const isPipeMode = hasFlag(args, "--pipe") || !process.stdin.isTTY;
84
+ const isInteractive = hasFlag(args, "--interactive");
85
+ if (isInteractive) {
86
+ const providerName = parseArg(args, "--provider");
87
+ if (!providerName) {
88
+ process.stderr.write(
89
+ "Error: Interactive mode requires --provider (openai|anthropic|ollama)\n"
90
+ );
91
+ process.exit(1);
92
+ return;
93
+ }
94
+ const { resolveProvider, ModelAdapter } = await import("../model-adapter-BB7G4MFI.js");
95
+ const { runInteractiveMode } = await import("../session-VISISNWJ.js");
96
+ const modelConfig = resolveProvider(providerName, {
97
+ model: parseArg(args, "--model"),
98
+ apiKey: parseArg(args, "--api-key")
99
+ });
100
+ const model = new ModelAdapter(modelConfig);
101
+ await runInteractiveMode(
102
+ {
103
+ worldPath,
104
+ plan,
105
+ level,
106
+ trace,
107
+ onVerdict: (verdict, event) => {
108
+ if (verdict.status !== "ALLOW") {
109
+ process.stderr.write(
110
+ ` [${verdict.status}] ${event.intent} \u2014 ${verdict.reason ?? verdict.ruleId ?? "governance rule"}
111
+ `
112
+ );
113
+ }
114
+ },
115
+ onPlanProgress: (progress) => {
116
+ process.stderr.write(
117
+ ` [plan] ${progress.completed}/${progress.total} (${progress.percentage}%)
118
+ `
119
+ );
120
+ },
121
+ onPlanComplete: () => {
122
+ process.stderr.write(` [plan] Complete!
123
+ `);
124
+ }
125
+ },
126
+ model
127
+ );
128
+ } else if (isPipeMode) {
129
+ const { runPipeMode } = await import("../session-VISISNWJ.js");
130
+ await runPipeMode({
131
+ worldPath,
132
+ plan,
133
+ level,
134
+ trace
135
+ });
136
+ } else {
137
+ process.stdout.write(RUN_USAGE + "\n");
138
+ process.exit(0);
139
+ }
140
+ }
141
+ export {
142
+ main
143
+ };
@@ -1,11 +1,14 @@
1
1
  import {
2
2
  CONFIGURE_AI_EXIT_CODES,
3
- createProvider,
3
+ createProvider
4
+ } from "./chunk-Q6O7ZLO2.js";
5
+ import {
4
6
  getConfigPath,
5
7
  loadConfig,
6
8
  redactConfig,
7
9
  saveConfig
8
- } from "./chunk-T4X42QXC.js";
10
+ } from "./chunk-OT6PXH54.js";
11
+ import "./chunk-YZFATT7X.js";
9
12
 
10
13
  // src/cli/configure-ai.ts
11
14
  function parseArgs(argv) {
@@ -2,12 +2,14 @@ import {
2
2
  DeriveInputError,
3
3
  DeriveProviderError,
4
4
  deriveWorld
5
- } from "./chunk-D7BGWV2J.js";
5
+ } from "./chunk-NF5POFCI.js";
6
6
  import {
7
7
  DERIVE_EXIT_CODES
8
- } from "./chunk-T4X42QXC.js";
8
+ } from "./chunk-Q6O7ZLO2.js";
9
+ import "./chunk-OT6PXH54.js";
9
10
  import "./chunk-XPDMYECO.js";
10
- import "./chunk-O5OMJMIE.js";
11
+ import "./chunk-7P3S7MAY.js";
12
+ import "./chunk-YZFATT7X.js";
11
13
 
12
14
  // src/cli/derive.ts
13
15
  function parseArgs(argv) {
@@ -117,7 +119,7 @@ Normalization: ${n.fixCount} fix(es) applied
117
119
  process.stderr.write(`
118
120
  Bootstrapping to ${args.bootstrapDir}...
119
121
  `);
120
- const { main: bootstrapMain } = await import("./bootstrap-H4HHKQ5G.js");
122
+ const { main: bootstrapMain } = await import("./bootstrap-GXVDZNF7.js");
121
123
  await bootstrapMain([
122
124
  "--input",
123
125
  result.outputPath,
@@ -0,0 +1,170 @@
1
+ import {
2
+ loadConfig
3
+ } from "./chunk-OT6PXH54.js";
4
+ import {
5
+ __glob
6
+ } from "./chunk-YZFATT7X.js";
7
+
8
+ // import("../adapters/**/*") in src/cli/doctor.ts
9
+ var globImport_adapters = __glob({
10
+ "../adapters/express.ts": () => import("./adapters/express.js"),
11
+ "../adapters/index.ts": () => import("./adapters/index.js"),
12
+ "../adapters/langchain.ts": () => import("./adapters/langchain.js"),
13
+ "../adapters/openai.ts": () => import("./adapters/openai.js"),
14
+ "../adapters/openclaw.ts": () => import("./adapters/openclaw.js")
15
+ });
16
+
17
+ // src/cli/doctor.ts
18
+ var PACKAGE_VERSION = "0.2.0";
19
+ var MIN_NODE_VERSION = 18;
20
+ async function main(argv) {
21
+ const json = argv.includes("--json");
22
+ let worldPath;
23
+ for (let i = 0; i < argv.length; i++) {
24
+ if (argv[i] === "--world" && i + 1 < argv.length) {
25
+ worldPath = argv[++i];
26
+ }
27
+ }
28
+ const checks = [];
29
+ const nodeVersion = process.version;
30
+ const major = parseInt(nodeVersion.slice(1), 10);
31
+ checks.push({
32
+ label: "Node version",
33
+ status: major >= MIN_NODE_VERSION ? "pass" : "fail",
34
+ value: nodeVersion,
35
+ detail: major < MIN_NODE_VERSION ? `Requires Node >= ${MIN_NODE_VERSION}` : void 0
36
+ });
37
+ checks.push({
38
+ label: "NeuroVerse version",
39
+ status: "pass",
40
+ value: PACKAGE_VERSION
41
+ });
42
+ try {
43
+ const config = await loadConfig();
44
+ if (config?.provider && config?.apiKey) {
45
+ checks.push({
46
+ label: "AI provider configured",
47
+ status: "pass",
48
+ value: `${config.provider}${config.model ? ` (${config.model})` : ""}`
49
+ });
50
+ } else {
51
+ checks.push({
52
+ label: "AI provider configured",
53
+ status: "warn",
54
+ value: "not configured",
55
+ detail: "Run: neuroverse configure-ai --provider openai --model gpt-4.1-mini --api-key <key>"
56
+ });
57
+ }
58
+ } catch {
59
+ checks.push({
60
+ label: "AI provider configured",
61
+ status: "warn",
62
+ value: "not configured",
63
+ detail: "Run: neuroverse configure-ai"
64
+ });
65
+ }
66
+ if (worldPath) {
67
+ try {
68
+ const { existsSync } = await import("fs");
69
+ const { join } = await import("path");
70
+ const hasWorld = existsSync(join(worldPath, "world.json"));
71
+ checks.push({
72
+ label: "World file detected",
73
+ status: hasWorld ? "pass" : "fail",
74
+ value: hasWorld ? worldPath : "not found",
75
+ detail: hasWorld ? void 0 : `No world.json found in ${worldPath}`
76
+ });
77
+ } catch {
78
+ checks.push({
79
+ label: "World file detected",
80
+ status: "fail",
81
+ value: "error reading path"
82
+ });
83
+ }
84
+ } else {
85
+ const { existsSync } = await import("fs");
86
+ const { join } = await import("path");
87
+ const candidates = ["./world", "./.neuroverse", "./worlds"];
88
+ let found;
89
+ for (const dir of candidates) {
90
+ if (existsSync(join(dir, "world.json"))) {
91
+ found = dir;
92
+ break;
93
+ }
94
+ }
95
+ checks.push({
96
+ label: "World file detected",
97
+ status: found ? "pass" : "warn",
98
+ value: found ?? "none found",
99
+ detail: found ? void 0 : "Build a world: neuroverse build <input.md>"
100
+ });
101
+ }
102
+ try {
103
+ const { evaluateGuard } = await import("./guard-engine-JLTUARGU.js");
104
+ checks.push({
105
+ label: "Guard engine",
106
+ status: typeof evaluateGuard === "function" ? "pass" : "fail",
107
+ value: "loaded"
108
+ });
109
+ } catch {
110
+ checks.push({ label: "Guard engine", status: "fail", value: "failed to load" });
111
+ }
112
+ try {
113
+ const { validateWorld } = await import("./validate-engine-UIABSIHD.js");
114
+ checks.push({
115
+ label: "Validation engine",
116
+ status: typeof validateWorld === "function" ? "pass" : "fail",
117
+ value: "loaded"
118
+ });
119
+ } catch {
120
+ checks.push({ label: "Validation engine", status: "fail", value: "failed to load" });
121
+ }
122
+ const adapterNames = ["openai", "express", "langchain", "openclaw"];
123
+ const loadedAdapters = [];
124
+ for (const name of adapterNames) {
125
+ try {
126
+ await globImport_adapters(`../adapters/${name}`);
127
+ loadedAdapters.push(name);
128
+ } catch {
129
+ }
130
+ }
131
+ checks.push({
132
+ label: "Adapters",
133
+ status: loadedAdapters.length > 0 ? "pass" : "warn",
134
+ value: loadedAdapters.length > 0 ? loadedAdapters.join(", ") : "none"
135
+ });
136
+ if (json) {
137
+ const hasFailure2 = checks.some((c) => c.status === "fail");
138
+ process.stdout.write(JSON.stringify({
139
+ status: hasFailure2 ? "fail" : "pass",
140
+ checks
141
+ }, null, 2) + "\n");
142
+ process.exit(hasFailure2 ? 1 : 0);
143
+ return;
144
+ }
145
+ process.stderr.write("\nNeuroVerse Environment Check\n");
146
+ process.stderr.write("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n");
147
+ const maxLabel = Math.max(...checks.map((c) => c.label.length));
148
+ for (const check of checks) {
149
+ const icon = check.status === "pass" ? "ok" : check.status === "warn" ? "!!" : "FAIL";
150
+ const pad = " ".repeat(maxLabel - check.label.length);
151
+ process.stderr.write(` ${check.label}${pad} ${icon} ${check.value}
152
+ `);
153
+ if (check.detail) {
154
+ process.stderr.write(` ${" ".repeat(maxLabel)} ${check.detail}
155
+ `);
156
+ }
157
+ }
158
+ const hasFailure = checks.some((c) => c.status === "fail");
159
+ process.stderr.write("\n");
160
+ if (hasFailure) {
161
+ process.stderr.write("Some checks failed. Fix the issues above and re-run.\n");
162
+ } else {
163
+ process.stderr.write("System ready.\n");
164
+ }
165
+ process.stderr.write("\n");
166
+ process.exit(hasFailure ? 1 : 0);
167
+ }
168
+ export {
169
+ main
170
+ };
@@ -4,7 +4,8 @@ import {
4
4
  } from "./chunk-BUWWN2NX.js";
5
5
  import {
6
6
  loadWorld
7
- } from "./chunk-M3TZFGHO.js";
7
+ } from "./chunk-JZPQGIKR.js";
8
+ import "./chunk-YZFATT7X.js";
8
9
 
9
10
  // src/cli/explain.ts
10
11
  function parseArgs(argv) {
@@ -1,12 +1,18 @@
1
1
  import {
2
2
  GUARD_EXIT_CODES
3
3
  } from "./chunk-MWDQ4MJB.js";
4
+ import {
5
+ describeActiveWorld,
6
+ resolveWorldPath
7
+ } from "./chunk-AKW5YVCE.js";
4
8
  import {
5
9
  evaluateGuard
6
- } from "./chunk-B4NF3OLW.js";
10
+ } from "./chunk-4JRYGIO7.js";
7
11
  import {
8
12
  loadWorld
9
- } from "./chunk-M3TZFGHO.js";
13
+ } from "./chunk-JZPQGIKR.js";
14
+ import "./chunk-4QXB6PEO.js";
15
+ import "./chunk-YZFATT7X.js";
10
16
 
11
17
  // src/cli/guard.ts
12
18
  function parseArgs(argv) {
@@ -28,9 +34,6 @@ function parseArgs(argv) {
28
34
  }
29
35
  }
30
36
  }
31
- if (!worldPath) {
32
- throw new Error("--world <path> is required");
33
- }
34
37
  return { worldPath, trace, level };
35
38
  }
36
39
  async function readStdin() {
@@ -43,6 +46,17 @@ async function readStdin() {
43
46
  async function main(argv = process.argv.slice(2)) {
44
47
  try {
45
48
  const args = parseArgs(argv);
49
+ const worldPath = resolveWorldPath(args.worldPath);
50
+ if (!worldPath) {
51
+ throw new Error(
52
+ "No world specified. Use --world <path>, set NEUROVERSE_WORLD, or run `neuroverse world use <name>`"
53
+ );
54
+ }
55
+ const worldInfo = describeActiveWorld(args.worldPath);
56
+ if (worldInfo) {
57
+ process.stderr.write(`Using world: ${worldInfo.name}
58
+ `);
59
+ }
46
60
  const input = await readStdin();
47
61
  if (!input.trim()) {
48
62
  const errorResult = {
@@ -65,7 +79,7 @@ async function main(argv = process.argv.slice(2)) {
65
79
  process.stdout.write(JSON.stringify(errorResult, null, 2) + "\n");
66
80
  process.exit(GUARD_EXIT_CODES.ERROR);
67
81
  }
68
- const world = await loadWorld(args.worldPath);
82
+ const world = await loadWorld(worldPath);
69
83
  const options = { trace: args.trace, level: args.level };
70
84
  const verdict = evaluateGuard(event, world, options);
71
85
  process.stdout.write(JSON.stringify(verdict, null, 2) + "\n");
@@ -271,6 +271,10 @@ interface IntentPattern {
271
271
  interface GuardsConfig {
272
272
  guards: Guard[];
273
273
  intent_vocabulary: Record<string, IntentPattern>;
274
+ /** All known action surfaces (e.g. "shell", "http", "db", "email", "deploy").
275
+ * When declared, the validator checks that every surface has at least one
276
+ * governing guard — surfaces without guards are reported as fail-open. */
277
+ tool_surfaces?: string[];
274
278
  }
275
279
  interface WorldDefinition {
276
280
  world: WorldIdentity;
@@ -287,6 +291,174 @@ interface WorldDefinition {
287
291
  metadata: WorldMetadata;
288
292
  }
289
293
 
294
+ /**
295
+ * Plan Contract — Plan Enforcement Types
296
+ *
297
+ * Defines the input/output contract for plan-based governance.
298
+ *
299
+ * Plans are temporary guard overlays — "mom's rules for this trip."
300
+ * They define what an agent should do (steps) and what it must not
301
+ * exceed (constraints). Plans layer on top of worlds, narrowing
302
+ * behavior without overriding safety or world-level governance.
303
+ *
304
+ * INVARIANTS:
305
+ * - Plans can only restrict, never expand. A plan cannot override a world BLOCK.
306
+ * - Plan enforcement is deterministic: same event + same plan → same verdict.
307
+ * - No AI in the evaluation loop. Parsing and evaluation are pure functions.
308
+ */
309
+ interface PlanStep {
310
+ /** Auto-generated slug from label (e.g., "write_announcement_blog_post"). */
311
+ id: string;
312
+ /** Human-readable step name. */
313
+ label: string;
314
+ /** Optional detail about the step. */
315
+ description?: string;
316
+ /** Restrict this step to specific tools (optional). */
317
+ tools?: string[];
318
+ /** Step IDs that must complete first (optional). */
319
+ requires?: string[];
320
+ /** Semantic tags for action mapping (e.g., ["deploy", "marketing"]). */
321
+ tags?: string[];
322
+ /** Completion condition name (optional). */
323
+ verify?: string;
324
+ /** Current step status. */
325
+ status: 'pending' | 'active' | 'completed' | 'skipped';
326
+ }
327
+ interface PlanConstraint {
328
+ /** Auto-generated constraint ID. */
329
+ id: string;
330
+ /** Constraint type. 'approval' always returns PAUSE until human confirms. */
331
+ type: 'budget' | 'time' | 'scope' | 'approval' | 'custom';
332
+ /** Human-readable description. */
333
+ description: string;
334
+ /** Enforcement mode. */
335
+ enforcement: 'block' | 'pause';
336
+ /** Numeric limit (for budget/time). */
337
+ limit?: number;
338
+ /** Unit for the limit (e.g., "USD", "minutes"). */
339
+ unit?: string;
340
+ /** Pattern that activates this constraint. */
341
+ trigger?: string;
342
+ }
343
+ /**
344
+ * How step completion is determined:
345
+ * - 'trust' — caller asserts completion, plan advances (default)
346
+ * - 'verified' — steps with a `verify` field require evidence to advance;
347
+ * steps without `verify` still advance on trust
348
+ */
349
+ type PlanCompletionMode = 'trust' | 'verified';
350
+ /**
351
+ * Evidence provided when advancing a step in verified mode.
352
+ * The verifier checks that evidence.type matches step.verify.
353
+ */
354
+ interface StepEvidence {
355
+ /** Evidence type — must match the step's `verify` field. */
356
+ type: string;
357
+ /** Proof payload (URL, hash, output snippet, etc.). */
358
+ proof: string;
359
+ /** When the evidence was produced. */
360
+ timestamp?: string;
361
+ }
362
+ /**
363
+ * Result of attempting to advance a step.
364
+ */
365
+ interface AdvanceResult {
366
+ /** Whether the step was successfully advanced. */
367
+ success: boolean;
368
+ /** Updated plan (if success). */
369
+ plan?: PlanDefinition;
370
+ /** Why advancement failed (if !success). */
371
+ reason?: string;
372
+ /** The evidence that was accepted (if verified mode). */
373
+ evidence?: StepEvidence;
374
+ }
375
+ interface PlanDefinition {
376
+ /** Unique plan identifier. */
377
+ plan_id: string;
378
+ /** Human-readable objective. */
379
+ objective: string;
380
+ /** Whether steps must run in order. */
381
+ sequential: boolean;
382
+ /**
383
+ * How step completion is determined.
384
+ * - 'trust' (default) — caller asserts "done", plan advances
385
+ * - 'verified' — steps with `verify` require evidence to advance
386
+ */
387
+ completion: PlanCompletionMode;
388
+ /** The steps in this plan. */
389
+ steps: PlanStep[];
390
+ /** Constraints that apply to this plan. */
391
+ constraints: PlanConstraint[];
392
+ /** Optional parent world ID. */
393
+ world_id?: string;
394
+ /** When this plan was created. */
395
+ created_at: string;
396
+ /** Optional expiry time. */
397
+ expires_at?: string;
398
+ }
399
+ type PlanStatus = 'ON_PLAN' | 'OFF_PLAN' | 'CONSTRAINT_VIOLATED' | 'PLAN_COMPLETE';
400
+ interface PlanVerdict {
401
+ /** Whether the action is allowed by this plan. */
402
+ allowed: boolean;
403
+ /** Plan verdict status. */
404
+ status: PlanStatus;
405
+ /** Why the action was blocked or paused. */
406
+ reason?: string;
407
+ /** Which step this action matched (if any). */
408
+ matchedStep?: string;
409
+ /** Nearest step when OFF_PLAN (for agent self-correction). */
410
+ closestStep?: string;
411
+ /** How close the action was to the nearest step (0-1). */
412
+ similarityScore?: number;
413
+ /** Current plan progress. */
414
+ progress: PlanProgress;
415
+ }
416
+ interface PlanProgress {
417
+ /** Number of completed steps. */
418
+ completed: number;
419
+ /** Total number of steps. */
420
+ total: number;
421
+ /** Completion percentage. */
422
+ percentage: number;
423
+ }
424
+ interface PlanCheck {
425
+ /** The plan being enforced. */
426
+ planId: string;
427
+ /** Whether the action matched a plan step. */
428
+ matched: boolean;
429
+ /** Which step was matched. */
430
+ matchedStepId?: string;
431
+ /** Label of the matched step. */
432
+ matchedStepLabel?: string;
433
+ /** Nearest step when no match (for self-correction). */
434
+ closestStepId?: string;
435
+ /** Label of the nearest step. */
436
+ closestStepLabel?: string;
437
+ /** Similarity score to the nearest step. */
438
+ similarityScore?: number;
439
+ /** Whether step sequence requirements are satisfied. */
440
+ sequenceValid?: boolean;
441
+ /** Results of constraint checks. */
442
+ constraintsChecked: Array<{
443
+ constraintId: string;
444
+ passed: boolean;
445
+ reason?: string;
446
+ }>;
447
+ /** Current progress. */
448
+ progress: {
449
+ completed: number;
450
+ total: number;
451
+ };
452
+ }
453
+ declare const PLAN_EXIT_CODES: {
454
+ readonly ON_PLAN: 0;
455
+ readonly OFF_PLAN: 1;
456
+ readonly CONSTRAINT_VIOLATED: 2;
457
+ readonly ERROR: 3;
458
+ readonly PLAN_COMPLETE: 4;
459
+ };
460
+ type PlanExitCode = (typeof PLAN_EXIT_CODES)[keyof typeof PLAN_EXIT_CODES];
461
+
290
462
  /**
291
463
  * Guard Contract — CLI Governance Evaluation Types
292
464
  *
@@ -406,6 +578,8 @@ interface EvaluationTrace {
406
578
  invariantChecks: InvariantCheck[];
407
579
  /** Safety checks (injection, scope escape) */
408
580
  safetyChecks: SafetyCheck[];
581
+ /** Plan enforcement check (Phase 1.5) — present when a plan is active */
582
+ planCheck?: PlanCheck;
409
583
  /** Every role rule checked */
410
584
  roleChecks: RoleCheck[];
411
585
  /** Every declarative guard checked */
@@ -490,7 +664,7 @@ interface LevelCheck {
490
664
  */
491
665
  interface PrecedenceResolution {
492
666
  /** Which check category produced the final verdict */
493
- decidingLayer: 'session-allowlist' | 'safety' | 'role' | 'guard' | 'kernel-rule' | 'level-constraint' | 'default-allow';
667
+ decidingLayer: 'session-allowlist' | 'safety' | 'plan-enforcement' | 'role' | 'guard' | 'kernel-rule' | 'level-constraint' | 'default-allow';
494
668
  /** Specific ID of the deciding check (guard ID, rule ID, etc.) */
495
669
  decidingId?: string;
496
670
  /** Resolution strategy used */
@@ -517,6 +691,12 @@ interface GuardEngineOptions {
517
691
  * The caller owns persistence (allow-once, allow-always, etc.).
518
692
  */
519
693
  sessionAllowlist?: Set<string>;
694
+ /**
695
+ * Active plan overlay — temporary task-scoped governance.
696
+ * When set, plan enforcement runs at Phase 1.5 (after safety, before roles).
697
+ * Plans can only restrict, never expand.
698
+ */
699
+ plan?: PlanDefinition;
520
700
  }
521
701
  declare const GUARD_EXIT_CODES: {
522
702
  readonly ALLOW: 0;
@@ -526,4 +706,4 @@ declare const GUARD_EXIT_CODES: {
526
706
  };
527
707
  type GuardExitCode = (typeof GUARD_EXIT_CODES)[keyof typeof GUARD_EXIT_CODES];
528
708
 
529
- export { type EvaluationTrace as E, type GuardVerdict as G, type InvariantCheck as I, type KernelRuleCheck as K, type LevelCheck as L, type PrecedenceResolution as P, type RoleCheck as R, type SafetyCheck as S, type ViabilityStatus as V, type WorldDefinition as W, type GuardEvent as a, type GuardEngineOptions as b, GUARD_EXIT_CODES as c, type GuardCheck as d, type GuardExitCode as e, type GuardStatus as f, type VerdictEvidence as g };
709
+ export { type AdvanceResult as A, type EvaluationTrace as E, type GuardVerdict as G, type InvariantCheck as I, type KernelRuleCheck as K, type LevelCheck as L, type PlanDefinition as P, type RoleCheck as R, type StepEvidence as S, type ViabilityStatus as V, type WorldDefinition as W, type GuardEvent as a, type PlanProgress as b, type GuardEngineOptions as c, type PlanVerdict as d, type PlanCheck as e, GUARD_EXIT_CODES as f, type GuardCheck as g, type GuardExitCode as h, type GuardStatus as i, PLAN_EXIT_CODES as j, type PlanCompletionMode as k, type PlanConstraint as l, type PlanExitCode as m, type PlanStatus as n, type PlanStep as o, type PrecedenceResolution as p, type SafetyCheck as q, type VerdictEvidence as r };