agent-army 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +162 -0
  2. package/dist/adapters/api-adapter.d.ts +76 -0
  3. package/dist/adapters/api-adapter.js +251 -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 +207 -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 +83 -0
  16. package/dist/bin.js.map +1 -0
  17. package/dist/commands/deploy.d.ts +7 -0
  18. package/dist/commands/deploy.js +13 -0
  19. package/dist/commands/deploy.js.map +1 -0
  20. package/dist/commands/destroy.d.ts +7 -0
  21. package/dist/commands/destroy.js +13 -0
  22. package/dist/commands/destroy.js.map +1 -0
  23. package/dist/commands/init.d.ts +9 -0
  24. package/dist/commands/init.js +538 -0
  25. package/dist/commands/init.js.map +1 -0
  26. package/dist/commands/list.d.ts +8 -0
  27. package/dist/commands/list.js +42 -0
  28. package/dist/commands/list.js.map +1 -0
  29. package/dist/commands/ssh.d.ts +9 -0
  30. package/dist/commands/ssh.js +101 -0
  31. package/dist/commands/ssh.js.map +1 -0
  32. package/dist/commands/status.d.ts +7 -0
  33. package/dist/commands/status.js +13 -0
  34. package/dist/commands/status.js.map +1 -0
  35. package/dist/commands/validate.d.ts +7 -0
  36. package/dist/commands/validate.js +13 -0
  37. package/dist/commands/validate.js.map +1 -0
  38. package/dist/lib/config.d.ts +66 -0
  39. package/dist/lib/config.js +239 -0
  40. package/dist/lib/config.js.map +1 -0
  41. package/dist/lib/constants.d.ts +147 -0
  42. package/dist/lib/constants.js +307 -0
  43. package/dist/lib/constants.js.map +1 -0
  44. package/dist/lib/exec.d.ts +22 -0
  45. package/dist/lib/exec.js +60 -0
  46. package/dist/lib/exec.js.map +1 -0
  47. package/dist/lib/prerequisites.d.ts +8 -0
  48. package/dist/lib/prerequisites.js +124 -0
  49. package/dist/lib/prerequisites.js.map +1 -0
  50. package/dist/lib/process.d.ts +18 -0
  51. package/dist/lib/process.js +37 -0
  52. package/dist/lib/process.js.map +1 -0
  53. package/dist/lib/pulumi.d.ts +39 -0
  54. package/dist/lib/pulumi.js +87 -0
  55. package/dist/lib/pulumi.js.map +1 -0
  56. package/dist/lib/tailscale.d.ts +24 -0
  57. package/dist/lib/tailscale.js +71 -0
  58. package/dist/lib/tailscale.js.map +1 -0
  59. package/dist/lib/ui.d.ts +27 -0
  60. package/dist/lib/ui.js +89 -0
  61. package/dist/lib/ui.js.map +1 -0
  62. package/dist/tools/deploy.d.ts +16 -0
  63. package/dist/tools/deploy.js +133 -0
  64. package/dist/tools/deploy.js.map +1 -0
  65. package/dist/tools/destroy.d.ts +16 -0
  66. package/dist/tools/destroy.js +186 -0
  67. package/dist/tools/destroy.js.map +1 -0
  68. package/dist/tools/index.d.ts +17 -0
  69. package/dist/tools/index.js +28 -0
  70. package/dist/tools/index.js.map +1 -0
  71. package/dist/tools/status.d.ts +16 -0
  72. package/dist/tools/status.js +213 -0
  73. package/dist/tools/status.js.map +1 -0
  74. package/dist/tools/validate.d.ts +16 -0
  75. package/dist/tools/validate.js +215 -0
  76. package/dist/tools/validate.js.map +1 -0
  77. package/dist/types.d.ts +50 -0
  78. package/dist/types.js +6 -0
  79. package/dist/types.js.map +1 -0
  80. package/package.json +32 -0
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ /**
3
+ * agent-army ssh — SSH to agent by name/alias
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.sshCommand = sshCommand;
40
+ const p = __importStar(require("@clack/prompts"));
41
+ const config_1 = require("../lib/config");
42
+ const pulumi_1 = require("../lib/pulumi");
43
+ const constants_1 = require("../lib/constants");
44
+ const ui_1 = require("../lib/ui");
45
+ const child_process_1 = require("child_process");
46
+ async function sshCommand(agentNameOrAlias, commandArgs, opts) {
47
+ // Check for legacy config and offer migration
48
+ await (0, config_1.checkAndMigrateLegacy)();
49
+ // Resolve config name
50
+ let configName;
51
+ try {
52
+ configName = (0, config_1.resolveConfigName)(opts.config);
53
+ }
54
+ catch (err) {
55
+ (0, ui_1.exitWithError)(err.message);
56
+ }
57
+ // Load manifest
58
+ const manifest = (0, config_1.loadManifest)(configName);
59
+ if (!manifest) {
60
+ (0, ui_1.exitWithError)(`Config '${configName}' could not be loaded.`);
61
+ }
62
+ // Select stack
63
+ const stackResult = (0, pulumi_1.selectOrCreateStack)(manifest.stackName);
64
+ if (!stackResult.ok) {
65
+ (0, ui_1.exitWithError)(`Could not select Pulumi stack "${manifest.stackName}".`);
66
+ }
67
+ // Resolve agent name/alias
68
+ const query = agentNameOrAlias.toLowerCase();
69
+ const resolvedRole = constants_1.AGENT_ALIASES[query] ?? query;
70
+ // Find agent in manifest
71
+ const agent = manifest.agents.find((a) => a.role === resolvedRole ||
72
+ a.name === query ||
73
+ a.name === `agent-${query}` ||
74
+ a.displayName.toLowerCase() === query);
75
+ if (!agent) {
76
+ const validNames = manifest.agents
77
+ .map((a) => `${a.role}, ${a.displayName.toLowerCase()}, ${a.name}`)
78
+ .join("\n ");
79
+ (0, ui_1.exitWithError)(`Unknown agent: "${agentNameOrAlias}"\nValid identifiers (any of these work):\n ${validNames}`);
80
+ }
81
+ // Get tailnet DNS name
82
+ const tailnetDnsName = (0, pulumi_1.getConfig)("tailnetDnsName");
83
+ if (!tailnetDnsName) {
84
+ (0, ui_1.exitWithError)("Could not determine tailnet DNS name from Pulumi config.");
85
+ }
86
+ const tsHost = (0, constants_1.tailscaleHostname)(manifest.stackName, agent.name);
87
+ const sshHost = `${tsHost}.${tailnetDnsName}`;
88
+ const user = opts.user ?? constants_1.SSH_USER;
89
+ p.log.info(`Connecting to ${agent.displayName} (${sshHost})...`);
90
+ // Build SSH command
91
+ const sshArgs = ["-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null", `${user}@${sshHost}`];
92
+ if (commandArgs.length > 0) {
93
+ sshArgs.push(commandArgs.join(" "));
94
+ }
95
+ // Spawn interactive SSH
96
+ const child = (0, child_process_1.spawn)("ssh", sshArgs, { stdio: "inherit" });
97
+ child.on("close", (code) => {
98
+ process.exit(code ?? 0);
99
+ });
100
+ }
101
+ //# sourceMappingURL=ssh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssh.js","sourceRoot":"","sources":["../../commands/ssh.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * agent-army status — Show agent statuses from stack outputs
3
+ *
4
+ * This command wraps the platform-agnostic statusTool with the CLI adapter.
5
+ */
6
+ import { type StatusOptions } from "../tools";
7
+ export declare function statusCommand(opts: StatusOptions): Promise<void>;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ /**
3
+ * agent-army status — Show agent statuses from stack outputs
4
+ *
5
+ * This command wraps the platform-agnostic statusTool with the CLI adapter.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.statusCommand = statusCommand;
9
+ const tools_1 = require("../tools");
10
+ async function statusCommand(opts) {
11
+ await (0, tools_1.statusTool)((0, tools_1.createCLIAdapter)(), opts);
12
+ }
13
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../commands/status.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AAIH,sCAEC;AAJD,oCAA4E;AAErE,KAAK,UAAU,aAAa,CAAC,IAAmB;IACrD,MAAM,IAAA,kBAAU,EAAC,IAAA,wBAAgB,GAAE,EAAE,IAAI,CAAC,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * agent-army validate — Health check agents via Tailscale SSH
3
+ *
4
+ * This command wraps the platform-agnostic validateTool with the CLI adapter.
5
+ */
6
+ import { type ValidateOptions } from "../tools";
7
+ export declare function validateCommand(opts: ValidateOptions): Promise<void>;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ /**
3
+ * agent-army validate — Health check agents via Tailscale SSH
4
+ *
5
+ * This command wraps the platform-agnostic validateTool with the CLI adapter.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.validateCommand = validateCommand;
9
+ const tools_1 = require("../tools");
10
+ async function validateCommand(opts) {
11
+ await (0, tools_1.validateTool)((0, tools_1.createCLIAdapter)(), opts);
12
+ }
13
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../commands/validate.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AAIH,0CAEC;AAJD,oCAAgF;AAEzE,KAAK,UAAU,eAAe,CAAC,IAAqB;IACzD,MAAM,IAAA,oBAAY,EAAC,IAAA,wBAAgB,GAAE,EAAE,IAAI,CAAC,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Load/save agent-army manifests from ~/.agent-army/configs/
3
+ */
4
+ import type { ArmyManifest } from "../types";
5
+ /**
6
+ * Get the configs directory path (~/.agent-army/configs/)
7
+ */
8
+ export declare function configsDir(): string;
9
+ /**
10
+ * Ensure the configs directory exists
11
+ */
12
+ export declare function ensureConfigsDir(): void;
13
+ /**
14
+ * Get the path to a config file by name
15
+ */
16
+ export declare function configPath(name: string): string;
17
+ /**
18
+ * Get the legacy manifest path (./agent-army.json in CWD)
19
+ */
20
+ export declare function legacyManifestPath(): string;
21
+ /**
22
+ * Copy a named config to ./agent-army.json so the Pulumi program can read it.
23
+ * The Pulumi program (index.ts) always reads from the project root manifest.
24
+ */
25
+ export declare function syncManifestToProject(name: string): void;
26
+ /**
27
+ * Check if a legacy manifest exists in CWD
28
+ */
29
+ export declare function legacyManifestExists(): boolean;
30
+ /**
31
+ * Load a legacy manifest from CWD
32
+ */
33
+ export declare function loadLegacyManifest(): ArmyManifest | null;
34
+ /**
35
+ * Check for legacy manifest and offer migration.
36
+ * Returns the migrated config name if migration occurred, null otherwise.
37
+ */
38
+ export declare function checkAndMigrateLegacy(): Promise<string | null>;
39
+ /**
40
+ * Check if a config exists by name
41
+ */
42
+ export declare function manifestExists(name: string): boolean;
43
+ /**
44
+ * Load a manifest by name. Returns null if not found or invalid.
45
+ */
46
+ export declare function loadManifest(name: string): ArmyManifest | null;
47
+ /**
48
+ * Save a manifest by name
49
+ */
50
+ export declare function saveManifest(name: string, manifest: ArmyManifest): void;
51
+ /**
52
+ * List all saved config names
53
+ */
54
+ export declare function listManifests(): string[];
55
+ /**
56
+ * Delete a config by name. Returns true if deleted, false if not found.
57
+ */
58
+ export declare function deleteManifest(name: string): boolean;
59
+ /**
60
+ * Resolve a config name: auto-selects if only one config exists,
61
+ * errors with list if ambiguous or none found.
62
+ * @param name Optional explicit config name
63
+ * @returns The resolved config name
64
+ * @throws Error if no configs exist or multiple configs exist without explicit name
65
+ */
66
+ export declare function resolveConfigName(name?: string): string;
@@ -0,0 +1,239 @@
1
+ "use strict";
2
+ /**
3
+ * Load/save agent-army manifests from ~/.agent-army/configs/
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.configsDir = configsDir;
40
+ exports.ensureConfigsDir = ensureConfigsDir;
41
+ exports.configPath = configPath;
42
+ exports.legacyManifestPath = legacyManifestPath;
43
+ exports.syncManifestToProject = syncManifestToProject;
44
+ exports.legacyManifestExists = legacyManifestExists;
45
+ exports.loadLegacyManifest = loadLegacyManifest;
46
+ exports.checkAndMigrateLegacy = checkAndMigrateLegacy;
47
+ exports.manifestExists = manifestExists;
48
+ exports.loadManifest = loadManifest;
49
+ exports.saveManifest = saveManifest;
50
+ exports.listManifests = listManifests;
51
+ exports.deleteManifest = deleteManifest;
52
+ exports.resolveConfigName = resolveConfigName;
53
+ const fs = __importStar(require("fs"));
54
+ const path = __importStar(require("path"));
55
+ const os = __importStar(require("os"));
56
+ const readline = __importStar(require("readline"));
57
+ const constants_1 = require("./constants");
58
+ /**
59
+ * Get the configs directory path (~/.agent-army/configs/)
60
+ */
61
+ function configsDir() {
62
+ return path.join(os.homedir(), constants_1.CONFIG_DIR);
63
+ }
64
+ /**
65
+ * Ensure the configs directory exists
66
+ */
67
+ function ensureConfigsDir() {
68
+ const dir = configsDir();
69
+ if (!fs.existsSync(dir)) {
70
+ fs.mkdirSync(dir, { recursive: true });
71
+ }
72
+ }
73
+ /**
74
+ * Get the path to a config file by name
75
+ */
76
+ function configPath(name) {
77
+ return path.join(configsDir(), `${name}.json`);
78
+ }
79
+ /**
80
+ * Get the legacy manifest path (./agent-army.json in CWD)
81
+ */
82
+ function legacyManifestPath() {
83
+ return path.join(process.cwd(), constants_1.MANIFEST_FILE);
84
+ }
85
+ /**
86
+ * Copy a named config to ./agent-army.json so the Pulumi program can read it.
87
+ * The Pulumi program (index.ts) always reads from the project root manifest.
88
+ */
89
+ function syncManifestToProject(name) {
90
+ const src = configPath(name);
91
+ const dest = legacyManifestPath();
92
+ fs.copyFileSync(src, dest);
93
+ }
94
+ /**
95
+ * Check if a legacy manifest exists in CWD
96
+ */
97
+ function legacyManifestExists() {
98
+ return fs.existsSync(legacyManifestPath());
99
+ }
100
+ /**
101
+ * Load a legacy manifest from CWD
102
+ */
103
+ function loadLegacyManifest() {
104
+ const filePath = legacyManifestPath();
105
+ if (!fs.existsSync(filePath))
106
+ return null;
107
+ try {
108
+ const raw = fs.readFileSync(filePath, "utf-8");
109
+ return JSON.parse(raw);
110
+ }
111
+ catch (err) {
112
+ console.warn(`[config] Failed to load legacy manifest at ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
113
+ return null;
114
+ }
115
+ }
116
+ /**
117
+ * Prompt user for yes/no confirmation
118
+ */
119
+ async function confirm(message) {
120
+ const rl = readline.createInterface({
121
+ input: process.stdin,
122
+ output: process.stdout,
123
+ });
124
+ return new Promise((resolve) => {
125
+ rl.question(`${message} [y/N] `, (answer) => {
126
+ rl.close();
127
+ resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
128
+ });
129
+ });
130
+ }
131
+ /**
132
+ * Check for legacy manifest and offer migration.
133
+ * Returns the migrated config name if migration occurred, null otherwise.
134
+ */
135
+ async function checkAndMigrateLegacy() {
136
+ if (!legacyManifestExists())
137
+ return null;
138
+ const legacy = loadLegacyManifest();
139
+ if (!legacy)
140
+ return null;
141
+ console.log(`\nFound legacy config at ${legacyManifestPath()}`);
142
+ console.log(` Stack: ${legacy.stackName}`);
143
+ console.log(` Region: ${legacy.region}`);
144
+ console.log(` Agents: ${legacy.agents.length}`);
145
+ const shouldMigrate = await confirm("\nMigrate this config to ~/.agent-army/configs/?");
146
+ if (!shouldMigrate) {
147
+ return null;
148
+ }
149
+ const configName = legacy.stackName;
150
+ saveManifest(configName, legacy);
151
+ console.log(`\nMigrated to: ${configPath(configName)}`);
152
+ const shouldDelete = await confirm("Delete the old ./agent-army.json file?");
153
+ if (shouldDelete) {
154
+ fs.unlinkSync(legacyManifestPath());
155
+ console.log("Deleted legacy config.");
156
+ }
157
+ return configName;
158
+ }
159
+ /**
160
+ * Check if a config exists by name
161
+ */
162
+ function manifestExists(name) {
163
+ return fs.existsSync(configPath(name));
164
+ }
165
+ /**
166
+ * Load a manifest by name. Returns null if not found or invalid.
167
+ */
168
+ function loadManifest(name) {
169
+ const filePath = configPath(name);
170
+ if (!fs.existsSync(filePath))
171
+ return null;
172
+ try {
173
+ const raw = fs.readFileSync(filePath, "utf-8");
174
+ return JSON.parse(raw);
175
+ }
176
+ catch (err) {
177
+ console.warn(`[config] Failed to load manifest '${name}' at ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
178
+ return null;
179
+ }
180
+ }
181
+ /**
182
+ * Save a manifest by name
183
+ */
184
+ function saveManifest(name, manifest) {
185
+ ensureConfigsDir();
186
+ const filePath = configPath(name);
187
+ fs.writeFileSync(filePath, JSON.stringify(manifest, null, 2) + "\n", "utf-8");
188
+ }
189
+ /**
190
+ * List all saved config names
191
+ */
192
+ function listManifests() {
193
+ const dir = configsDir();
194
+ if (!fs.existsSync(dir))
195
+ return [];
196
+ return fs
197
+ .readdirSync(dir)
198
+ .filter((f) => f.endsWith(".json"))
199
+ .map((f) => f.replace(/\.json$/, ""))
200
+ .sort();
201
+ }
202
+ /**
203
+ * Delete a config by name. Returns true if deleted, false if not found.
204
+ */
205
+ function deleteManifest(name) {
206
+ const filePath = configPath(name);
207
+ if (!fs.existsSync(filePath))
208
+ return false;
209
+ fs.unlinkSync(filePath);
210
+ return true;
211
+ }
212
+ /**
213
+ * Resolve a config name: auto-selects if only one config exists,
214
+ * errors with list if ambiguous or none found.
215
+ * @param name Optional explicit config name
216
+ * @returns The resolved config name
217
+ * @throws Error if no configs exist or multiple configs exist without explicit name
218
+ */
219
+ function resolveConfigName(name) {
220
+ if (name) {
221
+ if (!manifestExists(name)) {
222
+ const available = listManifests();
223
+ if (available.length === 0) {
224
+ throw new Error(`Config '${name}' not found. No configs exist. Run 'agent-army init' to create one.`);
225
+ }
226
+ throw new Error(`Config '${name}' not found. Available configs:\n ${available.join("\n ")}`);
227
+ }
228
+ return name;
229
+ }
230
+ const configs = listManifests();
231
+ if (configs.length === 0) {
232
+ throw new Error("No configs found. Run 'agent-army init' to create one.");
233
+ }
234
+ if (configs.length === 1) {
235
+ return configs[0];
236
+ }
237
+ throw new Error(`Multiple configs found. Specify one with --config:\n ${configs.join("\n ")}`);
238
+ }
239
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../lib/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Constants, preset definitions, aliases, and defaults
3
+ */
4
+ /** Available preset agents */
5
+ export declare const PRESETS: {
6
+ readonly pm: {
7
+ readonly name: "agent-pm";
8
+ readonly displayName: "Juno";
9
+ readonly role: "pm";
10
+ readonly preset: "pm";
11
+ readonly volumeSize: 30;
12
+ readonly description: "Break down tickets, research, plan and sequence work, track progress, unblock teams";
13
+ };
14
+ readonly eng: {
15
+ readonly name: "agent-eng";
16
+ readonly displayName: "Titus";
17
+ readonly role: "eng";
18
+ readonly preset: "eng";
19
+ readonly volumeSize: 50;
20
+ readonly description: "Lead engineering, coding, shipping";
21
+ };
22
+ readonly tester: {
23
+ readonly name: "agent-tester";
24
+ readonly displayName: "Scout";
25
+ readonly role: "tester";
26
+ readonly preset: "tester";
27
+ readonly volumeSize: 30;
28
+ readonly description: "Quality assurance, verification, bug hunting";
29
+ };
30
+ };
31
+ /** Map agent aliases to role keys */
32
+ export declare const AGENT_ALIASES: Record<string, string>;
33
+ /** Available cloud providers */
34
+ export declare const PROVIDERS: readonly [{
35
+ readonly value: "aws";
36
+ readonly label: "AWS";
37
+ readonly hint: "Amazon Web Services EC2 instances";
38
+ }, {
39
+ readonly value: "hetzner";
40
+ readonly label: "Hetzner";
41
+ readonly hint: "Hetzner Cloud servers (EU/US)";
42
+ }];
43
+ /** Common AWS regions for selection */
44
+ export declare const AWS_REGIONS: {
45
+ value: string;
46
+ label: string;
47
+ }[];
48
+ /** Hetzner Cloud locations */
49
+ export declare const HETZNER_LOCATIONS: {
50
+ value: string;
51
+ label: string;
52
+ }[];
53
+ /** Instance type options (AWS) */
54
+ export declare const INSTANCE_TYPES: {
55
+ value: string;
56
+ label: string;
57
+ }[];
58
+ /** Hetzner server types — EU locations (cx shared vCPU) */
59
+ export declare const HETZNER_SERVER_TYPES_EU: {
60
+ value: string;
61
+ label: string;
62
+ }[];
63
+ /** Hetzner server types — US locations (cpx shared vCPU, cx not available) */
64
+ export declare const HETZNER_SERVER_TYPES_US: {
65
+ value: string;
66
+ label: string;
67
+ }[];
68
+ /** US Hetzner locations (cx types not available) */
69
+ export declare const HETZNER_US_LOCATIONS: string[];
70
+ /** Get server type options for a Hetzner location */
71
+ export declare function hetznerServerTypes(location: string): {
72
+ value: string;
73
+ label: string;
74
+ }[];
75
+ /** Default SSH user for agent instances (Ubuntu 24.04 AMI default) */
76
+ export declare const SSH_USER = "ubuntu";
77
+ /** Estimated monthly cost per instance type (AWS) */
78
+ export declare const COST_ESTIMATES: Record<string, number>;
79
+ /** Estimated monthly cost per server type (Hetzner) */
80
+ export declare const HETZNER_COST_ESTIMATES: Record<string, number>;
81
+ /** Manifest filename */
82
+ export declare const MANIFEST_FILE = "agent-army.json";
83
+ /** Config directory under home (~/.agent-army/configs/) */
84
+ export declare const CONFIG_DIR = ".agent-army/configs";
85
+ /**
86
+ * Supported model providers with their API key prefixes and available models
87
+ */
88
+ export declare const MODEL_PROVIDERS: {
89
+ readonly anthropic: {
90
+ readonly name: "Anthropic";
91
+ readonly envVar: "ANTHROPIC_API_KEY";
92
+ readonly keyPrefix: "sk-ant-";
93
+ readonly models: readonly [{
94
+ readonly value: "anthropic/claude-opus-4-6";
95
+ readonly label: "Claude Opus 4.6 (Recommended)";
96
+ }, {
97
+ readonly value: "anthropic/claude-sonnet-4-5";
98
+ readonly label: "Claude Sonnet 4.5";
99
+ }, {
100
+ readonly value: "anthropic/claude-haiku-4-5";
101
+ readonly label: "Claude Haiku 4.5";
102
+ }];
103
+ };
104
+ };
105
+ /**
106
+ * Build the Tailscale hostname for an agent.
107
+ * Includes the stack name to avoid conflicts across deployments.
108
+ * Example: "dev-agent-pm", "prod-agent-eng"
109
+ */
110
+ export declare function tailscaleHostname(stackName: string, agentName: string): string;
111
+ /** Key instructions for onboarding prompts */
112
+ export declare const KEY_INSTRUCTIONS: {
113
+ readonly anthropicApiKey: {
114
+ readonly title: "Anthropic API Key";
115
+ readonly steps: readonly ["To get your Anthropic API key:", "1. Go to https://console.anthropic.com/account/keys", "2. Click \"Create Key\"", "3. Copy the key (starts with sk-ant-)"];
116
+ };
117
+ readonly tailscaleAuthKey: {
118
+ readonly title: "Tailscale Auth Key";
119
+ readonly steps: readonly ["To get your Tailscale auth key:", "1. Go to https://login.tailscale.com/admin/settings/keys", "2. Click \"Generate auth key\"", "3. Enable \"Reusable\" AND \"Ephemeral\" — ephemeral nodes auto-remove when offline", "4. Copy the key (starts with tskey-auth-)"];
120
+ };
121
+ readonly tailscaleApiKey: {
122
+ readonly title: "Tailscale API Key (optional)";
123
+ readonly steps: readonly ["For reliable cleanup of Tailscale devices during destroy:", "1. Go to https://login.tailscale.com/admin/settings/keys", "2. Under \"API access tokens\", click \"Generate access token\"", "3. Copy the key (starts with tskey-api-)", "4. This is optional but recommended for clean teardowns"];
124
+ };
125
+ readonly tailnetDnsName: {
126
+ readonly title: "Tailnet DNS Name";
127
+ readonly steps: readonly ["To find your Tailnet DNS name:", "1. Go to https://login.tailscale.com/admin/dns", "2. Look for your tailnet name at the top", "3. It looks like \"tailXXXXX.ts.net\" or a custom domain"];
128
+ };
129
+ readonly slackCredentials: {
130
+ readonly title: "Slack App Setup";
131
+ readonly steps: readonly ["Create a Slack app for each agent using the manifest shown below:", "1. Go to https://api.slack.com/apps → \"Create New App\" → \"From a manifest\"", "2. Select your workspace, paste the JSON manifest, and create the app", "3. Go to \"OAuth & Permissions\" — copy the Bot Token (xoxb-...)", "4. Under \"Basic Information\" → \"App-Level Tokens\", generate a token", " with the connections:write scope — copy it (xapp-...)"];
132
+ };
133
+ readonly linearApiKey: {
134
+ readonly title: "Linear API Key";
135
+ readonly steps: readonly ["Create a separate Linear account for each agent:", "1. Invite you+agentname@domain.com to your Linear workspace", " (plus-addressing forwards to your inbox — no new email needed)", " Follow the link in the invite email to create the account and join the org", "2. Go to Settings → Security & Access → Personal API keys → \"New API key\"", "3. Copy the key (starts with lin_api_)"];
136
+ };
137
+ readonly githubToken: {
138
+ readonly title: "GitHub Token";
139
+ readonly steps: readonly ["To get a GitHub personal access token for gh CLI:", "1. Go to https://github.com/settings/tokens?type=beta", "2. Click \"Generate new token\" → Fine-grained token", "3. Select repositories, set expiration, and permissions (e.g., repo, read:org)", "4. Copy the token (starts with github_pat_ or ghp_)"];
140
+ };
141
+ readonly hcloudToken: {
142
+ readonly title: "Hetzner Cloud API Token";
143
+ readonly steps: readonly ["To get your Hetzner Cloud API token:", "1. Go to https://console.hetzner.cloud/", "2. Select your project (or create one)", "3. Go to Security → API Tokens", "4. Click \"Generate API Token\" with Read & Write permissions", "5. Copy the token"];
144
+ };
145
+ };
146
+ /** Generate a Slack app manifest JSON for a given agent */
147
+ export declare function slackAppManifest(agentName: string): string;