@datagusto/cli 0.0.0-stage → 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.
- package/LICENSE +21 -0
- package/README.md +186 -2
- package/bin/run.js +5 -0
- package/dist/adapters/claude-code.d.ts +47 -0
- package/dist/adapters/claude-code.js +533 -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 +740 -0
- package/dist/adapters/kiro.js.map +1 -0
- package/dist/adapters/types.d.ts +79 -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 +8 -0
- package/dist/display.js.map +1 -0
- package/dist/fs/atomic.d.ts +17 -0
- package/dist/fs/atomic.js +41 -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/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
package/dist/display.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { sep } from "node:path";
|
|
2
|
+
/** Show paths under home as ~/…, which is shorter and hides the username. */
|
|
3
|
+
export function tildify(path, homeDir) {
|
|
4
|
+
if (path === homeDir)
|
|
5
|
+
return "~";
|
|
6
|
+
return path.startsWith(homeDir + sep) ? "~" + path.slice(homeDir.length) : path;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=display.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"display.js","sourceRoot":"","sources":["../src/display.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAEhC,6EAA6E;AAC7E,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,OAAe;IACnD,IAAI,IAAI,KAAK,OAAO;QAAE,OAAO,GAAG,CAAC;IACjC,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAClF,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crash-safe file writes.
|
|
3
|
+
*
|
|
4
|
+
* Every file the CLI writes (plugin config, hook entries, the installs
|
|
5
|
+
* ledger) goes through here so a failed or interrupted setup never leaves a
|
|
6
|
+
* half-written file behind (ADR-0003 TR-5). The data lands in a temp file in
|
|
7
|
+
* the same directory, gets its final mode, and is then renamed over the
|
|
8
|
+
* target — rename is atomic on the same filesystem.
|
|
9
|
+
*/
|
|
10
|
+
export interface AtomicWriteOptions {
|
|
11
|
+
/** Final file mode, e.g. 0o600 for anything holding an API key. */
|
|
12
|
+
mode?: number;
|
|
13
|
+
}
|
|
14
|
+
/** Write `data` to `path` via temp file → chmod → rename. */
|
|
15
|
+
export declare function writeFileAtomic(path: string, data: string, options?: AtomicWriteOptions): Promise<void>;
|
|
16
|
+
/** Create `dir` (and parents) if missing and force it to `mode`. */
|
|
17
|
+
export declare function ensureDir(dir: string, mode?: number): Promise<void>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crash-safe file writes.
|
|
3
|
+
*
|
|
4
|
+
* Every file the CLI writes (plugin config, hook entries, the installs
|
|
5
|
+
* ledger) goes through here so a failed or interrupted setup never leaves a
|
|
6
|
+
* half-written file behind (ADR-0003 TR-5). The data lands in a temp file in
|
|
7
|
+
* the same directory, gets its final mode, and is then renamed over the
|
|
8
|
+
* target — rename is atomic on the same filesystem.
|
|
9
|
+
*/
|
|
10
|
+
import { chmod, mkdir, open, rename, rm } from "node:fs/promises";
|
|
11
|
+
import { randomBytes } from "node:crypto";
|
|
12
|
+
import { basename, dirname, join } from "node:path";
|
|
13
|
+
/** Write `data` to `path` via temp file → chmod → rename. */
|
|
14
|
+
export async function writeFileAtomic(path, data, options = {}) {
|
|
15
|
+
const mode = options.mode ?? 0o644;
|
|
16
|
+
const tmp = join(dirname(path), `.${basename(path)}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`);
|
|
17
|
+
try {
|
|
18
|
+
// "wx" refuses to follow a pre-planted file or symlink at the temp path.
|
|
19
|
+
const handle = await open(tmp, "wx", mode);
|
|
20
|
+
try {
|
|
21
|
+
await handle.writeFile(data, "utf8");
|
|
22
|
+
await handle.sync();
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
await handle.close();
|
|
26
|
+
}
|
|
27
|
+
// open()'s mode is filtered by the umask; set the final mode explicitly.
|
|
28
|
+
await chmod(tmp, mode);
|
|
29
|
+
await rename(tmp, path);
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
await rm(tmp, { force: true });
|
|
33
|
+
throw err;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** Create `dir` (and parents) if missing and force it to `mode`. */
|
|
37
|
+
export async function ensureDir(dir, mode = 0o700) {
|
|
38
|
+
await mkdir(dir, { recursive: true, mode });
|
|
39
|
+
await chmod(dir, mode);
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=atomic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atomic.js","sourceRoot":"","sources":["../../src/fs/atomic.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAOpD,6DAA6D;AAC7D,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAY,EACZ,IAAY,EACZ,UAA8B,EAAE;IAEhC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,KAAK,CAAC;IACnC,MAAM,GAAG,GAAG,IAAI,CACd,OAAO,CAAC,IAAI,CAAC,EACb,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAC1E,CAAC;IAEF,IAAI,CAAC;QACH,yEAAyE;QACzE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAC3C,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACrC,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACtB,CAAC;gBAAS,CAAC;YACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;QACD,yEAAyE;QACzE,MAAM,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACvB,MAAM,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/B,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,oEAAoE;AACpE,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW,EAAE,IAAI,GAAG,KAAK;IACvD,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,MAAM,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ReadStream } from "node:tty";
|
|
2
|
+
export declare const API_KEY_ENV = "DATAGUSTO_API_KEY";
|
|
3
|
+
export type KeySource = "env" | "stdin" | "prompt";
|
|
4
|
+
export interface ResolvedKey {
|
|
5
|
+
key: string;
|
|
6
|
+
source: KeySource;
|
|
7
|
+
}
|
|
8
|
+
/** A key problem the user can fix; the message says how. */
|
|
9
|
+
export declare class KeyInputError extends Error {
|
|
10
|
+
name: string;
|
|
11
|
+
}
|
|
12
|
+
export interface KeyInputDeps {
|
|
13
|
+
env?: NodeJS.ProcessEnv;
|
|
14
|
+
stdin?: NodeJS.ReadableStream & {
|
|
15
|
+
isTTY?: boolean;
|
|
16
|
+
};
|
|
17
|
+
/** Hidden-input prompt; injectable for tests. */
|
|
18
|
+
prompt?: (question: string) => Promise<string>;
|
|
19
|
+
}
|
|
20
|
+
export declare function resolveApiKey(deps?: KeyInputDeps): Promise<ResolvedKey>;
|
|
21
|
+
/** Trim and sanity-check a key. Only the platform can say it is valid. */
|
|
22
|
+
export declare function validateApiKey(raw: string, from: string): string;
|
|
23
|
+
/** Read one line from a TTY without echoing it. */
|
|
24
|
+
export declare function promptHidden(question: string, input?: ReadStream, output?: NodeJS.WritableStream): Promise<string>;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// dg CLI - API key input
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// The key is never taken from argv: a flag value lands in shell history and
|
|
6
|
+
// is visible to every user on the machine via `ps` (ADR-0003 TR-4). Sources,
|
|
7
|
+
// in order:
|
|
8
|
+
//
|
|
9
|
+
// 1. DATAGUSTO_API_KEY env var
|
|
10
|
+
// 2. stdin, when it is piped (`pbpaste | dg setup claude-code`)
|
|
11
|
+
// 3. a hidden prompt, when stdin is a terminal
|
|
12
|
+
export const API_KEY_ENV = "DATAGUSTO_API_KEY";
|
|
13
|
+
const KEY_PREFIX = "agt_";
|
|
14
|
+
/** A key problem the user can fix; the message says how. */
|
|
15
|
+
export class KeyInputError extends Error {
|
|
16
|
+
name = "KeyInputError";
|
|
17
|
+
}
|
|
18
|
+
export async function resolveApiKey(deps = {}) {
|
|
19
|
+
const env = deps.env ?? process.env;
|
|
20
|
+
const stdin = deps.stdin ?? process.stdin;
|
|
21
|
+
const fromEnv = env[API_KEY_ENV];
|
|
22
|
+
if (fromEnv !== undefined && fromEnv.trim() !== "") {
|
|
23
|
+
return { key: validateApiKey(fromEnv, `the ${API_KEY_ENV} environment variable`), source: "env" };
|
|
24
|
+
}
|
|
25
|
+
if (!stdin.isTTY) {
|
|
26
|
+
const piped = await readAll(stdin);
|
|
27
|
+
if (piped.trim() === "") {
|
|
28
|
+
throw new KeyInputError(`No API key given. Pipe it in, set ${API_KEY_ENV}, or run this in a terminal to be prompted.`);
|
|
29
|
+
}
|
|
30
|
+
return { key: validateApiKey(piped, "stdin"), source: "stdin" };
|
|
31
|
+
}
|
|
32
|
+
const prompt = deps.prompt ?? ((q) => promptHidden(q, stdin));
|
|
33
|
+
const typed = await prompt("Paste your Datagusto API key (input is hidden): ");
|
|
34
|
+
return { key: validateApiKey(typed, "the prompt"), source: "prompt" };
|
|
35
|
+
}
|
|
36
|
+
/** Trim and sanity-check a key. Only the platform can say it is valid. */
|
|
37
|
+
export function validateApiKey(raw, from) {
|
|
38
|
+
const key = raw.trim();
|
|
39
|
+
if (key === "") {
|
|
40
|
+
throw new KeyInputError(`The API key from ${from} is empty.`);
|
|
41
|
+
}
|
|
42
|
+
if (/\s/.test(key)) {
|
|
43
|
+
throw new KeyInputError(`The API key from ${from} contains spaces or line breaks. Copy it again from the Datagusto dashboard.`);
|
|
44
|
+
}
|
|
45
|
+
if (!key.startsWith(KEY_PREFIX)) {
|
|
46
|
+
throw new KeyInputError(`That doesn't look like a Datagusto agent API key (they start with "${KEY_PREFIX}"). ` +
|
|
47
|
+
"Copy it from your agent's page in the Datagusto dashboard.");
|
|
48
|
+
}
|
|
49
|
+
return key;
|
|
50
|
+
}
|
|
51
|
+
async function readAll(stream) {
|
|
52
|
+
let out = "";
|
|
53
|
+
stream.setEncoding("utf8");
|
|
54
|
+
for await (const chunk of stream)
|
|
55
|
+
out += chunk;
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
/** Read one line from a TTY without echoing it. */
|
|
59
|
+
export function promptHidden(question, input = process.stdin, output = process.stderr) {
|
|
60
|
+
return new Promise((resolve, reject) => {
|
|
61
|
+
let value = "";
|
|
62
|
+
const finish = () => {
|
|
63
|
+
input.off("data", onData);
|
|
64
|
+
input.setRawMode(false);
|
|
65
|
+
input.pause();
|
|
66
|
+
output.write("\n");
|
|
67
|
+
};
|
|
68
|
+
const onData = (chunk) => {
|
|
69
|
+
for (const ch of chunk) {
|
|
70
|
+
if (ch === "\r" || ch === "\n" || ch === "\u0004") {
|
|
71
|
+
finish();
|
|
72
|
+
resolve(value);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (ch === "\u0003") {
|
|
76
|
+
// Raw mode swallows Ctrl-C's SIGINT, so honour it here.
|
|
77
|
+
finish();
|
|
78
|
+
reject(new KeyInputError("Cancelled."));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (ch === "\u007f" || ch === "\b") {
|
|
82
|
+
value = value.slice(0, -1);
|
|
83
|
+
}
|
|
84
|
+
else if (ch >= " ") {
|
|
85
|
+
value += ch;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
output.write(question);
|
|
90
|
+
input.setEncoding("utf8");
|
|
91
|
+
input.setRawMode(true);
|
|
92
|
+
input.resume();
|
|
93
|
+
input.on("data", onData);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=key-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-input.js","sourceRoot":"","sources":["../src/key-input.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,yBAAyB;AACzB,8EAA8E;AAC9E,EAAE;AACF,4EAA4E;AAC5E,6EAA6E;AAC7E,YAAY;AACZ,EAAE;AACF,iCAAiC;AACjC,qEAAqE;AACrE,iDAAiD;AAIjD,MAAM,CAAC,MAAM,WAAW,GAAG,mBAAmB,CAAC;AAC/C,MAAM,UAAU,GAAG,MAAM,CAAC;AAS1B,4DAA4D;AAC5D,MAAM,OAAO,aAAc,SAAQ,KAAK;IAC7B,IAAI,GAAG,eAAe,CAAC;CACjC;AASD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAqB,EAAE;IACzD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACpC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC;IAE1C,MAAM,OAAO,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC;IACjC,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACnD,OAAO,EAAE,GAAG,EAAE,cAAc,CAAC,OAAO,EAAE,OAAO,WAAW,uBAAuB,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IACpG,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACxB,MAAM,IAAI,aAAa,CACrB,qCAAqC,WAAW,6CAA6C,CAC9F,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IAClE,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,KAAmB,CAAC,CAAC,CAAC;IACpF,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,kDAAkD,CAAC,CAAC;IAC/E,OAAO,EAAE,GAAG,EAAE,cAAc,CAAC,KAAK,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AACxE,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,IAAY;IACtD,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACvB,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;QACf,MAAM,IAAI,aAAa,CAAC,oBAAoB,IAAI,YAAY,CAAC,CAAC;IAChE,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACnB,MAAM,IAAI,aAAa,CACrB,oBAAoB,IAAI,8EAA8E,CACvG,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,aAAa,CACrB,sEAAsE,UAAU,MAAM;YACpF,4DAA4D,CAC/D,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,KAAK,UAAU,OAAO,CAAC,MAA6B;IAClD,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAC3B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM;QAAE,GAAG,IAAI,KAAK,CAAC;IAC/C,OAAO,GAAG,CAAC;AACb,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,YAAY,CAC1B,QAAgB,EAChB,QAAoB,OAAO,CAAC,KAAK,EACjC,SAAgC,OAAO,CAAC,MAAM;IAE9C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,KAAK,GAAG,EAAE,CAAC;QAEf,MAAM,MAAM,GAAG,GAAG,EAAE;YAClB,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAC1B,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YACxB,KAAK,CAAC,KAAK,EAAE,CAAC;YACd,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC,CAAC;QAEF,MAAM,MAAM,GAAG,CAAC,KAAa,EAAE,EAAE;YAC/B,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;gBACvB,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,KAAK,QAAQ,EAAE,CAAC;oBAClD,MAAM,EAAE,CAAC;oBACT,OAAO,CAAC,KAAK,CAAC,CAAC;oBACf,OAAO;gBACT,CAAC;gBACD,IAAI,EAAE,KAAK,QAAQ,EAAE,CAAC;oBACpB,wDAAwD;oBACxD,MAAM,EAAE,CAAC;oBACT,MAAM,CAAC,IAAI,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC;oBACxC,OAAO;gBACT,CAAC;gBACD,IAAI,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;oBACnC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC7B,CAAC;qBAAM,IAAI,EAAE,IAAI,GAAG,EAAE,CAAC;oBACrB,KAAK,IAAI,EAAE,CAAC;gBACd,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACvB,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC1B,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACvB,KAAK,CAAC,MAAM,EAAE,CAAC;QACf,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type AgentName } from "../adapters/types.js";
|
|
2
|
+
export interface InstallRecord {
|
|
3
|
+
agent: AgentName;
|
|
4
|
+
/** Absolute workspace dir for per-workspace installs (Kiro), else null. */
|
|
5
|
+
workspace: string | null;
|
|
6
|
+
/** Datagusto agent UUID the installed key belongs to. */
|
|
7
|
+
agentId: string;
|
|
8
|
+
/** Every file or dir setup created or edited, for remove and status. */
|
|
9
|
+
paths: string[];
|
|
10
|
+
installedAt: string;
|
|
11
|
+
cliVersion: string;
|
|
12
|
+
}
|
|
13
|
+
/** The ledger exists but can't be trusted; we refuse to overwrite it. */
|
|
14
|
+
export declare class LedgerError extends Error {
|
|
15
|
+
name: string;
|
|
16
|
+
}
|
|
17
|
+
/** `$DATAGUSTO_HOME`, else `~/.datagusto`. */
|
|
18
|
+
export declare function datagustoHome(env?: NodeJS.ProcessEnv): string;
|
|
19
|
+
export declare function listInstalls(dir?: string): Promise<InstallRecord[]>;
|
|
20
|
+
export declare function findInstall(agent: AgentName, workspace: string | null, dir?: string): Promise<InstallRecord | undefined>;
|
|
21
|
+
/** Add a record, replacing any earlier one for the same agent + workspace. */
|
|
22
|
+
export declare function recordInstall(record: InstallRecord, dir?: string): Promise<void>;
|
|
23
|
+
/** Drop the record for agent + workspace; returns it if there was one. */
|
|
24
|
+
export declare function forgetInstall(agent: AgentName, workspace: string | null, dir?: string): Promise<InstallRecord | undefined>;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// dg CLI - installs ledger (~/.datagusto/installs.json)
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// Remembers what `dg setup` touched so `dg status` and `dg remove` can find
|
|
6
|
+
// it again, which matters for Kiro, where every workspace has its own hooks.
|
|
7
|
+
// It holds paths and the Datagusto agent id only. The API key lives in the
|
|
8
|
+
// plugin's own config file and must never be written here.
|
|
9
|
+
import { readFile } from "node:fs/promises";
|
|
10
|
+
import { homedir } from "node:os";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { AGENT_NAMES } from "../adapters/types.js";
|
|
13
|
+
import { ensureDir, writeFileAtomic } from "../fs/atomic.js";
|
|
14
|
+
const LEDGER_FILE = "installs.json";
|
|
15
|
+
const LEDGER_VERSION = 1;
|
|
16
|
+
/** The ledger exists but can't be trusted; we refuse to overwrite it. */
|
|
17
|
+
export class LedgerError extends Error {
|
|
18
|
+
name = "LedgerError";
|
|
19
|
+
}
|
|
20
|
+
/** `$DATAGUSTO_HOME`, else `~/.datagusto`. */
|
|
21
|
+
export function datagustoHome(env = process.env) {
|
|
22
|
+
return env.DATAGUSTO_HOME || join(homedir(), ".datagusto");
|
|
23
|
+
}
|
|
24
|
+
export async function listInstalls(dir = datagustoHome()) {
|
|
25
|
+
return (await readLedger(dir)).installs;
|
|
26
|
+
}
|
|
27
|
+
export async function findInstall(agent, workspace, dir = datagustoHome()) {
|
|
28
|
+
return (await listInstalls(dir)).find((r) => sameTarget(r, agent, workspace));
|
|
29
|
+
}
|
|
30
|
+
/** Add a record, replacing any earlier one for the same agent + workspace. */
|
|
31
|
+
export async function recordInstall(record, dir = datagustoHome()) {
|
|
32
|
+
const ledger = await readLedger(dir);
|
|
33
|
+
const installs = ledger.installs.filter((r) => !sameTarget(r, record.agent, record.workspace));
|
|
34
|
+
installs.push(pick(record));
|
|
35
|
+
await writeLedger(dir, installs);
|
|
36
|
+
}
|
|
37
|
+
/** Drop the record for agent + workspace; returns it if there was one. */
|
|
38
|
+
export async function forgetInstall(agent, workspace, dir = datagustoHome()) {
|
|
39
|
+
const ledger = await readLedger(dir);
|
|
40
|
+
const existing = ledger.installs.find((r) => sameTarget(r, agent, workspace));
|
|
41
|
+
if (!existing)
|
|
42
|
+
return undefined;
|
|
43
|
+
await writeLedger(dir, ledger.installs.filter((r) => r !== existing));
|
|
44
|
+
return existing;
|
|
45
|
+
}
|
|
46
|
+
// -- Internal helpers ---------------------------------------------------------
|
|
47
|
+
function sameTarget(r, agent, workspace) {
|
|
48
|
+
return r.agent === agent && r.workspace === workspace;
|
|
49
|
+
}
|
|
50
|
+
/** Copy known fields only, so nothing else (e.g. an API key) is persisted. */
|
|
51
|
+
function pick(r) {
|
|
52
|
+
return {
|
|
53
|
+
agent: r.agent,
|
|
54
|
+
workspace: r.workspace,
|
|
55
|
+
agentId: r.agentId,
|
|
56
|
+
paths: [...r.paths],
|
|
57
|
+
installedAt: r.installedAt,
|
|
58
|
+
cliVersion: r.cliVersion,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
async function readLedger(dir) {
|
|
62
|
+
const path = join(dir, LEDGER_FILE);
|
|
63
|
+
let raw;
|
|
64
|
+
try {
|
|
65
|
+
raw = await readFile(path, "utf8");
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
if (err.code === "ENOENT") {
|
|
69
|
+
return { version: LEDGER_VERSION, installs: [] };
|
|
70
|
+
}
|
|
71
|
+
throw err;
|
|
72
|
+
}
|
|
73
|
+
let parsed;
|
|
74
|
+
try {
|
|
75
|
+
parsed = JSON.parse(raw);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
throw new LedgerError(`${path} is not valid JSON. Fix or delete it, then run the command again.`);
|
|
79
|
+
}
|
|
80
|
+
if (!isLedger(parsed)) {
|
|
81
|
+
throw new LedgerError(`${path} isn't a ledger this version of dg understands. Update the CLI, or fix or delete the file.`);
|
|
82
|
+
}
|
|
83
|
+
return parsed;
|
|
84
|
+
}
|
|
85
|
+
async function writeLedger(dir, installs) {
|
|
86
|
+
await ensureDir(dir, 0o700);
|
|
87
|
+
const body = { version: LEDGER_VERSION, installs };
|
|
88
|
+
await writeFileAtomic(join(dir, LEDGER_FILE), JSON.stringify(body, null, 2) + "\n", {
|
|
89
|
+
mode: 0o600,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function isLedger(v) {
|
|
93
|
+
if (typeof v !== "object" || v === null)
|
|
94
|
+
return false;
|
|
95
|
+
const l = v;
|
|
96
|
+
return l.version === LEDGER_VERSION && Array.isArray(l.installs) && l.installs.every(isRecord);
|
|
97
|
+
}
|
|
98
|
+
function isRecord(v) {
|
|
99
|
+
if (typeof v !== "object" || v === null)
|
|
100
|
+
return false;
|
|
101
|
+
const r = v;
|
|
102
|
+
return (AGENT_NAMES.includes(r.agent) &&
|
|
103
|
+
(r.workspace === null || typeof r.workspace === "string") &&
|
|
104
|
+
typeof r.agentId === "string" &&
|
|
105
|
+
Array.isArray(r.paths) &&
|
|
106
|
+
r.paths.every((p) => typeof p === "string") &&
|
|
107
|
+
typeof r.installedAt === "string" &&
|
|
108
|
+
typeof r.cliVersion === "string");
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=installs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installs.js","sourceRoot":"","sources":["../../src/state/installs.ts"],"names":[],"mappings":"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"}
|
package/dist/vendor.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface VendoredPlugin {
|
|
2
|
+
pluginVersion: string;
|
|
3
|
+
/** POSIX path relative to the plugin root → sha256 hex. */
|
|
4
|
+
files: Record<string, string>;
|
|
5
|
+
}
|
|
6
|
+
/** The bundled builds are missing or unreadable, i.e. a broken package. */
|
|
7
|
+
export declare class VendorError extends Error {
|
|
8
|
+
name: string;
|
|
9
|
+
}
|
|
10
|
+
/** cli/vendor/, resolved from dist/vendor.js. */
|
|
11
|
+
export declare function defaultVendorDir(): string;
|
|
12
|
+
export declare function loadVendoredPlugin(vendorDir: string, plugin: string): Promise<VendoredPlugin>;
|
|
13
|
+
/** sha256 of the raw bytes, hex. Must match scripts/write-vendor-manifest.mjs. */
|
|
14
|
+
export declare function hashFile(path: string): Promise<string>;
|
|
15
|
+
/** Files under `root` that are missing or don't match `files`' hashes. */
|
|
16
|
+
export declare function changedFiles(root: string, files: Record<string, string>): Promise<string[]>;
|
package/dist/vendor.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// dg CLI - bundled plugin builds (cli/vendor/)
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// scripts/vendor-plugins.sh copies each plugin's runtime files into
|
|
6
|
+
// vendor/<plugin>/ and hashes them into vendor/manifest.json. Setup checks
|
|
7
|
+
// the copies against the manifest before installing them, and doctor checks
|
|
8
|
+
// the installed files against the hashes recorded at install time.
|
|
9
|
+
import { createHash } from "node:crypto";
|
|
10
|
+
import { readFile } from "node:fs/promises";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
const MANIFEST_FILE = "manifest.json";
|
|
14
|
+
const MANIFEST_VERSION = 1;
|
|
15
|
+
/** The bundled builds are missing or unreadable, i.e. a broken package. */
|
|
16
|
+
export class VendorError extends Error {
|
|
17
|
+
name = "VendorError";
|
|
18
|
+
}
|
|
19
|
+
/** cli/vendor/, resolved from dist/vendor.js. */
|
|
20
|
+
export function defaultVendorDir() {
|
|
21
|
+
return fileURLToPath(new URL("../vendor/", import.meta.url));
|
|
22
|
+
}
|
|
23
|
+
export async function loadVendoredPlugin(vendorDir, plugin) {
|
|
24
|
+
const path = join(vendorDir, MANIFEST_FILE);
|
|
25
|
+
let manifest;
|
|
26
|
+
try {
|
|
27
|
+
manifest = JSON.parse(await readFile(path, "utf8"));
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
throw new VendorError(`The plugin files bundled with dg are missing (${path}). Reinstall the CLI: npm install -g @datagusto/cli`);
|
|
31
|
+
}
|
|
32
|
+
const entry = manifest.version === MANIFEST_VERSION ? manifest.plugins?.[plugin] : undefined;
|
|
33
|
+
const safe = (rel) => rel !== "" && !rel.startsWith("/") && !rel.split("/").some((p) => p === ".." || p === "");
|
|
34
|
+
if (!entry ||
|
|
35
|
+
typeof entry.files !== "object" ||
|
|
36
|
+
Object.keys(entry.files).length === 0 ||
|
|
37
|
+
!Object.keys(entry.files).every(safe)) {
|
|
38
|
+
throw new VendorError(`This copy of dg doesn't include the ${plugin} plugin. Reinstall the CLI: npm install -g @datagusto/cli`);
|
|
39
|
+
}
|
|
40
|
+
return entry;
|
|
41
|
+
}
|
|
42
|
+
/** sha256 of the raw bytes, hex. Must match scripts/write-vendor-manifest.mjs. */
|
|
43
|
+
export async function hashFile(path) {
|
|
44
|
+
return createHash("sha256").update(await readFile(path)).digest("hex");
|
|
45
|
+
}
|
|
46
|
+
/** Files under `root` that are missing or don't match `files`' hashes. */
|
|
47
|
+
export async function changedFiles(root, files) {
|
|
48
|
+
const bad = [];
|
|
49
|
+
for (const [rel, expected] of Object.entries(files)) {
|
|
50
|
+
try {
|
|
51
|
+
if ((await hashFile(join(root, ...rel.split("/")))) !== expected)
|
|
52
|
+
bad.push(rel);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
bad.push(rel);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return bad;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=vendor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vendor.js","sourceRoot":"","sources":["../src/vendor.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,59 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagusto/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Connect a coding agent (Claude Code, Kiro) to your company's Datagusto server with one command",
|
|
5
|
+
"homepage": "https://github.com/datagusto/safety-platform-plugins/tree/main/cli#readme",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/datagusto/safety-platform-plugins.git",
|
|
9
|
+
"directory": "cli"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/datagusto/safety-platform-plugins/issues"
|
|
13
|
+
},
|
|
14
|
+
"type": "module",
|
|
15
|
+
"bin": {
|
|
16
|
+
"dg": "bin/run.js",
|
|
17
|
+
"datagusto": "bin/run.js"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"typecheck": "tsc --noEmit",
|
|
21
|
+
"vendor": "./scripts/vendor-plugins.sh",
|
|
22
|
+
"build": "tsc",
|
|
23
|
+
"prepublishOnly": "npm run vendor && npm run build",
|
|
24
|
+
"test": "npm run vendor && npm run build && node --test tests/*.test.mjs"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"bin/",
|
|
28
|
+
"dist/",
|
|
29
|
+
"vendor/",
|
|
30
|
+
"README.md"
|
|
31
|
+
],
|
|
32
|
+
"oclif": {
|
|
33
|
+
"bin": "dg",
|
|
34
|
+
"binAliases": [
|
|
35
|
+
"datagusto"
|
|
36
|
+
],
|
|
37
|
+
"dirname": "datagusto",
|
|
38
|
+
"commands": "./dist/commands",
|
|
39
|
+
"plugins": [
|
|
40
|
+
"@oclif/plugin-help"
|
|
41
|
+
],
|
|
42
|
+
"topicSeparator": " "
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=22"
|
|
46
|
+
},
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@oclif/core": "^5.1.2",
|
|
53
|
+
"@oclif/plugin-help": "^7.0.2"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@types/node": "^22.0.0",
|
|
57
|
+
"typescript": "^6.0.3"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "datagusto-safety-plugin",
|
|
3
|
+
"description": "Integrates Datagusto safety validation API with Claude Code's hook lifecycle (PreToolUse / PermissionRequest / PostToolUse / PostToolUseFailure / UserPromptSubmit / SessionStart / SessionEnd).",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"author": { "name": "Datagusto" },
|
|
6
|
+
"userConfig": {
|
|
7
|
+
"server_url": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"title": "Datagusto server URL",
|
|
10
|
+
"description": "Datagusto server base URL, e.g. https://datagusto.example.com. Leave empty if you connected with `dg setup claude-code`, which writes it to claude-code.json."
|
|
11
|
+
},
|
|
12
|
+
"api_key": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"title": "Datagusto API key",
|
|
15
|
+
"description": "Bearer auth key for the Datagusto API. Leave empty if you connected with `dg setup claude-code`, which writes it to claude-code.json.",
|
|
16
|
+
"sensitive": true
|
|
17
|
+
},
|
|
18
|
+
"timeout_ms": {
|
|
19
|
+
"type": "number",
|
|
20
|
+
"title": "Request timeout (ms)",
|
|
21
|
+
"description": "Per-request timeout for Datagusto API calls.",
|
|
22
|
+
"default": 30000
|
|
23
|
+
},
|
|
24
|
+
"fail_closed": {
|
|
25
|
+
"type": "boolean",
|
|
26
|
+
"title": "Fail closed on API errors",
|
|
27
|
+
"description": "Deny/block tool execution when the API is unreachable or errors.",
|
|
28
|
+
"default": true
|
|
29
|
+
},
|
|
30
|
+
"verbose": {
|
|
31
|
+
"type": "boolean",
|
|
32
|
+
"title": "Verbose logging",
|
|
33
|
+
"description": "Per-hook debug logging to stderr.",
|
|
34
|
+
"default": false
|
|
35
|
+
},
|
|
36
|
+
"monitor_only": {
|
|
37
|
+
"type": "boolean",
|
|
38
|
+
"title": "Monitor-only mode",
|
|
39
|
+
"description": "Log decisions without enforcing them.",
|
|
40
|
+
"default": false
|
|
41
|
+
},
|
|
42
|
+
"auto_approve_vetted_permissions": {
|
|
43
|
+
"type": "boolean",
|
|
44
|
+
"title": "Auto-approve vetted permissions",
|
|
45
|
+
"description": "When Datagusto's PreToolUse check already allowed a call, auto-resolve Claude Code's own native permission dialog instead of prompting the user again. Never overrides an explicit Datagusto ask/deny. Off by default — opt in to reduce double-prompting.",
|
|
46
|
+
"default": false
|
|
47
|
+
},
|
|
48
|
+
"allow_uncategorized_tools": {
|
|
49
|
+
"type": "boolean",
|
|
50
|
+
"title": "Allow uncategorized tools",
|
|
51
|
+
"description": "The alignment layer default-denies tools its intent-judge didn't predict from the prompt. When true, that specific deny is downgraded to allow if the assigned guardrail rules also allowed the call. Intent violations and assigned-rule blocks are never downgraded.",
|
|
52
|
+
"default": true
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|