@zanii/blackbox 0.0.0-stage → 0.2.0

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 (135) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +109 -2
  3. package/dist/agents/index.d.ts +34 -0
  4. package/dist/agents/index.js +73 -0
  5. package/dist/analysis/detectors.d.ts +36 -0
  6. package/dist/analysis/detectors.js +339 -0
  7. package/dist/analysis/faults.d.ts +9 -0
  8. package/dist/analysis/faults.js +250 -0
  9. package/dist/analysis/index.d.ts +68 -0
  10. package/dist/analysis/index.js +388 -0
  11. package/dist/analysis/landing.d.ts +25 -0
  12. package/dist/analysis/landing.js +225 -0
  13. package/dist/analysis/memory.d.ts +13 -0
  14. package/dist/analysis/memory.js +33 -0
  15. package/dist/analysis/waste.d.ts +29 -0
  16. package/dist/analysis/waste.js +79 -0
  17. package/dist/approvals/index.d.ts +11 -0
  18. package/dist/approvals/index.js +27 -0
  19. package/dist/approvals/warnings.d.ts +2 -0
  20. package/dist/approvals/warnings.js +28 -0
  21. package/dist/attest/index.d.ts +17 -0
  22. package/dist/attest/index.js +106 -0
  23. package/dist/authority/index.d.ts +24 -0
  24. package/dist/authority/index.js +77 -0
  25. package/dist/billing/index.d.ts +99 -0
  26. package/dist/billing/index.js +174 -0
  27. package/dist/cli.d.ts +2 -0
  28. package/dist/cli.js +1057 -0
  29. package/dist/client/index.d.ts +146 -0
  30. package/dist/client/index.js +210 -0
  31. package/dist/compliance/index.d.ts +41 -0
  32. package/dist/compliance/index.js +96 -0
  33. package/dist/cost/index.d.ts +133 -0
  34. package/dist/cost/index.js +293 -0
  35. package/dist/data/index.d.ts +191 -0
  36. package/dist/data/index.js +762 -0
  37. package/dist/directives/index.d.ts +35 -0
  38. package/dist/directives/index.js +80 -0
  39. package/dist/drills/index.d.ts +43 -0
  40. package/dist/drills/index.js +101 -0
  41. package/dist/duty/index.d.ts +21 -0
  42. package/dist/duty/index.js +68 -0
  43. package/dist/fleet/index.d.ts +141 -0
  44. package/dist/fleet/index.js +454 -0
  45. package/dist/hooks/ai-sdk.d.ts +42 -0
  46. package/dist/hooks/ai-sdk.js +62 -0
  47. package/dist/hooks/claude-agent-sdk.d.ts +14 -0
  48. package/dist/hooks/claude-agent-sdk.js +70 -0
  49. package/dist/hooks/index.d.ts +7 -0
  50. package/dist/hooks/index.js +10 -0
  51. package/dist/hooks/langchain-agent.d.ts +69 -0
  52. package/dist/hooks/langchain-agent.js +163 -0
  53. package/dist/hooks/langchain.d.ts +41 -0
  54. package/dist/hooks/langchain.js +216 -0
  55. package/dist/hooks/langgraph-checkpoint.d.ts +12 -0
  56. package/dist/hooks/langgraph-checkpoint.js +73 -0
  57. package/dist/hooks/memory.d.ts +17 -0
  58. package/dist/hooks/memory.js +64 -0
  59. package/dist/hooks/openai-agents.d.ts +6 -0
  60. package/dist/hooks/openai-agents.js +40 -0
  61. package/dist/hooks/protect.d.ts +7 -0
  62. package/dist/hooks/protect.js +39 -0
  63. package/dist/hooks/providers.d.ts +16 -0
  64. package/dist/hooks/providers.js +149 -0
  65. package/dist/hooks/shared.d.ts +11 -0
  66. package/dist/hooks/shared.js +39 -0
  67. package/dist/index.d.ts +46 -0
  68. package/dist/index.js +48 -0
  69. package/dist/investigate/index.d.ts +66 -0
  70. package/dist/investigate/index.js +119 -0
  71. package/dist/mcp-server/index.d.ts +85 -0
  72. package/dist/mcp-server/index.js +216 -0
  73. package/dist/mcp-wrap/index.d.ts +17 -0
  74. package/dist/mcp-wrap/index.js +170 -0
  75. package/dist/money/index.d.ts +114 -0
  76. package/dist/money/index.js +622 -0
  77. package/dist/occurrence/index.d.ts +108 -0
  78. package/dist/occurrence/index.js +168 -0
  79. package/dist/ocsf/index.d.ts +22 -0
  80. package/dist/ocsf/index.js +168 -0
  81. package/dist/otlp/index.d.ts +24 -0
  82. package/dist/otlp/index.js +143 -0
  83. package/dist/packs/index.d.ts +48 -0
  84. package/dist/packs/index.js +343 -0
  85. package/dist/policy/delta.d.ts +11 -0
  86. package/dist/policy/delta.js +39 -0
  87. package/dist/policy/drafts.d.ts +34 -0
  88. package/dist/policy/drafts.js +129 -0
  89. package/dist/policy/index.d.ts +47 -0
  90. package/dist/policy/index.js +154 -0
  91. package/dist/precog/index.d.ts +96 -0
  92. package/dist/precog/index.js +167 -0
  93. package/dist/precog/intervention.d.ts +22 -0
  94. package/dist/precog/intervention.js +44 -0
  95. package/dist/precog/normal.d.ts +31 -0
  96. package/dist/precog/normal.js +89 -0
  97. package/dist/preflight/index.d.ts +11 -0
  98. package/dist/preflight/index.js +19 -0
  99. package/dist/ratings/index.d.ts +21 -0
  100. package/dist/ratings/index.js +48 -0
  101. package/dist/reconcile/claude-code.d.ts +19 -0
  102. package/dist/reconcile/claude-code.js +220 -0
  103. package/dist/reconcile/codex.d.ts +5 -0
  104. package/dist/reconcile/codex.js +191 -0
  105. package/dist/reconcile/index.d.ts +19 -0
  106. package/dist/reconcile/index.js +50 -0
  107. package/dist/reconcile/record.d.ts +49 -0
  108. package/dist/reconcile/record.js +225 -0
  109. package/dist/reconcile/shared.d.ts +65 -0
  110. package/dist/reconcile/shared.js +113 -0
  111. package/dist/replay/index.d.ts +11 -0
  112. package/dist/replay/index.js +64 -0
  113. package/dist/replay/repair.d.ts +10 -0
  114. package/dist/replay/repair.js +62 -0
  115. package/dist/session/drain.d.ts +13 -0
  116. package/dist/session/drain.js +35 -0
  117. package/dist/session/index.d.ts +275 -0
  118. package/dist/session/index.js +681 -0
  119. package/dist/undo/index.d.ts +45 -0
  120. package/dist/undo/index.js +212 -0
  121. package/dist/verify/anchor.d.ts +54 -0
  122. package/dist/verify/anchor.js +77 -0
  123. package/dist/verify/chain.d.ts +27 -0
  124. package/dist/verify/chain.js +105 -0
  125. package/dist/verify/envelope.d.ts +28 -0
  126. package/dist/verify/envelope.js +55 -0
  127. package/dist/verify/index.d.ts +3 -0
  128. package/dist/verify/index.js +3 -0
  129. package/dist/version.d.ts +1 -0
  130. package/dist/version.js +2 -0
  131. package/dist/weather/index.d.ts +24 -0
  132. package/dist/weather/index.js +45 -0
  133. package/dist/workspace-receipt/index.d.ts +15 -0
  134. package/dist/workspace-receipt/index.js +121 -0
  135. package/package.json +56 -3
@@ -0,0 +1,40 @@
1
+ // OpenAI Agents SDK (JS) run hooks (spec/sdk.md §5). Mirrors hooks/openai_agents.py.
2
+ //
3
+ // const runner = new Runner(); attachBlackbox(runner, session); await runner.run(agent, "…");
4
+ //
5
+ // The JS SDK's hooks are events on the Runner (agent / handoff / tool); it has no model-call event,
6
+ // so model-call ids come from the gateway alone here.
7
+ import { neverThrow } from "./shared.js";
8
+ const nameOf = (x) => String(x?.name ?? "agent").slice(0, 256);
9
+ /** Audit K23: the SDK turns a tool's exception into this answer (its default error function), so a
10
+ * tool that failed isn't recorded as a success. */
11
+ const TOOL_ERROR = "An error occurred while running the tool.";
12
+ const failed = (result) => typeof result === "string" && result.startsWith(TOOL_ERROR);
13
+ export function attachBlackbox(runner, session) {
14
+ const on = (event, listener) => runner.on(event, ((...args) => neverThrow(() => listener(...args))));
15
+ on("agent_start", (_context, agent) => session.event("step", nameOf(agent), {}));
16
+ on("agent_handoff", (_context, from, to) => session.event("step", nameOf(to), { handoff_from: nameOf(from) }));
17
+ on("agent_tool_start", (_context, agent, tool, details) => {
18
+ const call = details
19
+ ?.toolCall;
20
+ let args = call?.arguments;
21
+ try {
22
+ args = typeof args === "string" ? JSON.parse(args) : args;
23
+ }
24
+ catch { }
25
+ session.event("tool.call", nameOf(tool), {
26
+ agent: nameOf(agent),
27
+ ...(call?.callId ? { call_id: call.callId } : {}),
28
+ ...(args === undefined ? {} : { args }),
29
+ });
30
+ });
31
+ on("agent_tool_end", (_context, agent, tool, result, details) => {
32
+ const callId = details?.toolCall?.callId;
33
+ session.event("tool.result", nameOf(tool), {
34
+ ok: !failed(result),
35
+ agent: nameOf(agent),
36
+ ...(callId ? { call_id: callId } : {}),
37
+ ...(failed(result) ? { error: String(result).slice(0, 500) } : {}),
38
+ });
39
+ });
40
+ }
@@ -0,0 +1,7 @@
1
+ export declare const MANAGED_START = "<!-- blackbox:managed:start -->";
2
+ export declare const MANAGED_END = "<!-- blackbox:managed:end -->";
3
+ /** The managed block (markers included), or null when the text has none. */
4
+ export declare function managedBlock(text: string): string | null;
5
+ /** Why this file tool call must not run, or null. `current` is the file's text now (null when
6
+ * it doesn't exist). Tools: write_file {content}, edit_file {old_string, new_string}, delete. */
7
+ export declare function protectedEdit(current: string | null, tool: string, args: Record<string, unknown>): string | null;
@@ -0,0 +1,39 @@
1
+ // Protected regions (spec/sdk.md §5.2, idea S5): a machine-managed block in a file the agent may
2
+ // edit (an AGENTS.md, a memory file), between `<!-- blackbox:managed:start -->` and
3
+ // `<!-- blackbox:managed:end -->`. A write, edit or delete that would change or remove it is
4
+ // refused before the tool runs. Mirrors protect.py.
5
+ export const MANAGED_START = "<!-- blackbox:managed:start -->";
6
+ export const MANAGED_END = "<!-- blackbox:managed:end -->";
7
+ /** The managed block (markers included), or null when the text has none. */
8
+ export function managedBlock(text) {
9
+ const i = text.indexOf(MANAGED_START);
10
+ const j = i < 0 ? -1 : text.indexOf(MANAGED_END, i);
11
+ return i < 0 || j < 0 ? null : text.slice(i, j + MANAGED_END.length);
12
+ }
13
+ const str = (v) => (typeof v === "string" ? v : undefined);
14
+ /** Why this file tool call must not run, or null. `current` is the file's text now (null when
15
+ * it doesn't exist). Tools: write_file {content}, edit_file {old_string, new_string}, delete. */
16
+ export function protectedEdit(current, tool, args) {
17
+ const block = current === null ? null : managedBlock(current);
18
+ if (block === null)
19
+ return null;
20
+ const path = str(args.file_path) ?? str(args.path) ?? "the file";
21
+ const refuse = `blackbox: ${path} has a machine-managed block (between the blackbox:managed markers) that can't be changed or removed. The edit wasn't applied.`;
22
+ if (tool === "delete" || tool === "delete_file" || tool === "rm")
23
+ return `${refuse}`;
24
+ if (tool === "write_file") {
25
+ const content = str(args.content) ?? "";
26
+ return managedBlock(content) === block ? null : refuse;
27
+ }
28
+ if (tool === "edit_file") {
29
+ const oldText = str(args.old_string);
30
+ const newText = str(args.new_string) ?? "";
31
+ if (oldText === undefined || !current.includes(oldText))
32
+ return null; // the tool fails itself
33
+ const after = args.replace_all === true
34
+ ? current.split(oldText).join(newText)
35
+ : current.replace(oldText, () => newText);
36
+ return managedBlock(after) === block ? null : refuse;
37
+ }
38
+ return null;
39
+ }
@@ -0,0 +1,16 @@
1
+ import { type EventSink } from "./shared.ts";
2
+ /** The ids a provider's response (or its first stream event) carries, as `llmCall` takes them:
3
+ * Anthropic, OpenAI and OpenAI-compatible APIs (by `object`), Gemini and Vertex (`responseId`), and
4
+ * Bedrock (the AWS SDK's `$metadata.requestId`) (audit K4). */
5
+ export declare function llmIdsOf(response: unknown): Record<string, string>;
6
+ /** `client.messages.create` and `.stream` report each model call to the session. */
7
+ export declare function wrapAnthropic<T extends object>(client: T, sink: EventSink): T;
8
+ /** `client.chat.completions.create` / `.stream` and `client.responses.create` / `.stream` report
9
+ * each model call. */
10
+ export declare function wrapOpenAI<T extends object>(client: T, sink: EventSink): T;
11
+ /** Audit K4: Google's `@google/genai` client (Gemini, and Vertex AI with `vertexai: true`):
12
+ * `models.generateContent` and `models.generateContentStream` report each model call. */
13
+ export declare function wrapGemini<T extends object>(client: T, sink: EventSink): T;
14
+ /** Audit K4: the AWS SDK's `BedrockRuntimeClient`: every `send(command)` (Converse, ConverseStream,
15
+ * InvokeModel, …) reports its request id, which the gateway records from `x-amzn-requestid`. */
16
+ export declare function wrapBedrock<T extends object>(client: T, sink: EventSink): T;
@@ -0,0 +1,149 @@
1
+ // Audit S9 / S18: report model calls made with the official Anthropic and OpenAI clients, so the
2
+ // dual witness (spec/findings.md §2) works without the app calling llmCall by hand. Duck-typed: no
3
+ // dependency on either client. Mirrors sdks/python/src/zanii_blackbox/hooks/providers.py.
4
+ //
5
+ // const anthropic = wrapAnthropic(new Anthropic({ baseURL: gateway }), session);
6
+ // const openai = wrapOpenAI(new OpenAI({ baseURL: gateway }), session);
7
+ import { llmIds, neverThrow, providerOf } from "./shared.js";
8
+ /** The ids a provider's response (or its first stream event) carries, as `llmCall` takes them:
9
+ * Anthropic, OpenAI and OpenAI-compatible APIs (by `object`), Gemini and Vertex (`responseId`), and
10
+ * Bedrock (the AWS SDK's `$metadata.requestId`) (audit K4). */
11
+ export function llmIdsOf(response) {
12
+ const r = (response ?? {});
13
+ const google = r.responseId;
14
+ if (typeof google === "string" && ("candidates" in r || "usageMetadata" in r))
15
+ return {
16
+ provider: "gemini",
17
+ response_id: google,
18
+ ...(typeof r.modelVersion === "string" ? { model: r.modelVersion } : {}),
19
+ };
20
+ const aws = r.$metadata?.requestId;
21
+ if (typeof aws === "string")
22
+ return { provider: "bedrock", request_id: aws };
23
+ // A stream event: Anthropic's message_start carries `message`, OpenAI's response.* `response`.
24
+ const inner = (typeof r.message === "object" && r.message) ||
25
+ (typeof r.response === "object" && r.response) ||
26
+ r;
27
+ const o = inner;
28
+ const id = typeof o.id === "string" ? o.id : undefined;
29
+ const provider = providerOf(id, typeof o.object === "string" ? o.object : undefined);
30
+ if (!provider)
31
+ return {};
32
+ const requestId = typeof r._request_id === "string"
33
+ ? r._request_id
34
+ : typeof o._request_id === "string"
35
+ ? o._request_id
36
+ : undefined;
37
+ return {
38
+ provider,
39
+ ...llmIds(id, requestId, typeof o.model === "string" ? o.model : undefined, typeof o.object === "string" ? o.object : undefined),
40
+ };
41
+ }
42
+ /** `client.messages.create` and `.stream` report each model call to the session. */
43
+ export function wrapAnthropic(client, sink) {
44
+ return wrap(client, [
45
+ ["messages", "create"],
46
+ ["messages", "stream"],
47
+ ["messages", "parse"],
48
+ // audit K18: the beta namespace (structured output, tools in preview) goes to the same API
49
+ ["beta", "messages", "create"],
50
+ ["beta", "messages", "stream"],
51
+ ["beta", "messages", "parse"],
52
+ ], sink);
53
+ }
54
+ /** `client.chat.completions.create` / `.stream` and `client.responses.create` / `.stream` report
55
+ * each model call. */
56
+ export function wrapOpenAI(client, sink) {
57
+ return wrap(client, [
58
+ ["chat", "completions", "create"],
59
+ ["chat", "completions", "stream"],
60
+ ["responses", "create"],
61
+ ["responses", "stream"],
62
+ // audit K18: structured output and the beta namespace
63
+ ["chat", "completions", "parse"],
64
+ ["responses", "parse"],
65
+ ["beta", "chat", "completions", "parse"],
66
+ ["beta", "chat", "completions", "stream"],
67
+ ], sink);
68
+ }
69
+ /** Audit K4: Google's `@google/genai` client (Gemini, and Vertex AI with `vertexai: true`):
70
+ * `models.generateContent` and `models.generateContentStream` report each model call. */
71
+ export function wrapGemini(client, sink) {
72
+ return wrap(client, [
73
+ ["models", "generateContent"],
74
+ ["models", "generateContentStream"],
75
+ ], sink);
76
+ }
77
+ /** Audit K4: the AWS SDK's `BedrockRuntimeClient`: every `send(command)` (Converse, ConverseStream,
78
+ * InvokeModel, …) reports its request id, which the gateway records from `x-amzn-requestid`. */
79
+ export function wrapBedrock(client, sink) {
80
+ return wrap(client, [["send"]], sink);
81
+ }
82
+ /** The streaming helpers' promise of the final message, which carries the ids. */
83
+ const FINAL = ["finalMessage", "finalChatCompletion", "finalResponse"];
84
+ function wrap(target, paths, sink) {
85
+ return new Proxy(target, {
86
+ get(obj, prop, receiver) {
87
+ const value = Reflect.get(obj, prop, receiver);
88
+ const here = paths.filter((p) => p[0] === prop);
89
+ if (here.length === 0 || value === null || value === undefined)
90
+ return value;
91
+ if (here.some((p) => p.length === 1) && typeof value === "function")
92
+ return (...args) => {
93
+ const result = value.apply(obj, args);
94
+ neverThrow(() => observe(result, sink));
95
+ return result; // the client's own promise, untouched (e.g. APIPromise.withResponse())
96
+ };
97
+ return typeof value === "object"
98
+ ? wrap(value, here.map((p) => p.slice(1)), sink)
99
+ : value;
100
+ },
101
+ });
102
+ }
103
+ function observe(result, sink) {
104
+ const then = result?.then;
105
+ if (typeof then !== "function") {
106
+ seen(result, sink);
107
+ return;
108
+ }
109
+ // Registered before the caller's own await, so a stream is patched before it's iterated.
110
+ result.then((r) => neverThrow(() => seen(r, sink)), () => { });
111
+ }
112
+ function seen(result, sink) {
113
+ if (result === null || typeof result !== "object")
114
+ return;
115
+ // A streaming helper (e.g. messages.stream()): whatever way the app reads it, its final message
116
+ // resolves once the stream ends.
117
+ for (const name of FINAL) {
118
+ const final = result[name];
119
+ if (typeof final === "function") {
120
+ final.call(result).then((m) => neverThrow(() => report(llmIdsOf(m), sink)), () => { });
121
+ return;
122
+ }
123
+ }
124
+ const iter = result[Symbol.asyncIterator];
125
+ if (typeof iter !== "function") {
126
+ report(llmIdsOf(result), sink);
127
+ return;
128
+ }
129
+ // A stream: the ids come with its first event that has one; the stream itself is unchanged.
130
+ const original = iter.bind(result);
131
+ let reported = false;
132
+ result[Symbol.asyncIterator] = async function* () {
133
+ for await (const event of { [Symbol.asyncIterator]: original }) {
134
+ if (!reported)
135
+ neverThrow(() => {
136
+ const ids = llmIdsOf(event);
137
+ if (ids.provider) {
138
+ reported = true;
139
+ report(ids, sink);
140
+ }
141
+ });
142
+ yield event;
143
+ }
144
+ };
145
+ }
146
+ function report(ids, sink) {
147
+ if (ids.provider)
148
+ sink.event("llm.call", ids.provider, { ...ids });
149
+ }
@@ -0,0 +1,11 @@
1
+ /** A BlackboxSession, or anything with the same `event` method. */
2
+ export interface EventSink {
3
+ event(type: string, name?: string, data?: Record<string, unknown>): void;
4
+ }
5
+ /** Runs a hook body; a hook must never break the framework it's attached to (spec/sdk.md §4). */
6
+ export declare function neverThrow(fn: () => void): void;
7
+ /** A provider's response id → the key the gateway records it under (spec/findings.md §2). */
8
+ export declare function llmIds(id: string | undefined, requestId?: string, model?: string,
9
+ /** An OpenAI-style `object` field: how an OpenAI-compatible API's own ids are told apart (K4). */
10
+ object?: string): Record<string, string>;
11
+ export declare function providerOf(id: string | undefined, object?: string): string | undefined;
@@ -0,0 +1,39 @@
1
+ // What both hook adapters share. Mirrors sdks/python/src/zanii_blackbox/hooks/shared.py.
2
+ /** Runs a hook body; a hook must never break the framework it's attached to (spec/sdk.md §4). */
3
+ export function neverThrow(fn) {
4
+ try {
5
+ fn();
6
+ }
7
+ catch { }
8
+ }
9
+ /** A provider's response id → the key the gateway records it under (spec/findings.md §2). */
10
+ export function llmIds(id, requestId, model,
11
+ /** An OpenAI-style `object` field: how an OpenAI-compatible API's own ids are told apart (K4). */
12
+ object) {
13
+ const ids = {};
14
+ if (id) {
15
+ if (id.startsWith("resp_") || object === "response")
16
+ ids.response_id = id;
17
+ else if (id.startsWith("chatcmpl") || object?.startsWith("chat.completion"))
18
+ ids.completion_id = id;
19
+ else
20
+ ids.message_id = id;
21
+ }
22
+ if (requestId)
23
+ ids.request_id = requestId;
24
+ if (model)
25
+ ids.model = model;
26
+ return ids;
27
+ }
28
+ export function providerOf(id, object) {
29
+ if (!id)
30
+ return undefined;
31
+ if (id.startsWith("msg_"))
32
+ return "anthropic";
33
+ if (id.startsWith("resp_") || id.startsWith("chatcmpl"))
34
+ return "openai";
35
+ // audit K4: an OpenAI-compatible API (vLLM, Azure, Jais, …) with ids of its own
36
+ if (object === "response" || object?.startsWith("chat.completion"))
37
+ return "openai";
38
+ return undefined;
39
+ }
@@ -0,0 +1,46 @@
1
+ export { causality, memoryXray } from "./agents/index.ts";
2
+ export { type DetectorOptions, detectors, fingerprint } from "./analysis/detectors.ts";
3
+ export { FAULTS, type Fault, faultOf } from "./analysis/faults.ts";
4
+ export { type AnalyzeOptions, analyze, type ClaimVerdict, type CriterionResult, checkFlightPlan, checkpointReplay, dualWitness, eventsOf, type Finding as AnalysisFinding, findingKey, type Landing, landing, OUTCOMES, type Outcome, type OutcomeRollup, rollup, type Severity, type WasteReason, type WasteReport, waste, } from "./analysis/index.ts";
5
+ export { type ApprovalFinding, approvalFindings } from "./approvals/index.ts";
6
+ export { textWarnings } from "./approvals/warnings.ts";
7
+ export { type Attestation, attest, isReadOnly, normalise, parseCommand } from "./attest/index.ts";
8
+ export { type AuthorityFinding, authorityAt, authorityTimeline, automationSurprise, type Mode as AuthorityMode, type Span as AuthoritySpan, } from "./authority/index.ts";
9
+ export { type Invoice, type InvoiceLine, invoice, loadPlans, type Plan, type Plans, renderTaxInvoice, stripeSignatureOk, type TaxInvoice, type TaxInvoiceInput, taxInvoice, } from "./billing/index.ts";
10
+ export { BlackboxApiError, type Client, type ClientOptions, client, type SessionQuery, } from "./client/index.ts";
11
+ export { complianceFacts, complianceReport, type Facts, type Framework, type Report as ComplianceReport, renderReport, } from "./compliance/index.ts";
12
+ export { type CallCost, type CostReport, callMicroUsd, effectivePrice, formatAed, type LoadedPrices, loadPrices, type ModelPrice, type PriceTable, priceCall, priceFor, promptTokens, requestsOf, sessionCost, type Tokens, toAedFils, tokensOf, } from "./cost/index.ts";
13
+ export { type AuditRow, CORE_EVIDENCE, CORE_IDENTIFIERS, type Connector as AuditConnector, canaryIdentifier, checkAuditConnector, type DataFinding, type DataRules, dataClasses, dataFindings, dataFingerprint, dataMeta, dataScan, dataTopology, hasEvidence, type Identifier, type Lineage, lineage, luhn, normalizeValue, parseAuditLog, parseCsv, reconcileSystem, type SystemReport, type Topology, toolWitness, unevidenced, verifyToolWitness, witnessOf, } from "./data/index.ts";
14
+ export { type Directive, type DirectiveItem, type DirectiveOptions, directives, fleetDirectives, } from "./directives/index.ts";
15
+ export { checkDrill, drillReport, type Fault as DrillFault } from "./drills/index.ts";
16
+ export { checkDuty, type DutyFinding, type DutyLimits, dutyFindings } from "./duty/index.ts";
17
+ export { aggregateFindings, airworthiness, type Collision, collisions, didFromSeed, type FindingGroup, incidentReport, logbook, type Summary, sessionSummary, signatureOf, signatures, signCertificate, verifyCertificate, } from "./fleet/index.ts";
18
+ export { attachBlackbox, BlackboxAgentHooks, BlackboxCallbackHandler, type BlackboxCallbacks, blackboxAgentHooks, blackboxCallbacks, blackboxMiddleware, type EventSink, llmIds, llmIdsOf, trackMemory, wrapAnthropic, wrapBedrock, wrapGemini, wrapOpenAI, } from "./hooks/index.ts";
19
+ export { type AgentSink, BlackboxStoppedError, blackboxAgentMiddleware, blackboxHitl, type HitlRequest, } from "./hooks/langchain-agent.ts";
20
+ export { blackboxCheckpointer } from "./hooks/langgraph-checkpoint.ts";
21
+ export { MANAGED_END, MANAGED_START, managedBlock, protectedEdit } from "./hooks/protect.ts";
22
+ export { type Investigation, investigation, renderInvestigation, } from "./investigate/index.ts";
23
+ export { type McpWrapOptions, mcpWrap } from "./mcp-wrap/index.ts";
24
+ export { type AmountUnit, anthropicStatement, type Baseline, baselines, type Connector, checkConnector, checkStatement, csvStatement, customStatement, decimalToMicroUsd, fuel, modelSpend, openaiStatement, pageParams, parseXml, reconcileBilling, requestFor, resolvePath, type Statement, } from "./money/index.ts";
25
+ export { filingPack, type OccurrenceFacts, type OccurrenceFramework, type OccurrenceReport, occurrenceFacts, occurrenceReport, renderOccurrence, } from "./occurrence/index.ts";
26
+ export { ingestOcsf, type OcsfEvent, type OcsfVersion, ocsfLine, toOcsf } from "./ocsf/index.ts";
27
+ export { toOtlp } from "./otlp/index.ts";
28
+ export { checkIdentifier, checkPack, corePack, type PackEntry, packData, packFrameworks, } from "./packs/index.ts";
29
+ export { type PolicyChange, type PolicyDelta, policyDelta } from "./policy/delta.ts";
30
+ export { type Draft, type DraftGroup, policyDrafts } from "./policy/drafts.ts";
31
+ export { audited, type CompiledPolicy, compilePolicy, type Decision, decide, loadPolicy, type Policy, policyFindings, type Rule, } from "./policy/index.ts";
32
+ export { calibration, FEATURES, features, MIN_EACH, type PrecogModel, precogFindings, precogReport, predict, prefixOf, splitOf, TARGET, train, } from "./precog/index.ts";
33
+ export { type InterventionEvidence, interventionEvidence, interventionGain, } from "./precog/intervention.ts";
34
+ export { activities, buildNormal, type NormalModel, type NormalScore, normalScore, normalThreshold, } from "./precog/normal.ts";
35
+ export { type PreflightFinding, preflightFindings } from "./preflight/index.ts";
36
+ export { type Rating, type TypeUnratedFinding, typeRatings, typeUnrated, } from "./ratings/index.ts";
37
+ export { type Finding, type FindingCode, type Harness, loadLocal, type ReconcileOptions, RecordNotVerified, type Report, reconcile, } from "./reconcile/index.ts";
38
+ export { cassette, requestKey, type Take } from "./replay/index.ts";
39
+ export { ORPHAN_TEXT, repairToolCalls } from "./replay/repair.ts";
40
+ export { type DrainResult, drainSpools } from "./session/drain.ts";
41
+ export { BlackboxSession, checkEgress, type EgressCheck, type FlightPlan, type LlmCallIds, type SessionError, type SessionOptions, type SessionState, type SessionStats, session, stableEventId, } from "./session/index.ts";
42
+ export { type Compensation, checkCompensations, runUndo, type UndoFinding, type UndoStatus, type UndoStep, undoFindings, undoPlan, } from "./undo/index.ts";
43
+ export * from "./verify/index.ts";
44
+ export { VERSION } from "./version.ts";
45
+ export { type Conditions, type Sample, weather } from "./weather/index.ts";
46
+ export { postReceipt, receiptFor, type Tree, workspaceTree } from "./workspace-receipt/index.ts";
package/dist/index.js ADDED
@@ -0,0 +1,48 @@
1
+ // Public API of @zanii/blackbox. Everything customers can import is re-exported here.
2
+ // Keep this file in step with sdks/python/src/zanii_blackbox/__init__.py (the SDKs mirror each other).
3
+ export { causality, memoryXray } from "./agents/index.js";
4
+ export { detectors, fingerprint } from "./analysis/detectors.js";
5
+ export { FAULTS, faultOf } from "./analysis/faults.js";
6
+ export { analyze, checkFlightPlan, checkpointReplay, dualWitness, eventsOf, findingKey, landing, OUTCOMES, rollup, waste, } from "./analysis/index.js";
7
+ export { approvalFindings } from "./approvals/index.js";
8
+ export { textWarnings } from "./approvals/warnings.js";
9
+ export { attest, isReadOnly, normalise, parseCommand } from "./attest/index.js";
10
+ export { authorityAt, authorityTimeline, automationSurprise, } from "./authority/index.js";
11
+ export { invoice, loadPlans, renderTaxInvoice, stripeSignatureOk, taxInvoice, } from "./billing/index.js";
12
+ export { BlackboxApiError, client, } from "./client/index.js";
13
+ export { complianceFacts, complianceReport, renderReport, } from "./compliance/index.js";
14
+ export { callMicroUsd, effectivePrice, formatAed, loadPrices, priceCall, priceFor, promptTokens, requestsOf, sessionCost, toAedFils, tokensOf, } from "./cost/index.js";
15
+ export { CORE_EVIDENCE, CORE_IDENTIFIERS, canaryIdentifier, checkAuditConnector, dataClasses, dataFindings, dataFingerprint, dataMeta, dataScan, dataTopology, hasEvidence, lineage, luhn, normalizeValue, parseAuditLog, parseCsv, reconcileSystem, toolWitness, unevidenced, verifyToolWitness, witnessOf, } from "./data/index.js";
16
+ export { directives, fleetDirectives, } from "./directives/index.js";
17
+ export { checkDrill, drillReport } from "./drills/index.js";
18
+ export { checkDuty, dutyFindings } from "./duty/index.js";
19
+ export { aggregateFindings, airworthiness, collisions, didFromSeed, incidentReport, logbook, sessionSummary, signatureOf, signatures, signCertificate, verifyCertificate, } from "./fleet/index.js";
20
+ export { attachBlackbox, BlackboxAgentHooks, BlackboxCallbackHandler, blackboxAgentHooks, blackboxCallbacks, blackboxMiddleware, llmIds, llmIdsOf, trackMemory, wrapAnthropic, wrapBedrock, wrapGemini, wrapOpenAI, } from "./hooks/index.js";
21
+ export { BlackboxStoppedError, blackboxAgentMiddleware, blackboxHitl, } from "./hooks/langchain-agent.js";
22
+ export { blackboxCheckpointer } from "./hooks/langgraph-checkpoint.js";
23
+ export { MANAGED_END, MANAGED_START, managedBlock, protectedEdit } from "./hooks/protect.js";
24
+ export { investigation, renderInvestigation, } from "./investigate/index.js";
25
+ export { mcpWrap } from "./mcp-wrap/index.js";
26
+ export { anthropicStatement, baselines, checkConnector, checkStatement, csvStatement, customStatement, decimalToMicroUsd, fuel, modelSpend, openaiStatement, pageParams, parseXml, reconcileBilling, requestFor, resolvePath, } from "./money/index.js";
27
+ export { filingPack, occurrenceFacts, occurrenceReport, renderOccurrence, } from "./occurrence/index.js";
28
+ export { ingestOcsf, ocsfLine, toOcsf } from "./ocsf/index.js";
29
+ export { toOtlp } from "./otlp/index.js";
30
+ export { checkIdentifier, checkPack, corePack, packData, packFrameworks, } from "./packs/index.js";
31
+ export { policyDelta } from "./policy/delta.js";
32
+ export { policyDrafts } from "./policy/drafts.js";
33
+ export { audited, compilePolicy, decide, loadPolicy, policyFindings, } from "./policy/index.js";
34
+ export { calibration, FEATURES, features, MIN_EACH, precogFindings, precogReport, predict, prefixOf, splitOf, TARGET, train, } from "./precog/index.js";
35
+ export { interventionEvidence, interventionGain, } from "./precog/intervention.js";
36
+ export { activities, buildNormal, normalScore, normalThreshold, } from "./precog/normal.js";
37
+ export { preflightFindings } from "./preflight/index.js";
38
+ export { typeRatings, typeUnrated, } from "./ratings/index.js";
39
+ export { loadLocal, RecordNotVerified, reconcile, } from "./reconcile/index.js";
40
+ export { cassette, requestKey } from "./replay/index.js";
41
+ export { ORPHAN_TEXT, repairToolCalls } from "./replay/repair.js";
42
+ export { drainSpools } from "./session/drain.js";
43
+ export { BlackboxSession, checkEgress, session, stableEventId, } from "./session/index.js";
44
+ export { checkCompensations, runUndo, undoFindings, undoPlan, } from "./undo/index.js";
45
+ export * from "./verify/index.js";
46
+ export { VERSION } from "./version.js";
47
+ export { weather } from "./weather/index.js";
48
+ export { postReceipt, receiptFor, workspaceTree } from "./workspace-receipt/index.js";
@@ -0,0 +1,66 @@
1
+ import { type Span } from "../authority/index.ts";
2
+ import type { Directive } from "../directives/index.ts";
3
+ import { type Summary } from "../fleet/index.ts";
4
+ export interface InvestigationOptions {
5
+ summary: Summary;
6
+ models: readonly string[];
7
+ directives?: readonly Directive[];
8
+ }
9
+ /** spec/investigations.md §1. */
10
+ export declare function investigation(lines: readonly string[], opts: InvestigationOptions): {
11
+ kind: "blackbox.investigation";
12
+ v: 1;
13
+ session_id: string;
14
+ label: string | null;
15
+ started_at: string;
16
+ last_event_at: string;
17
+ events: number;
18
+ outcome: string | null;
19
+ authority: Span[];
20
+ findings: {
21
+ seq: number;
22
+ code: string;
23
+ fault: string;
24
+ severity: string;
25
+ source: string;
26
+ in_control: import("../authority/index.ts").Mode | null;
27
+ in_control_by: string | null;
28
+ weather: {} | null;
29
+ }[];
30
+ directives: {
31
+ id: string;
32
+ applies_to: {
33
+ model: string;
34
+ } | {
35
+ tool: string;
36
+ };
37
+ pattern: string[];
38
+ affected_ppm: number;
39
+ }[] | null;
40
+ drill: {
41
+ drill: true;
42
+ planned: import("../drills/index.ts").Fault[];
43
+ injected: {
44
+ seq: number;
45
+ kind: string;
46
+ }[];
47
+ findings_after: string[];
48
+ recovered: boolean;
49
+ outcome: string | null;
50
+ } | null;
51
+ };
52
+ export type Investigation = ReturnType<typeof investigation> & {
53
+ verification?: {
54
+ ok: boolean;
55
+ identity: boolean;
56
+ proofs: string;
57
+ };
58
+ investigated_at?: string;
59
+ bundle_sha256?: string;
60
+ signed?: {
61
+ by: string;
62
+ sig: string;
63
+ };
64
+ };
65
+ /** spec/investigations.md §3: the reading copy. The signed JSON is the report; this isn't. */
66
+ export declare function renderInvestigation(r: Investigation): string;
@@ -0,0 +1,119 @@
1
+ // Investigations (spec/investigations.md): the independent investigator's report and its reading
2
+ // copy. Pure; mirrors sdks/python/src/zanii_blackbox/investigate.py; pinned by
3
+ // spec/vectors/investigations.json.
4
+ import { faultOf } from "../analysis/faults.js";
5
+ import { authorityTimeline } from "../authority/index.js";
6
+ import { drillReport } from "../drills/index.js";
7
+ import { signatureOf } from "../fleet/index.js";
8
+ /** spec/investigations.md §1. */
9
+ export function investigation(lines, opts) {
10
+ const { summary, models } = opts;
11
+ const authority = authorityTimeline(lines);
12
+ const spanAt = (seq) => authority.find((s) => seq >= s.from_seq && (s.to_seq === null || seq <= s.to_seq));
13
+ const findings = lines
14
+ .map((l) => JSON.parse(l))
15
+ .filter((e) => e.kind === "finding")
16
+ .map((e) => {
17
+ const code = String(e.meta.code);
18
+ const ref = e.meta.ref;
19
+ const span = spanAt(typeof ref?.seq === "number" ? ref.seq : e.seq);
20
+ return {
21
+ seq: e.seq,
22
+ code,
23
+ fault: faultOf(code).fault,
24
+ severity: String(e.meta.severity),
25
+ source: String(e.meta.source),
26
+ in_control: span?.mode ?? null,
27
+ in_control_by: span?.by ?? null,
28
+ weather: e.meta.weather ?? null,
29
+ };
30
+ });
31
+ const signature = signatureOf(summary)?.signature;
32
+ const matches = (d) => d.signature === signature &&
33
+ ("model" in d.applies_to
34
+ ? models.includes(d.applies_to.model)
35
+ : Object.hasOwn(summary.tools, d.applies_to.tool));
36
+ const drill = drillReport(lines);
37
+ return {
38
+ kind: "blackbox.investigation",
39
+ v: 1,
40
+ session_id: summary.session_id,
41
+ label: summary.label,
42
+ started_at: summary.started_at,
43
+ last_event_at: summary.last_event_at,
44
+ events: summary.events,
45
+ outcome: summary.outcome,
46
+ authority,
47
+ findings,
48
+ directives: opts.directives
49
+ ? opts.directives.filter(matches).map((d) => ({
50
+ id: d.id,
51
+ applies_to: d.applies_to,
52
+ pattern: d.pattern,
53
+ affected_ppm: d.affected_ppm,
54
+ }))
55
+ : null,
56
+ drill: drill.drill ? drill : null,
57
+ };
58
+ }
59
+ const cell = (v) => v === null || v === undefined || v === ""
60
+ ? "—"
61
+ : String(v)
62
+ .replace(/\r\n|\r|\n/g, " ")
63
+ .replace(/\|/g, "\\|");
64
+ const row = (cells) => `| ${cells.map(cell).join(" | ")} |`;
65
+ const head = (names) => [row(names), `|${names.map(() => "---|").join("")}`];
66
+ /** spec/investigations.md §3: the reading copy. The signed JSON is the report; this isn't. */
67
+ export function renderInvestigation(r) {
68
+ const out = [`# Investigation: ${r.session_id}`, "", ...head(["Fact", "Value"])];
69
+ const v = r.verification;
70
+ out.push(row(["Label", r.label]), row(["Started", r.started_at]), row(["Last event", r.last_event_at]), row(["Events", r.events]), row(["Outcome", r.outcome]), row([
71
+ "Record verified",
72
+ v === undefined
73
+ ? "not checked"
74
+ : `${v.ok ? "yes" : "NO"} (identity ${v.identity ? "ok" : "not ok"}, ledger proofs ${v.proofs.replace("_", " ")})`,
75
+ ]), row(["Bundle SHA-256", r.bundle_sha256]), row(["Investigator", r.signed ? r.signed.by : "unsigned"]), row(["Investigated at", r.investigated_at]));
76
+ if (v && !v.ok)
77
+ out.push("", "**The record does not verify. Everything below may have been altered.**");
78
+ out.push("", "## Who had the controls", "");
79
+ if (r.authority.length === 0)
80
+ out.push("No authority recorded.");
81
+ else {
82
+ out.push(...head(["From seq", "To seq", "Mode", "By", "Reason"]));
83
+ for (const s of r.authority)
84
+ out.push(row([s.from_seq, s.to_seq ?? "end", s.mode, s.by, s.reason]));
85
+ }
86
+ out.push("", "## Findings", "");
87
+ if (r.findings.length === 0)
88
+ out.push("None recorded.");
89
+ else {
90
+ out.push(...head(["Seq", "Code", "Fault", "Severity", "In control", "Weather"]));
91
+ for (const f of r.findings) {
92
+ const weather = Array.isArray(f.weather)
93
+ ? f.weather
94
+ .map((w) => `${w.model}: ${w.status}`)
95
+ .join(", ")
96
+ : null;
97
+ const control = f.in_control === null ? null : `${f.in_control} (${f.in_control_by ?? "—"})`;
98
+ out.push(row([f.seq, f.code, f.fault, f.severity, control, weather]));
99
+ }
100
+ }
101
+ out.push("", "## Matching directives", "");
102
+ if (r.directives === null)
103
+ out.push("No directives were given.");
104
+ else if (r.directives.length === 0)
105
+ out.push("None matched.");
106
+ else {
107
+ out.push(...head(["Directive", "Applies to", "Pattern", "Affected (ppm)"]));
108
+ for (const d of r.directives) {
109
+ const to = "model" in d.applies_to ? `model ${d.applies_to.model}` : `tool ${d.applies_to.tool}`;
110
+ out.push(row([d.id, to, d.pattern.join(", "), d.affected_ppm]));
111
+ }
112
+ }
113
+ if (r.drill) {
114
+ const d = r.drill;
115
+ out.push("", "## Drill", "", `This session was a drill: ${d.planned.length} faults planned, ${d.injected.length} injected (${d.injected.map((i) => i.kind).join(", ") || "none"}).`, `Recovered: ${d.recovered ? "yes" : "no"}. Findings after the first fault: ${d.findings_after.join(", ") || "none"}.`);
116
+ }
117
+ out.push("", "## What this report proves", "", "If the record verifies, these events are the ones the gateway recorded, in this order, and unchanged since. Its chain is intact and its anchors are signed by the pinned identity; with ledger proofs checked, they were also on the ledger at the times shown.", "It does not prove what the agent intended, or that the providers and tools behaved as their answers say. It also can't show what happened outside the gateway.", "The signature shows who wrote this report. Check it with `blackbox verify-certificate <report>.json --did <investigator>`.", "");
118
+ return out.join("\n");
119
+ }