clawup 1.0.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 (190) hide show
  1. package/README.md +245 -0
  2. package/dist/adapters/api-adapter.d.ts +76 -0
  3. package/dist/adapters/api-adapter.js +250 -0
  4. package/dist/adapters/api-adapter.js.map +1 -0
  5. package/dist/adapters/cli-adapter.d.ts +15 -0
  6. package/dist/adapters/cli-adapter.js +208 -0
  7. package/dist/adapters/cli-adapter.js.map +1 -0
  8. package/dist/adapters/index.d.ts +22 -0
  9. package/dist/adapters/index.js +32 -0
  10. package/dist/adapters/index.js.map +1 -0
  11. package/dist/adapters/types.d.ts +135 -0
  12. package/dist/adapters/types.js +14 -0
  13. package/dist/adapters/types.js.map +1 -0
  14. package/dist/bin.d.ts +8 -0
  15. package/dist/bin.js +221 -0
  16. package/dist/bin.js.map +1 -0
  17. package/dist/commands/config.d.ts +21 -0
  18. package/dist/commands/config.js +323 -0
  19. package/dist/commands/config.js.map +1 -0
  20. package/dist/commands/deploy.d.ts +7 -0
  21. package/dist/commands/deploy.js +13 -0
  22. package/dist/commands/deploy.js.map +1 -0
  23. package/dist/commands/destroy.d.ts +7 -0
  24. package/dist/commands/destroy.js +13 -0
  25. package/dist/commands/destroy.js.map +1 -0
  26. package/dist/commands/init.d.ts +13 -0
  27. package/dist/commands/init.js +698 -0
  28. package/dist/commands/init.js.map +1 -0
  29. package/dist/commands/list.d.ts +8 -0
  30. package/dist/commands/list.js +42 -0
  31. package/dist/commands/list.js.map +1 -0
  32. package/dist/commands/push.d.ts +7 -0
  33. package/dist/commands/push.js +19 -0
  34. package/dist/commands/push.js.map +1 -0
  35. package/dist/commands/redeploy.d.ts +7 -0
  36. package/dist/commands/redeploy.js +13 -0
  37. package/dist/commands/redeploy.js.map +1 -0
  38. package/dist/commands/secrets.d.ts +16 -0
  39. package/dist/commands/secrets.js +169 -0
  40. package/dist/commands/secrets.js.map +1 -0
  41. package/dist/commands/ssh.d.ts +9 -0
  42. package/dist/commands/ssh.js +108 -0
  43. package/dist/commands/ssh.js.map +1 -0
  44. package/dist/commands/status.d.ts +7 -0
  45. package/dist/commands/status.js +13 -0
  46. package/dist/commands/status.js.map +1 -0
  47. package/dist/commands/update.d.ts +7 -0
  48. package/dist/commands/update.js +126 -0
  49. package/dist/commands/update.js.map +1 -0
  50. package/dist/commands/validate.d.ts +7 -0
  51. package/dist/commands/validate.js +13 -0
  52. package/dist/commands/validate.js.map +1 -0
  53. package/dist/commands/webhooks.d.ts +7 -0
  54. package/dist/commands/webhooks.js +13 -0
  55. package/dist/commands/webhooks.js.map +1 -0
  56. package/dist/lib/__tests__/identity.test.d.ts +1 -0
  57. package/dist/lib/__tests__/identity.test.js +186 -0
  58. package/dist/lib/__tests__/identity.test.js.map +1 -0
  59. package/dist/lib/__tests__/validate-agent.test.d.ts +1 -0
  60. package/dist/lib/__tests__/validate-agent.test.js +38 -0
  61. package/dist/lib/__tests__/validate-agent.test.js.map +1 -0
  62. package/dist/lib/config.d.ts +69 -0
  63. package/dist/lib/config.js +218 -0
  64. package/dist/lib/config.js.map +1 -0
  65. package/dist/lib/constants.d.ts +5 -0
  66. package/dist/lib/constants.js +29 -0
  67. package/dist/lib/constants.js.map +1 -0
  68. package/dist/lib/exec.d.ts +24 -0
  69. package/dist/lib/exec.js +63 -0
  70. package/dist/lib/exec.js.map +1 -0
  71. package/dist/lib/prerequisites.d.ts +8 -0
  72. package/dist/lib/prerequisites.js +146 -0
  73. package/dist/lib/prerequisites.js.map +1 -0
  74. package/dist/lib/process.d.ts +18 -0
  75. package/dist/lib/process.js +37 -0
  76. package/dist/lib/process.js.map +1 -0
  77. package/dist/lib/pulumi.d.ts +37 -0
  78. package/dist/lib/pulumi.js +87 -0
  79. package/dist/lib/pulumi.js.map +1 -0
  80. package/dist/lib/tailscale.d.ts +75 -0
  81. package/dist/lib/tailscale.js +251 -0
  82. package/dist/lib/tailscale.js.map +1 -0
  83. package/dist/lib/tool-helpers.d.ts +15 -0
  84. package/dist/lib/tool-helpers.js +35 -0
  85. package/dist/lib/tool-helpers.js.map +1 -0
  86. package/dist/lib/ui.d.ts +26 -0
  87. package/dist/lib/ui.js +86 -0
  88. package/dist/lib/ui.js.map +1 -0
  89. package/dist/lib/update-check.d.ts +8 -0
  90. package/dist/lib/update-check.js +151 -0
  91. package/dist/lib/update-check.js.map +1 -0
  92. package/dist/lib/vendor.d.ts +34 -0
  93. package/dist/lib/vendor.js +128 -0
  94. package/dist/lib/vendor.js.map +1 -0
  95. package/dist/lib/workspace.d.ts +21 -0
  96. package/dist/lib/workspace.js +170 -0
  97. package/dist/lib/workspace.js.map +1 -0
  98. package/dist/tools/deploy.d.ts +16 -0
  99. package/dist/tools/deploy.js +181 -0
  100. package/dist/tools/deploy.js.map +1 -0
  101. package/dist/tools/destroy.d.ts +16 -0
  102. package/dist/tools/destroy.js +119 -0
  103. package/dist/tools/destroy.js.map +1 -0
  104. package/dist/tools/index.d.ts +20 -0
  105. package/dist/tools/index.js +34 -0
  106. package/dist/tools/index.js.map +1 -0
  107. package/dist/tools/push.d.ts +29 -0
  108. package/dist/tools/push.js +341 -0
  109. package/dist/tools/push.js.map +1 -0
  110. package/dist/tools/redeploy.d.ts +17 -0
  111. package/dist/tools/redeploy.js +181 -0
  112. package/dist/tools/redeploy.js.map +1 -0
  113. package/dist/tools/status.d.ts +16 -0
  114. package/dist/tools/status.js +205 -0
  115. package/dist/tools/status.js.map +1 -0
  116. package/dist/tools/validate.d.ts +16 -0
  117. package/dist/tools/validate.js +219 -0
  118. package/dist/tools/validate.js.map +1 -0
  119. package/dist/tools/webhooks.d.ts +17 -0
  120. package/dist/tools/webhooks.js +181 -0
  121. package/dist/tools/webhooks.js.map +1 -0
  122. package/dist/types.d.ts +6 -0
  123. package/dist/types.js +10 -0
  124. package/dist/types.js.map +1 -0
  125. package/infra/Pulumi.yaml +6 -0
  126. package/infra/dist/components/cloud-init.js +412 -0
  127. package/infra/dist/components/config-generator.js +254 -0
  128. package/infra/dist/components/hetzner-agent.js +162 -0
  129. package/infra/dist/components/index.js +18 -0
  130. package/infra/dist/components/openclaw-agent.js +287 -0
  131. package/infra/dist/components/shared.js +132 -0
  132. package/infra/dist/components/types.js +6 -0
  133. package/infra/dist/index.js +387 -0
  134. package/infra/dist/shared-vpc.js +167 -0
  135. package/infra/node_modules/@clawup/core/dist/__tests__/schemas.test.d.ts +2 -0
  136. package/infra/node_modules/@clawup/core/dist/__tests__/schemas.test.d.ts.map +1 -0
  137. package/infra/node_modules/@clawup/core/dist/__tests__/schemas.test.js +124 -0
  138. package/infra/node_modules/@clawup/core/dist/__tests__/schemas.test.js.map +1 -0
  139. package/infra/node_modules/@clawup/core/dist/coding-agent-registry.d.ts +32 -0
  140. package/infra/node_modules/@clawup/core/dist/coding-agent-registry.d.ts.map +1 -0
  141. package/infra/node_modules/@clawup/core/dist/coding-agent-registry.js +56 -0
  142. package/infra/node_modules/@clawup/core/dist/coding-agent-registry.js.map +1 -0
  143. package/infra/node_modules/@clawup/core/dist/constants.d.ts +137 -0
  144. package/infra/node_modules/@clawup/core/dist/constants.d.ts.map +1 -0
  145. package/infra/node_modules/@clawup/core/dist/constants.js +314 -0
  146. package/infra/node_modules/@clawup/core/dist/constants.js.map +1 -0
  147. package/infra/node_modules/@clawup/core/dist/dep-registry.d.ts +25 -0
  148. package/infra/node_modules/@clawup/core/dist/dep-registry.d.ts.map +1 -0
  149. package/infra/node_modules/@clawup/core/dist/dep-registry.js +46 -0
  150. package/infra/node_modules/@clawup/core/dist/dep-registry.js.map +1 -0
  151. package/infra/node_modules/@clawup/core/dist/deps.d.ts +18 -0
  152. package/infra/node_modules/@clawup/core/dist/deps.d.ts.map +1 -0
  153. package/infra/node_modules/@clawup/core/dist/deps.js +39 -0
  154. package/infra/node_modules/@clawup/core/dist/deps.js.map +1 -0
  155. package/infra/node_modules/@clawup/core/dist/identity.d.ts +20 -0
  156. package/infra/node_modules/@clawup/core/dist/identity.d.ts.map +1 -0
  157. package/infra/node_modules/@clawup/core/dist/identity.js +217 -0
  158. package/infra/node_modules/@clawup/core/dist/identity.js.map +1 -0
  159. package/infra/node_modules/@clawup/core/dist/index.d.ts +18 -0
  160. package/infra/node_modules/@clawup/core/dist/index.d.ts.map +1 -0
  161. package/infra/node_modules/@clawup/core/dist/index.js +52 -0
  162. package/infra/node_modules/@clawup/core/dist/index.js.map +1 -0
  163. package/infra/node_modules/@clawup/core/dist/plugin-registry.d.ts +13 -0
  164. package/infra/node_modules/@clawup/core/dist/plugin-registry.d.ts.map +1 -0
  165. package/infra/node_modules/@clawup/core/dist/plugin-registry.js +24 -0
  166. package/infra/node_modules/@clawup/core/dist/plugin-registry.js.map +1 -0
  167. package/infra/node_modules/@clawup/core/dist/schemas/identity.d.ts +74 -0
  168. package/infra/node_modules/@clawup/core/dist/schemas/identity.d.ts.map +1 -0
  169. package/infra/node_modules/@clawup/core/dist/schemas/identity.js +45 -0
  170. package/infra/node_modules/@clawup/core/dist/schemas/identity.js.map +1 -0
  171. package/infra/node_modules/@clawup/core/dist/schemas/index.d.ts +6 -0
  172. package/infra/node_modules/@clawup/core/dist/schemas/index.d.ts.map +1 -0
  173. package/infra/node_modules/@clawup/core/dist/schemas/index.js +13 -0
  174. package/infra/node_modules/@clawup/core/dist/schemas/index.js.map +1 -0
  175. package/infra/node_modules/@clawup/core/dist/schemas/manifest.d.ts +159 -0
  176. package/infra/node_modules/@clawup/core/dist/schemas/manifest.d.ts.map +1 -0
  177. package/infra/node_modules/@clawup/core/dist/schemas/manifest.js +54 -0
  178. package/infra/node_modules/@clawup/core/dist/schemas/manifest.js.map +1 -0
  179. package/infra/node_modules/@clawup/core/dist/skills.d.ts +30 -0
  180. package/infra/node_modules/@clawup/core/dist/skills.d.ts.map +1 -0
  181. package/infra/node_modules/@clawup/core/dist/skills.js +52 -0
  182. package/infra/node_modules/@clawup/core/dist/skills.js.map +1 -0
  183. package/infra/node_modules/@clawup/core/dist/types.d.ts +59 -0
  184. package/infra/node_modules/@clawup/core/dist/types.d.ts.map +1 -0
  185. package/infra/node_modules/@clawup/core/dist/types.js +30 -0
  186. package/infra/node_modules/@clawup/core/dist/types.js.map +1 -0
  187. package/infra/node_modules/@clawup/core/package.json +46 -0
  188. package/infra/package.json +12 -0
  189. package/package.json +43 -0
  190. package/scripts/postinstall.mjs +395 -0
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ /**
3
+ * Status Tool — Show agent statuses from stack outputs
4
+ *
5
+ * Platform-agnostic implementation using RuntimeAdapter.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.statusTool = void 0;
9
+ const config_1 = require("../lib/config");
10
+ const core_1 = require("@clawup/core");
11
+ const workspace_1 = require("../lib/workspace");
12
+ const tailscale_1 = require("../lib/tailscale");
13
+ const tool_helpers_1 = require("../lib/tool-helpers");
14
+ /**
15
+ * SSH options for non-interactive connections
16
+ */
17
+ const SSH_OPTS = [
18
+ "-o", "StrictHostKeyChecking=no",
19
+ "-o", "UserKnownHostsFile=/dev/null",
20
+ "-o", "BatchMode=yes",
21
+ ];
22
+ /**
23
+ * Fetch Claude Code version via SSH (best effort, returns "—" on failure)
24
+ */
25
+ function getClaudeCodeVersion(exec, host, timeout = 5) {
26
+ const result = exec.capture("ssh", [
27
+ "-o", `ConnectTimeout=${timeout}`,
28
+ ...SSH_OPTS,
29
+ `${core_1.SSH_USER}@${host}`,
30
+ `"/home/${core_1.SSH_USER}/.local/bin/claude --version 2>/dev/null || echo ''"`,
31
+ ]);
32
+ if (result.exitCode === 0 && result.stdout?.trim()) {
33
+ return result.stdout.trim();
34
+ }
35
+ return "—";
36
+ }
37
+ /**
38
+ * Fetch GitHub CLI version via SSH (best effort, returns "—" on failure)
39
+ */
40
+ function getGhVersion(exec, host, timeout = 5) {
41
+ const result = exec.capture("ssh", [
42
+ "-o", `ConnectTimeout=${timeout}`,
43
+ ...SSH_OPTS,
44
+ `${core_1.SSH_USER}@${host}`,
45
+ `"gh --version 2>/dev/null | head -n1 | awk '{print \\$3}' || echo ''"`,
46
+ ]);
47
+ if (result.exitCode === 0 && result.stdout?.trim()) {
48
+ return result.stdout.trim();
49
+ }
50
+ return "—";
51
+ }
52
+ /**
53
+ * Fetch GitHub CLI auth status via SSH (best effort, returns "✓" or "—")
54
+ */
55
+ function getGhAuthStatus(exec, host, timeout = 5) {
56
+ const result = exec.capture("ssh", [
57
+ "-o", `ConnectTimeout=${timeout}`,
58
+ ...SSH_OPTS,
59
+ `${core_1.SSH_USER}@${host}`,
60
+ `"gh auth status 2>&1 >/dev/null && echo 'OK' || echo 'no'"`,
61
+ ]);
62
+ if (result.exitCode === 0 && result.stdout?.trim() === "OK") {
63
+ return "✓";
64
+ }
65
+ return "—";
66
+ }
67
+ /**
68
+ * Status tool implementation
69
+ */
70
+ const statusTool = async (runtime, options) => {
71
+ const { ui, exec } = runtime;
72
+ if (!options.json) {
73
+ ui.intro("Agent Army");
74
+ }
75
+ // Ensure workspace is set up (no-op in dev mode)
76
+ const wsResult = (0, workspace_1.ensureWorkspace)();
77
+ if (!wsResult.ok) {
78
+ ui.log.error(wsResult.error ?? "Failed to set up workspace.");
79
+ process.exit(1);
80
+ }
81
+ const cwd = (0, workspace_1.getWorkspaceDir)();
82
+ // Resolve config name and load manifest
83
+ let configName;
84
+ try {
85
+ configName = (0, config_1.resolveConfigName)(options.config);
86
+ }
87
+ catch (err) {
88
+ ui.log.error(err.message);
89
+ process.exit(1);
90
+ }
91
+ const manifest = (0, config_1.loadManifest)(configName);
92
+ if (!manifest) {
93
+ ui.log.error(`Config '${configName}' could not be loaded.`);
94
+ process.exit(1);
95
+ }
96
+ // Select/create stack
97
+ const selectResult = exec.capture("pulumi", ["stack", "select", manifest.stackName], cwd);
98
+ if (selectResult.exitCode !== 0) {
99
+ const initResult = exec.capture("pulumi", ["stack", "init", manifest.stackName], cwd);
100
+ if (initResult.exitCode !== 0) {
101
+ if (!options.json) {
102
+ ui.log.error(initResult.stderr || selectResult.stderr);
103
+ ui.log.error(`Could not select Pulumi stack "${manifest.stackName}".`);
104
+ }
105
+ process.exit(1);
106
+ }
107
+ }
108
+ // Get outputs
109
+ const outputs = (0, tool_helpers_1.getStackOutputs)(exec, true, cwd);
110
+ if (!outputs) {
111
+ ui.log.error("Could not fetch stack outputs. Has the stack been deployed?");
112
+ process.exit(1);
113
+ }
114
+ // Get tailnet DNS name for SSH connections
115
+ const tailnetDnsName = (0, tool_helpers_1.getConfig)(exec, "tailnetDnsName", cwd);
116
+ // Warn if Tailscale is not running (SSH version columns will show "—")
117
+ const tailscaleUp = (0, tailscale_1.isTailscaleRunning)();
118
+ if (!tailscaleUp && !options.json) {
119
+ ui.log.warn("Tailscale is not running — CLI version columns will show \"—\".\n" +
120
+ " Open the Tailscale app or run: tailscale up");
121
+ }
122
+ // Build status data with Claude Code and GitHub CLI versions (fetched via SSH)
123
+ const statusData = manifest.agents.map((agent) => {
124
+ let claudeCodeVersion = "—";
125
+ let ghVersion = "—";
126
+ let ghAuth = "—";
127
+ if (tailnetDnsName) {
128
+ const tsHost = (0, core_1.tailscaleHostname)(manifest.stackName, agent.name);
129
+ const host = `${tsHost}.${tailnetDnsName}`;
130
+ claudeCodeVersion = getClaudeCodeVersion(exec, host);
131
+ ghVersion = getGhVersion(exec, host);
132
+ if (ghVersion !== "—") {
133
+ ghAuth = getGhAuthStatus(exec, host);
134
+ }
135
+ }
136
+ return {
137
+ name: agent.displayName,
138
+ role: agent.role,
139
+ instanceId: outputs[`${agent.role}InstanceId`] ?? "—",
140
+ publicIp: outputs[`${agent.role}PublicIp`] ?? "—",
141
+ tailscaleUrl: outputs[`${agent.role}TailscaleUrl`] ?? "—",
142
+ claudeCodeVersion,
143
+ ghVersion,
144
+ ghAuth,
145
+ };
146
+ });
147
+ // JSON output
148
+ if (options.json) {
149
+ console.log(JSON.stringify(statusData, null, 2));
150
+ return;
151
+ }
152
+ // Table output
153
+ ui.log.step(`Stack: ${manifest.stackName} | Region: ${manifest.region}`);
154
+ console.log();
155
+ // Header
156
+ const nameW = 12;
157
+ const roleW = 10;
158
+ const idW = 22;
159
+ const ipW = 16;
160
+ const claudeW = 16;
161
+ const ghW = 8;
162
+ const authW = 6;
163
+ const header = [
164
+ "Agent".padEnd(nameW),
165
+ "Role".padEnd(roleW),
166
+ "Instance ID".padEnd(idW),
167
+ "Public IP".padEnd(ipW),
168
+ "Claude Code".padEnd(claudeW),
169
+ "gh".padEnd(ghW),
170
+ "Auth".padEnd(authW),
171
+ ].join(" ");
172
+ const separator = [
173
+ "─".repeat(nameW),
174
+ "─".repeat(roleW),
175
+ "─".repeat(idW),
176
+ "─".repeat(ipW),
177
+ "─".repeat(claudeW),
178
+ "─".repeat(ghW),
179
+ "─".repeat(authW),
180
+ ].join(" ");
181
+ console.log(` ${header}`);
182
+ console.log(` ${separator}`);
183
+ for (const s of statusData) {
184
+ const row = [
185
+ s.name.padEnd(nameW),
186
+ s.role.padEnd(roleW),
187
+ s.instanceId.padEnd(idW),
188
+ s.publicIp.padEnd(ipW),
189
+ s.claudeCodeVersion.padEnd(claudeW),
190
+ s.ghVersion.padEnd(ghW),
191
+ s.ghAuth.padEnd(authW),
192
+ ].join(" ");
193
+ console.log(` ${row}`);
194
+ }
195
+ console.log();
196
+ // Show Tailscale URLs
197
+ const urlLines = statusData
198
+ .filter((s) => s.tailscaleUrl !== "—")
199
+ .map((s) => ` ${s.name}: ${s.tailscaleUrl}`);
200
+ if (urlLines.length > 0) {
201
+ ui.note(urlLines.join("\n"), "Tailscale URLs");
202
+ }
203
+ };
204
+ exports.statusTool = statusTool;
205
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../tools/status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Validate Tool — Health check agents via Tailscale SSH
3
+ *
4
+ * Platform-agnostic implementation using RuntimeAdapter.
5
+ */
6
+ import type { ToolImplementation } from "../adapters";
7
+ export interface ValidateOptions {
8
+ /** SSH timeout in seconds */
9
+ timeout?: string;
10
+ /** Config name (auto-detected if only one) */
11
+ config?: string;
12
+ }
13
+ /**
14
+ * Validate tool implementation
15
+ */
16
+ export declare const validateTool: ToolImplementation<ValidateOptions>;
@@ -0,0 +1,219 @@
1
+ "use strict";
2
+ /**
3
+ * Validate Tool — Health check agents via Tailscale SSH
4
+ *
5
+ * Platform-agnostic implementation using RuntimeAdapter.
6
+ */
7
+ var __importDefault = (this && this.__importDefault) || function (mod) {
8
+ return (mod && mod.__esModule) ? mod : { "default": mod };
9
+ };
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.validateTool = void 0;
12
+ const config_1 = require("../lib/config");
13
+ const core_1 = require("@clawup/core");
14
+ const workspace_1 = require("../lib/workspace");
15
+ const tailscale_1 = require("../lib/tailscale");
16
+ const tool_helpers_1 = require("../lib/tool-helpers");
17
+ const picocolors_1 = __importDefault(require("picocolors"));
18
+ /**
19
+ * SSH options for non-interactive connections
20
+ */
21
+ const SSH_OPTS = [
22
+ "-o", "StrictHostKeyChecking=no",
23
+ "-o", "UserKnownHostsFile=/dev/null",
24
+ "-o", "BatchMode=yes",
25
+ ];
26
+ /**
27
+ * Run an SSH check command
28
+ */
29
+ function runSshCheck(exec, host, command, timeout) {
30
+ const result = exec.capture("ssh", [
31
+ "-o", `ConnectTimeout=${timeout}`,
32
+ ...SSH_OPTS,
33
+ `${core_1.SSH_USER}@${host}`,
34
+ `"${command.replace(/"/g, '\\"')}"`,
35
+ ]);
36
+ return { ok: result.exitCode === 0, output: result.stdout || result.stderr };
37
+ }
38
+ /**
39
+ * Validate tool implementation
40
+ */
41
+ const validateTool = async (runtime, options) => {
42
+ const { ui, exec } = runtime;
43
+ ui.intro("Agent Army");
44
+ (0, tailscale_1.requireTailscale)();
45
+ // Ensure workspace is set up (no-op in dev mode)
46
+ const wsResult = (0, workspace_1.ensureWorkspace)();
47
+ if (!wsResult.ok) {
48
+ ui.log.error(wsResult.error ?? "Failed to set up workspace.");
49
+ process.exit(1);
50
+ }
51
+ const cwd = (0, workspace_1.getWorkspaceDir)();
52
+ // Resolve config name and load manifest
53
+ let configName;
54
+ try {
55
+ configName = (0, config_1.resolveConfigName)(options.config);
56
+ }
57
+ catch (err) {
58
+ ui.log.error(err.message);
59
+ process.exit(1);
60
+ }
61
+ const manifest = (0, config_1.loadManifest)(configName);
62
+ if (!manifest) {
63
+ ui.log.error(`Config '${configName}' could not be loaded.`);
64
+ process.exit(1);
65
+ }
66
+ // Select/create stack
67
+ const selectResult = exec.capture("pulumi", ["stack", "select", manifest.stackName], cwd);
68
+ if (selectResult.exitCode !== 0) {
69
+ const initResult = exec.capture("pulumi", ["stack", "init", manifest.stackName], cwd);
70
+ if (initResult.exitCode !== 0) {
71
+ ui.log.error(`Could not select Pulumi stack "${manifest.stackName}".`);
72
+ process.exit(1);
73
+ }
74
+ }
75
+ // Get tailnet
76
+ const tailnetDnsName = (0, tool_helpers_1.getConfig)(exec, "tailnetDnsName", cwd);
77
+ if (!tailnetDnsName) {
78
+ ui.log.error("Could not determine tailnet DNS name from Pulumi config.");
79
+ process.exit(1);
80
+ }
81
+ const timeout = parseInt(options.timeout ?? "30", 10);
82
+ const results = [];
83
+ ui.log.step(`Validating ${manifest.agents.length} agents (timeout: ${timeout}s)...`);
84
+ console.log();
85
+ for (const agent of manifest.agents) {
86
+ const tsHost = (0, core_1.tailscaleHostname)(manifest.stackName, agent.name);
87
+ const host = `${tsHost}.${tailnetDnsName}`;
88
+ const checks = [];
89
+ ui.log.info(`${picocolors_1.default.bold(agent.displayName)} (${agent.role}) — ${host}`);
90
+ // Check 1: SSH connectivity
91
+ const ssh = runSshCheck(exec, host, "echo 'SSH OK'", timeout);
92
+ checks.push({
93
+ name: "SSH connectivity",
94
+ passed: ssh.ok,
95
+ detail: ssh.ok ? "connected" : "connection failed",
96
+ });
97
+ if (ssh.ok) {
98
+ // Check 2: OpenClaw gateway running (systemd user service)
99
+ const gateway = runSshCheck(exec, host, "systemctl --user is-active openclaw-gateway", timeout);
100
+ checks.push({
101
+ name: "OpenClaw gateway",
102
+ passed: gateway.ok,
103
+ detail: gateway.ok ? "running" : gateway.output || "not running",
104
+ });
105
+ // Check 3: Workspace files present
106
+ const workspace = runSshCheck(exec, host, `test -f /home/${core_1.SSH_USER}/.openclaw/workspace/SOUL.md && test -f /home/${core_1.SSH_USER}/.openclaw/workspace/HEARTBEAT.md && echo 'OK'`, timeout);
107
+ checks.push({
108
+ name: "Workspace files",
109
+ passed: workspace.ok,
110
+ detail: workspace.ok ? "SOUL.md + HEARTBEAT.md present" : "missing files",
111
+ });
112
+ // Check 4: Claude Code CLI installed
113
+ const claudeCode = runSshCheck(exec, host, `/home/${core_1.SSH_USER}/.local/bin/claude --version 2>/dev/null || echo 'not installed'`, timeout);
114
+ const claudeVersion = claudeCode.output.trim();
115
+ const claudeInstalled = claudeCode.ok && !claudeVersion.includes("not installed");
116
+ checks.push({
117
+ name: "Claude Code CLI",
118
+ passed: claudeInstalled,
119
+ detail: claudeInstalled ? claudeVersion : "not installed",
120
+ });
121
+ // Check 5: Claude Code auth (API key or OAuth token)
122
+ if (claudeInstalled) {
123
+ const credCheck = runSshCheck(exec, host, `grep -E '"(ANTHROPIC_API_KEY|CLAUDE_CODE_OAUTH_TOKEN)"' /home/${core_1.SSH_USER}/.openclaw/openclaw.json | head -1`, timeout);
124
+ const hasApiKey = credCheck.output.includes("ANTHROPIC_API_KEY");
125
+ const hasOAuthToken = credCheck.output.includes("CLAUDE_CODE_OAUTH_TOKEN");
126
+ const credIsConfigured = credCheck.ok && (hasApiKey || hasOAuthToken);
127
+ const credType = hasOAuthToken ? "OAuth token" : "API key";
128
+ if (credIsConfigured) {
129
+ const envVar = hasOAuthToken ? "CLAUDE_CODE_OAUTH_TOKEN" : "ANTHROPIC_API_KEY";
130
+ const testScript = `
131
+ export ${envVar}=$(jq -r '.env.${envVar}' /home/${core_1.SSH_USER}/.openclaw/openclaw.json)
132
+ timeout 15 /home/${core_1.SSH_USER}/.local/bin/claude -p 'hi' 2>&1 | head -5
133
+ `.trim();
134
+ const authTest = runSshCheck(exec, host, testScript, timeout + 15);
135
+ const authWorks = authTest.ok &&
136
+ !authTest.output.includes("Invalid API key") &&
137
+ !authTest.output.includes("not authenticated");
138
+ checks.push({
139
+ name: "Claude Code auth",
140
+ passed: authWorks,
141
+ detail: authWorks ? `${credType} verified` : `${credType} test failed: ${authTest.output.substring(0, 50)}`,
142
+ });
143
+ }
144
+ else {
145
+ checks.push({
146
+ name: "Claude Code auth",
147
+ passed: false,
148
+ detail: "No credentials configured",
149
+ });
150
+ }
151
+ }
152
+ // Check 6: GitHub CLI installed
153
+ const ghVersion = runSshCheck(exec, host, `gh --version 2>/dev/null | head -n1 || echo 'not installed'`, timeout);
154
+ const ghVersionStr = ghVersion.output.trim();
155
+ const ghInstalled = ghVersion.ok && !ghVersionStr.includes("not installed");
156
+ checks.push({
157
+ name: "GitHub CLI",
158
+ passed: ghInstalled,
159
+ detail: ghInstalled ? ghVersionStr : "not installed",
160
+ });
161
+ // Check 7: GitHub CLI auth status (if installed)
162
+ if (ghInstalled) {
163
+ const ghAuth = runSshCheck(exec, host, `gh auth status 2>&1 | head -n2 || echo 'not authenticated'`, timeout);
164
+ const ghAuthStr = ghAuth.output.trim();
165
+ const ghAuthenticated = ghAuth.ok &&
166
+ !ghAuthStr.includes("not authenticated") &&
167
+ !ghAuthStr.includes("not logged");
168
+ checks.push({
169
+ name: "GitHub CLI auth",
170
+ passed: ghAuthenticated,
171
+ detail: ghAuthenticated ? "authenticated" : "not authenticated (optional)",
172
+ });
173
+ }
174
+ }
175
+ else {
176
+ checks.push({ name: "OpenClaw gateway", passed: false, detail: "skipped (no SSH)" });
177
+ checks.push({ name: "Workspace files", passed: false, detail: "skipped (no SSH)" });
178
+ checks.push({ name: "Claude Code CLI", passed: false, detail: "skipped (no SSH)" });
179
+ checks.push({ name: "Claude Code auth", passed: false, detail: "skipped (no SSH)" });
180
+ checks.push({ name: "GitHub CLI", passed: false, detail: "skipped (no SSH)" });
181
+ checks.push({ name: "GitHub CLI auth", passed: false, detail: "skipped (no SSH)" });
182
+ }
183
+ // Display check results
184
+ const allPassed = checks.every((c) => c.passed);
185
+ for (const check of checks) {
186
+ const icon = check.passed ? picocolors_1.default.green("PASS") : picocolors_1.default.red("FAIL");
187
+ console.log(` ${icon} ${check.name}: ${check.detail ?? ""}`);
188
+ }
189
+ console.log();
190
+ results.push({ agent: agent.displayName, checks, passed: allPassed });
191
+ }
192
+ // Summary
193
+ const passed = results.filter((r) => r.passed).length;
194
+ const failed = results.filter((r) => !r.passed).length;
195
+ const summaryLines = [
196
+ `Total: ${results.length}`,
197
+ `Passed: ${passed}`,
198
+ `Failed: ${failed}`,
199
+ ];
200
+ ui.note(summaryLines.join("\n"), "Validation Summary");
201
+ if (failed > 0) {
202
+ ui.log.warn("Some agents failed validation.");
203
+ console.log(" 1. Wait 3-5 minutes for cloud-init to complete");
204
+ const agentHints = results
205
+ .filter((r) => !r.passed)
206
+ .map((r) => {
207
+ const agent = manifest.agents.find((a) => a.displayName === r.agent);
208
+ return agent ? agent.role : r.agent;
209
+ });
210
+ console.log(` 2. Check logs: clawup ssh ${agentHints[0] ?? "<role>"} -- journalctl -u openclaw`);
211
+ console.log(" 3. Verify Tailscale: tailscale status");
212
+ process.exit(1);
213
+ }
214
+ else {
215
+ ui.log.success("All agents are healthy!");
216
+ }
217
+ };
218
+ exports.validateTool = validateTool;
219
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../tools/validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Webhooks Setup Tool — Configure Linear webhooks for deployed agents
3
+ *
4
+ * Collects signing secrets, stores them in Pulumi config for persistence,
5
+ * then applies them live via SSH (no redeploy needed).
6
+ *
7
+ * Platform-agnostic implementation using RuntimeAdapter.
8
+ */
9
+ import type { ToolImplementation } from "../adapters";
10
+ export interface WebhooksSetupOptions {
11
+ /** Config name (auto-detected if only one) */
12
+ config?: string;
13
+ }
14
+ /**
15
+ * Webhooks setup tool implementation
16
+ */
17
+ export declare const webhooksSetupTool: ToolImplementation<WebhooksSetupOptions>;
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+ /**
3
+ * Webhooks Setup Tool — Configure Linear webhooks for deployed agents
4
+ *
5
+ * Collects signing secrets, stores them in Pulumi config for persistence,
6
+ * then applies them live via SSH (no redeploy needed).
7
+ *
8
+ * Platform-agnostic implementation using RuntimeAdapter.
9
+ */
10
+ var __importDefault = (this && this.__importDefault) || function (mod) {
11
+ return (mod && mod.__esModule) ? mod : { "default": mod };
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.webhooksSetupTool = void 0;
15
+ const config_1 = require("../lib/config");
16
+ const core_1 = require("@clawup/core");
17
+ const workspace_1 = require("../lib/workspace");
18
+ const tool_helpers_1 = require("../lib/tool-helpers");
19
+ const picocolors_1 = __importDefault(require("picocolors"));
20
+ /** SSH options for non-interactive connections */
21
+ const SSH_OPTS = [
22
+ "-o", "StrictHostKeyChecking=no",
23
+ "-o", "UserKnownHostsFile=/dev/null",
24
+ "-o", "BatchMode=yes",
25
+ ];
26
+ /**
27
+ * Run a command over SSH
28
+ */
29
+ function sshExec(exec, host, command) {
30
+ const result = exec.capture("ssh", [
31
+ "-o", "ConnectTimeout=15",
32
+ ...SSH_OPTS,
33
+ `${core_1.SSH_USER}@${host}`,
34
+ `"${command.replace(/"/g, '\\"')}"`,
35
+ ]);
36
+ return { ok: result.exitCode === 0, output: result.stdout || result.stderr };
37
+ }
38
+ /**
39
+ * Webhooks setup tool implementation
40
+ */
41
+ const webhooksSetupTool = async (runtime, options) => {
42
+ const { ui, exec } = runtime;
43
+ ui.intro("Agent Army — Webhook Setup");
44
+ // Ensure workspace is set up
45
+ const wsResult = (0, workspace_1.ensureWorkspace)();
46
+ if (!wsResult.ok) {
47
+ ui.log.error(wsResult.error ?? "Failed to set up workspace.");
48
+ process.exit(1);
49
+ }
50
+ const cwd = (0, workspace_1.getWorkspaceDir)();
51
+ // Resolve config name and load manifest
52
+ let configName;
53
+ try {
54
+ configName = (0, config_1.resolveConfigName)(options.config);
55
+ }
56
+ catch (err) {
57
+ ui.log.error(err.message);
58
+ process.exit(1);
59
+ }
60
+ const manifest = (0, config_1.loadManifest)(configName);
61
+ if (!manifest) {
62
+ ui.log.error(`Config '${configName}' could not be loaded.`);
63
+ process.exit(1);
64
+ }
65
+ // Select stack
66
+ const selectResult = exec.capture("pulumi", ["stack", "select", manifest.stackName], cwd);
67
+ if (selectResult.exitCode !== 0) {
68
+ ui.log.error(`Could not select Pulumi stack "${manifest.stackName}". Run ${picocolors_1.default.cyan("clawup deploy")} first.`);
69
+ process.exit(1);
70
+ }
71
+ // Get stack outputs
72
+ const outputs = (0, tool_helpers_1.getStackOutputs)(exec, true, cwd);
73
+ if (!outputs) {
74
+ ui.log.error(`Could not fetch stack outputs. Run ${picocolors_1.default.cyan("clawup deploy")} first.`);
75
+ process.exit(1);
76
+ }
77
+ // Get tailnet DNS name for SSH
78
+ const tailnetDnsName = (0, tool_helpers_1.getConfig)(exec, "tailnetDnsName", cwd);
79
+ if (!tailnetDnsName) {
80
+ ui.log.error("Could not read tailnetDnsName from Pulumi config.");
81
+ process.exit(1);
82
+ }
83
+ // Check if any webhook URLs exist
84
+ const agentsWithUrls = manifest.agents.filter((agent) => outputs[`${agent.role}WebhookUrl`]);
85
+ if (agentsWithUrls.length === 0) {
86
+ ui.log.error("No webhook URLs found in stack outputs.\n" +
87
+ ` Make sure agents are deployed and exposing webhook endpoints.\n` +
88
+ ` Run ${picocolors_1.default.cyan("clawup deploy")} if you haven't already.`);
89
+ process.exit(1);
90
+ }
91
+ ui.note([
92
+ "This will walk you through creating Linear webhooks for each agent.",
93
+ "You'll need access to your Linear workspace settings.",
94
+ ].join("\n"), "Linear Webhook Setup");
95
+ // Collect webhook secrets for each agent
96
+ const secrets = [];
97
+ for (const agent of manifest.agents) {
98
+ const webhookUrl = outputs[`${agent.role}WebhookUrl`];
99
+ if (!webhookUrl) {
100
+ ui.log.warn(`No webhook URL found for ${agent.displayName} (${agent.role}) — skipping.`);
101
+ continue;
102
+ }
103
+ ui.note([
104
+ `Webhook URL: ${picocolors_1.default.cyan(String(webhookUrl))}`,
105
+ "",
106
+ "Steps:",
107
+ "1. Go to Linear Settings → API → Webhooks → \"New webhook\"",
108
+ "2. Paste the URL above",
109
+ "3. Select events to receive (e.g., Issues, Comments)",
110
+ "4. Create the webhook and copy the \"Signing secret\"",
111
+ ].join("\n"), `${agent.displayName} (${agent.role})`);
112
+ const secret = await ui.text({
113
+ message: `Signing secret for ${agent.displayName}`,
114
+ placeholder: "Paste the signing secret from Linear",
115
+ validate: (val) => {
116
+ if (!val)
117
+ return "Signing secret is required";
118
+ },
119
+ });
120
+ secrets.push({
121
+ role: agent.role,
122
+ name: agent.name,
123
+ agentName: agent.displayName,
124
+ secret: secret,
125
+ });
126
+ }
127
+ if (secrets.length === 0) {
128
+ ui.log.warn("No webhook secrets collected.");
129
+ ui.outro("Nothing to do.");
130
+ return;
131
+ }
132
+ // Store secrets in Pulumi config (for persistence across deploys)
133
+ const configSpinner = ui.spinner("Saving webhook secrets to Pulumi config...");
134
+ for (const { role, secret } of secrets) {
135
+ exec.capture("pulumi", ["config", "set", `${role}LinearWebhookSecret`, secret, "--secret"], cwd);
136
+ }
137
+ configSpinner.stop(`Saved ${secrets.length} webhook secret(s) to Pulumi config`);
138
+ // Apply secrets live via SSH
139
+ const applySpinner = ui.spinner("Applying webhook secrets to running agents...");
140
+ let applied = 0;
141
+ let failed = 0;
142
+ for (const { role, name, agentName, secret } of secrets) {
143
+ const tsHost = (0, core_1.tailscaleHostname)(manifest.stackName, name);
144
+ const host = `${tsHost}.${tailnetDnsName}`;
145
+ // Escape the secret for use inside jq
146
+ const escapedSecret = secret.replace(/'/g, "'\\''");
147
+ const jqCmd = `jq '.plugins.entries.linear.config.webhookSecret = \\\"${escapedSecret.replace(/\\/g, "\\\\").replace(/"/g, '\\\\\\"')}\\\"' ` +
148
+ `/home/${core_1.SSH_USER}/.openclaw/openclaw.json > /tmp/openclaw-patched.json && ` +
149
+ `mv /tmp/openclaw-patched.json /home/${core_1.SSH_USER}/.openclaw/openclaw.json`;
150
+ const patchResult = sshExec(exec, host, jqCmd);
151
+ if (!patchResult.ok) {
152
+ applySpinner.stop(`Failed to patch config on ${agentName}`);
153
+ ui.log.warn(` ${agentName}: ${patchResult.output}`);
154
+ failed++;
155
+ continue;
156
+ }
157
+ const restartResult = sshExec(exec, host, "systemctl --user restart openclaw-gateway");
158
+ if (!restartResult.ok) {
159
+ applySpinner.stop(`Failed to restart gateway on ${agentName}`);
160
+ ui.log.warn(` ${agentName}: ${restartResult.output}`);
161
+ failed++;
162
+ continue;
163
+ }
164
+ applied++;
165
+ }
166
+ if (applied > 0 && failed === 0) {
167
+ applySpinner.stop(`Applied to ${applied} agent(s)`);
168
+ }
169
+ else if (applied > 0) {
170
+ applySpinner.stop(`Applied to ${applied} agent(s), ${failed} failed`);
171
+ }
172
+ else {
173
+ applySpinner.stop(`Failed to apply to any agents`);
174
+ }
175
+ if (failed > 0) {
176
+ ui.log.warn(`Some agents could not be reached. They will pick up the secrets on next deploy.`);
177
+ }
178
+ ui.outro("Webhook setup complete!");
179
+ };
180
+ exports.webhooksSetupTool = webhooksSetupTool;
181
+ //# sourceMappingURL=webhooks.js.map