@mapick/cost-firewall 0.1.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 (104) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +161 -0
  3. package/dist/breaker.d.ts +30 -0
  4. package/dist/breaker.d.ts.map +1 -0
  5. package/dist/breaker.js +131 -0
  6. package/dist/breaker.js.map +1 -0
  7. package/dist/cli/index.d.ts +18 -0
  8. package/dist/cli/index.d.ts.map +1 -0
  9. package/dist/cli/index.js +244 -0
  10. package/dist/cli/index.js.map +1 -0
  11. package/dist/config-warn.d.ts +11 -0
  12. package/dist/config-warn.d.ts.map +1 -0
  13. package/dist/config-warn.js +26 -0
  14. package/dist/config-warn.js.map +1 -0
  15. package/dist/config.d.ts +7 -0
  16. package/dist/config.d.ts.map +1 -0
  17. package/dist/config.js +32 -0
  18. package/dist/config.js.map +1 -0
  19. package/dist/dashboard/html.d.ts +2 -0
  20. package/dist/dashboard/html.d.ts.map +1 -0
  21. package/dist/dashboard/html.js +898 -0
  22. package/dist/dashboard/html.js.map +1 -0
  23. package/dist/dashboard/index.d.ts +8 -0
  24. package/dist/dashboard/index.d.ts.map +1 -0
  25. package/dist/dashboard/index.js +163 -0
  26. package/dist/dashboard/index.js.map +1 -0
  27. package/dist/dashboard/sse.d.ts +9 -0
  28. package/dist/dashboard/sse.d.ts.map +1 -0
  29. package/dist/dashboard/sse.js +22 -0
  30. package/dist/dashboard/sse.js.map +1 -0
  31. package/dist/hooks/agent-end.d.ts +18 -0
  32. package/dist/hooks/agent-end.d.ts.map +1 -0
  33. package/dist/hooks/agent-end.js +25 -0
  34. package/dist/hooks/agent-end.js.map +1 -0
  35. package/dist/hooks/before-agent-reply.d.ts +29 -0
  36. package/dist/hooks/before-agent-reply.d.ts.map +1 -0
  37. package/dist/hooks/before-agent-reply.js +42 -0
  38. package/dist/hooks/before-agent-reply.js.map +1 -0
  39. package/dist/hooks/index.d.ts +7 -0
  40. package/dist/hooks/index.d.ts.map +1 -0
  41. package/dist/hooks/index.js +17 -0
  42. package/dist/hooks/index.js.map +1 -0
  43. package/dist/hooks/model-call.d.ts +39 -0
  44. package/dist/hooks/model-call.d.ts.map +1 -0
  45. package/dist/hooks/model-call.js +120 -0
  46. package/dist/hooks/model-call.js.map +1 -0
  47. package/dist/index.d.ts +13 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +49 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/pricing.d.ts +12 -0
  52. package/dist/pricing.d.ts.map +1 -0
  53. package/dist/pricing.js +43 -0
  54. package/dist/pricing.js.map +1 -0
  55. package/dist/provider/auth.d.ts +14 -0
  56. package/dist/provider/auth.d.ts.map +1 -0
  57. package/dist/provider/auth.js +53 -0
  58. package/dist/provider/auth.js.map +1 -0
  59. package/dist/provider/index.d.ts +12 -0
  60. package/dist/provider/index.d.ts.map +1 -0
  61. package/dist/provider/index.js +134 -0
  62. package/dist/provider/index.js.map +1 -0
  63. package/dist/provider/route.d.ts +10 -0
  64. package/dist/provider/route.d.ts.map +1 -0
  65. package/dist/provider/route.js +19 -0
  66. package/dist/provider/route.js.map +1 -0
  67. package/dist/provider/stream.d.ts +10 -0
  68. package/dist/provider/stream.d.ts.map +1 -0
  69. package/dist/provider/stream.js +120 -0
  70. package/dist/provider/stream.js.map +1 -0
  71. package/dist/provider/synthetic.d.ts +13 -0
  72. package/dist/provider/synthetic.d.ts.map +1 -0
  73. package/dist/provider/synthetic.js +59 -0
  74. package/dist/provider/synthetic.js.map +1 -0
  75. package/dist/provider/upstream/anthropic.d.ts +13 -0
  76. package/dist/provider/upstream/anthropic.d.ts.map +1 -0
  77. package/dist/provider/upstream/anthropic.js +62 -0
  78. package/dist/provider/upstream/anthropic.js.map +1 -0
  79. package/dist/provider/upstream/openai.d.ts +17 -0
  80. package/dist/provider/upstream/openai.d.ts.map +1 -0
  81. package/dist/provider/upstream/openai.js +75 -0
  82. package/dist/provider/upstream/openai.js.map +1 -0
  83. package/dist/source.d.ts +35 -0
  84. package/dist/source.d.ts.map +1 -0
  85. package/dist/source.js +41 -0
  86. package/dist/source.js.map +1 -0
  87. package/dist/state.d.ts +56 -0
  88. package/dist/state.d.ts.map +1 -0
  89. package/dist/state.js +178 -0
  90. package/dist/state.js.map +1 -0
  91. package/dist/store.d.ts +23 -0
  92. package/dist/store.d.ts.map +1 -0
  93. package/dist/store.js +68 -0
  94. package/dist/store.js.map +1 -0
  95. package/dist/tools/index.d.ts +13 -0
  96. package/dist/tools/index.d.ts.map +1 -0
  97. package/dist/tools/index.js +63 -0
  98. package/dist/tools/index.js.map +1 -0
  99. package/dist/types.d.ts +98 -0
  100. package/dist/types.d.ts.map +1 -0
  101. package/dist/types.js +7 -0
  102. package/dist/types.js.map +1 -0
  103. package/openclaw.plugin.json +44 -0
  104. package/package.json +49 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/dashboard/html.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,mBAAmB,CAAC,MAAW;IAC7C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA83BD,CAAC;AACT,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Dashboard HTTP route registration
3
+ */
4
+ import type { FirewallState } from "../state.js";
5
+ import type { EventStore } from "../store.js";
6
+ import { SseManager } from "./sse.js";
7
+ export declare function registerDashboard(api: any, state: FirewallState, store: EventStore): SseManager;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dashboard/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAkBtC,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,UAAU,GAChB,UAAU,CAiJZ"}
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Dashboard HTTP route registration
3
+ */
4
+ import { getStatus } from "../cli/index.js";
5
+ import { renderDashboardHtml } from "./html.js";
6
+ import { SseManager } from "./sse.js";
7
+ import { writeFile, readFile } from "node:fs/promises";
8
+ import { join } from "node:path";
9
+ import { homedir } from "node:os";
10
+ function getConfigPath() {
11
+ return process.env.OPENCLAW_CONFIG_PATH
12
+ ?? join(process.env.OPENCLAW_STATE_DIR ?? join(homedir(), ".openclaw"), "openclaw.json");
13
+ }
14
+ function readBody(req) {
15
+ return new Promise((resolve) => {
16
+ let data = "";
17
+ req.on("data", (chunk) => { data += chunk; });
18
+ req.on("end", () => resolve(data));
19
+ });
20
+ }
21
+ export function registerDashboard(api, state, store) {
22
+ const sse = new SseManager();
23
+ const corsHeaders = {
24
+ "Access-Control-Allow-Origin": "*",
25
+ "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
26
+ "Access-Control-Allow-Headers": "Content-Type, Authorization",
27
+ };
28
+ // Dashboard HTML
29
+ api.registerHttpRoute({
30
+ path: "/mapick/dashboard",
31
+ auth: "plugin",
32
+ handler: async (_req, res) => {
33
+ const stats = await getStatus(state, store);
34
+ res.writeHead(200, {
35
+ ...corsHeaders,
36
+ "Content-Type": "text/html; charset=utf-8",
37
+ "Cache-Control": "no-cache, no-store, must-revalidate",
38
+ "Pragma": "no-cache",
39
+ "Expires": "0",
40
+ });
41
+ res.end(renderDashboardHtml(stats));
42
+ },
43
+ });
44
+ // Stats API
45
+ api.registerHttpRoute({
46
+ path: "/mapick/api/stats",
47
+ auth: "plugin",
48
+ handler: async (_req, res) => {
49
+ const stats = await getStatus(state, store);
50
+ res.writeHead(200, { ...corsHeaders, "Content-Type": "application/json" });
51
+ res.end(JSON.stringify(stats));
52
+ },
53
+ });
54
+ // SSE
55
+ api.registerHttpRoute({
56
+ path: "/mapick/api/live",
57
+ auth: "plugin",
58
+ handler: (req, res) => {
59
+ res.writeHead(200, { ...corsHeaders, "Content-Type": "text/event-stream", "Cache-Control": "no-cache", Connection: "keep-alive" });
60
+ const unsubscribe = sse.subscribe((data) => res.write(data));
61
+ req.on("close", unsubscribe);
62
+ },
63
+ });
64
+ // Emergency Stop
65
+ api.registerHttpRoute({
66
+ path: "/mapick/api/stop",
67
+ auth: "plugin",
68
+ handler: (_req, res) => {
69
+ state.setEmergencyStop(true);
70
+ res.writeHead(200, { ...corsHeaders, "Content-Type": "application/json" });
71
+ res.end(JSON.stringify({ ok: true, emergency_stop: true }));
72
+ },
73
+ });
74
+ // Resume
75
+ api.registerHttpRoute({
76
+ path: "/mapick/api/resume",
77
+ auth: "plugin",
78
+ handler: (_req, res) => {
79
+ state.setEmergencyStop(false);
80
+ res.writeHead(200, { ...corsHeaders, "Content-Type": "application/json" });
81
+ res.end(JSON.stringify({ ok: true, emergency_stop: false }));
82
+ },
83
+ });
84
+ // Reset source
85
+ api.registerHttpRoute({
86
+ path: "/mapick/api/reset-source",
87
+ auth: "plugin",
88
+ handler: (req, res) => {
89
+ const url = new URL(req.url, "http://localhost");
90
+ const source = url.searchParams.get("source") || "";
91
+ if (source) {
92
+ state.breaker.reset(source);
93
+ res.writeHead(200, { ...corsHeaders, "Content-Type": "application/json" });
94
+ res.end(JSON.stringify({ ok: true, source }));
95
+ }
96
+ else {
97
+ res.writeHead(400, { ...corsHeaders, "Content-Type": "application/json" });
98
+ res.end(JSON.stringify({ error: "missing source param" }));
99
+ }
100
+ },
101
+ });
102
+ // Events API
103
+ api.registerHttpRoute({
104
+ path: "/mapick/api/events",
105
+ auth: "plugin",
106
+ handler: async (_req, res) => {
107
+ try {
108
+ const raw = await readFile(store.getEventsFilePath(), "utf-8");
109
+ const events = raw.trim().split("\n").slice(-30).map((l) => {
110
+ try {
111
+ return JSON.parse(l);
112
+ }
113
+ catch {
114
+ return null;
115
+ }
116
+ }).filter(Boolean);
117
+ res.writeHead(200, { ...corsHeaders, "Content-Type": "application/json" });
118
+ res.end(JSON.stringify(events));
119
+ }
120
+ catch {
121
+ res.writeHead(200, { ...corsHeaders, "Content-Type": "application/json" });
122
+ res.end(JSON.stringify([]));
123
+ }
124
+ },
125
+ });
126
+ // Config update (POST JSON)
127
+ api.registerHttpRoute({
128
+ path: "/mapick/api/config",
129
+ auth: "plugin",
130
+ handler: async (req, res) => {
131
+ try {
132
+ const body = await readBody(req);
133
+ const cfg = JSON.parse(body);
134
+ const configPath = getConfigPath();
135
+ const raw = await readFile(configPath, "utf-8");
136
+ const openclawConfig = JSON.parse(raw);
137
+ const entry = openclawConfig?.plugins?.entries?.["mapick-firewall"];
138
+ const current = entry?.config || {};
139
+ if (cfg.mode) {
140
+ state.setMode(cfg.mode);
141
+ }
142
+ if (cfg.dailyTokenLimit !== undefined) {
143
+ current.dailyTokenLimit = cfg.dailyTokenLimit;
144
+ state.config.dailyTokenLimit = cfg.dailyTokenLimit;
145
+ }
146
+ if (cfg.breaker) {
147
+ current.breaker = { ...current.breaker, ...cfg.breaker };
148
+ state.config.breaker = { ...state.config.breaker, ...cfg.breaker };
149
+ }
150
+ entry.config = current;
151
+ await writeFile(configPath, JSON.stringify(openclawConfig, null, 2));
152
+ res.writeHead(200, { ...corsHeaders, "Content-Type": "application/json" });
153
+ res.end(JSON.stringify({ ok: true, config: current }));
154
+ }
155
+ catch (e) {
156
+ res.writeHead(400, { ...corsHeaders, "Content-Type": "application/json" });
157
+ res.end(JSON.stringify({ error: e.message }));
158
+ }
159
+ },
160
+ });
161
+ return sse;
162
+ }
163
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/dashboard/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * SSE real-time push
3
+ */
4
+ export declare class SseManager {
5
+ private clients;
6
+ subscribe(send: (data: string) => void): () => void;
7
+ broadcast(data: object): void;
8
+ }
9
+ //# sourceMappingURL=sse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/dashboard/sse.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAqC;IAEpD,SAAS,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI;IAKnD,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;CAU9B"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * SSE real-time push
3
+ */
4
+ export class SseManager {
5
+ clients = new Set();
6
+ subscribe(send) {
7
+ this.clients.add(send);
8
+ return () => this.clients.delete(send);
9
+ }
10
+ broadcast(data) {
11
+ const message = `data: ${JSON.stringify(data)}\n\n`;
12
+ for (const send of this.clients) {
13
+ try {
14
+ send(message);
15
+ }
16
+ catch {
17
+ this.clients.delete(send);
18
+ }
19
+ }
20
+ }
21
+ }
22
+ //# sourceMappingURL=sse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse.js","sourceRoot":"","sources":["../../src/dashboard/sse.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,OAAO,UAAU;IACb,OAAO,GAAG,IAAI,GAAG,EAA0B,CAAC;IAEpD,SAAS,CAAC,IAA4B;QACpC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvB,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IAED,SAAS,CAAC,IAAY;QACpB,MAAM,OAAO,GAAG,SAAS,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;QACpD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAChC,IAAI,CAAC;gBACH,IAAI,CAAC,OAAO,CAAC,CAAC;YAChB,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * agent_end hook handler
3
+ *
4
+ * Responsibilities:
5
+ * - Run finalization stats
6
+ * - Delayed cleanup of run state
7
+ */
8
+ import type { FirewallState } from "../state.js";
9
+ import type { EventStore } from "../store.js";
10
+ export interface AgentEndEvent {
11
+ runId?: string;
12
+ agentId?: string;
13
+ sessionId?: string;
14
+ sessionKey?: string;
15
+ outcome?: "success" | "error";
16
+ }
17
+ export declare function createAgentEndHandler(state: FirewallState, store: EventStore): (event: AgentEndEvent, ctx: any) => void;
18
+ //# sourceMappingURL=agent-end.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-end.d.ts","sourceRoot":"","sources":["../../src/hooks/agent-end.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;CAC/B;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,UAAU,IAGf,OAAO,aAAa,EACpB,KAAK,GAAG,KACP,IAAI,CAgBR"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * agent_end hook handler
3
+ *
4
+ * Responsibilities:
5
+ * - Run finalization stats
6
+ * - Delayed cleanup of run state
7
+ */
8
+ export function createAgentEndHandler(state, store) {
9
+ return function handleAgentEnd(event, ctx) {
10
+ const runId = event.runId ?? ctx?.runId;
11
+ if (!runId)
12
+ return;
13
+ const run = state.getRun(runId);
14
+ if (!run)
15
+ return;
16
+ store.append({
17
+ type: "agent_end",
18
+ runId,
19
+ source: run.source,
20
+ outcome: event.outcome,
21
+ });
22
+ state.cleanupRun(runId);
23
+ };
24
+ }
25
+ //# sourceMappingURL=agent-end.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-end.js","sourceRoot":"","sources":["../../src/hooks/agent-end.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,MAAM,UAAU,qBAAqB,CACnC,KAAoB,EACpB,KAAiB;IAEjB,OAAO,SAAS,cAAc,CAC5B,KAAoB,EACpB,GAAQ;QAER,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,GAAG,EAAE,KAAK,CAAC;QACxC,IAAI,CAAC,KAAK;YAAE,OAAO;QAEnB,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,CAAC,GAAG;YAAE,OAAO;QAEjB,KAAK,CAAC,MAAM,CAAC;YACX,IAAI,EAAE,WAAW;YACjB,KAAK;YACL,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB,CAAC,CAAC;QAEH,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * before_agent_reply hook handler
3
+ *
4
+ * Responsibilities:
5
+ * - Emergency Stop blocking
6
+ * - Daily Budget blocking
7
+ * - Source Cooldown blocking
8
+ */
9
+ import type { FirewallState } from "../state.js";
10
+ import type { EventStore } from "../store.js";
11
+ export interface BeforeAgentReplyEvent {
12
+ agentId?: string;
13
+ sessionId?: string;
14
+ sessionKey?: string;
15
+ }
16
+ export interface BeforeAgentReplyCtx {
17
+ agentId?: string;
18
+ sessionId?: string;
19
+ }
20
+ export interface HandledReply {
21
+ handled: true;
22
+ reply: {
23
+ text: string;
24
+ isError: boolean;
25
+ };
26
+ reason: string;
27
+ }
28
+ export declare function createBeforeAgentReplyHandler(state: FirewallState, store: EventStore): (event: BeforeAgentReplyEvent, ctx: BeforeAgentReplyCtx) => Promise<HandledReply | undefined>;
29
+ //# sourceMappingURL=before-agent-reply.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"before-agent-reply.d.ts","sourceRoot":"","sources":["../../src/hooks/before-agent-reply.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,IAAI,CAAC;IACd,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,UAAU,IAGf,OAAO,qBAAqB,EAC5B,KAAK,mBAAmB,KACvB,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAoCrC"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * before_agent_reply hook handler
3
+ *
4
+ * Responsibilities:
5
+ * - Emergency Stop blocking
6
+ * - Daily Budget blocking
7
+ * - Source Cooldown blocking
8
+ */
9
+ export function createBeforeAgentReplyHandler(state, store) {
10
+ return async function handleBeforeAgentReply(event, ctx) {
11
+ const source = event.agentId ?? event.sessionKey ?? "unknown";
12
+ // Unified precheck
13
+ const result = state.precheck(source);
14
+ if (!result.allow) {
15
+ store.append({
16
+ type: "blocked",
17
+ source,
18
+ reason: result.reason,
19
+ layer: result.layer,
20
+ });
21
+ state.globalStats.todayBlocked++;
22
+ const messages = {
23
+ emergency_stop: "Mapick Cost Firewall: all AI calls are paused.",
24
+ daily_token_limit: "Mapick Cost Firewall: today's token limit has been reached.",
25
+ source_cooldown: "Mapick Cost Firewall: this source is cooling down.",
26
+ consecutive_failures: "Mapick Cost Firewall: this source is cooling down due to consecutive failures.",
27
+ token_velocity: "Mapick Cost Firewall: this source is cooling down due to high token velocity.",
28
+ call_frequency: "Mapick Cost Firewall: this source is cooling down due to high call frequency.",
29
+ };
30
+ return {
31
+ handled: true,
32
+ reply: {
33
+ text: messages[result.reason] ?? "Mapick Cost Firewall: request blocked.",
34
+ isError: true,
35
+ },
36
+ reason: result.reason,
37
+ };
38
+ }
39
+ return undefined;
40
+ };
41
+ }
42
+ //# sourceMappingURL=before-agent-reply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"before-agent-reply.js","sourceRoot":"","sources":["../../src/hooks/before-agent-reply.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAyBH,MAAM,UAAU,6BAA6B,CAC3C,KAAoB,EACpB,KAAiB;IAEjB,OAAO,KAAK,UAAU,sBAAsB,CAC1C,KAA4B,EAC5B,GAAwB;QAExB,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,UAAU,IAAI,SAAS,CAAC;QAE9D,mBAAmB;QACnB,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAEtC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,KAAK,CAAC,MAAM,CAAC;gBACX,IAAI,EAAE,SAAS;gBACf,MAAM;gBACN,MAAM,EAAE,MAAM,CAAC,MAAO;gBACtB,KAAK,EAAE,MAAM,CAAC,KAAK;aACpB,CAAC,CAAC;YACH,KAAK,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC;YAEjC,MAAM,QAAQ,GAA2B;gBACvC,cAAc,EAAE,gDAAgD;gBAChE,iBAAiB,EAAE,6DAA6D;gBAChF,eAAe,EAAE,oDAAoD;gBACrE,oBAAoB,EAAE,gFAAgF;gBACtG,cAAc,EAAE,+EAA+E;gBAC/F,cAAc,EAAE,+EAA+E;aAChG,CAAC;YAEF,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,KAAK,EAAE;oBACL,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAO,CAAC,IAAI,wCAAwC;oBAC1E,OAAO,EAAE,IAAI;iBACd;gBACD,MAAM,EAAE,MAAM,CAAC,MAAO;aACvB,CAAC;QACJ,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Hook registration entry point
3
+ */
4
+ import type { FirewallState } from "../state.js";
5
+ import type { EventStore } from "../store.js";
6
+ export declare function registerHooks(api: any, state: FirewallState, store: EventStore): void;
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK9C,wBAAgB,aAAa,CAC3B,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,UAAU,GAChB,IAAI,CAUN"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Hook registration entry point
3
+ */
4
+ import { createBeforeAgentReplyHandler } from "./before-agent-reply.js";
5
+ import { createModelCallStartedHandler, createModelCallEndedHandler } from "./model-call.js";
6
+ import { createAgentEndHandler } from "./agent-end.js";
7
+ export function registerHooks(api, state, store) {
8
+ api.on("before_agent_reply", createBeforeAgentReplyHandler(state, store));
9
+ api.on("model_call_started", createModelCallStartedHandler(state, store));
10
+ api.on("model_call_ended", createModelCallEndedHandler(state, store));
11
+ api.on("agent_end", createAgentEndHandler(state, store));
12
+ if (state.config.privacy?.enableRawConversationHooks) {
13
+ // llm_input/output — opt-in only
14
+ // To be implemented in future versions
15
+ }
16
+ }
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,6BAA6B,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,MAAM,UAAU,aAAa,CAC3B,GAAQ,EACR,KAAoB,EACpB,KAAiB;IAEjB,GAAG,CAAC,EAAE,CAAC,oBAAoB,EAAE,6BAA6B,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAC1E,GAAG,CAAC,EAAE,CAAC,oBAAoB,EAAE,6BAA6B,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAC1E,GAAG,CAAC,EAAE,CAAC,kBAAkB,EAAE,2BAA2B,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IACtE,GAAG,CAAC,EAAE,CAAC,WAAW,EAAE,qBAAqB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAEzD,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,0BAA0B,EAAE,CAAC;QACrD,iCAAiC;QACjC,uCAAuC;IACzC,CAAC;AACH,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * model_call_started / model_call_ended hook handler
3
+ *
4
+ * Responsibilities:
5
+ * - Record metadata for each LLM call
6
+ * - Estimate cost
7
+ * - Update breaker state
8
+ * - Write event log
9
+ */
10
+ import type { FirewallState } from "../state.js";
11
+ import type { EventStore } from "../store.js";
12
+ export interface ModelCallStartedEvent {
13
+ runId: string;
14
+ callId: string;
15
+ sessionKey?: string;
16
+ sessionId?: string;
17
+ provider: string;
18
+ model: string;
19
+ api?: string;
20
+ transport?: string;
21
+ }
22
+ export interface ModelCallEndedEvent extends ModelCallStartedEvent {
23
+ durationMs: number;
24
+ outcome: "completed" | "error";
25
+ errorCategory?: string;
26
+ failureKind?: "aborted" | "connection_closed" | "connection_reset" | "terminated" | "timeout";
27
+ requestPayloadBytes?: number;
28
+ responseStreamBytes?: number;
29
+ timeToFirstByteMs?: number;
30
+ upstreamRequestIdHash?: string;
31
+ usage?: {
32
+ prompt_tokens?: number;
33
+ completion_tokens?: number;
34
+ total_tokens?: number;
35
+ };
36
+ }
37
+ export declare function createModelCallStartedHandler(state: FirewallState, store: EventStore): (event: ModelCallStartedEvent, ctx: any) => void;
38
+ export declare function createModelCallEndedHandler(state: FirewallState, store: EventStore): (event: ModelCallEndedEvent, ctx: any) => void;
39
+ //# sourceMappingURL=model-call.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-call.d.ts","sourceRoot":"","sources":["../../src/hooks/model-call.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAI9C,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAoB,SAAQ,qBAAqB;IAChE,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,SAAS,GAAG,mBAAmB,GAAG,kBAAkB,GAAG,YAAY,GAAG,SAAS,CAAC;IAC9F,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,KAAK,CAAC,EAAE;QACN,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;CACH;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,UAAU,IAGf,OAAO,qBAAqB,EAC5B,KAAK,GAAG,KACP,IAAI,CAeR;AAED,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,UAAU,IAGf,OAAO,mBAAmB,EAC1B,KAAK,GAAG,KACP,IAAI,CAmGR"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * model_call_started / model_call_ended hook handler
3
+ *
4
+ * Responsibilities:
5
+ * - Record metadata for each LLM call
6
+ * - Estimate cost
7
+ * - Update breaker state
8
+ * - Write event log
9
+ */
10
+ import { sourceFromModelCall } from "../source.js";
11
+ export function createModelCallStartedHandler(state, store) {
12
+ return function handleModelCallStarted(event, ctx) {
13
+ const source = sourceFromModelCall(event, ctx);
14
+ const run = state.getOrCreateRun(event.runId, source, event.sessionId, event.sessionKey);
15
+ state.addCallToRun(event.runId, event.callId, {
16
+ callId: event.callId,
17
+ provider: event.provider,
18
+ model: event.model,
19
+ api: event.api,
20
+ transport: event.transport,
21
+ startedAt: Date.now(),
22
+ });
23
+ run.llmCallTimestamps.push(Date.now());
24
+ };
25
+ }
26
+ export function createModelCallEndedHandler(state, store) {
27
+ return function handleModelCallEnded(event, ctx) {
28
+ const source = sourceFromModelCall(event, ctx);
29
+ const run = state.getOrCreateRun(event.runId, source, event.sessionId, event.sessionKey);
30
+ // Use precise usage if available from the event, otherwise fallback to bytes/4 estimation
31
+ let estimatedTokens;
32
+ if (event.usage?.prompt_tokens || event.usage?.completion_tokens) {
33
+ // Precise token count from upstream provider
34
+ estimatedTokens = (event.usage.prompt_tokens ?? 0) + (event.usage.completion_tokens ?? 0);
35
+ }
36
+ else {
37
+ // Fallback: 1 token ≈ 4 bytes
38
+ const totalBytes = (event.requestPayloadBytes ?? 0) + (event.responseStreamBytes ?? 0);
39
+ estimatedTokens = Math.round(totalBytes / 4);
40
+ }
41
+ const call = run.calls.get(event.callId);
42
+ if (call) {
43
+ call.durationMs = event.durationMs;
44
+ call.outcome = event.outcome;
45
+ call.errorCategory = event.errorCategory;
46
+ call.failureKind = event.failureKind;
47
+ call.requestPayloadBytes = event.requestPayloadBytes;
48
+ call.responseStreamBytes = event.responseStreamBytes;
49
+ call.estimatedCost = estimatedTokens;
50
+ }
51
+ if (event.outcome === "error") {
52
+ state.breaker.recordFailure(source);
53
+ }
54
+ else {
55
+ state.breaker.recordSuccess(source);
56
+ }
57
+ state.updateRunCost(event.runId, estimatedTokens);
58
+ state.updateSourceStats(source, estimatedTokens);
59
+ // Token velocity + call frequency + zero output detection
60
+ if (event.outcome === "completed") {
61
+ state.breaker.recordTokens(source, estimatedTokens);
62
+ // Zero output detection: spent tokens but output is zero
63
+ if (estimatedTokens > 0 && event.responseStreamBytes && event.responseStreamBytes < 100) {
64
+ store.append({
65
+ type: "zero_output_warning",
66
+ source,
67
+ provider: event.provider,
68
+ model: event.model,
69
+ estimatedCost: estimatedTokens,
70
+ });
71
+ }
72
+ }
73
+ state.breaker.recordCall(source);
74
+ // RunState status detection: cumulative tokens / call count / repeated prompts
75
+ const runTokens = run.cumulativeCost + estimatedTokens;
76
+ const runCalls = run.llmCallTimestamps.length;
77
+ const prevStatus = run.status;
78
+ if (runTokens > 500000) {
79
+ run.status = "danger";
80
+ run.reason = "run_tokens_exceeded";
81
+ }
82
+ else if (runCalls > 50) {
83
+ run.status = "warning";
84
+ run.reason = "run_calls_high";
85
+ }
86
+ if (run.status !== prevStatus) {
87
+ store.append({
88
+ type: "run_status_change",
89
+ runId: event.runId,
90
+ source,
91
+ cumulativeTokens: runTokens,
92
+ runCalls,
93
+ status: run.status,
94
+ reason: run.reason,
95
+ });
96
+ }
97
+ // Single run cumulative token warning
98
+ const runCumulative = run.cumulativeCost + estimatedTokens;
99
+ if (runCumulative > 200000) {
100
+ store.append({
101
+ type: "run_token_warning",
102
+ runId: event.runId,
103
+ source,
104
+ cumulativeTokens: runCumulative,
105
+ });
106
+ }
107
+ store.append({
108
+ type: "model_call_ended",
109
+ runId: event.runId,
110
+ callId: event.callId,
111
+ source,
112
+ provider: event.provider,
113
+ model: event.model,
114
+ outcome: event.outcome,
115
+ failureKind: event.failureKind,
116
+ estimatedCost: estimatedTokens,
117
+ });
118
+ };
119
+ }
120
+ //# sourceMappingURL=model-call.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-call.js","sourceRoot":"","sources":["../../src/hooks/model-call.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AA6BnD,MAAM,UAAU,6BAA6B,CAC3C,KAAoB,EACpB,KAAiB;IAEjB,OAAO,SAAS,sBAAsB,CACpC,KAA4B,EAC5B,GAAQ;QAER,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC/C,MAAM,GAAG,GAAG,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;QAEzF,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE;YAC5C,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC,CAAC;QAEH,GAAG,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACzC,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,2BAA2B,CACzC,KAAoB,EACpB,KAAiB;IAEjB,OAAO,SAAS,oBAAoB,CAClC,KAA0B,EAC1B,GAAQ;QAER,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC/C,MAAM,GAAG,GAAG,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;QAEzF,0FAA0F;QAC1F,IAAI,eAAuB,CAAC;QAC5B,IAAI,KAAK,CAAC,KAAK,EAAE,aAAa,IAAI,KAAK,CAAC,KAAK,EAAE,iBAAiB,EAAE,CAAC;YACjE,6CAA6C;YAC7C,eAAe,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,iBAAiB,IAAI,CAAC,CAAC,CAAC;QAC5F,CAAC;aAAM,CAAC;YACN,8BAA8B;YAC9B,MAAM,UAAU,GAAG,CAAC,KAAK,CAAC,mBAAmB,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,mBAAmB,IAAI,CAAC,CAAC,CAAC;YACvF,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;QAC/C,CAAC;QAED,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;YACnC,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;YAC7B,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC;YACzC,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;YACrC,IAAI,CAAC,mBAAmB,GAAG,KAAK,CAAC,mBAAmB,CAAC;YACrD,IAAI,CAAC,mBAAmB,GAAG,KAAK,CAAC,mBAAmB,CAAC;YACrD,IAAI,CAAC,aAAa,GAAG,eAAe,CAAC;QACvC,CAAC;QAED,IAAI,KAAK,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;YAC9B,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QACtC,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QACtC,CAAC;QAED,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;QAClD,KAAK,CAAC,iBAAiB,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;QAEjD,0DAA0D;QAC1D,IAAI,KAAK,CAAC,OAAO,KAAK,WAAW,EAAE,CAAC;YAClC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;YACpD,yDAAyD;YACzD,IAAI,eAAe,GAAG,CAAC,IAAI,KAAK,CAAC,mBAAmB,IAAI,KAAK,CAAC,mBAAmB,GAAG,GAAG,EAAE,CAAC;gBACxF,KAAK,CAAC,MAAM,CAAC;oBACX,IAAI,EAAE,qBAAqB;oBAC3B,MAAM;oBACN,QAAQ,EAAE,KAAK,CAAC,QAAQ;oBACxB,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,aAAa,EAAE,eAAe;iBAC/B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QACD,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAEjC,+EAA+E;QAC/E,MAAM,SAAS,GAAG,GAAG,CAAC,cAAc,GAAG,eAAe,CAAC;QACvD,MAAM,QAAQ,GAAG,GAAG,CAAC,iBAAiB,CAAC,MAAM,CAAC;QAC9C,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC;QAE9B,IAAI,SAAS,GAAG,MAAM,EAAE,CAAC;YACvB,GAAG,CAAC,MAAM,GAAG,QAAQ,CAAC;YACtB,GAAG,CAAC,MAAM,GAAG,qBAAqB,CAAC;QACrC,CAAC;aAAM,IAAI,QAAQ,GAAG,EAAE,EAAE,CAAC;YACzB,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC;YACvB,GAAG,CAAC,MAAM,GAAG,gBAAgB,CAAC;QAChC,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC9B,KAAK,CAAC,MAAM,CAAC;gBACX,IAAI,EAAE,mBAAmB;gBACzB,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,MAAM;gBACN,gBAAgB,EAAE,SAAS;gBAC3B,QAAQ;gBACR,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,MAAM,EAAE,GAAG,CAAC,MAAM;aACnB,CAAC,CAAC;QACL,CAAC;QAED,sCAAsC;QACtC,MAAM,aAAa,GAAG,GAAG,CAAC,cAAc,GAAG,eAAe,CAAC;QAC3D,IAAI,aAAa,GAAG,MAAM,EAAE,CAAC;YAC3B,KAAK,CAAC,MAAM,CAAC;gBACX,IAAI,EAAE,mBAAmB;gBACzB,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,MAAM;gBACN,gBAAgB,EAAE,aAAa;aAChC,CAAC,CAAC;QACL,CAAC;QAED,KAAK,CAAC,MAAM,CAAC;YACX,IAAI,EAAE,kBAAkB;YACxB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,MAAM;YACN,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,aAAa,EAAE,eAAe;SAC/B,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @mapick/cost-firewall — OpenClaw plugin entry point
3
+ */
4
+ import { PLUGIN_ID, PLUGIN_NAME } from "./types.js";
5
+ declare const _default: {
6
+ id: string;
7
+ name: string;
8
+ version: string;
9
+ register(api: any): void;
10
+ };
11
+ export default _default;
12
+ export { PLUGIN_ID, PLUGIN_NAME };
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;;;;;kBAepC,GAAG;;AALnB,wBA0CE;AAEF,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC"}