aether-colony 5.1.0 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.aether/aether-utils.sh +157 -42
- package/.aether/agents/aether-ambassador.md +140 -0
- package/.aether/agents/aether-archaeologist.md +108 -0
- package/.aether/agents/aether-architect.md +133 -0
- package/.aether/agents/aether-auditor.md +144 -0
- package/.aether/agents/aether-builder.md +184 -0
- package/.aether/agents/aether-chaos.md +115 -0
- package/.aether/agents/aether-chronicler.md +122 -0
- package/.aether/agents/aether-gatekeeper.md +116 -0
- package/.aether/agents/aether-includer.md +117 -0
- package/.aether/agents/aether-keeper.md +177 -0
- package/.aether/agents/aether-measurer.md +128 -0
- package/.aether/agents/aether-oracle.md +137 -0
- package/.aether/agents/aether-probe.md +133 -0
- package/.aether/agents/aether-queen.md +286 -0
- package/.aether/agents/aether-route-setter.md +130 -0
- package/.aether/agents/aether-sage.md +106 -0
- package/.aether/agents/aether-scout.md +101 -0
- package/.aether/agents/aether-surveyor-disciplines.md +391 -0
- package/.aether/agents/aether-surveyor-nest.md +329 -0
- package/.aether/agents/aether-surveyor-pathogens.md +264 -0
- package/.aether/agents/aether-surveyor-provisions.md +334 -0
- package/.aether/agents/aether-tracker.md +137 -0
- package/.aether/agents/aether-watcher.md +174 -0
- package/.aether/agents/aether-weaver.md +130 -0
- package/.aether/commands/claude/archaeology.md +334 -0
- package/.aether/commands/claude/build.md +65 -0
- package/.aether/commands/claude/chaos.md +336 -0
- package/.aether/commands/claude/colonize.md +259 -0
- package/.aether/commands/claude/continue.md +60 -0
- package/.aether/commands/claude/council.md +507 -0
- package/.aether/commands/claude/data-clean.md +81 -0
- package/.aether/commands/claude/dream.md +268 -0
- package/.aether/commands/claude/entomb.md +498 -0
- package/.aether/commands/claude/export-signals.md +57 -0
- package/.aether/commands/claude/feedback.md +96 -0
- package/.aether/commands/claude/flag.md +151 -0
- package/.aether/commands/claude/flags.md +169 -0
- package/.aether/commands/claude/focus.md +76 -0
- package/.aether/commands/claude/help.md +154 -0
- package/.aether/commands/claude/history.md +140 -0
- package/.aether/commands/claude/import-signals.md +71 -0
- package/.aether/commands/claude/init.md +505 -0
- package/.aether/commands/claude/insert-phase.md +105 -0
- package/.aether/commands/claude/interpret.md +278 -0
- package/.aether/commands/claude/lay-eggs.md +210 -0
- package/.aether/commands/claude/maturity.md +113 -0
- package/.aether/commands/claude/memory-details.md +77 -0
- package/.aether/commands/claude/migrate-state.md +171 -0
- package/.aether/commands/claude/oracle.md +642 -0
- package/.aether/commands/claude/organize.md +232 -0
- package/.aether/commands/claude/patrol.md +620 -0
- package/.aether/commands/claude/pause-colony.md +233 -0
- package/.aether/commands/claude/phase.md +115 -0
- package/.aether/commands/claude/pheromones.md +156 -0
- package/.aether/commands/claude/plan.md +693 -0
- package/.aether/commands/claude/preferences.md +65 -0
- package/.aether/commands/claude/quick.md +100 -0
- package/.aether/commands/claude/redirect.md +76 -0
- package/.aether/commands/claude/resume-colony.md +197 -0
- package/.aether/commands/claude/resume.md +388 -0
- package/.aether/commands/claude/run.md +231 -0
- package/.aether/commands/claude/seal.md +774 -0
- package/.aether/commands/claude/skill-create.md +286 -0
- package/.aether/commands/claude/status.md +410 -0
- package/.aether/commands/claude/swarm.md +349 -0
- package/.aether/commands/claude/tunnels.md +426 -0
- package/.aether/commands/claude/update.md +132 -0
- package/.aether/commands/claude/verify-castes.md +143 -0
- package/.aether/commands/claude/watch.md +239 -0
- package/.aether/commands/colonize.yaml +4 -0
- package/.aether/commands/council.yaml +205 -0
- package/.aether/commands/init.yaml +46 -13
- package/.aether/commands/insert-phase.yaml +4 -0
- package/.aether/commands/opencode/archaeology.md +331 -0
- package/.aether/commands/opencode/build.md +1168 -0
- package/.aether/commands/opencode/chaos.md +329 -0
- package/.aether/commands/opencode/colonize.md +195 -0
- package/.aether/commands/opencode/continue.md +1436 -0
- package/.aether/commands/opencode/council.md +437 -0
- package/.aether/commands/opencode/data-clean.md +77 -0
- package/.aether/commands/opencode/dream.md +260 -0
- package/.aether/commands/opencode/entomb.md +377 -0
- package/.aether/commands/opencode/export-signals.md +54 -0
- package/.aether/commands/opencode/feedback.md +99 -0
- package/.aether/commands/opencode/flag.md +149 -0
- package/.aether/commands/opencode/flags.md +167 -0
- package/.aether/commands/opencode/focus.md +73 -0
- package/.aether/commands/opencode/help.md +157 -0
- package/.aether/commands/opencode/history.md +136 -0
- package/.aether/commands/opencode/import-signals.md +68 -0
- package/.aether/commands/opencode/init.md +518 -0
- package/.aether/commands/opencode/insert-phase.md +111 -0
- package/.aether/commands/opencode/interpret.md +272 -0
- package/.aether/commands/opencode/lay-eggs.md +213 -0
- package/.aether/commands/opencode/maturity.md +108 -0
- package/.aether/commands/opencode/memory-details.md +83 -0
- package/.aether/commands/opencode/migrate-state.md +165 -0
- package/.aether/commands/opencode/oracle.md +593 -0
- package/.aether/commands/opencode/organize.md +226 -0
- package/.aether/commands/opencode/patrol.md +626 -0
- package/.aether/commands/opencode/pause-colony.md +203 -0
- package/.aether/commands/opencode/phase.md +113 -0
- package/.aether/commands/opencode/pheromones.md +162 -0
- package/.aether/commands/opencode/plan.md +684 -0
- package/.aether/commands/opencode/preferences.md +71 -0
- package/.aether/commands/opencode/quick.md +91 -0
- package/.aether/commands/opencode/redirect.md +84 -0
- package/.aether/commands/opencode/resume-colony.md +190 -0
- package/.aether/commands/opencode/resume.md +394 -0
- package/.aether/commands/opencode/run.md +237 -0
- package/.aether/commands/opencode/seal.md +452 -0
- package/.aether/commands/opencode/skill-create.md +63 -0
- package/.aether/commands/opencode/status.md +307 -0
- package/.aether/commands/opencode/swarm.md +15 -0
- package/.aether/commands/opencode/tunnels.md +400 -0
- package/.aether/commands/opencode/update.md +127 -0
- package/.aether/commands/opencode/verify-castes.md +139 -0
- package/.aether/commands/opencode/watch.md +227 -0
- package/.aether/commands/plan.yaml +53 -2
- package/.aether/commands/quick.yaml +104 -0
- package/.aether/commands/resume-colony.yaml +6 -4
- package/.aether/commands/resume.yaml +9 -0
- package/.aether/commands/run.yaml +37 -1
- package/.aether/commands/seal.yaml +9 -0
- package/.aether/commands/status.yaml +45 -1
- package/.aether/docs/command-playbooks/build-full.md +3 -2
- package/.aether/docs/command-playbooks/build-prep.md +12 -4
- package/.aether/docs/command-playbooks/build-verify.md +51 -0
- package/.aether/docs/command-playbooks/continue-advance.md +115 -6
- package/.aether/docs/command-playbooks/continue-full.md +1 -0
- package/.aether/docs/command-playbooks/continue-verify.md +33 -0
- package/.aether/utils/clash-detect.sh +239 -0
- package/.aether/utils/council.sh +425 -0
- package/.aether/utils/error-handler.sh +3 -3
- package/.aether/utils/flag.sh +23 -12
- package/.aether/utils/hive.sh +2 -2
- package/.aether/utils/hooks/clash-pre-tool-use.js +99 -0
- package/.aether/utils/immune.sh +508 -0
- package/.aether/utils/learning.sh +2 -2
- package/.aether/utils/merge-driver-lockfile.sh +35 -0
- package/.aether/utils/midden.sh +712 -0
- package/.aether/utils/pheromone.sh +1376 -108
- package/.aether/utils/queen.sh +31 -21
- package/.aether/utils/session.sh +264 -0
- package/.aether/utils/spawn-tree.sh +7 -7
- package/.aether/utils/spawn.sh +2 -2
- package/.aether/utils/state-api.sh +216 -5
- package/.aether/utils/swarm.sh +1 -1
- package/.aether/utils/worktree.sh +189 -0
- package/.claude/commands/ant/colonize.md +2 -0
- package/.claude/commands/ant/council.md +205 -0
- package/.claude/commands/ant/init.md +53 -14
- package/.claude/commands/ant/insert-phase.md +4 -0
- package/.claude/commands/ant/plan.md +27 -1
- package/.claude/commands/ant/quick.md +100 -0
- package/.claude/commands/ant/resume-colony.md +3 -2
- package/.claude/commands/ant/resume.md +9 -0
- package/.claude/commands/ant/run.md +37 -1
- package/.claude/commands/ant/seal.md +9 -0
- package/.claude/commands/ant/status.md +45 -1
- package/.opencode/commands/ant/colonize.md +2 -0
- package/.opencode/commands/ant/council.md +143 -0
- package/.opencode/commands/ant/init.md +53 -13
- package/.opencode/commands/ant/insert-phase.md +4 -0
- package/.opencode/commands/ant/plan.md +26 -1
- package/.opencode/commands/ant/quick.md +91 -0
- package/.opencode/commands/ant/resume-colony.md +3 -2
- package/.opencode/commands/ant/resume.md +9 -0
- package/.opencode/commands/ant/run.md +37 -1
- package/.opencode/commands/ant/status.md +2 -0
- package/CHANGELOG.md +116 -0
- package/README.md +34 -8
- package/bin/cli.js +103 -61
- package/bin/lib/banner.js +14 -0
- package/bin/lib/init.js +8 -7
- package/bin/lib/interactive-setup.js +251 -0
- package/bin/npx-entry.js +21 -0
- package/bin/npx-install.js +9 -167
- package/bin/validate-package.sh +23 -0
- package/package.json +11 -3
- package/.aether/docs/plans/pheromone-display-plan.md +0 -257
- package/.aether/schemas/example-prompt-builder.xml +0 -234
- package/.aether/scripts/incident-test-add.sh +0 -47
- package/.aether/scripts/weekly-audit.sh +0 -79
package/bin/cli.js
CHANGED
|
@@ -1313,79 +1313,111 @@ program.on('option:quiet', () => {
|
|
|
1313
1313
|
globalQuiet = true;
|
|
1314
1314
|
});
|
|
1315
1315
|
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
log(` Commands: ${result.copied} files -> ${COMMANDS_DEST}`);
|
|
1330
|
-
if (result.removed.length > 0) {
|
|
1331
|
-
log(` Commands: removed ${result.removed.length} stale files`);
|
|
1332
|
-
for (const f of result.removed) log(` - ${f}`);
|
|
1333
|
-
}
|
|
1334
|
-
} else {
|
|
1335
|
-
console.error(' Commands source not found. Skipping.');
|
|
1336
|
-
}
|
|
1337
|
-
} else {
|
|
1338
|
-
const result = syncDirWithCleanup(COMMANDS_SRC, COMMANDS_DEST);
|
|
1316
|
+
/**
|
|
1317
|
+
* Perform a global installation of commands, agents, and hub setup.
|
|
1318
|
+
* Extracted so it can be called from the interactive installer.
|
|
1319
|
+
*/
|
|
1320
|
+
async function performGlobalInstall() {
|
|
1321
|
+
log(c.header(`aether-colony v${VERSION} — installing...`));
|
|
1322
|
+
|
|
1323
|
+
// Sync commands to ~/.claude/commands/ant/ (with orphan cleanup)
|
|
1324
|
+
if (!fs.existsSync(COMMANDS_SRC)) {
|
|
1325
|
+
// Running from source repo — commands are in .claude/commands/ant/
|
|
1326
|
+
const repoCommands = path.join(PACKAGE_DIR, '.claude', 'commands', 'ant');
|
|
1327
|
+
if (fs.existsSync(repoCommands)) {
|
|
1328
|
+
const result = syncDirWithCleanup(repoCommands, COMMANDS_DEST);
|
|
1339
1329
|
log(` Commands: ${result.copied} files -> ${COMMANDS_DEST}`);
|
|
1340
1330
|
if (result.removed.length > 0) {
|
|
1341
1331
|
log(` Commands: removed ${result.removed.length} stale files`);
|
|
1342
1332
|
for (const f of result.removed) log(` - ${f}`);
|
|
1343
1333
|
}
|
|
1334
|
+
} else {
|
|
1335
|
+
console.error(' Commands source not found. Skipping.');
|
|
1336
|
+
}
|
|
1337
|
+
} else {
|
|
1338
|
+
const result = syncDirWithCleanup(COMMANDS_SRC, COMMANDS_DEST);
|
|
1339
|
+
log(` Commands: ${result.copied} files -> ${COMMANDS_DEST}`);
|
|
1340
|
+
if (result.removed.length > 0) {
|
|
1341
|
+
log(` Commands: removed ${result.removed.length} stale files`);
|
|
1342
|
+
for (const f of result.removed) log(` - ${f}`);
|
|
1344
1343
|
}
|
|
1344
|
+
}
|
|
1345
1345
|
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
}
|
|
1346
|
+
// Sync agents to ~/.claude/agents/ant/ (with orphan cleanup)
|
|
1347
|
+
const repoAgents = path.join(PACKAGE_DIR, '.claude', 'agents', 'ant');
|
|
1348
|
+
if (fs.existsSync(repoAgents)) {
|
|
1349
|
+
const result = syncDirWithCleanup(repoAgents, AGENTS_DEST);
|
|
1350
|
+
log(` Agents (claude): ${result.copied} files -> ${AGENTS_DEST}`);
|
|
1351
|
+
if (result.removed.length > 0) {
|
|
1352
|
+
log(` Agents (claude): removed ${result.removed.length} stale files`);
|
|
1353
|
+
for (const f of result.removed) log(` - ${f}`);
|
|
1355
1354
|
}
|
|
1355
|
+
}
|
|
1356
1356
|
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
}
|
|
1357
|
+
// Sync OpenCode commands to ~/.opencode/command/ (with orphan cleanup)
|
|
1358
|
+
const opencodeCmdsSrc = path.join(PACKAGE_DIR, '.opencode', 'commands', 'ant');
|
|
1359
|
+
if (fs.existsSync(opencodeCmdsSrc)) {
|
|
1360
|
+
const result = syncDirWithCleanup(opencodeCmdsSrc, OPENCODE_COMMANDS_DEST);
|
|
1361
|
+
log(` Commands (opencode): ${result.copied} files -> ${OPENCODE_COMMANDS_DEST}`);
|
|
1362
|
+
if (result.removed.length > 0) {
|
|
1363
|
+
log(` Commands (opencode): removed ${result.removed.length} stale files`);
|
|
1364
|
+
for (const f of result.removed) log(` - ${f}`);
|
|
1366
1365
|
}
|
|
1366
|
+
}
|
|
1367
1367
|
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
}
|
|
1368
|
+
// Sync OpenCode agents to ~/.opencode/agent/ (with orphan cleanup)
|
|
1369
|
+
const opencodeAgentsSrc = path.join(PACKAGE_DIR, '.opencode', 'agents');
|
|
1370
|
+
if (fs.existsSync(opencodeAgentsSrc)) {
|
|
1371
|
+
const result = syncDirWithCleanup(opencodeAgentsSrc, OPENCODE_AGENTS_DEST);
|
|
1372
|
+
log(` Agents (opencode): ${result.copied} files -> ${OPENCODE_AGENTS_DEST}`);
|
|
1373
|
+
if (result.removed.length > 0) {
|
|
1374
|
+
log(` Agents (opencode): removed ${result.removed.length} stale files`);
|
|
1375
|
+
for (const f of result.removed) log(` - ${f}`);
|
|
1377
1376
|
}
|
|
1377
|
+
}
|
|
1378
1378
|
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1379
|
+
// Set up distribution hub at ~/.aether/
|
|
1380
|
+
log('');
|
|
1381
|
+
log(c.colony('Setting up distribution hub...'));
|
|
1382
|
+
setupHub();
|
|
1383
1383
|
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1384
|
+
log('');
|
|
1385
|
+
log(c.success('Install complete.'));
|
|
1386
|
+
log(` ${c.queen('Claude Code:')} run /ant to get started`);
|
|
1387
|
+
log(` ${c.colony('OpenCode:')} run /ant to get started`);
|
|
1388
|
+
log(` ${c.colony('Hub:')} ${c.dim('~/.aether/')} (for coordinated updates across repos)`);
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
// Install command
|
|
1392
|
+
program
|
|
1393
|
+
.command('install')
|
|
1394
|
+
.description('Install commands and agents to ~/.claude/ and set up distribution hub')
|
|
1395
|
+
.action(wrapCommand(performGlobalInstall));
|
|
1396
|
+
|
|
1397
|
+
// Setup command — set up Aether in the current directory from hub
|
|
1398
|
+
program
|
|
1399
|
+
.command('setup')
|
|
1400
|
+
.description('Set up Aether in the current directory (copies system files from hub)')
|
|
1401
|
+
.option('-f, --force', 'Overwrite existing setup')
|
|
1402
|
+
.action(wrapCommand(async (options) => {
|
|
1403
|
+
if (!fs.existsSync(HUB_VERSION)) {
|
|
1404
|
+
console.error('Aether hub not installed.');
|
|
1405
|
+
console.error('Run "npx aether-colony" or "aether install" to install the hub first.');
|
|
1406
|
+
process.exit(1);
|
|
1407
|
+
}
|
|
1408
|
+
const repoPath = process.cwd();
|
|
1409
|
+
log(c.header('Setting up Aether in this directory...'));
|
|
1410
|
+
const result = await initializeRepo(repoPath, { setupOnly: true });
|
|
1411
|
+
if (result.success) {
|
|
1412
|
+
log('');
|
|
1413
|
+
log(c.success('Aether is ready.'));
|
|
1414
|
+
log(` ${result.filesCopied} system files synced to .aether/`);
|
|
1415
|
+
log('');
|
|
1416
|
+
log(' Next steps:');
|
|
1417
|
+
log(' In Claude Code: /ant:init "your goal"');
|
|
1418
|
+
log(' Or terminal: aether init --goal "your goal"');
|
|
1419
|
+
log('');
|
|
1420
|
+
}
|
|
1389
1421
|
}));
|
|
1390
1422
|
|
|
1391
1423
|
// Update command
|
|
@@ -2172,10 +2204,20 @@ module.exports = {
|
|
|
2172
2204
|
syncDirWithCleanup,
|
|
2173
2205
|
syncSkillsToHub,
|
|
2174
2206
|
listFilesRecursive,
|
|
2175
|
-
cleanEmptyDirs
|
|
2207
|
+
cleanEmptyDirs,
|
|
2208
|
+
performGlobalInstall,
|
|
2209
|
+
run
|
|
2176
2210
|
};
|
|
2177
2211
|
|
|
2212
|
+
/**
|
|
2213
|
+
* Parse CLI arguments. Called automatically when run directly,
|
|
2214
|
+
* or explicitly by npx-entry.js when delegating a subcommand.
|
|
2215
|
+
*/
|
|
2216
|
+
function run() {
|
|
2217
|
+
program.parse();
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2178
2220
|
// Parse command line arguments only when run directly (not when required as a module)
|
|
2179
2221
|
if (require.main === module) {
|
|
2180
|
-
|
|
2222
|
+
run();
|
|
2181
2223
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared ASCII banner for Aether installers.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const BANNER = `
|
|
6
|
+
█████╗ ███████╗████████╗██╗ ██╗███████╗██████╗
|
|
7
|
+
██╔══██╗██╔════╝╚══██╔══╝██║ ██║██╔════╝██╔══██╗
|
|
8
|
+
███████║█████╗ ██║ ███████║█████╗ ██████╔╝
|
|
9
|
+
██╔══██║██╔══╝ ██║ ██╔══██║██╔══╝ ██╔══██╗
|
|
10
|
+
██║ ██║███████╗ ██║ ██║ ██║███████╗██║ ██║
|
|
11
|
+
╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
|
|
12
|
+
`;
|
|
13
|
+
|
|
14
|
+
module.exports = { BANNER };
|
package/bin/lib/init.js
CHANGED
|
@@ -321,7 +321,7 @@ function validateInitialization(repoPath) {
|
|
|
321
321
|
* @returns {object} Result: { success: boolean, stateFile: string|null, message: string }
|
|
322
322
|
*/
|
|
323
323
|
async function initializeRepo(repoPath, options = {}) {
|
|
324
|
-
const { goal, skipIfExists = false, quiet = false } = options;
|
|
324
|
+
const { goal, skipIfExists = false, quiet = false, setupOnly = false } = options;
|
|
325
325
|
|
|
326
326
|
// Check if already initialized
|
|
327
327
|
if (isInitialized(repoPath) && skipIfExists) {
|
|
@@ -411,12 +411,13 @@ locks/
|
|
|
411
411
|
`;
|
|
412
412
|
fs.writeFileSync(gitignorePath, gitignoreContent);
|
|
413
413
|
|
|
414
|
-
// Create initial state
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
414
|
+
// Create initial colony state (skipped in setupOnly mode)
|
|
415
|
+
let stateFile = null;
|
|
416
|
+
if (!setupOnly) {
|
|
417
|
+
const state = createInitialState(goal);
|
|
418
|
+
stateFile = path.join(repoPath, '.aether', 'data', 'COLONY_STATE.json');
|
|
419
|
+
fs.writeFileSync(stateFile, JSON.stringify(state, null, 2) + '\n');
|
|
420
|
+
}
|
|
420
421
|
|
|
421
422
|
// Get hub version
|
|
422
423
|
const hubVersion = readJsonSafe(HUB_VERSION);
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* interactive-setup.js — Interactive menu for npx aether-colony
|
|
3
|
+
*
|
|
4
|
+
* Displays an environment-aware menu with three options:
|
|
5
|
+
* [1] Full setup — Install globally + set up this repo
|
|
6
|
+
* [2] Global only — Install hub, commands, and agents (~/.aether/)
|
|
7
|
+
* [3] Repo only — Set up Aether in this directory (.aether/)
|
|
8
|
+
*
|
|
9
|
+
* Zero npm dependencies — uses built-in Node readline.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const os = require('os');
|
|
15
|
+
const readline = require('readline');
|
|
16
|
+
|
|
17
|
+
const { BANNER } = require('./banner');
|
|
18
|
+
|
|
19
|
+
const VERSION = require('../../package.json').version;
|
|
20
|
+
const HOME_DIR = os.homedir();
|
|
21
|
+
const HUB_VERSION_PATH = path.join(HOME_DIR, '.aether', 'version.json');
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Detect the current environment state.
|
|
25
|
+
* @returns {{ hubInstalled: boolean, hasAether: boolean, isProjectDir: boolean }}
|
|
26
|
+
*/
|
|
27
|
+
function detectEnvironment() {
|
|
28
|
+
const cwd = process.cwd();
|
|
29
|
+
|
|
30
|
+
const hubInstalled = fs.existsSync(HUB_VERSION_PATH);
|
|
31
|
+
|
|
32
|
+
const hasAether = fs.existsSync(path.join(cwd, '.aether', 'aether-utils.sh'));
|
|
33
|
+
|
|
34
|
+
const isProjectDir =
|
|
35
|
+
fs.existsSync(path.join(cwd, '.git')) ||
|
|
36
|
+
fs.existsSync(path.join(cwd, 'package.json')) ||
|
|
37
|
+
fs.existsSync(path.join(cwd, 'Makefile')) ||
|
|
38
|
+
fs.existsSync(path.join(cwd, 'pyproject.toml')) ||
|
|
39
|
+
fs.existsSync(path.join(cwd, 'Cargo.toml'));
|
|
40
|
+
|
|
41
|
+
return { hubInstalled, hasAether, isProjectDir };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Choose the context-sensitive default menu option.
|
|
46
|
+
* @param {{ hubInstalled: boolean, hasAether: boolean, isProjectDir: boolean }} env
|
|
47
|
+
* @returns {1|2|3}
|
|
48
|
+
*/
|
|
49
|
+
function getDefaultOption(env) {
|
|
50
|
+
if (!env.hubInstalled && env.isProjectDir) return 1;
|
|
51
|
+
if (!env.hubInstalled) return 2;
|
|
52
|
+
if (env.hubInstalled && !env.hasAether) return 3;
|
|
53
|
+
return 1;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Readline promise helper.
|
|
58
|
+
* @param {readline.Interface} rl
|
|
59
|
+
* @param {string} question
|
|
60
|
+
* @returns {Promise<string>}
|
|
61
|
+
*/
|
|
62
|
+
function prompt(rl, question) {
|
|
63
|
+
return new Promise(resolve => rl.question(question, resolve));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Log a message with 🐜 ant prefix.
|
|
68
|
+
* @param {string} msg
|
|
69
|
+
*/
|
|
70
|
+
function log(msg) {
|
|
71
|
+
console.log(`🐜 ${msg}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Main interactive setup entry point.
|
|
76
|
+
* Handles --global, --repo, --yes flags and non-TTY environments.
|
|
77
|
+
*/
|
|
78
|
+
async function interactiveSetup() {
|
|
79
|
+
const args = process.argv.slice(2);
|
|
80
|
+
const flagGlobal = args.includes('--global');
|
|
81
|
+
const flagRepo = args.includes('--repo');
|
|
82
|
+
const flagYes = args.includes('--yes');
|
|
83
|
+
|
|
84
|
+
// Import performGlobalInstall lazily to avoid circular require issues
|
|
85
|
+
const { performGlobalInstall } = require('../cli');
|
|
86
|
+
const { initializeRepo } = require('./init');
|
|
87
|
+
|
|
88
|
+
const env = detectEnvironment();
|
|
89
|
+
|
|
90
|
+
// Non-TTY: auto-pick default without prompting
|
|
91
|
+
if (!process.stdin.isTTY && !flagGlobal && !flagRepo && !flagYes) {
|
|
92
|
+
const choice = getDefaultOption(env);
|
|
93
|
+
await executeChoice(choice, env, performGlobalInstall, initializeRepo);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Flag shortcuts: skip menu entirely
|
|
98
|
+
if (flagGlobal) {
|
|
99
|
+
await executeChoice(2, env, performGlobalInstall, initializeRepo);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (flagRepo) {
|
|
103
|
+
await executeChoice(3, env, performGlobalInstall, initializeRepo);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Already fully set up: offer refresh
|
|
108
|
+
if (env.hubInstalled && env.hasAether) {
|
|
109
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
110
|
+
try {
|
|
111
|
+
console.log(BANNER);
|
|
112
|
+
console.log(` 🐜 Aether Colony v${VERSION}\n`);
|
|
113
|
+
log('Aether is already set up in this directory.');
|
|
114
|
+
|
|
115
|
+
let answer;
|
|
116
|
+
if (flagYes) {
|
|
117
|
+
answer = 'y';
|
|
118
|
+
} else {
|
|
119
|
+
answer = await prompt(rl, '\n Already set up. Refresh? (y/n) [n]: ');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (answer.trim().toLowerCase() === 'y') {
|
|
123
|
+
await executeChoice(1, env, performGlobalInstall, initializeRepo);
|
|
124
|
+
} else {
|
|
125
|
+
log('Nothing changed. Run /ant:init "your goal" to start a colony.');
|
|
126
|
+
}
|
|
127
|
+
} finally {
|
|
128
|
+
rl.close();
|
|
129
|
+
}
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Interactive menu
|
|
134
|
+
const defaultChoice = flagYes ? getDefaultOption(env) : null;
|
|
135
|
+
|
|
136
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
137
|
+
try {
|
|
138
|
+
console.log(BANNER);
|
|
139
|
+
console.log(` 🐜 Aether Colony v${VERSION}\n`);
|
|
140
|
+
|
|
141
|
+
const defaultOption = getDefaultOption(env);
|
|
142
|
+
const option3Disabled = !env.isProjectDir;
|
|
143
|
+
|
|
144
|
+
console.log(' 🐜 What would you like to do?\n');
|
|
145
|
+
console.log(` [1] Full setup — Install globally + set up this repo${defaultOption === 1 ? ' (recommended)' : ''}`);
|
|
146
|
+
console.log(` [2] Global only — Install hub, commands, and agents (~/.aether/)${defaultOption === 2 ? ' (recommended)' : ''}`);
|
|
147
|
+
if (option3Disabled) {
|
|
148
|
+
console.log(' [3] Repo only — (not available: no project found in current directory)');
|
|
149
|
+
} else {
|
|
150
|
+
console.log(` [3] Repo only — Set up Aether in this directory (.aether/)${defaultOption === 3 ? ' (recommended)' : ''}`);
|
|
151
|
+
}
|
|
152
|
+
console.log('');
|
|
153
|
+
|
|
154
|
+
let choice;
|
|
155
|
+
if (flagYes) {
|
|
156
|
+
choice = defaultOption;
|
|
157
|
+
console.log(` Auto-selected [${choice}] (--yes flag)\n`);
|
|
158
|
+
} else {
|
|
159
|
+
const raw = await prompt(rl, ` Enter choice [${defaultOption}]: `);
|
|
160
|
+
const trimmed = raw.trim();
|
|
161
|
+
choice = trimmed === '' ? defaultOption : parseInt(trimmed, 10);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (isNaN(choice) || choice < 1 || choice > 3) {
|
|
165
|
+
console.error('\n Invalid choice. Please run again and select 1, 2, or 3.\n');
|
|
166
|
+
process.exit(1);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (choice === 3 && option3Disabled) {
|
|
170
|
+
console.error('\n Option 3 is not available outside a project directory.\n');
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
await executeChoice(choice, env, performGlobalInstall, initializeRepo);
|
|
175
|
+
} finally {
|
|
176
|
+
rl.close();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Execute the selected menu option.
|
|
182
|
+
* @param {1|2|3} choice
|
|
183
|
+
* @param {{ hubInstalled: boolean, hasAether: boolean, isProjectDir: boolean }} env
|
|
184
|
+
* @param {Function} performGlobalInstall
|
|
185
|
+
* @param {Function} initializeRepo
|
|
186
|
+
*/
|
|
187
|
+
async function executeChoice(choice, env, performGlobalInstall, initializeRepo) {
|
|
188
|
+
const cwd = process.cwd();
|
|
189
|
+
|
|
190
|
+
if (choice === 1) {
|
|
191
|
+
log('Running full setup...');
|
|
192
|
+
await performGlobalInstall();
|
|
193
|
+
const result = await initializeRepo(cwd, { setupOnly: true });
|
|
194
|
+
printRepoSuccess(result);
|
|
195
|
+
} else if (choice === 2) {
|
|
196
|
+
log('Running global install...');
|
|
197
|
+
await performGlobalInstall();
|
|
198
|
+
printGlobalSuccess();
|
|
199
|
+
} else if (choice === 3) {
|
|
200
|
+
if (!env.hubInstalled) {
|
|
201
|
+
console.error('\n Aether hub not installed. Run without --repo to install globally first.\n');
|
|
202
|
+
process.exit(1);
|
|
203
|
+
}
|
|
204
|
+
log('Setting up this repository...');
|
|
205
|
+
const result = await initializeRepo(cwd, { setupOnly: true });
|
|
206
|
+
printRepoSuccess(result);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Print success message after global install.
|
|
212
|
+
*/
|
|
213
|
+
function printGlobalSuccess() {
|
|
214
|
+
console.log('');
|
|
215
|
+
console.log(' 🐜 Global install complete!');
|
|
216
|
+
console.log('');
|
|
217
|
+
console.log(' Next steps:');
|
|
218
|
+
console.log(' cd into a project, then run: npx aether-colony --repo');
|
|
219
|
+
console.log(' Or: aether init --goal "your goal"');
|
|
220
|
+
console.log(' 🐜🐜🐜')
|
|
221
|
+
console.log('');
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Print success message after repo setup.
|
|
226
|
+
* @param {{ success: boolean, filesCopied?: number }} result
|
|
227
|
+
*/
|
|
228
|
+
function printRepoSuccess(result) {
|
|
229
|
+
if (!result || !result.success) {
|
|
230
|
+
console.error('\n Repo setup failed. Check that the Aether hub is installed.\n');
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
console.log('');
|
|
234
|
+
console.log(' 🐜 Aether is ready!');
|
|
235
|
+
if (result.filesCopied != null) {
|
|
236
|
+
console.log(` ${result.filesCopied} system files synced to .aether/`);
|
|
237
|
+
}
|
|
238
|
+
console.log('');
|
|
239
|
+
console.log(' Next steps:');
|
|
240
|
+
console.log(' In Claude Code: /ant:init "your goal"');
|
|
241
|
+
console.log(' Or terminal: aether init --goal "your goal"');
|
|
242
|
+
console.log(' 🐜🐜🐜');
|
|
243
|
+
console.log('');
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
module.exports = {
|
|
247
|
+
interactiveSetup,
|
|
248
|
+
detectEnvironment,
|
|
249
|
+
getDefaultOption,
|
|
250
|
+
executeChoice,
|
|
251
|
+
};
|
package/bin/npx-entry.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* npx-entry.js — Entry point for `npx aether-colony`
|
|
4
|
+
*
|
|
5
|
+
* With no subcommand: launches interactive setup menu.
|
|
6
|
+
* With a subcommand (e.g. `npx aether-colony install`): delegates to full CLI.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const args = process.argv.slice(2);
|
|
10
|
+
|
|
11
|
+
// If a subcommand is provided (not a flag), delegate to the full CLI
|
|
12
|
+
if (args.length > 0 && !args[0].startsWith('-')) {
|
|
13
|
+
const { run } = require('./cli.js');
|
|
14
|
+
run();
|
|
15
|
+
} else {
|
|
16
|
+
const { interactiveSetup } = require('./lib/interactive-setup');
|
|
17
|
+
interactiveSetup().catch(err => {
|
|
18
|
+
console.error('Setup failed:', err.message);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
});
|
|
21
|
+
}
|