@datagusto/cli 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.
- package/LICENSE +21 -0
- package/README.md +186 -2
- package/bin/run.js +5 -0
- package/dist/adapters/claude-code.d.ts +48 -0
- package/dist/adapters/claude-code.js +526 -0
- package/dist/adapters/claude-code.js.map +1 -0
- package/dist/adapters/claude-settings.d.ts +29 -0
- package/dist/adapters/claude-settings.js +115 -0
- package/dist/adapters/claude-settings.js.map +1 -0
- package/dist/adapters/index.d.ts +10 -0
- package/dist/adapters/index.js +37 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/kiro-agent.d.ts +29 -0
- package/dist/adapters/kiro-agent.js +124 -0
- package/dist/adapters/kiro-agent.js.map +1 -0
- package/dist/adapters/kiro.d.ts +24 -0
- package/dist/adapters/kiro.js +752 -0
- package/dist/adapters/kiro.js.map +1 -0
- package/dist/adapters/types.d.ts +81 -0
- package/dist/adapters/types.js +14 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/api/client.d.ts +36 -0
- package/dist/api/client.js +85 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/errors.d.ts +4 -0
- package/dist/api/errors.js +25 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/commands/remove.d.ts +13 -0
- package/dist/commands/remove.js +59 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/setup.d.ts +16 -0
- package/dist/commands/setup.js +114 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/status.d.ts +7 -0
- package/dist/commands/status.js +53 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/display.d.ts +2 -0
- package/dist/display.js +12 -0
- package/dist/display.js.map +1 -0
- package/dist/fs/atomic.d.ts +23 -0
- package/dist/fs/atomic.js +65 -0
- package/dist/fs/atomic.js.map +1 -0
- package/dist/key-input.d.ts +24 -0
- package/dist/key-input.js +96 -0
- package/dist/key-input.js.map +1 -0
- package/dist/platform.d.ts +24 -0
- package/dist/platform.js +61 -0
- package/dist/platform.js.map +1 -0
- package/dist/state/installs.d.ts +24 -0
- package/dist/state/installs.js +110 -0
- package/dist/state/installs.js.map +1 -0
- package/dist/vendor.d.ts +16 -0
- package/dist/vendor.js +60 -0
- package/dist/vendor.js.map +1 -0
- package/package.json +57 -4
- package/vendor/claude_code/.claude-plugin/plugin.json +55 -0
- package/vendor/claude_code/README.md +267 -0
- package/vendor/claude_code/dist/api-client.js +82 -0
- package/vendor/claude_code/dist/builtin-tools.generated.js +33 -0
- package/vendor/claude_code/dist/extractors.js +201 -0
- package/vendor/claude_code/dist/index.js +695 -0
- package/vendor/claude_code/dist/monitoring.js +66 -0
- package/vendor/claude_code/dist/state.js +71 -0
- package/vendor/claude_code/dist/types.js +5 -0
- package/vendor/claude_code/hooks/hooks.json +25 -0
- package/vendor/claude_code/package.json +26 -0
- package/vendor/kiro/.kiro/agents/kiro_default.json +20 -0
- package/vendor/kiro/.kiro/hooks/datagusto-post-tool-use.json +10 -0
- package/vendor/kiro/.kiro/hooks/datagusto-pre-tool-use.json +10 -0
- package/vendor/kiro/.kiro/hooks/datagusto-session-start.json +10 -0
- package/vendor/kiro/.kiro/hooks/datagusto-stop.json +10 -0
- package/vendor/kiro/.kiro/hooks/datagusto-user-prompt-submit.json +10 -0
- package/vendor/kiro/dist/api-client.js +82 -0
- package/vendor/kiro/dist/builtin-tools.generated.js +87 -0
- package/vendor/kiro/dist/engine.js +65 -0
- package/vendor/kiro/dist/extractors.js +201 -0
- package/vendor/kiro/dist/index.js +735 -0
- package/vendor/kiro/dist/monitoring.js +66 -0
- package/vendor/kiro/dist/state.js +71 -0
- package/vendor/kiro/dist/types.js +5 -0
- package/vendor/kiro/package.json +25 -0
- package/vendor/manifest.json +42 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Datagusto Safety Plugin - Pure extraction & hashing helpers
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
import { createHash } from "node:crypto";
|
|
5
|
+
import { BUILTIN_TOOLS } from "./builtin-tools.generated.js";
|
|
6
|
+
// -- Tool definition extraction ---------------------------------------------
|
|
7
|
+
const EMPTY_OBJECT_SCHEMA = {
|
|
8
|
+
type: "object",
|
|
9
|
+
properties: {},
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Build DatagustoTool[] from the bundled Claude Code built-in tool catalog
|
|
13
|
+
* (see builtin-tools.generated.ts). Unlike OpenClaw, none of Claude Code's
|
|
14
|
+
* hook payloads expose the active tool catalog, so we register this fixed
|
|
15
|
+
* snapshot at the start of each session rather than extracting it per-turn.
|
|
16
|
+
* Output schemas are not exposed by Claude Code either and stay as the
|
|
17
|
+
* empty-object placeholder.
|
|
18
|
+
*/
|
|
19
|
+
export function buildBuiltinToolDefinitions() {
|
|
20
|
+
return BUILTIN_TOOLS.map((t) => ({
|
|
21
|
+
name: t.id,
|
|
22
|
+
description: t.description,
|
|
23
|
+
input_schema: t.inputSchema,
|
|
24
|
+
output_schema: { ...EMPTY_OBJECT_SCHEMA },
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
// -- User instruction extraction --------------------------------------------
|
|
28
|
+
/**
|
|
29
|
+
* Returns true if the prompt is a Claude Code slash command (e.g. "/compact",
|
|
30
|
+
* "/code-review") or bash-mode shortcut (e.g. "!ls") that should not be sent
|
|
31
|
+
* to alignment. This replaces OpenClaw's `stripChannelMetadata` /
|
|
32
|
+
* `isOpenClawCommand` pair: Claude Code's `UserPromptSubmit` payload already
|
|
33
|
+
* hands over the raw, unwrapped prompt text (no channel metadata header to
|
|
34
|
+
* strip), so the only filtering needed is for command-mode input.
|
|
35
|
+
*/
|
|
36
|
+
export function isClaudeCodeCommand(prompt) {
|
|
37
|
+
const trimmed = prompt.trim();
|
|
38
|
+
return /^\/\w+/.test(trimmed) || trimmed.startsWith("!");
|
|
39
|
+
}
|
|
40
|
+
// -- Stable hashing ---------------------------------------------------------
|
|
41
|
+
/**
|
|
42
|
+
* Recursively sort object keys so that `JSON.stringify` produces
|
|
43
|
+
* a deterministic string regardless of insertion order.
|
|
44
|
+
*/
|
|
45
|
+
function stableStringify(value) {
|
|
46
|
+
if (value === null || value === undefined)
|
|
47
|
+
return JSON.stringify(value);
|
|
48
|
+
if (Array.isArray(value)) {
|
|
49
|
+
return "[" + value.map(stableStringify).join(",") + "]";
|
|
50
|
+
}
|
|
51
|
+
if (typeof value === "object") {
|
|
52
|
+
const obj = value;
|
|
53
|
+
const keys = Object.keys(obj).sort();
|
|
54
|
+
return ("{" +
|
|
55
|
+
keys
|
|
56
|
+
.map((k) => JSON.stringify(k) + ":" + stableStringify(obj[k]))
|
|
57
|
+
.join(",") +
|
|
58
|
+
"}");
|
|
59
|
+
}
|
|
60
|
+
return JSON.stringify(value);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* SHA-256 hash of a payload using stable (key-sorted) JSON serialization.
|
|
64
|
+
*/
|
|
65
|
+
export function hashPayload(payload) {
|
|
66
|
+
const data = stableStringify(payload);
|
|
67
|
+
return createHash("sha256").update(data, "utf8").digest("hex");
|
|
68
|
+
}
|
|
69
|
+
// -- Tool result serialization ----------------------------------------------
|
|
70
|
+
/**
|
|
71
|
+
* Normalize a Claude Code `tool_response` into a plain JSON-safe value
|
|
72
|
+
* suitable for the validate API's `output` field. Unlike OpenClaw's
|
|
73
|
+
* LangChain-style ToolMessage result, Claude Code's `tool_response` is
|
|
74
|
+
* already a plain string or JSON-shaped object, so this only guards
|
|
75
|
+
* against values that don't round-trip through JSON.
|
|
76
|
+
*/
|
|
77
|
+
export function serializeToolResult(result) {
|
|
78
|
+
if (result == null || typeof result === "string")
|
|
79
|
+
return result;
|
|
80
|
+
try {
|
|
81
|
+
return JSON.parse(JSON.stringify(result));
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return String(result);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// -- Block reason / phase extraction ------------------------------------------
|
|
88
|
+
// Datagusto returns triggered_guardrails / metadata at the top level of the
|
|
89
|
+
// validate response (see backend/app/api/v1/endpoints/safety.py). Older or
|
|
90
|
+
// alternate shapes nested them under evaluation_result, so we read both.
|
|
91
|
+
function getTriggeredGuardrails(data) {
|
|
92
|
+
return data.triggered_guardrails ?? data.evaluation_result?.triggered_guardrails ?? [];
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Extract a human-readable block reason from a ValidateResponse.
|
|
96
|
+
*
|
|
97
|
+
* Priority:
|
|
98
|
+
* 1. `data.message` (if present)
|
|
99
|
+
* 2. `actions[].result.message` from "block" actions in triggered guardrails
|
|
100
|
+
* 3. `actions[].result.warning_message` from "warn" actions
|
|
101
|
+
* 4. guardrail names as fallback
|
|
102
|
+
* 5. "policy violation" as last resort
|
|
103
|
+
*/
|
|
104
|
+
export function extractBlockReason(data) {
|
|
105
|
+
if (data.message)
|
|
106
|
+
return data.message;
|
|
107
|
+
const guardrails = getTriggeredGuardrails(data);
|
|
108
|
+
const triggered = guardrails.filter((g) => g.triggered);
|
|
109
|
+
// Collect messages from block actions first, then warn actions
|
|
110
|
+
const blockMessages = [];
|
|
111
|
+
const warnMessages = [];
|
|
112
|
+
for (const g of triggered) {
|
|
113
|
+
for (const action of g.actions ?? []) {
|
|
114
|
+
if (action.action_type === "block" && action.result?.message) {
|
|
115
|
+
blockMessages.push(action.result.message);
|
|
116
|
+
}
|
|
117
|
+
else if (action.action_type === "warn" && action.result?.warning_message) {
|
|
118
|
+
warnMessages.push(action.result.warning_message);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (blockMessages.length > 0)
|
|
123
|
+
return blockMessages.join("; ");
|
|
124
|
+
if (warnMessages.length > 0)
|
|
125
|
+
return warnMessages.join("; ");
|
|
126
|
+
// Fallback to guardrail names
|
|
127
|
+
const names = triggered
|
|
128
|
+
.map((g) => g.guardrail_name ?? g.guardrail_id ?? "unknown")
|
|
129
|
+
.join(", ");
|
|
130
|
+
if (names)
|
|
131
|
+
return `triggered: ${names}`;
|
|
132
|
+
return "policy violation";
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Extract a short "phase" tag (used in log messages and block reasons).
|
|
136
|
+
*
|
|
137
|
+
* Prefers `metadata.blocked_by` (set by safety_service for branches like
|
|
138
|
+
* "uncategorized_tool"), then falls back to the first triggered guardrail's
|
|
139
|
+
* id / name. Returns undefined if neither is present.
|
|
140
|
+
*/
|
|
141
|
+
export function extractPhase(data) {
|
|
142
|
+
const blockedBy = data.metadata?.blocked_by;
|
|
143
|
+
if (typeof blockedBy === "string" && blockedBy)
|
|
144
|
+
return blockedBy;
|
|
145
|
+
const triggered = getTriggeredGuardrails(data).filter((g) => g.triggered);
|
|
146
|
+
if (triggered.length > 0) {
|
|
147
|
+
return triggered[0].guardrail_id ?? triggered[0].guardrail_name;
|
|
148
|
+
}
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Normalize a /guardrails/evaluate response into the flat ValidateResponseExtended
|
|
153
|
+
* shape the PreToolUse/PostToolUse handlers already consume.
|
|
154
|
+
*
|
|
155
|
+
* The evaluate endpoint nests decisions inside `triggered_guardrails[].actions[]`,
|
|
156
|
+
* whereas the handlers read top-level `should_proceed` / `severity` /
|
|
157
|
+
* `injected_instruction`. This maps between them:
|
|
158
|
+
* - block action (or warn with allow_proceed=false) → should_proceed=false
|
|
159
|
+
* - warn action with allow_proceed=true → should_proceed stays true, surface
|
|
160
|
+
* severity + injected_instruction (drives the "ask" on_start / "inject" on_end paths)
|
|
161
|
+
* - modify / allow / none → should_proceed=true
|
|
162
|
+
*
|
|
163
|
+
* `should_proceed` from the response is authoritative and honored first; the
|
|
164
|
+
* action walk only enriches severity/instruction and provides a defensive
|
|
165
|
+
* fallback when actions imply a block the top-level flag didn't reflect.
|
|
166
|
+
*/
|
|
167
|
+
export function normalizeEvaluateResponse(data) {
|
|
168
|
+
const triggered = getTriggeredGuardrails(data).filter((g) => g.triggered);
|
|
169
|
+
let hardBlock = false;
|
|
170
|
+
let severity;
|
|
171
|
+
let injectedInstruction;
|
|
172
|
+
for (const g of triggered) {
|
|
173
|
+
for (const action of g.actions ?? []) {
|
|
174
|
+
if (action.action_type === "block") {
|
|
175
|
+
hardBlock = true;
|
|
176
|
+
}
|
|
177
|
+
else if (action.action_type === "warn") {
|
|
178
|
+
const r = action.result ?? {};
|
|
179
|
+
if (r.allow_proceed === false) {
|
|
180
|
+
hardBlock = true;
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
if (r.warning_message && !injectedInstruction) {
|
|
184
|
+
injectedInstruction = r.warning_message;
|
|
185
|
+
}
|
|
186
|
+
if (r.severity && !severity) {
|
|
187
|
+
severity = r.severity;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const shouldProceed = data.should_proceed !== false && !hardBlock;
|
|
194
|
+
return {
|
|
195
|
+
should_proceed: shouldProceed,
|
|
196
|
+
reason: extractBlockReason(data),
|
|
197
|
+
severity,
|
|
198
|
+
injected_instruction: injectedInstruction,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=extractors.js.map
|