@agenttower/cli 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/atc.js +0 -0
- package/dist/index.js +5 -3
- package/dist/init.js +76 -22
- package/package.json +1 -1
package/bin/atc.js
CHANGED
|
File without changes
|
package/dist/index.js
CHANGED
|
@@ -43,7 +43,7 @@ const child_process = __importStar(require("node:child_process"));
|
|
|
43
43
|
const client_1 = require("./client");
|
|
44
44
|
const init_1 = require("./init");
|
|
45
45
|
const human_1 = require("./human");
|
|
46
|
-
const VERSION = '0.3.
|
|
46
|
+
const VERSION = '0.3.1';
|
|
47
47
|
const COMMANDS = [
|
|
48
48
|
'init', 'checkin', 'brief', 'standing', 'squawk', 'claim', 'clear',
|
|
49
49
|
'note', 'notes', 'checkout', 'config',
|
|
@@ -58,7 +58,7 @@ function parseArgs(argv) {
|
|
|
58
58
|
if (a.startsWith('--')) {
|
|
59
59
|
const key = a.slice(2);
|
|
60
60
|
const next = argv[i + 1];
|
|
61
|
-
const boolFlags = ['pin', 'json', 'yes', 'manual', 'draft', 'activate', 'default', 'none'];
|
|
61
|
+
const boolFlags = ['pin', 'json', 'yes', 'manual', 'draft', 'activate', 'default', 'none', 'save-token'];
|
|
62
62
|
if (boolFlags.includes(key)) {
|
|
63
63
|
flags[key] = true;
|
|
64
64
|
}
|
|
@@ -124,7 +124,8 @@ function printHelp() {
|
|
|
124
124
|
` standing assign --project <p> <name1,name2,…> | --none\n` +
|
|
125
125
|
` standing propose <name> (--body "…" | --file f) (agent plane, uses ATC_TOKEN)\n\n` +
|
|
126
126
|
`Agent commands (require ATC_API + ATC_TOKEN):\n` +
|
|
127
|
-
` init [--token <freq-token>] [--yes] wire a project to Agent Tower\n` +
|
|
127
|
+
` init [--token <freq-token>] [--save-token] [--yes] wire a project to Agent Tower\n` +
|
|
128
|
+
` --save-token persists the token to .claude/settings.local.json (gitignored)\n` +
|
|
128
129
|
` checkin [--task "..."] [--as <callsign>] [--cli <name>]\n` +
|
|
129
130
|
` brief\n` +
|
|
130
131
|
` standing print the frequency's standing orders in full\n` +
|
|
@@ -203,6 +204,7 @@ async function main(argv) {
|
|
|
203
204
|
if (cmd === 'init') {
|
|
204
205
|
return (0, init_1.runInit)({
|
|
205
206
|
token: typeof flags.token === 'string' ? flags.token : undefined,
|
|
207
|
+
saveToken: flags['save-token'] === true,
|
|
206
208
|
yes: flags.yes === true,
|
|
207
209
|
json,
|
|
208
210
|
});
|
package/dist/init.js
CHANGED
|
@@ -41,8 +41,9 @@ exports.runInit = runInit;
|
|
|
41
41
|
* 1. Plan + confirm (unless --yes)
|
|
42
42
|
* 2. .mcp.json — create or merge agent-tower entry
|
|
43
43
|
* 3. AGENTS.md — append compliance block if absent
|
|
44
|
-
* 4. .gitignore — ensure .atc/
|
|
45
|
-
* 5.
|
|
44
|
+
* 4. .gitignore — ensure .atc/ (and, with --save-token, the local settings file)
|
|
45
|
+
* 5. --save-token: persist ATC_TOKEN into .claude/settings.local.json (gitignored)
|
|
46
|
+
* 6. Checkin + brief if a frequency token is available
|
|
46
47
|
*/
|
|
47
48
|
const fs = __importStar(require("node:fs"));
|
|
48
49
|
const path = __importStar(require("node:path"));
|
|
@@ -193,45 +194,82 @@ function applyAgentsMd(cwd) {
|
|
|
193
194
|
const content = existing ? existing + separator + COMPLIANCE_BLOCK : COMPLIANCE_BLOCK;
|
|
194
195
|
fs.writeFileSync(file, content);
|
|
195
196
|
}
|
|
196
|
-
function planGitignore(cwd) {
|
|
197
|
+
function planGitignore(cwd, needed) {
|
|
197
198
|
const file = path.join(cwd, '.gitignore');
|
|
198
199
|
const existing = readText(file);
|
|
199
200
|
if (existing) {
|
|
200
|
-
// Match exact line .atc/ (with or without trailing newline variations)
|
|
201
201
|
const lines = existing.split('\n').map((l) => l.trim());
|
|
202
|
-
|
|
202
|
+
const missing = needed.filter((n) => !lines.includes(n));
|
|
203
|
+
if (missing.length === 0)
|
|
203
204
|
return { action: 'unchanged' };
|
|
204
|
-
return { action: 'updated', preview:
|
|
205
|
+
return { action: 'updated', preview: missing.map((m) => `+ ${m}`).join(' ') };
|
|
205
206
|
}
|
|
206
|
-
return { action: 'created', preview:
|
|
207
|
+
return { action: 'created', preview: needed.map((m) => `+ ${m}`).join(' ') };
|
|
207
208
|
}
|
|
208
|
-
function applyGitignore(cwd) {
|
|
209
|
+
function applyGitignore(cwd, needed) {
|
|
209
210
|
const file = path.join(cwd, '.gitignore');
|
|
210
211
|
const existing = readText(file);
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
212
|
+
const lines = (existing ?? '').split('\n').map((l) => l.trim());
|
|
213
|
+
const missing = needed.filter((n) => !lines.includes(n));
|
|
214
|
+
if (existing && missing.length === 0)
|
|
215
|
+
return; // idempotent guard
|
|
216
|
+
const base = existing ? (existing.endsWith('\n') ? existing : existing + '\n') : '';
|
|
217
|
+
fs.writeFileSync(file, base + missing.join('\n') + '\n');
|
|
218
|
+
}
|
|
219
|
+
// ---------------------------------------------------------------------------
|
|
220
|
+
// --save-token: persist ATC_TOKEN into .claude/settings.local.json so this
|
|
221
|
+
// repo's Claude Code sessions get their own frequency without a global export.
|
|
222
|
+
// The file is local-only and we make sure it's gitignored above.
|
|
223
|
+
// ---------------------------------------------------------------------------
|
|
224
|
+
const SETTINGS_REL = path.join('.claude', 'settings.local.json');
|
|
225
|
+
function planSettings(cwd, token) {
|
|
226
|
+
const file = path.join(cwd, SETTINGS_REL);
|
|
227
|
+
const existing = readJson(file);
|
|
228
|
+
const env = existing?.env ?? {};
|
|
229
|
+
const masked = `ATC_TOKEN=atcf_…${token.slice(-4)}`;
|
|
230
|
+
if (env.ATC_TOKEN === token)
|
|
231
|
+
return { action: 'unchanged' };
|
|
232
|
+
return { action: existing ? 'updated' : 'created', preview: `+ env.${masked}` };
|
|
233
|
+
}
|
|
234
|
+
function applySettings(cwd, token, apiUrl) {
|
|
235
|
+
const file = path.join(cwd, SETTINGS_REL);
|
|
236
|
+
const existing = readJson(file) ?? {};
|
|
237
|
+
const env = (existing.env ?? {});
|
|
238
|
+
env.ATC_TOKEN = token;
|
|
239
|
+
if (apiUrl)
|
|
240
|
+
env.ATC_API = apiUrl; // only when targeting a non-default API
|
|
241
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
242
|
+
fs.writeFileSync(file, JSON.stringify({ ...existing, env }, null, 2) + '\n', { mode: 0o600 });
|
|
243
|
+
try {
|
|
244
|
+
fs.chmodSync(file, 0o600);
|
|
217
245
|
}
|
|
218
|
-
|
|
219
|
-
|
|
246
|
+
catch {
|
|
247
|
+
/* best-effort on platforms without chmod */
|
|
220
248
|
}
|
|
221
249
|
}
|
|
222
250
|
async function runInit(args) {
|
|
223
251
|
const cwd = process.cwd();
|
|
224
252
|
const json = args.json === true;
|
|
253
|
+
const token = args.token || process.env.ATC_TOKEN || '';
|
|
254
|
+
if (args.saveToken && !token) {
|
|
255
|
+
process.stderr.write("atc: --save-token needs a token — pass --token <atcf_…> or set ATC_TOKEN\n");
|
|
256
|
+
process.exit(1);
|
|
257
|
+
}
|
|
225
258
|
// -------------------------------------------------------------------------
|
|
226
259
|
// Step 1: Plan
|
|
227
260
|
// -------------------------------------------------------------------------
|
|
261
|
+
const gitignoreLines = ['.atc/', ...(args.saveToken ? ['.claude/settings.local.json'] : [])];
|
|
228
262
|
const mcpPlan = planMcp(cwd);
|
|
229
263
|
const agentsPlan = planAgentsMd(cwd);
|
|
230
|
-
const gitignorePlan = planGitignore(cwd);
|
|
264
|
+
const gitignorePlan = planGitignore(cwd, gitignoreLines);
|
|
265
|
+
const settingsPlan = args.saveToken ? planSettings(cwd, token) : null;
|
|
231
266
|
const steps = [
|
|
232
267
|
{ file: '.mcp.json', action: mcpPlan.action, preview: mcpPlan.preview },
|
|
233
268
|
{ file: 'AGENTS.md', action: agentsPlan.action, preview: agentsPlan.preview },
|
|
234
269
|
{ file: '.gitignore', action: gitignorePlan.action, preview: gitignorePlan.preview },
|
|
270
|
+
...(settingsPlan
|
|
271
|
+
? [{ file: SETTINGS_REL, action: settingsPlan.action, preview: settingsPlan.preview }]
|
|
272
|
+
: []),
|
|
235
273
|
];
|
|
236
274
|
if (!json) {
|
|
237
275
|
process.stdout.write('atc init — changes planned:\n\n');
|
|
@@ -318,7 +356,7 @@ async function runInit(args) {
|
|
|
318
356
|
// -------------------------------------------------------------------------
|
|
319
357
|
if (gitignorePlan.action !== 'unchanged') {
|
|
320
358
|
try {
|
|
321
|
-
applyGitignore(cwd);
|
|
359
|
+
applyGitignore(cwd, gitignoreLines);
|
|
322
360
|
if (!json)
|
|
323
361
|
process.stdout.write(` wrote .gitignore\n`);
|
|
324
362
|
}
|
|
@@ -328,9 +366,24 @@ async function runInit(args) {
|
|
|
328
366
|
}
|
|
329
367
|
}
|
|
330
368
|
// -------------------------------------------------------------------------
|
|
331
|
-
// Step 5:
|
|
369
|
+
// Step 5: --save-token → .claude/settings.local.json (gitignored above)
|
|
370
|
+
// -------------------------------------------------------------------------
|
|
371
|
+
if (settingsPlan && settingsPlan.action !== 'unchanged') {
|
|
372
|
+
try {
|
|
373
|
+
const cfgForApi = (0, client_1.loadConfig)();
|
|
374
|
+
const apiOverride = process.env.ATC_API ? cfgForApi.api : undefined;
|
|
375
|
+
applySettings(cwd, token, apiOverride);
|
|
376
|
+
if (!json)
|
|
377
|
+
process.stdout.write(` wrote ${SETTINGS_REL} (token saved for this repo's sessions)\n`);
|
|
378
|
+
}
|
|
379
|
+
catch (err) {
|
|
380
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
381
|
+
process.stderr.write(`atc: warning: could not write ${SETTINGS_REL}: ${msg}\n`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
// -------------------------------------------------------------------------
|
|
385
|
+
// Step 6: Checkin + brief (fail-open)
|
|
332
386
|
// -------------------------------------------------------------------------
|
|
333
|
-
const token = args.token || process.env.ATC_TOKEN || '';
|
|
334
387
|
let checkinResult = null;
|
|
335
388
|
if (token) {
|
|
336
389
|
const cfg = (0, client_1.loadConfig)();
|
|
@@ -349,8 +402,9 @@ async function runInit(args) {
|
|
|
349
402
|
if (r.ok) {
|
|
350
403
|
(0, client_1.saveSession)({ callsign: r.body.callsign, sessionToken: r.body.sessionToken, api: effectiveCfg.api });
|
|
351
404
|
const c = r.body.brief?.counts ?? {};
|
|
352
|
-
const
|
|
353
|
-
|
|
405
|
+
const so = r.body.brief?.standing;
|
|
406
|
+
const standing = so
|
|
407
|
+
? `\n⚑ standing orders present (${(so.orders ?? []).map((o) => o.name).join(', ') || 'assigned'}) — read them: atc standing`
|
|
354
408
|
: '';
|
|
355
409
|
checkinResult = r.body;
|
|
356
410
|
if (!json) {
|
package/package.json
CHANGED