@1claw/cli 0.36.6 → 0.37.1
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/README.md +66 -1
- package/dist/bundled-templates/registry.yaml +62 -0
- package/dist/bundled-templates/templates/agentkit/Dockerfile +28 -0
- package/dist/bundled-templates/templates/agentkit/README.md +36 -0
- package/dist/bundled-templates/templates/agentkit/agent.py +83 -0
- package/dist/bundled-templates/templates/agentkit/entrypoint.sh +34 -0
- package/dist/bundled-templates/templates/agentkit/requirements.txt +5 -0
- package/dist/bundled-templates/templates/agentkit/template.yaml +24 -0
- package/dist/bundled-templates/templates/agno/Dockerfile +28 -0
- package/dist/bundled-templates/templates/agno/README.md +36 -0
- package/dist/bundled-templates/templates/agno/agent.py +86 -0
- package/dist/bundled-templates/templates/agno/entrypoint.sh +34 -0
- package/dist/bundled-templates/templates/agno/requirements.txt +2 -0
- package/dist/bundled-templates/templates/agno/template.yaml +24 -0
- package/dist/bundled-templates/templates/coder/Dockerfile +28 -0
- package/dist/bundled-templates/templates/coder/README.md +36 -0
- package/dist/bundled-templates/templates/coder/agent.py +119 -0
- package/dist/bundled-templates/templates/coder/entrypoint.sh +34 -0
- package/dist/bundled-templates/templates/coder/requirements.txt +4 -0
- package/dist/bundled-templates/templates/coder/template.yaml +24 -0
- package/dist/bundled-templates/templates/crewai/Dockerfile +28 -0
- package/dist/bundled-templates/templates/crewai/README.md +29 -0
- package/dist/bundled-templates/templates/crewai/agent.py +109 -0
- package/dist/bundled-templates/templates/crewai/entrypoint.sh +34 -0
- package/dist/bundled-templates/templates/crewai/requirements.txt +3 -0
- package/dist/bundled-templates/templates/crewai/template.yaml +24 -0
- package/dist/bundled-templates/templates/elizaos/Dockerfile +31 -0
- package/dist/bundled-templates/templates/elizaos/README.md +36 -0
- package/dist/bundled-templates/templates/elizaos/agent.ts +100 -0
- package/dist/bundled-templates/templates/elizaos/entrypoint.sh +34 -0
- package/dist/bundled-templates/templates/elizaos/package.json +18 -0
- package/dist/bundled-templates/templates/elizaos/template.yaml +25 -0
- package/dist/bundled-templates/templates/elizaos/tsconfig.json +12 -0
- package/dist/bundled-templates/templates/langchain/Dockerfile +28 -0
- package/dist/bundled-templates/templates/langchain/README.md +37 -0
- package/dist/bundled-templates/templates/langchain/agent.py +115 -0
- package/dist/bundled-templates/templates/langchain/entrypoint.sh +36 -0
- package/dist/bundled-templates/templates/langchain/requirements.txt +4 -0
- package/dist/bundled-templates/templates/langchain/template.yaml +24 -0
- package/dist/bundled-templates/templates/llamaindex/Dockerfile +28 -0
- package/dist/bundled-templates/templates/llamaindex/README.md +36 -0
- package/dist/bundled-templates/templates/llamaindex/agent.py +97 -0
- package/dist/bundled-templates/templates/llamaindex/entrypoint.sh +34 -0
- package/dist/bundled-templates/templates/llamaindex/requirements.txt +3 -0
- package/dist/bundled-templates/templates/llamaindex/template.yaml +24 -0
- package/dist/bundled-templates/templates/mastra/Dockerfile +31 -0
- package/dist/bundled-templates/templates/mastra/README.md +31 -0
- package/dist/bundled-templates/templates/mastra/agent.ts +112 -0
- package/dist/bundled-templates/templates/mastra/entrypoint.sh +34 -0
- package/dist/bundled-templates/templates/mastra/package.json +17 -0
- package/dist/bundled-templates/templates/mastra/template.yaml +25 -0
- package/dist/bundled-templates/templates/mastra/tsconfig.json +12 -0
- package/dist/bundled-templates/templates/openai-agents/Dockerfile +28 -0
- package/dist/bundled-templates/templates/openai-agents/README.md +29 -0
- package/dist/bundled-templates/templates/openai-agents/agent.py +98 -0
- package/dist/bundled-templates/templates/openai-agents/entrypoint.sh +34 -0
- package/dist/bundled-templates/templates/openai-agents/requirements.txt +3 -0
- package/dist/bundled-templates/templates/openai-agents/template.yaml +24 -0
- package/dist/bundled-templates/templates/pydantic-ai/Dockerfile +28 -0
- package/dist/bundled-templates/templates/pydantic-ai/README.md +36 -0
- package/dist/bundled-templates/templates/pydantic-ai/agent.py +110 -0
- package/dist/bundled-templates/templates/pydantic-ai/entrypoint.sh +34 -0
- package/dist/bundled-templates/templates/pydantic-ai/requirements.txt +2 -0
- package/dist/bundled-templates/templates/pydantic-ai/template.yaml +24 -0
- package/dist/bundled-templates/templates/smolagents/Dockerfile +28 -0
- package/dist/bundled-templates/templates/smolagents/README.md +36 -0
- package/dist/bundled-templates/templates/smolagents/agent.py +97 -0
- package/dist/bundled-templates/templates/smolagents/entrypoint.sh +34 -0
- package/dist/bundled-templates/templates/smolagents/requirements.txt +2 -0
- package/dist/bundled-templates/templates/smolagents/template.yaml +24 -0
- package/dist/bundled-templates/templates/typescript-sdk/Dockerfile +31 -0
- package/dist/bundled-templates/templates/typescript-sdk/README.md +29 -0
- package/dist/bundled-templates/templates/typescript-sdk/agent.ts +130 -0
- package/dist/bundled-templates/templates/typescript-sdk/entrypoint.sh +34 -0
- package/dist/bundled-templates/templates/typescript-sdk/package.json +17 -0
- package/dist/bundled-templates/templates/typescript-sdk/template.yaml +25 -0
- package/dist/bundled-templates/templates/typescript-sdk/tsconfig.json +12 -0
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/init.js +10 -255
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/spawn.d.ts +3 -0
- package/dist/src/commands/spawn.d.ts.map +1 -0
- package/dist/src/commands/spawn.js +408 -0
- package/dist/src/commands/spawn.js.map +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/lib/container-config.d.ts +3 -1
- package/dist/src/lib/container-config.d.ts.map +1 -1
- package/dist/src/lib/container-config.js +3 -2
- package/dist/src/lib/container-config.js.map +1 -1
- package/dist/src/lib/module-deprecation.d.ts +8 -0
- package/dist/src/lib/module-deprecation.d.ts.map +1 -0
- package/dist/src/lib/module-deprecation.js +15 -0
- package/dist/src/lib/module-deprecation.js.map +1 -0
- package/dist/src/lib/paths.d.ts +12 -0
- package/dist/src/lib/paths.d.ts.map +1 -1
- package/dist/src/lib/paths.js +42 -1
- package/dist/src/lib/paths.js.map +1 -1
- package/dist/src/lib/provisioning.d.ts +30 -0
- package/dist/src/lib/provisioning.d.ts.map +1 -0
- package/dist/src/lib/provisioning.js +256 -0
- package/dist/src/lib/provisioning.js.map +1 -0
- package/dist/src/registry.yaml +62 -0
- package/dist/src/templates/agentkit/Dockerfile +34 -0
- package/dist/src/templates/agentkit/README.md +36 -0
- package/dist/src/templates/agentkit/agent.py +83 -0
- package/dist/src/templates/agentkit/entrypoint.sh +34 -0
- package/dist/src/templates/agentkit/requirements.txt +5 -0
- package/dist/src/templates/agentkit/template.yaml +24 -0
- package/dist/src/templates/agno/Dockerfile +34 -0
- package/dist/src/templates/agno/README.md +36 -0
- package/dist/src/templates/agno/agent.py +86 -0
- package/dist/src/templates/agno/entrypoint.sh +34 -0
- package/dist/src/templates/agno/requirements.txt +2 -0
- package/dist/src/templates/agno/template.yaml +24 -0
- package/dist/src/templates/coder/Dockerfile +34 -0
- package/dist/src/templates/coder/README.md +36 -0
- package/dist/src/templates/coder/agent.py +119 -0
- package/dist/src/templates/coder/entrypoint.sh +34 -0
- package/dist/src/templates/coder/requirements.txt +4 -0
- package/dist/src/templates/coder/template.yaml +24 -0
- package/dist/src/templates/crewai/Dockerfile +34 -0
- package/dist/src/templates/crewai/README.md +29 -0
- package/dist/src/templates/crewai/agent.py +109 -0
- package/dist/src/templates/crewai/entrypoint.sh +34 -0
- package/dist/src/templates/crewai/requirements.txt +3 -0
- package/dist/src/templates/crewai/template.yaml +24 -0
- package/dist/src/templates/elizaos/Dockerfile +31 -0
- package/dist/src/templates/elizaos/README.md +36 -0
- package/dist/src/templates/elizaos/agent.ts +100 -0
- package/dist/src/templates/elizaos/entrypoint.sh +34 -0
- package/dist/src/templates/elizaos/package.json +18 -0
- package/dist/src/templates/elizaos/template.yaml +25 -0
- package/dist/src/templates/elizaos/tsconfig.json +12 -0
- package/dist/src/templates/fetcher.d.ts +20 -0
- package/dist/src/templates/fetcher.d.ts.map +1 -0
- package/dist/src/templates/fetcher.js +189 -0
- package/dist/src/templates/fetcher.js.map +1 -0
- package/dist/src/templates/langchain/Dockerfile +34 -0
- package/dist/src/templates/langchain/README.md +37 -0
- package/dist/src/templates/langchain/agent.py +115 -0
- package/dist/src/templates/langchain/entrypoint.sh +36 -0
- package/dist/src/templates/langchain/requirements.txt +4 -0
- package/dist/src/templates/langchain/template.yaml +24 -0
- package/dist/src/templates/llamaindex/Dockerfile +34 -0
- package/dist/src/templates/llamaindex/README.md +36 -0
- package/dist/src/templates/llamaindex/agent.py +97 -0
- package/dist/src/templates/llamaindex/entrypoint.sh +34 -0
- package/dist/src/templates/llamaindex/requirements.txt +3 -0
- package/dist/src/templates/llamaindex/template.yaml +24 -0
- package/dist/src/templates/mastra/Dockerfile +31 -0
- package/dist/src/templates/mastra/README.md +31 -0
- package/dist/src/templates/mastra/agent.ts +112 -0
- package/dist/src/templates/mastra/entrypoint.sh +34 -0
- package/dist/src/templates/mastra/package.json +17 -0
- package/dist/src/templates/mastra/template.yaml +25 -0
- package/dist/src/templates/mastra/tsconfig.json +12 -0
- package/dist/src/templates/openai-agents/Dockerfile +34 -0
- package/dist/src/templates/openai-agents/README.md +29 -0
- package/dist/src/templates/openai-agents/agent.py +98 -0
- package/dist/src/templates/openai-agents/entrypoint.sh +34 -0
- package/dist/src/templates/openai-agents/requirements.txt +3 -0
- package/dist/src/templates/openai-agents/template.yaml +24 -0
- package/dist/src/templates/pydantic-ai/Dockerfile +34 -0
- package/dist/src/templates/pydantic-ai/README.md +36 -0
- package/dist/src/templates/pydantic-ai/agent.py +110 -0
- package/dist/src/templates/pydantic-ai/entrypoint.sh +34 -0
- package/dist/src/templates/pydantic-ai/requirements.txt +2 -0
- package/dist/src/templates/pydantic-ai/template.yaml +24 -0
- package/dist/src/templates/registry.d.ts +48 -0
- package/dist/src/templates/registry.d.ts.map +1 -0
- package/dist/src/templates/registry.js +168 -0
- package/dist/src/templates/registry.js.map +1 -0
- package/dist/src/templates/smolagents/Dockerfile +34 -0
- package/dist/src/templates/smolagents/README.md +36 -0
- package/dist/src/templates/smolagents/agent.py +97 -0
- package/dist/src/templates/smolagents/entrypoint.sh +34 -0
- package/dist/src/templates/smolagents/requirements.txt +2 -0
- package/dist/src/templates/smolagents/template.yaml +24 -0
- package/dist/src/templates/typescript-sdk/Dockerfile +31 -0
- package/dist/src/templates/typescript-sdk/README.md +29 -0
- package/dist/src/templates/typescript-sdk/agent.ts +130 -0
- package/dist/src/templates/typescript-sdk/entrypoint.sh +34 -0
- package/dist/src/templates/typescript-sdk/package.json +17 -0
- package/dist/src/templates/typescript-sdk/template.yaml +25 -0
- package/dist/src/templates/typescript-sdk/tsconfig.json +12 -0
- package/package.json +1 -1
package/dist/src/lib/paths.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { dirname, join } from "node:path";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
-
import { existsSync } from "node:fs";
|
|
3
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
4
|
+
import { homedir } from "node:os";
|
|
4
5
|
// Resolves bundled, non-TypeScript assets (Docker base context + module
|
|
5
6
|
// manifests) both when running from compiled `dist/` and from `src/` in dev.
|
|
6
7
|
//
|
|
@@ -8,6 +9,7 @@ import { existsSync } from "node:fs";
|
|
|
8
9
|
// `dist/src/`, alongside the copied `docker/` and `modules/` asset trees.
|
|
9
10
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
10
11
|
const srcRoot = join(here, "..");
|
|
12
|
+
const CONFIG_DIR = process.env.ONECLAW_CONFIG_DIR || join(homedir(), ".config", "1claw");
|
|
11
13
|
/** Directory containing the base Docker build context. */
|
|
12
14
|
export function dockerBaseContext() {
|
|
13
15
|
return join(srcRoot, "docker", "base");
|
|
@@ -32,6 +34,45 @@ export function moduleDir(name) {
|
|
|
32
34
|
export function deployTemplateDir(provider) {
|
|
33
35
|
return join(srcRoot, "deploy", provider);
|
|
34
36
|
}
|
|
37
|
+
/** Local cache directory for fetched templates. */
|
|
38
|
+
export function templatesCacheDir() {
|
|
39
|
+
return join(CONFIG_DIR, "templates");
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Directory containing bundled templates from the agent-templates submodule.
|
|
43
|
+
* Returns null if templates are not shipped with this CLI build.
|
|
44
|
+
*
|
|
45
|
+
* Search order:
|
|
46
|
+
* 1. dist/bundled-templates/templates (npm publish / monorepo build)
|
|
47
|
+
* 2. packages/agent-templates/templates (monorepo dev, submodule checkout)
|
|
48
|
+
* 3. dist/src/templates/ (legacy builds — only if template.yaml dirs exist)
|
|
49
|
+
*/
|
|
50
|
+
export function bundledTemplatesDir() {
|
|
51
|
+
// dist/bundled-templates/templates (srcRoot = dist/src → .. = dist)
|
|
52
|
+
const fromDist = join(srcRoot, "..", "bundled-templates", "templates");
|
|
53
|
+
if (dirHasTemplateManifests(fromDist))
|
|
54
|
+
return fromDist;
|
|
55
|
+
// Monorepo: packages/cli/dist/src/lib → ../../../agent-templates/templates
|
|
56
|
+
const monoRepo = join(srcRoot, "..", "..", "..", "agent-templates", "templates");
|
|
57
|
+
if (dirHasTemplateManifests(monoRepo))
|
|
58
|
+
return monoRepo;
|
|
59
|
+
// Legacy: templates copied into dist/src/templates/ (conflicts with compiled TS)
|
|
60
|
+
const legacy = join(srcRoot, "templates");
|
|
61
|
+
if (dirHasTemplateManifests(legacy))
|
|
62
|
+
return legacy;
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
function dirHasTemplateManifests(root) {
|
|
66
|
+
if (!existsSync(root))
|
|
67
|
+
return false;
|
|
68
|
+
try {
|
|
69
|
+
return readdirSync(root).some((d) => statSync(join(root, d)).isDirectory() &&
|
|
70
|
+
existsSync(join(root, d, "template.yaml")));
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
35
76
|
export function assetExists(path) {
|
|
36
77
|
return existsSync(path);
|
|
37
78
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/lib/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/lib/paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared provisioning and daemon lifecycle helpers used by both `init` and
|
|
3
|
+
* `spawn` commands. Extracted from init.ts to avoid duplication.
|
|
4
|
+
*/
|
|
5
|
+
import { type SecretPolicy } from "../local-policy.js";
|
|
6
|
+
export interface ProvisionResult {
|
|
7
|
+
agentId: string;
|
|
8
|
+
apiKey: string;
|
|
9
|
+
vaultId: string;
|
|
10
|
+
vaultName: string;
|
|
11
|
+
}
|
|
12
|
+
export interface StoreKeySpec {
|
|
13
|
+
path: string;
|
|
14
|
+
value?: string;
|
|
15
|
+
type?: string;
|
|
16
|
+
policy: SecretPolicy;
|
|
17
|
+
}
|
|
18
|
+
export declare function provisionCloudResources(containerName: string): Promise<ProvisionResult>;
|
|
19
|
+
export declare function resolvePassphrase(confirm: boolean): Promise<string>;
|
|
20
|
+
export declare function ensureDaemonRunning(opts: {
|
|
21
|
+
storeKeys?: StoreKeySpec[];
|
|
22
|
+
}): Promise<string>;
|
|
23
|
+
export declare function defaultModelForProvider(provider: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Ensure the user is authenticated. Prompts for login if needed.
|
|
26
|
+
* Returns true if authenticated, false if the user declined.
|
|
27
|
+
*/
|
|
28
|
+
export declare function ensureAuth(): Promise<boolean>;
|
|
29
|
+
export declare function waitForHealthy(port: number, endpoint?: string, timeoutMs?: number): Promise<boolean>;
|
|
30
|
+
//# sourceMappingURL=provisioning.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provisioning.d.ts","sourceRoot":"","sources":["../../../src/lib/provisioning.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgBH,OAAO,EAIH,KAAK,YAAY,EACpB,MAAM,oBAAoB,CAAC;AAS5B,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,YAAY,CAAC;CACxB;AAED,wBAAsB,uBAAuB,CACzC,aAAa,EAAE,MAAM,GACtB,OAAO,CAAC,eAAe,CAAC,CAkF1B;AAED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CA4BzE;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC5C,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC;CAC9B,GAAG,OAAO,CAAC,MAAM,CAAC,CA0FlB;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAahE;AAED;;;GAGG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC,CAgBnD;AAED,wBAAsB,cAAc,CAChC,IAAI,EAAE,MAAM,EACZ,QAAQ,SAAY,EACpB,SAAS,SAAQ,GAClB,OAAO,CAAC,OAAO,CAAC,CAalB"}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared provisioning and daemon lifecycle helpers used by both `init` and
|
|
3
|
+
* `spawn` commands. Extracted from init.ts to avoid duplication.
|
|
4
|
+
*/
|
|
5
|
+
import ora from "ora";
|
|
6
|
+
import inquirer from "inquirer";
|
|
7
|
+
import { api } from "../client.js";
|
|
8
|
+
import { getToken } from "../config.js";
|
|
9
|
+
import { loginWithDevice } from "../auth.js";
|
|
10
|
+
import { printInfo } from "../output.js";
|
|
11
|
+
import { vaultExists, createVault, loadVault, saveVault, addSecret, getSecret, } from "../local-vault.js";
|
|
12
|
+
import { loadPolicy, savePolicy, setSecretPolicy, } from "../local-policy.js";
|
|
13
|
+
import { daemonSocketPath, daemonHealthy, startDaemonDetached, stopDaemon, } from "./daemon-control.js";
|
|
14
|
+
import { sanitizeName } from "./container-config.js";
|
|
15
|
+
export async function provisionCloudResources(containerName) {
|
|
16
|
+
const sid = sanitizeName(containerName);
|
|
17
|
+
const agentSpinner = ora("Provisioning agent...").start();
|
|
18
|
+
let agentId;
|
|
19
|
+
let apiKey;
|
|
20
|
+
try {
|
|
21
|
+
const res = await api("/agents", {
|
|
22
|
+
method: "POST",
|
|
23
|
+
body: {
|
|
24
|
+
name: `docker-agent-${sid}`.slice(0, 60),
|
|
25
|
+
description: "Created by `1claw init --docker`",
|
|
26
|
+
shroud_enabled: true,
|
|
27
|
+
intents_api_enabled: true,
|
|
28
|
+
auth_method: "api_key",
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
agentId = "agent" in res ? res.agent.id : res.id;
|
|
32
|
+
if (!res.api_key) {
|
|
33
|
+
agentSpinner.fail("Agent created but no API key returned.");
|
|
34
|
+
throw new Error("No agent API key returned by the API.");
|
|
35
|
+
}
|
|
36
|
+
apiKey = res.api_key;
|
|
37
|
+
agentSpinner.succeed(`Agent provisioned (${agentId.slice(0, 8)}…)`);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
agentSpinner.fail("Failed to provision agent.");
|
|
41
|
+
throw err;
|
|
42
|
+
}
|
|
43
|
+
const vaultSpinner = ora("Creating vault...").start();
|
|
44
|
+
let vaultId;
|
|
45
|
+
let vaultName;
|
|
46
|
+
try {
|
|
47
|
+
const vault = await api("/vaults", {
|
|
48
|
+
method: "POST",
|
|
49
|
+
body: {
|
|
50
|
+
name: `docker-vault-${sid}`.slice(0, 60),
|
|
51
|
+
description: "Created by `1claw init --docker`",
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
vaultId = vault.id;
|
|
55
|
+
vaultName = vault.name;
|
|
56
|
+
vaultSpinner.succeed(`Vault created (${vaultName})`);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
vaultSpinner.fail("Failed to create vault.");
|
|
60
|
+
throw err;
|
|
61
|
+
}
|
|
62
|
+
const policySpinner = ora("Binding vault and granting read policy...").start();
|
|
63
|
+
try {
|
|
64
|
+
await api(`/agents/${agentId}`, {
|
|
65
|
+
method: "PATCH",
|
|
66
|
+
body: { vault_ids: [vaultId] },
|
|
67
|
+
});
|
|
68
|
+
await api(`/vaults/${vaultId}/policies`, {
|
|
69
|
+
method: "POST",
|
|
70
|
+
body: {
|
|
71
|
+
principal_type: "agent",
|
|
72
|
+
principal_id: agentId,
|
|
73
|
+
secret_path_pattern: "secrets/*",
|
|
74
|
+
permissions: ["read"],
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
await api(`/vaults/${vaultId}/policies`, {
|
|
78
|
+
method: "POST",
|
|
79
|
+
body: {
|
|
80
|
+
principal_type: "agent",
|
|
81
|
+
principal_id: agentId,
|
|
82
|
+
secret_path_pattern: "providers/*",
|
|
83
|
+
permissions: ["read"],
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
policySpinner.succeed("Vault bound; read policies on secrets/* and providers/* granted.");
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
policySpinner.fail("Failed to bind vault / create policy.");
|
|
90
|
+
throw err;
|
|
91
|
+
}
|
|
92
|
+
return { agentId, apiKey, vaultId, vaultName };
|
|
93
|
+
}
|
|
94
|
+
export async function resolvePassphrase(confirm) {
|
|
95
|
+
if (process.env.ONECLAW_VAULT_PASSPHRASE) {
|
|
96
|
+
return process.env.ONECLAW_VAULT_PASSPHRASE;
|
|
97
|
+
}
|
|
98
|
+
const { passphrase } = await inquirer.prompt([
|
|
99
|
+
{
|
|
100
|
+
type: "password",
|
|
101
|
+
name: "passphrase",
|
|
102
|
+
message: "Local vault passphrase:",
|
|
103
|
+
mask: "*",
|
|
104
|
+
validate: (v) => v.length >= 8 ? true : "Passphrase must be at least 8 characters",
|
|
105
|
+
},
|
|
106
|
+
]);
|
|
107
|
+
if (confirm) {
|
|
108
|
+
const { confirmed } = await inquirer.prompt([
|
|
109
|
+
{
|
|
110
|
+
type: "password",
|
|
111
|
+
name: "confirmed",
|
|
112
|
+
message: "Confirm passphrase:",
|
|
113
|
+
mask: "*",
|
|
114
|
+
},
|
|
115
|
+
]);
|
|
116
|
+
if (passphrase !== confirmed) {
|
|
117
|
+
throw new Error("Passphrases do not match.");
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return passphrase;
|
|
121
|
+
}
|
|
122
|
+
export async function ensureDaemonRunning(opts) {
|
|
123
|
+
const socketPath = daemonSocketPath();
|
|
124
|
+
const alreadyRunning = await daemonHealthy(socketPath);
|
|
125
|
+
const storeKeys = opts.storeKeys ?? [];
|
|
126
|
+
const needVaultWrite = storeKeys.length > 0;
|
|
127
|
+
const needStart = !alreadyRunning;
|
|
128
|
+
const needReload = needVaultWrite && alreadyRunning;
|
|
129
|
+
if (!needVaultWrite && !needStart) {
|
|
130
|
+
return socketPath;
|
|
131
|
+
}
|
|
132
|
+
const creatingVault = !vaultExists();
|
|
133
|
+
let passphrase;
|
|
134
|
+
if (creatingVault) {
|
|
135
|
+
printInfo("No local vault found — creating one for the daemon.");
|
|
136
|
+
passphrase = await resolvePassphrase(true);
|
|
137
|
+
createVault(passphrase);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
passphrase = await resolvePassphrase(false);
|
|
141
|
+
try {
|
|
142
|
+
loadVault(passphrase);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
throw new Error("Wrong passphrase for the existing local vault.\n" +
|
|
146
|
+
" • If you mistyped it, re-run and enter the correct passphrase.\n" +
|
|
147
|
+
" • If you've forgotten it, reset the vault with: 1claw local destroy --force\n" +
|
|
148
|
+
" (this permanently deletes the old local vault and its secrets), then re-run.");
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (needVaultWrite && passphrase) {
|
|
152
|
+
let vault;
|
|
153
|
+
try {
|
|
154
|
+
vault = loadVault(passphrase);
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
throw new Error("Wrong passphrase or corrupted local vault.");
|
|
158
|
+
}
|
|
159
|
+
const policy = loadPolicy();
|
|
160
|
+
for (const spec of storeKeys) {
|
|
161
|
+
if (spec.value !== undefined) {
|
|
162
|
+
addSecret(vault, spec.path, spec.value, spec.type ?? "api_key");
|
|
163
|
+
}
|
|
164
|
+
else if (!getSecret(vault, spec.path)) {
|
|
165
|
+
throw new Error(`Provider key secret "${spec.path}" not found in the local vault.\n` +
|
|
166
|
+
` Add it first: 1claw local add ${spec.path}`);
|
|
167
|
+
}
|
|
168
|
+
setSecretPolicy(policy, spec.path, spec.policy);
|
|
169
|
+
}
|
|
170
|
+
saveVault(vault, passphrase);
|
|
171
|
+
savePolicy(policy);
|
|
172
|
+
}
|
|
173
|
+
if (needReload) {
|
|
174
|
+
const spinner = ora("Reloading daemon to pick up new secrets...").start();
|
|
175
|
+
await stopDaemon(socketPath);
|
|
176
|
+
const ok = await startDaemonDetached(passphrase, socketPath);
|
|
177
|
+
if (!ok) {
|
|
178
|
+
spinner.fail("Daemon did not come back up.");
|
|
179
|
+
throw new Error("Failed to reload the daemon.\n" +
|
|
180
|
+
" • Check status: 1claw daemon status\n" +
|
|
181
|
+
" • Start it manually (shows errors): 1claw daemon start");
|
|
182
|
+
}
|
|
183
|
+
spinner.succeed(`Daemon reloaded on ${socketPath}`);
|
|
184
|
+
}
|
|
185
|
+
else if (needStart) {
|
|
186
|
+
if (!passphrase)
|
|
187
|
+
passphrase = await resolvePassphrase(false);
|
|
188
|
+
const spinner = ora("Starting local daemon...").start();
|
|
189
|
+
const ok = await startDaemonDetached(passphrase, socketPath);
|
|
190
|
+
if (!ok) {
|
|
191
|
+
spinner.fail("Daemon did not become ready in time.");
|
|
192
|
+
throw new Error("Failed to start the daemon.\n" +
|
|
193
|
+
" • Check status: 1claw daemon status\n" +
|
|
194
|
+
" • Start it manually (shows errors): 1claw daemon start\n" +
|
|
195
|
+
" • Stop a stuck daemon: 1claw daemon stop\n" +
|
|
196
|
+
" • Forgot the vault passphrase? Reset it: 1claw local destroy --force");
|
|
197
|
+
}
|
|
198
|
+
spinner.succeed(`Daemon running on ${socketPath}`);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
printInfo(`Reusing running daemon at ${socketPath}`);
|
|
202
|
+
}
|
|
203
|
+
return socketPath;
|
|
204
|
+
}
|
|
205
|
+
export function defaultModelForProvider(provider) {
|
|
206
|
+
switch (provider.toLowerCase()) {
|
|
207
|
+
case "anthropic":
|
|
208
|
+
return "claude-3-5-haiku-latest";
|
|
209
|
+
case "google":
|
|
210
|
+
case "gemini":
|
|
211
|
+
return "gemini-2.5-flash";
|
|
212
|
+
case "mistral":
|
|
213
|
+
return "mistral-small-latest";
|
|
214
|
+
case "openai":
|
|
215
|
+
default:
|
|
216
|
+
return "gpt-4o-mini";
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Ensure the user is authenticated. Prompts for login if needed.
|
|
221
|
+
* Returns true if authenticated, false if the user declined.
|
|
222
|
+
*/
|
|
223
|
+
export async function ensureAuth() {
|
|
224
|
+
if (getToken())
|
|
225
|
+
return true;
|
|
226
|
+
printInfo("You need to log in to provision cloud resources.");
|
|
227
|
+
const { shouldLogin } = await inquirer.prompt([
|
|
228
|
+
{
|
|
229
|
+
type: "confirm",
|
|
230
|
+
name: "shouldLogin",
|
|
231
|
+
message: "Log in now? (choose No to run offline with --local)",
|
|
232
|
+
default: true,
|
|
233
|
+
},
|
|
234
|
+
]);
|
|
235
|
+
if (!shouldLogin)
|
|
236
|
+
return false;
|
|
237
|
+
const auth = await loginWithDevice();
|
|
238
|
+
return !!auth;
|
|
239
|
+
}
|
|
240
|
+
export async function waitForHealthy(port, endpoint = "/health", timeoutMs = 30000) {
|
|
241
|
+
const deadline = Date.now() + timeoutMs;
|
|
242
|
+
const url = `http://localhost:${port}${endpoint}`;
|
|
243
|
+
while (Date.now() < deadline) {
|
|
244
|
+
try {
|
|
245
|
+
const res = await fetch(url);
|
|
246
|
+
if (res.ok)
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
// not up yet
|
|
251
|
+
}
|
|
252
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
253
|
+
}
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=provisioning.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provisioning.js","sourceRoot":"","sources":["../../../src/lib/provisioning.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
templates:
|
|
3
|
+
- name: langchain
|
|
4
|
+
display_name: "LangChain / LangGraph"
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
language: python
|
|
7
|
+
description: "Python agent using LangChain with 1Claw MCP for secrets and signing"
|
|
8
|
+
- name: crewai
|
|
9
|
+
display_name: "CrewAI"
|
|
10
|
+
version: 1.0.0
|
|
11
|
+
language: python
|
|
12
|
+
description: "Multi-agent crew with 1Claw-managed secrets"
|
|
13
|
+
- name: openai-agents
|
|
14
|
+
display_name: "OpenAI Agents SDK"
|
|
15
|
+
version: 1.0.0
|
|
16
|
+
language: python
|
|
17
|
+
description: "OpenAI Agents SDK with tool calling and 1Claw MCP integration"
|
|
18
|
+
- name: elizaos
|
|
19
|
+
display_name: "ElizaOS"
|
|
20
|
+
version: 1.0.0
|
|
21
|
+
language: node
|
|
22
|
+
description: "ElizaOS character runtime with vault-backed secrets"
|
|
23
|
+
- name: agentkit
|
|
24
|
+
display_name: "Coinbase AgentKit"
|
|
25
|
+
version: 1.0.0
|
|
26
|
+
language: python
|
|
27
|
+
description: "Coinbase AgentKit for onchain agents with 1Claw key management"
|
|
28
|
+
- name: smolagents
|
|
29
|
+
display_name: "HuggingFace smolagents"
|
|
30
|
+
version: 1.0.0
|
|
31
|
+
language: python
|
|
32
|
+
description: "HuggingFace lightweight agents with 1Claw secrets"
|
|
33
|
+
- name: llamaindex
|
|
34
|
+
display_name: "LlamaIndex"
|
|
35
|
+
version: 1.0.0
|
|
36
|
+
language: python
|
|
37
|
+
description: "LlamaIndex agent with tool integration and 1Claw MCP"
|
|
38
|
+
- name: pydantic-ai
|
|
39
|
+
display_name: "Pydantic AI"
|
|
40
|
+
version: 1.0.0
|
|
41
|
+
language: python
|
|
42
|
+
description: "Type-safe Python agent with structured output"
|
|
43
|
+
- name: agno
|
|
44
|
+
display_name: "Agno"
|
|
45
|
+
version: 1.0.0
|
|
46
|
+
language: python
|
|
47
|
+
description: "Agno multi-modal agent with 1Claw secrets"
|
|
48
|
+
- name: mastra
|
|
49
|
+
display_name: "Mastra"
|
|
50
|
+
version: 1.0.0
|
|
51
|
+
language: node
|
|
52
|
+
description: "TypeScript-first AI agent framework"
|
|
53
|
+
- name: typescript-sdk
|
|
54
|
+
display_name: "TypeScript SDK"
|
|
55
|
+
version: 1.0.0
|
|
56
|
+
language: node
|
|
57
|
+
description: "Plain TypeScript agent using @1claw/sdk with Shroud LLM routing"
|
|
58
|
+
- name: coder
|
|
59
|
+
display_name: "Coder"
|
|
60
|
+
version: 1.0.0
|
|
61
|
+
language: python
|
|
62
|
+
description: "Coder workspace automation agent"
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
FROM python:3.12-slim
|
|
2
|
+
|
|
3
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
4
|
+
curl tini && \
|
|
5
|
+
rm -rf /var/lib/apt/lists/*
|
|
6
|
+
|
|
7
|
+
WORKDIR /app
|
|
8
|
+
|
|
9
|
+
COPY requirements.txt .
|
|
10
|
+
RUN pip install --no-cache-dir -r requirements.txt
|
|
11
|
+
|
|
12
|
+
RUN pip install --no-cache-dir 1claw-mcp 2>/dev/null || \
|
|
13
|
+
(apt-get update && apt-get install -y --no-install-recommends nodejs npm && \
|
|
14
|
+
npm install -g @1claw/mcp@latest && \
|
|
15
|
+
rm -rf /var/lib/apt/lists/*) || \
|
|
16
|
+
echo "WARN: 1claw-mcp install deferred to runtime"
|
|
17
|
+
|
|
18
|
+
COPY agent.py .
|
|
19
|
+
COPY entrypoint.sh .
|
|
20
|
+
RUN chmod +x entrypoint.sh
|
|
21
|
+
|
|
22
|
+
RUN mkdir -p /run/1claw
|
|
23
|
+
|
|
24
|
+
ENV NODE_ENV=production
|
|
25
|
+
ENV ONECLAW_DAEMON_SOCKET=/run/1claw/daemon.sock
|
|
26
|
+
ENV ONECLAW_FRAMEWORK=agentkit
|
|
27
|
+
|
|
28
|
+
EXPOSE 3000
|
|
29
|
+
|
|
30
|
+
HEALTHCHECK --interval=10s --timeout=3s --start-period=10s --retries=5 \
|
|
31
|
+
CMD curl -sf http://localhost:3000/health || exit 1
|
|
32
|
+
|
|
33
|
+
ENTRYPOINT ["tini", "--"]
|
|
34
|
+
CMD ["./entrypoint.sh"]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Coinbase AgentKit Template
|
|
2
|
+
|
|
3
|
+
A Python agent using [Coinbase AgentKit](https://github.com/coinbase/agentkit) for onchain operations with 1Claw key management.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
1claw spawn agentkit
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or with your own API key:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
1claw spawn agentkit --llm-api-key sk-...
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## What's included
|
|
18
|
+
|
|
19
|
+
- **agent.py** — AgentKit-powered LangGraph agent with onchain tools
|
|
20
|
+
- **Flask server** on port 3000 with `/chat` and `/health` endpoints
|
|
21
|
+
- **Shroud integration** — LLM calls are routed through Shroud for inspection
|
|
22
|
+
- **MCP server** — started automatically for tool access to 1Claw vault
|
|
23
|
+
|
|
24
|
+
## Customizing
|
|
25
|
+
|
|
26
|
+
Edit `agent.py` to configure AgentKit actions (deploy tokens, transfer,
|
|
27
|
+
check balances, etc.). Set CDP API credentials via the 1Claw vault for
|
|
28
|
+
Coinbase Developer Platform integration.
|
|
29
|
+
|
|
30
|
+
## LLM authentication
|
|
31
|
+
|
|
32
|
+
The template supports three methods (configured at spawn time):
|
|
33
|
+
|
|
34
|
+
1. **BYOK** — `1claw spawn agentkit --llm-api-key sk-...`
|
|
35
|
+
2. **Token Billing** — enable in Dashboard, no key needed
|
|
36
|
+
3. **Anthropic WIF** — OIDC federation for Anthropic models
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Coinbase AgentKit agent pre-wired with 1Claw MCP for secrets and signing.
|
|
3
|
+
|
|
4
|
+
LLM calls are routed through Shroud when ONECLAW_LLM_VIA_SHROUD is set.
|
|
5
|
+
The container never sees raw API keys — they are injected by the host daemon.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
from flask import Flask, request, jsonify
|
|
10
|
+
from langchain_openai import ChatOpenAI
|
|
11
|
+
from coinbase_agentkit import AgentKit, AgentKitConfig
|
|
12
|
+
from coinbase_agentkit_langchain import get_langchain_tools
|
|
13
|
+
from langgraph.prebuilt import create_react_agent
|
|
14
|
+
|
|
15
|
+
app = Flask(__name__)
|
|
16
|
+
|
|
17
|
+
SHROUD_URL = os.environ.get("ONECLAW_SHROUD_URL", "https://shroud.1claw.xyz")
|
|
18
|
+
LLM_VIA_SHROUD = os.environ.get("ONECLAW_LLM_VIA_SHROUD", "").lower() == "true"
|
|
19
|
+
MODEL = os.environ.get("ONECLAW_SHROUD_MODEL", "gpt-4o-mini")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def create_agent():
|
|
23
|
+
"""Build an AgentKit-powered LangGraph agent. Returns None if no LLM."""
|
|
24
|
+
if not LLM_VIA_SHROUD:
|
|
25
|
+
return None
|
|
26
|
+
|
|
27
|
+
llm = ChatOpenAI(
|
|
28
|
+
model=MODEL,
|
|
29
|
+
base_url=f"{SHROUD_URL}/v1",
|
|
30
|
+
api_key="shroud-injected",
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
agentkit = AgentKit(AgentKitConfig())
|
|
34
|
+
tools = get_langchain_tools(agentkit)
|
|
35
|
+
return create_react_agent(llm, tools=tools)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
agent_executor = create_agent()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@app.route("/health")
|
|
42
|
+
def health():
|
|
43
|
+
return jsonify({"status": "ok", "framework": "agentkit", "llm_wired": LLM_VIA_SHROUD})
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@app.route("/chat", methods=["POST"])
|
|
47
|
+
def chat():
|
|
48
|
+
data = request.get_json(silent=True) or {}
|
|
49
|
+
message = data.get("message", "").strip()
|
|
50
|
+
if not message:
|
|
51
|
+
return jsonify({"error": "No message provided"}), 400
|
|
52
|
+
|
|
53
|
+
if not agent_executor:
|
|
54
|
+
return jsonify({
|
|
55
|
+
"response": "No LLM configured. Use --llm-api-key or enable Token Billing.",
|
|
56
|
+
"framework": "agentkit",
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
result = agent_executor.invoke({"messages": [{"role": "user", "content": message}]})
|
|
61
|
+
output = result["messages"][-1].content if result.get("messages") else str(result)
|
|
62
|
+
return jsonify({"response": output, "framework": "agentkit"})
|
|
63
|
+
except Exception as e:
|
|
64
|
+
return jsonify({"error": str(e)}), 500
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@app.route("/")
|
|
68
|
+
def index():
|
|
69
|
+
return """<!DOCTYPE html>
|
|
70
|
+
<html><head><title>1Claw AgentKit Agent</title></head>
|
|
71
|
+
<body style="font-family:system-ui;max-width:600px;margin:40px auto;padding:0 20px">
|
|
72
|
+
<h1>1Claw Coinbase AgentKit</h1>
|
|
73
|
+
<p>Send messages via <code>POST /chat</code> with <code>{"message": "..."}</code></p>
|
|
74
|
+
<p>Health: <a href="/health">/health</a></p>
|
|
75
|
+
<p style="color:#666;font-size:0.9em">
|
|
76
|
+
Credentials stay in the host daemon — this container never sees secret values.
|
|
77
|
+
</p></body></html>"""
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if __name__ == "__main__":
|
|
81
|
+
port = int(os.environ.get("CHAT_UI_PORT", "3000"))
|
|
82
|
+
print(f"AgentKit agent listening on http://0.0.0.0:{port}")
|
|
83
|
+
app.run(host="0.0.0.0", port=port)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
DAEMON_SOCKET="${ONECLAW_DAEMON_SOCKET:-/run/1claw/daemon.sock}"
|
|
5
|
+
CHAT_UI_PORT="${CHAT_UI_PORT:-3000}"
|
|
6
|
+
|
|
7
|
+
echo "─────────────────────────────────────────────"
|
|
8
|
+
echo " 1Claw AgentKit Agent"
|
|
9
|
+
echo " Framework: agentkit"
|
|
10
|
+
echo " Agent ID: ${ONECLAW_AGENT_ID:-not set}"
|
|
11
|
+
|
|
12
|
+
if [ -S "$DAEMON_SOCKET" ]; then
|
|
13
|
+
echo " Mode: ${ONECLAW_MODE:-cloud} (daemon socket)"
|
|
14
|
+
echo " Socket: $DAEMON_SOCKET"
|
|
15
|
+
else
|
|
16
|
+
echo " Mode: standalone (no daemon socket)"
|
|
17
|
+
fi
|
|
18
|
+
echo "─────────────────────────────────────────────"
|
|
19
|
+
|
|
20
|
+
if [ "$ONECLAW_LLM_VIA_SHROUD" = "true" ]; then
|
|
21
|
+
export OPENAI_BASE_URL="${ONECLAW_SHROUD_URL}/v1"
|
|
22
|
+
echo "LLM routed through Shroud: ${ONECLAW_SHROUD_PROVIDER}/${ONECLAW_SHROUD_MODEL}"
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
if [ -S "$DAEMON_SOCKET" ]; then
|
|
26
|
+
if command -v 1claw-mcp >/dev/null 2>&1; then
|
|
27
|
+
ONECLAW_LOCAL_VAULT=true ONECLAW_DAEMON_SOCKET="$DAEMON_SOCKET" \
|
|
28
|
+
1claw-mcp --local 2>/tmp/mcp.log &
|
|
29
|
+
echo "MCP server started in background."
|
|
30
|
+
fi
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
echo "Ready: http://0.0.0.0:${CHAT_UI_PORT}"
|
|
34
|
+
exec python agent.py
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: agentkit
|
|
2
|
+
display_name: "Coinbase AgentKit"
|
|
3
|
+
version: 1.0.0
|
|
4
|
+
description: "Coinbase AgentKit for onchain agents with 1Claw key management"
|
|
5
|
+
author: 1Claw
|
|
6
|
+
language: python
|
|
7
|
+
homepage: https://github.com/coinbase/agentkit
|
|
8
|
+
|
|
9
|
+
docker:
|
|
10
|
+
base_image: python:3.12-slim
|
|
11
|
+
context_files:
|
|
12
|
+
- Dockerfile
|
|
13
|
+
- requirements.txt
|
|
14
|
+
- agent.py
|
|
15
|
+
- entrypoint.sh
|
|
16
|
+
env:
|
|
17
|
+
ONECLAW_FRAMEWORK: agentkit
|
|
18
|
+
health_endpoint: /health
|
|
19
|
+
health_port: 3000
|
|
20
|
+
|
|
21
|
+
post_spawn_message: |
|
|
22
|
+
Edit agent.py to customize your AgentKit agent's onchain capabilities.
|
|
23
|
+
Your 1Claw MCP server is available at the daemon socket.
|
|
24
|
+
LLM calls are routed through Shroud for inspection and redaction.
|