@phnx-labs/agents-cli 1.20.72 → 1.20.74
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/CHANGELOG.md +395 -0
- package/README.md +40 -4
- package/dist/bin/agents +0 -0
- package/dist/commands/activity.d.ts +12 -0
- package/dist/commands/activity.js +68 -0
- package/dist/commands/apply.d.ts +13 -0
- package/dist/commands/apply.js +28 -3
- package/dist/commands/browser.js +1 -1
- package/dist/commands/cloud.js +21 -11
- package/dist/commands/doctor.js +21 -5
- package/dist/commands/events.d.ts +11 -10
- package/dist/commands/events.js +30 -21
- package/dist/commands/exec.d.ts +34 -0
- package/dist/commands/exec.js +337 -39
- package/dist/commands/export.d.ts +11 -0
- package/dist/commands/export.js +215 -0
- package/dist/commands/feed.d.ts +13 -0
- package/dist/commands/feed.js +130 -29
- package/dist/commands/hq.d.ts +2 -0
- package/dist/commands/hq.js +58 -0
- package/dist/commands/import.js +51 -3
- package/dist/commands/lease.d.ts +19 -0
- package/dist/commands/lease.js +138 -11
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +123 -0
- package/dist/commands/logs.js +1 -1
- package/dist/commands/mine.d.ts +27 -0
- package/dist/commands/mine.js +207 -0
- package/dist/commands/monitors.js +79 -49
- package/dist/commands/plugins.js +1 -0
- package/dist/commands/profiles.js +158 -0
- package/dist/commands/repo.js +2 -60
- package/dist/commands/resources.d.ts +5 -0
- package/dist/commands/resources.js +95 -0
- package/dist/commands/routines.d.ts +2 -0
- package/dist/commands/routines.js +139 -37
- package/dist/commands/secrets.js +234 -47
- package/dist/commands/send.d.ts +15 -0
- package/dist/commands/send.js +62 -0
- package/dist/commands/sessions-tail.d.ts +1 -0
- package/dist/commands/sessions-tail.js +20 -9
- package/dist/commands/sessions.js +18 -3
- package/dist/commands/setup-mine.d.ts +18 -0
- package/dist/commands/setup-mine.js +106 -0
- package/dist/commands/setup-share.js +2 -2
- package/dist/commands/setup.js +9 -2
- package/dist/commands/share.d.ts +8 -1
- package/dist/commands/share.js +122 -37
- package/dist/commands/ssh.d.ts +9 -0
- package/dist/commands/ssh.js +196 -26
- package/dist/commands/sync.js +1 -1
- package/dist/commands/teams.js +11 -2
- package/dist/commands/versions.js +36 -5
- package/dist/commands/view.js +75 -27
- package/dist/index.js +80 -10
- package/dist/lib/activity.d.ts +124 -0
- package/dist/lib/activity.js +542 -0
- package/dist/lib/agents.d.ts +35 -0
- package/dist/lib/agents.js +79 -6
- package/dist/lib/artifact-actions.d.ts +1 -1
- package/dist/lib/artifact-actions.js +1 -1
- package/dist/lib/ask-classifier.d.ts +2 -1
- package/dist/lib/ask-classifier.js +3 -3
- package/dist/lib/auth-health.d.ts +32 -4
- package/dist/lib/auth-health.js +40 -1
- package/dist/lib/auto-pull.js +8 -1
- package/dist/lib/brand.d.ts +40 -0
- package/dist/lib/brand.js +122 -0
- package/dist/lib/browser/drivers/ssh.js +4 -7
- package/dist/lib/browser/service.js +6 -8
- package/dist/lib/channels/providers/index.d.ts +2 -0
- package/dist/lib/channels/providers/index.js +20 -0
- package/dist/lib/channels/providers/mailbox.d.ts +2 -0
- package/dist/lib/channels/providers/mailbox.js +26 -0
- package/dist/lib/channels/providers/openclaw-telegram.d.ts +2 -0
- package/dist/lib/channels/providers/openclaw-telegram.js +34 -0
- package/dist/lib/channels/providers/rush.d.ts +6 -0
- package/dist/lib/channels/providers/rush.js +55 -0
- package/dist/lib/channels/registry.d.ts +42 -0
- package/dist/lib/channels/registry.js +20 -0
- package/dist/lib/channels/resolve.d.ts +11 -0
- package/dist/lib/channels/resolve.js +12 -0
- package/dist/lib/cli-resources.d.ts +18 -0
- package/dist/lib/cli-resources.js +53 -4
- package/dist/lib/cloud/codex.js +6 -3
- package/dist/lib/cloud/factory.d.ts +1 -0
- package/dist/lib/cloud/factory.js +10 -4
- package/dist/lib/cloud/rush.d.ts +3 -1
- package/dist/lib/cloud/rush.js +6 -1
- package/dist/lib/cloud/types.d.ts +2 -0
- package/dist/lib/codex-home.d.ts +35 -0
- package/dist/lib/codex-home.js +136 -0
- package/dist/lib/config-transfer.d.ts +16 -0
- package/dist/lib/config-transfer.js +56 -0
- package/dist/lib/crabbox/cli.d.ts +44 -0
- package/dist/lib/crabbox/cli.js +120 -20
- package/dist/lib/crabbox/lease.d.ts +52 -1
- package/dist/lib/crabbox/lease.js +117 -16
- package/dist/lib/crabbox/progress.d.ts +31 -0
- package/dist/lib/crabbox/progress.js +76 -0
- package/dist/lib/crabbox/runtimes.d.ts +4 -0
- package/dist/lib/crabbox/runtimes.js +33 -8
- package/dist/lib/crabbox/setup-copy.d.ts +87 -0
- package/dist/lib/crabbox/setup-copy.js +127 -0
- package/dist/lib/daemon.d.ts +5 -5
- package/dist/lib/daemon.js +9 -9
- package/dist/lib/drive-sync.js +6 -3
- package/dist/lib/event-stream.d.ts +36 -0
- package/dist/lib/event-stream.js +68 -0
- package/dist/lib/events.d.ts +1 -1
- package/dist/lib/exec.d.ts +11 -0
- package/dist/lib/exec.js +23 -2
- package/dist/lib/export.d.ts +72 -0
- package/dist/lib/export.js +269 -0
- package/dist/lib/feed-policy.d.ts +1 -1
- package/dist/lib/feed-policy.js +14 -9
- package/dist/lib/feed-ranking.d.ts +32 -0
- package/dist/lib/feed-ranking.js +224 -0
- package/dist/lib/feed.d.ts +35 -2
- package/dist/lib/feed.js +66 -3
- package/dist/lib/fleet/auth-sync.d.ts +53 -0
- package/dist/lib/fleet/auth-sync.js +92 -0
- package/dist/lib/fleet/remote-login.d.ts +187 -0
- package/dist/lib/fleet/remote-login.js +556 -0
- package/dist/lib/format.d.ts +30 -3
- package/dist/lib/format.js +34 -5
- package/dist/lib/fs-atomic.d.ts +7 -2
- package/dist/lib/fs-atomic.js +8 -12
- package/dist/lib/git.d.ts +16 -0
- package/dist/lib/git.js +79 -2
- package/dist/lib/heal.js +11 -3
- package/dist/lib/hosts/progress.d.ts +28 -10
- package/dist/lib/hosts/progress.js +79 -22
- package/dist/lib/hosts/remote-cmd.js +4 -0
- package/dist/lib/hq/floor.d.ts +87 -0
- package/dist/lib/hq/floor.js +226 -0
- package/dist/lib/import.d.ts +23 -0
- package/dist/lib/import.js +74 -2
- package/dist/lib/isolation-boundary-report.d.ts +10 -0
- package/dist/lib/isolation-boundary-report.js +35 -0
- package/dist/lib/menubar/install-menubar.js +14 -20
- package/dist/lib/notify.d.ts +1 -0
- package/dist/lib/notify.js +3 -3
- package/dist/lib/open-url.d.ts +2 -0
- package/dist/lib/open-url.js +19 -0
- package/dist/lib/openclaw-keychain.d.ts +56 -0
- package/dist/lib/openclaw-keychain.js +236 -0
- package/dist/lib/overdue.js +10 -0
- package/dist/lib/permissions.d.ts +44 -1
- package/dist/lib/permissions.js +284 -7
- package/dist/lib/project-launch.d.ts +6 -12
- package/dist/lib/project-launch.js +13 -228
- package/dist/lib/project-resources.d.ts +7 -0
- package/dist/lib/project-resources.js +306 -0
- package/dist/lib/pty-client.d.ts +27 -0
- package/dist/lib/pty-client.js +136 -10
- package/dist/lib/refresh.js +14 -10
- package/dist/lib/resource-profiles.d.ts +26 -0
- package/dist/lib/resource-profiles.js +157 -0
- package/dist/lib/resources/permissions.js +7 -1
- package/dist/lib/resources/types.d.ts +1 -1
- package/dist/lib/resources.d.ts +1 -1
- package/dist/lib/resources.js +32 -3
- package/dist/lib/routines.d.ts +11 -0
- package/dist/lib/routines.js +56 -15
- package/dist/lib/runner.d.ts +1 -0
- package/dist/lib/runner.js +66 -5
- package/dist/lib/secrets/bundles.d.ts +16 -3
- package/dist/lib/secrets/bundles.js +206 -37
- package/dist/lib/secrets/icloud-import.d.ts +2 -2
- package/dist/lib/secrets/icloud-import.js +9 -6
- package/dist/lib/secrets/mcp.js +1 -1
- package/dist/lib/secrets/vault-age-helper.d.ts +1 -0
- package/dist/lib/secrets/vault-age-helper.js +34 -0
- package/dist/lib/secrets/vault.d.ts +49 -0
- package/dist/lib/secrets/vault.js +397 -0
- package/dist/lib/self-heal/checks/path.js +3 -1
- package/dist/lib/self-heal/checks/shadowing.js +10 -2
- package/dist/lib/self-heal/checks/shims.js +19 -11
- package/dist/lib/session/cloud.d.ts +2 -2
- package/dist/lib/session/cloud.js +2 -2
- package/dist/lib/session/db.d.ts +4 -0
- package/dist/lib/session/db.js +44 -7
- package/dist/lib/session/discover.d.ts +2 -0
- package/dist/lib/session/discover.js +114 -3
- package/dist/lib/session/stream-render.d.ts +3 -0
- package/dist/lib/session/stream-render.js +130 -0
- package/dist/lib/session/types.d.ts +6 -0
- package/dist/lib/share/analytics.d.ts +13 -0
- package/dist/lib/share/analytics.js +45 -0
- package/dist/lib/share/config.d.ts +19 -5
- package/dist/lib/share/config.js +44 -8
- package/dist/lib/share/provision.d.ts +58 -6
- package/dist/lib/share/provision.js +97 -22
- package/dist/lib/share/publish.d.ts +36 -13
- package/dist/lib/share/publish.js +55 -8
- package/dist/lib/share/worker-template.js +83 -17
- package/dist/lib/shims.d.ts +35 -0
- package/dist/lib/shims.js +159 -13
- package/dist/lib/ssh-exec.d.ts +14 -0
- package/dist/lib/ssh-exec.js +57 -0
- package/dist/lib/staleness/detectors/hooks.js +25 -1
- package/dist/lib/staleness/detectors/permissions.js +66 -0
- package/dist/lib/staleness/detectors/workflows.js +20 -0
- package/dist/lib/staleness/writers/hooks.js +58 -4
- package/dist/lib/staleness/writers/permissions.js +2 -2
- package/dist/lib/staleness/writers/skills.js +1 -1
- package/dist/lib/staleness/writers/sources.d.ts +10 -1
- package/dist/lib/staleness/writers/sources.js +68 -1
- package/dist/lib/star-nudge.d.ts +45 -0
- package/dist/lib/star-nudge.js +91 -0
- package/dist/lib/startup/command-registry.d.ts +7 -1
- package/dist/lib/startup/command-registry.js +19 -3
- package/dist/lib/state.d.ts +2 -0
- package/dist/lib/state.js +17 -4
- package/dist/lib/subagents-registry.d.ts +2 -0
- package/dist/lib/subagents-registry.js +3 -0
- package/dist/lib/teams/parsers.js +214 -6
- package/dist/lib/teams/supervisor.d.ts +7 -0
- package/dist/lib/teams/supervisor.js +2 -1
- package/dist/lib/template.d.ts +1 -1
- package/dist/lib/template.js +1 -1
- package/dist/lib/triggers/webhook.js +36 -3
- package/dist/lib/types.d.ts +84 -0
- package/dist/lib/uninstall.js +1 -45
- package/dist/lib/version.d.ts +40 -0
- package/dist/lib/version.js +94 -16
- package/dist/lib/versions.d.ts +24 -0
- package/dist/lib/versions.js +269 -78
- package/dist/lib/workflows.d.ts +2 -0
- package/dist/lib/workflows.js +88 -0
- package/package.json +2 -1
- package/dist/commands/daemon.d.ts +0 -10
- package/dist/commands/daemon.js +0 -121
|
@@ -24,6 +24,7 @@ export declare function tailFile(filePath: string, onLine: (line: string) => voi
|
|
|
24
24
|
*/
|
|
25
25
|
export declare function streamSessionTail(session: SessionMeta, options?: {
|
|
26
26
|
fromStart?: boolean;
|
|
27
|
+
raw?: boolean;
|
|
27
28
|
}): Promise<void>;
|
|
28
29
|
/** Attach the `tail` subcommand to an existing `sessions` command. */
|
|
29
30
|
export declare function registerSessionsTailCommand(sessionsCmd: Command): void;
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Implements `agents sessions tail` — position-tracked reader on the session
|
|
5
5
|
* JSONL, driven by an fs.watch on the parent directory. Claude and Codex
|
|
6
|
-
* only for v1 (both use append-only JSONL).
|
|
6
|
+
* only for v1 (both use append-only JSONL). Output is compact by default;
|
|
7
|
+
* --json keeps the raw JSONL stream.
|
|
7
8
|
*/
|
|
8
9
|
import * as fs from 'fs';
|
|
9
10
|
import * as fsp from 'fs/promises';
|
|
@@ -11,6 +12,7 @@ import * as path from 'path';
|
|
|
11
12
|
import chalk from 'chalk';
|
|
12
13
|
import { discoverSessions, resolveSessionById } from '../lib/session/discover.js';
|
|
13
14
|
import { setHelpSections } from '../lib/help.js';
|
|
15
|
+
import { makeStreamRenderer } from '../lib/session/stream-render.js';
|
|
14
16
|
const TAIL_SUPPORTED = ['claude', 'codex'];
|
|
15
17
|
/** Whether a session's transcript can be live-tailed (append-only JSONL agents). */
|
|
16
18
|
export function isTailable(agent) {
|
|
@@ -186,7 +188,7 @@ async function runTail(sessionId, options) {
|
|
|
186
188
|
}
|
|
187
189
|
session = resolved;
|
|
188
190
|
}
|
|
189
|
-
await streamSessionTail(session, { fromStart: options.fromStart });
|
|
191
|
+
await streamSessionTail(session, { fromStart: options.fromStart, raw: options.json });
|
|
190
192
|
}
|
|
191
193
|
/**
|
|
192
194
|
* Live-tail one already-resolved session's transcript to stdout until Ctrl+C.
|
|
@@ -194,6 +196,7 @@ async function runTail(sessionId, options) {
|
|
|
194
196
|
*/
|
|
195
197
|
export async function streamSessionTail(session, options = {}) {
|
|
196
198
|
const filePath = session.filePath.split('#')[0];
|
|
199
|
+
const render = options.raw ? undefined : makeStreamRenderer(session.agent, session.cwd);
|
|
197
200
|
if (process.stderr.isTTY) {
|
|
198
201
|
process.stderr.write(chalk.gray(`Tailing ${session.agent} ${session.shortId} — ${filePath}\n`) +
|
|
199
202
|
chalk.gray('Ctrl+C to stop.\n'));
|
|
@@ -204,7 +207,13 @@ export async function streamSessionTail(session, options = {}) {
|
|
|
204
207
|
process.on('SIGTERM', onSig);
|
|
205
208
|
try {
|
|
206
209
|
await tailFile(filePath, (line) => {
|
|
207
|
-
|
|
210
|
+
if (!render) {
|
|
211
|
+
process.stdout.write(line + '\n');
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const out = render(line);
|
|
215
|
+
if (out)
|
|
216
|
+
process.stdout.write(out + '\n');
|
|
208
217
|
}, ac, { fromStart: options.fromStart });
|
|
209
218
|
}
|
|
210
219
|
finally {
|
|
@@ -216,9 +225,10 @@ export async function streamSessionTail(session, options = {}) {
|
|
|
216
225
|
export function registerSessionsTailCommand(sessionsCmd) {
|
|
217
226
|
const tailCmd = sessionsCmd
|
|
218
227
|
.command('tail [sessionId]')
|
|
219
|
-
.description('Stream
|
|
228
|
+
.description('Stream compact live lines from a session file as events are written. Long-running: Ctrl+C to stop. Claude and Codex only.')
|
|
220
229
|
.option('--latest', 'Tail the most recent tailable session (claude or codex)')
|
|
221
|
-
.option('--from-start', 'Emit the full file first, then follow (default: start at EOF)')
|
|
230
|
+
.option('--from-start', 'Emit the full file first, then follow (default: start at EOF)')
|
|
231
|
+
.option('--json', 'Emit raw JSONL events instead of compact live lines');
|
|
222
232
|
setHelpSections(tailCmd, {
|
|
223
233
|
examples: `
|
|
224
234
|
# Follow the most recent active Claude or Codex session
|
|
@@ -230,15 +240,16 @@ export function registerSessionsTailCommand(sessionsCmd) {
|
|
|
230
240
|
# Replay from the beginning, then follow
|
|
231
241
|
agents sessions tail a1b2c3d4 --from-start
|
|
232
242
|
|
|
233
|
-
# Pipe through jq to extract just user messages
|
|
234
|
-
agents sessions tail --latest | jq 'select(.type == "user")'
|
|
243
|
+
# Pipe raw events through jq to extract just user messages
|
|
244
|
+
agents sessions tail --latest --json | jq 'select(.type == "user")'
|
|
235
245
|
`,
|
|
236
246
|
notes: `
|
|
237
247
|
- Only Claude and Codex sessions are tailable — they append JSONL one event per line.
|
|
248
|
+
- Live tail is compact by default; pass --json for the raw JSONL stream.
|
|
238
249
|
- Gemini, OpenCode, and OpenClaw use formats that rewrite the file or store state elsewhere.
|
|
239
250
|
`,
|
|
240
251
|
});
|
|
241
|
-
tailCmd.action(async (sessionId,
|
|
242
|
-
await runTail(sessionId,
|
|
252
|
+
tailCmd.action(async (sessionId, _options, command) => {
|
|
253
|
+
await runTail(sessionId, command.optsWithGlobals());
|
|
243
254
|
});
|
|
244
255
|
}
|
|
@@ -807,6 +807,8 @@ function canonicalSessionsCommand(query, options) {
|
|
|
807
807
|
a.push('--active');
|
|
808
808
|
if (options.teams)
|
|
809
809
|
a.push('--teams');
|
|
810
|
+
if (options.routine)
|
|
811
|
+
a.push('--routine');
|
|
810
812
|
if (options.agent)
|
|
811
813
|
a.push('-a', options.agent);
|
|
812
814
|
for (const h of options.host ?? [])
|
|
@@ -941,6 +943,7 @@ async function sessionsAction(query, options) {
|
|
|
941
943
|
// the browser's window so the flag is honored, not swallowed.
|
|
942
944
|
if (useInteractiveBrowser(options) &&
|
|
943
945
|
!query &&
|
|
946
|
+
!options.routine &&
|
|
944
947
|
!options.flat &&
|
|
945
948
|
!options.tree &&
|
|
946
949
|
!options.markdown &&
|
|
@@ -1038,6 +1041,7 @@ async function sessionsAction(query, options) {
|
|
|
1038
1041
|
since,
|
|
1039
1042
|
until: options.until,
|
|
1040
1043
|
sortBy,
|
|
1044
|
+
origin: options.routine ? 'routine' : undefined,
|
|
1041
1045
|
};
|
|
1042
1046
|
let sessions = await discoverSessions({
|
|
1043
1047
|
...scope,
|
|
@@ -1164,6 +1168,11 @@ function teamTag(session) {
|
|
|
1164
1168
|
const parts = [origin.handle, origin.mode].filter(Boolean).join(' · ');
|
|
1165
1169
|
return parts ? `[${parts}] ` : '[team] ';
|
|
1166
1170
|
}
|
|
1171
|
+
function originTag(session) {
|
|
1172
|
+
if (session.origin !== 'routine')
|
|
1173
|
+
return '';
|
|
1174
|
+
return `[routine${session.routineName ? ` · ${session.routineName}` : ''}] `;
|
|
1175
|
+
}
|
|
1167
1176
|
/** Adapt a SessionMeta's persisted signals to the badge renderer's shape. */
|
|
1168
1177
|
function metaSignals(s) {
|
|
1169
1178
|
return {
|
|
@@ -1182,7 +1191,7 @@ function flatSessionRow(session, live, showTicket = false, cols = {}) {
|
|
|
1182
1191
|
const agentColor = colorAgent(session.agent);
|
|
1183
1192
|
const when = formatRelativeTime(session.lastActivity ?? session.timestamp);
|
|
1184
1193
|
const project = session.project || '-';
|
|
1185
|
-
const tag = teamTag(session);
|
|
1194
|
+
const tag = originTag(session) || teamTag(session);
|
|
1186
1195
|
const label = session.label;
|
|
1187
1196
|
const { glyph, preview } = liveGlyphAndPreview(live);
|
|
1188
1197
|
// A running session's live preview says what the agent is doing now; a
|
|
@@ -1220,7 +1229,7 @@ function flatSessionRow(session, live, showTicket = false, cols = {}) {
|
|
|
1220
1229
|
function treeSessionRow(session, live) {
|
|
1221
1230
|
const agentColor = colorAgent(session.agent);
|
|
1222
1231
|
const when = formatRelativeTime(session.lastActivity ?? session.timestamp);
|
|
1223
|
-
const tag = teamTag(session);
|
|
1232
|
+
const tag = originTag(session) || teamTag(session);
|
|
1224
1233
|
const label = session.label;
|
|
1225
1234
|
const { glyph, preview } = liveGlyphAndPreview(live);
|
|
1226
1235
|
const topic = (preview || (tag ? `${tag}${session.topic ?? ''}` : session.topic)) || '-';
|
|
@@ -1592,7 +1601,7 @@ export function formatPickerLabel(s, query, cols = {}) {
|
|
|
1592
1601
|
const agentColor = colorAgent(s.agent);
|
|
1593
1602
|
const when = formatRelativeTime(s.lastActivity ?? s.timestamp);
|
|
1594
1603
|
const project = s.project || '-';
|
|
1595
|
-
const tag = teamTag(s);
|
|
1604
|
+
const tag = originTag(s) || teamTag(s);
|
|
1596
1605
|
const label = s.label;
|
|
1597
1606
|
const topic = tag ? `${tag}${s.topic ?? ''}` : s.topic;
|
|
1598
1607
|
const versionStr = s.version || '-';
|
|
@@ -2197,6 +2206,7 @@ export function registerSessionsCommands(program) {
|
|
|
2197
2206
|
.option('--opencode', 'Shorthand for --agent opencode')
|
|
2198
2207
|
.option('--all', 'Include sessions from every directory (not just current project)')
|
|
2199
2208
|
.option('--teams', 'Include team-spawned sessions (hidden by default)')
|
|
2209
|
+
.option('--routine', 'Show only sessions archived from routine runs')
|
|
2200
2210
|
.option('-p, --project <name>', 'Filter by project name (searches across all directories)')
|
|
2201
2211
|
.option('--since <time>', 'Only sessions newer than this (e.g., 2h, 7d, 4w, or ISO date)')
|
|
2202
2212
|
.option('--until <time>', 'Only sessions older than this (ISO timestamp)')
|
|
@@ -2246,6 +2256,10 @@ export function registerSessionsCommands(program) {
|
|
|
2246
2256
|
# Search across every directory, not just this project
|
|
2247
2257
|
agents sessions "topic" --all
|
|
2248
2258
|
|
|
2259
|
+
# Show routine-run sessions and open one by routine run id
|
|
2260
|
+
agents sessions --routine --all
|
|
2261
|
+
agents sessions 2026-07-21T10-30-00-000Z
|
|
2262
|
+
|
|
2249
2263
|
# Export for analysis
|
|
2250
2264
|
agents sessions --since 30d --limit 200 --json > sessions.json
|
|
2251
2265
|
|
|
@@ -2262,6 +2276,7 @@ export function registerSessionsCommands(program) {
|
|
|
2262
2276
|
- --first and --last are mutually exclusive.
|
|
2263
2277
|
- A filter flag (--include/--exclude/--first/--last) without --markdown/--json defaults to --markdown output.
|
|
2264
2278
|
- --cloud sources from Rush Cloud captured runs instead of local disk.
|
|
2279
|
+
- --routine shows only transcripts archived from routine run directories; routine rows also resolve by run id.
|
|
2265
2280
|
- Without --teams, team-spawned sessions are hidden by default.
|
|
2266
2281
|
`,
|
|
2267
2282
|
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `agents setup mine` — interactive wizard to white-label the CLI under your own
|
|
3
|
+
* name. Pick a name, choose which features to turn off, and get a personally-
|
|
4
|
+
* named binary (e.g. `jack`) that runs every agents verb as yours. Delegates the
|
|
5
|
+
* actual minting to `initBrand` (see mine.ts); the `agents mine` group manages
|
|
6
|
+
* brands afterward.
|
|
7
|
+
*
|
|
8
|
+
* Idempotent: re-running for an existing brand offers to re-mint it.
|
|
9
|
+
*/
|
|
10
|
+
import type { Command } from 'commander';
|
|
11
|
+
/**
|
|
12
|
+
* Interactive white-label setup. Returns true when a brand exists afterward,
|
|
13
|
+
* false if the user backed out. Never throws on cancel — the `agents setup` hub
|
|
14
|
+
* relies on that.
|
|
15
|
+
*/
|
|
16
|
+
export declare function runMineWizard(): Promise<boolean>;
|
|
17
|
+
/** Register `agents setup mine` under the parent `setup` command. */
|
|
18
|
+
export declare function registerSetupMineCommand(setupCmd: Command): void;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `agents setup mine` — interactive wizard to white-label the CLI under your own
|
|
3
|
+
* name. Pick a name, choose which features to turn off, and get a personally-
|
|
4
|
+
* named binary (e.g. `jack`) that runs every agents verb as yours. Delegates the
|
|
5
|
+
* actual minting to `initBrand` (see mine.ts); the `agents mine` group manages
|
|
6
|
+
* brands afterward.
|
|
7
|
+
*
|
|
8
|
+
* Idempotent: re-running for an existing brand offers to re-mint it.
|
|
9
|
+
*/
|
|
10
|
+
import chalk from 'chalk';
|
|
11
|
+
import { initBrand } from './mine.js';
|
|
12
|
+
import { validateBrandName, getBrandConfig } from '../lib/brand.js';
|
|
13
|
+
import { isShimsInPath } from '../lib/shims.js';
|
|
14
|
+
import { isInteractiveTerminal, isPromptCancelled } from './utils.js';
|
|
15
|
+
/**
|
|
16
|
+
* Optional/heavier top-level commands a brand commonly turns off. Kept short so
|
|
17
|
+
* the checkbox is scannable — anything can still be toggled later with
|
|
18
|
+
* `agents mine toggle <name> --disable <cmd>`.
|
|
19
|
+
*/
|
|
20
|
+
const DISABLEABLE_FEATURES = [
|
|
21
|
+
{ name: 'teams', hint: 'coordinate multiple agents on shared work' },
|
|
22
|
+
{ name: 'cloud', hint: 'dispatch agent tasks to the cloud' },
|
|
23
|
+
{ name: 'browser', hint: 'automate a browser' },
|
|
24
|
+
{ name: 'computer', hint: 'drive native desktop apps' },
|
|
25
|
+
{ name: 'secrets', hint: 'keychain-backed env bundles' },
|
|
26
|
+
{ name: 'routines', hint: 'run agents on a cron schedule' },
|
|
27
|
+
{ name: 'monitors', hint: 'event-triggered watchers' },
|
|
28
|
+
{ name: 'wallet', hint: 'payment cards' },
|
|
29
|
+
];
|
|
30
|
+
/**
|
|
31
|
+
* Interactive white-label setup. Returns true when a brand exists afterward,
|
|
32
|
+
* false if the user backed out. Never throws on cancel — the `agents setup` hub
|
|
33
|
+
* relies on that.
|
|
34
|
+
*/
|
|
35
|
+
export async function runMineWizard() {
|
|
36
|
+
if (!isInteractiveTerminal()) {
|
|
37
|
+
console.log(chalk.dim('Non-interactive shell. Create a brand directly, e.g.:\n') +
|
|
38
|
+
chalk.cyan(' agents mine init jack --disable teams cloud'));
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
const { input, checkbox, confirm } = await import('@inquirer/prompts');
|
|
42
|
+
console.log(chalk.bold('Make it yours — a personally-named CLI that IS agents-cli.\n'));
|
|
43
|
+
const name = (await input({
|
|
44
|
+
message: 'What should your CLI be called? (e.g. jack)',
|
|
45
|
+
validate: (v) => {
|
|
46
|
+
const err = validateBrandName(v.trim());
|
|
47
|
+
return err ?? true;
|
|
48
|
+
},
|
|
49
|
+
})).trim();
|
|
50
|
+
// Existing brand → offer to re-mint rather than error out.
|
|
51
|
+
let force = false;
|
|
52
|
+
if (getBrandConfig(name)) {
|
|
53
|
+
const again = await confirm({
|
|
54
|
+
message: `Brand "${name}" already exists. Re-mint it?`,
|
|
55
|
+
default: false,
|
|
56
|
+
});
|
|
57
|
+
if (!again) {
|
|
58
|
+
printNextSteps(name, !isShimsInPath());
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
force = true;
|
|
62
|
+
}
|
|
63
|
+
const disabled = await checkbox({
|
|
64
|
+
message: `Any features to turn OFF for ${name}? (space to toggle, enter to accept)`,
|
|
65
|
+
choices: DISABLEABLE_FEATURES.map((f) => ({
|
|
66
|
+
name: `${f.name} ${chalk.dim(f.hint)}`,
|
|
67
|
+
value: f.name,
|
|
68
|
+
})),
|
|
69
|
+
required: false,
|
|
70
|
+
});
|
|
71
|
+
const { pathWarning } = initBrand(name, { disabledCommands: disabled, force });
|
|
72
|
+
console.log(chalk.green(`\nMinted ${chalk.bold(name)} — your own agents CLI.`));
|
|
73
|
+
if (disabled.length > 0) {
|
|
74
|
+
console.log(chalk.dim(` turned off: ${disabled.join(', ')}`));
|
|
75
|
+
}
|
|
76
|
+
printNextSteps(name, pathWarning);
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
function printNextSteps(name, pathWarning) {
|
|
80
|
+
console.log(chalk.bold('\nTry it:'));
|
|
81
|
+
console.log(' ' + chalk.cyan(`${name} --help`) + chalk.dim(` # your CLI, your name`));
|
|
82
|
+
console.log(' ' + chalk.cyan(`${name} run claude "hello"`));
|
|
83
|
+
console.log(chalk.dim(` Manage it later: agents mine toggle ${name} --disable <cmd> · agents mine list`));
|
|
84
|
+
if (pathWarning) {
|
|
85
|
+
console.log(chalk.yellow(`\n note: the shims dir isn't on your PATH yet — run 'agents setup' or open a new shell.`));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/** Register `agents setup mine` under the parent `setup` command. */
|
|
89
|
+
export function registerSetupMineCommand(setupCmd) {
|
|
90
|
+
setupCmd
|
|
91
|
+
.command('mine')
|
|
92
|
+
.description('White-label the CLI — mint your own personally-named binary (e.g. `jack`).')
|
|
93
|
+
.action(async () => {
|
|
94
|
+
try {
|
|
95
|
+
await runMineWizard();
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
if (isPromptCancelled(err)) {
|
|
99
|
+
console.log(chalk.yellow('\nCancelled'));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
console.error(chalk.red(err.message));
|
|
103
|
+
process.exitCode = 1;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
@@ -18,7 +18,7 @@ import { isInteractiveTerminal, isPromptCancelled } from './utils.js';
|
|
|
18
18
|
export async function runShareWizard() {
|
|
19
19
|
if (!isInteractiveTerminal()) {
|
|
20
20
|
console.error(chalk.red('agents setup share needs an interactive terminal. ' +
|
|
21
|
-
'Non-interactively, use `agents share setup` (provision) or `agents share join
|
|
21
|
+
'Non-interactively, use `agents share setup` (provision) or `agents share join [url]`.'));
|
|
22
22
|
return false;
|
|
23
23
|
}
|
|
24
24
|
const existing = readShareConfig();
|
|
@@ -44,7 +44,7 @@ export async function runShareWizard() {
|
|
|
44
44
|
{
|
|
45
45
|
name: 'Join an existing endpoint (a teammate already provisioned one)',
|
|
46
46
|
value: 'join',
|
|
47
|
-
description: '
|
|
47
|
+
description: 'Use synced config when present, or paste the base URL + write token from the endpoint owner.',
|
|
48
48
|
},
|
|
49
49
|
],
|
|
50
50
|
});
|
package/dist/commands/setup.js
CHANGED
|
@@ -16,11 +16,12 @@ import { isGitRepo, cloneIntoExisting, pullRepo } from '../lib/git.js';
|
|
|
16
16
|
import { isPromptCancelled, isInteractiveTerminal } from './utils.js';
|
|
17
17
|
import { AGENTS, agentConfigDirName, getUnmanagedAgentInstalls, countSessionFiles, agentLabel } from '../lib/agents.js';
|
|
18
18
|
import { setGlobalDefault } from '../lib/versions.js';
|
|
19
|
-
import { ensureShimCurrent, switchHomeFileSymlinks, isShimsInPath, addShimsToPath, getPathSetupInstructions } from '../lib/shims.js';
|
|
19
|
+
import { ensureShimCurrent, switchHomeFileSymlinks, isShimsInPath, addShimsToPath, getPathSetupInstructions, assertIsolationBoundary } from '../lib/shims.js';
|
|
20
20
|
import { setHelpSections } from '../lib/help.js';
|
|
21
21
|
import { registerSetupBrowserCommand, runBrowserWizard } from './setup-browser.js';
|
|
22
22
|
import { registerSetupComputerCommand, runComputerWizard } from './setup-computer.js';
|
|
23
23
|
import { registerSetupShareCommand, runShareWizard } from './setup-share.js';
|
|
24
|
+
import { registerSetupMineCommand } from './setup-mine.js';
|
|
24
25
|
const HOME = os.homedir();
|
|
25
26
|
/**
|
|
26
27
|
* Import an existing unmanaged agent installation into agents-cli.
|
|
@@ -28,6 +29,11 @@ const HOME = os.homedir();
|
|
|
28
29
|
*/
|
|
29
30
|
async function importAgent(agentId, version) {
|
|
30
31
|
const agent = AGENTS[agentId];
|
|
32
|
+
// setup has its own hand-rolled adoption (rename + symlink inline, rather than
|
|
33
|
+
// calling switchConfigSymlink), so the primitive gates never see it. Check the
|
|
34
|
+
// boundary here, before the first mkdirSync — which would otherwise create the
|
|
35
|
+
// scaffolding this very check reads.
|
|
36
|
+
assertIsolationBoundary(agentId, 'adopt your existing install');
|
|
31
37
|
const configDir = agent.configDir;
|
|
32
38
|
const versionsDir = getVersionsDir();
|
|
33
39
|
const versionHome = path.join(versionsDir, agentId, version, 'home');
|
|
@@ -266,10 +272,11 @@ export function registerSetupCommand(program) {
|
|
|
266
272
|
.description('First-time setup. Clones a config repo and installs agent CLIs.')
|
|
267
273
|
.option('-f, --force', 'Re-run setup even if ~/.agents/.system/ already exists (use with caution)')
|
|
268
274
|
.option('--no-system-repo', 'Skip cloning the system repo (you must populate ~/.agents/.system/ yourself)');
|
|
269
|
-
// Capability subcommands: `agents setup browser|computer|share`.
|
|
275
|
+
// Capability subcommands: `agents setup browser|computer|share|mine`.
|
|
270
276
|
registerSetupBrowserCommand(setupCmd);
|
|
271
277
|
registerSetupComputerCommand(setupCmd);
|
|
272
278
|
registerSetupShareCommand(setupCmd);
|
|
279
|
+
registerSetupMineCommand(setupCmd);
|
|
273
280
|
setHelpSections(setupCmd, {
|
|
274
281
|
examples: `
|
|
275
282
|
# First-time setup (clones the system repo into ~/.agents/.system/)
|
package/dist/commands/share.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
|
+
import { type CloudflareRequester } from '../lib/share/provision.js';
|
|
3
|
+
import { type PublishResult } from '../lib/share/publish.js';
|
|
4
|
+
export declare function formatSharePublishResult(result: PublishResult, json?: boolean): string;
|
|
2
5
|
export declare function registerShareCommands(program: Command): void;
|
|
3
6
|
/** Provision a fresh R2 bucket + Worker on the user's Cloudflare and persist the
|
|
4
7
|
* endpoint config + write token. Shared by `agents share setup` and the unified
|
|
@@ -10,8 +13,12 @@ export declare function runShareProvision(opts: {
|
|
|
10
13
|
account?: string;
|
|
11
14
|
token?: string;
|
|
12
15
|
domain?: string;
|
|
16
|
+
analyticsToken?: string;
|
|
17
|
+
request?: CloudflareRequester;
|
|
13
18
|
}): Promise<void>;
|
|
14
19
|
/** Join an existing share endpoint (no provisioning): prompt for the endpoint
|
|
15
20
|
* details + write token and persist them. Shared by `agents share join` and the
|
|
16
21
|
* unified `agents setup share` wizard. */
|
|
17
|
-
export declare function runShareJoin(baseUrl
|
|
22
|
+
export declare function runShareJoin(baseUrl?: string, opts?: {
|
|
23
|
+
token?: string;
|
|
24
|
+
}): Promise<void>;
|
package/dist/commands/share.js
CHANGED
|
@@ -2,18 +2,33 @@
|
|
|
2
2
|
// Worker, and get a shareable link (~$0). See apps/cli/docs/share.md.
|
|
3
3
|
import { existsSync } from 'node:fs';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
|
-
import { DEFAULT_BUCKET_NAME, DEFAULT_CF_BUNDLE, DEFAULT_WORKER_NAME, generateWriteToken, readCloudflareCreds, readShareConfig, storeWriteToken, writeShareConfig, } from '../lib/share/config.js';
|
|
6
|
-
import { addCustomDomain, createBucket, deployWorker, enableWorkersDev, findZoneId, } from '../lib/share/provision.js';
|
|
5
|
+
import { DEFAULT_BUCKET_NAME, DEFAULT_CF_BUNDLE, DEFAULT_SHARE_DOMAIN, DEFAULT_WORKER_NAME, generateWriteToken, readCloudflareCreds, readShareConfig, readWriteTokenEnv, readWriteTokenFromBundle, storeWriteToken, writeShareConfig, } from '../lib/share/config.js';
|
|
6
|
+
import { addCustomDomain, configureBucketLifecycle, createBucket, deployWorker, enableWorkersDev, findZoneId, setWorkerSecret, } from '../lib/share/provision.js';
|
|
7
7
|
import { publishFile } from '../lib/share/publish.js';
|
|
8
8
|
import { renderWorkerScript } from '../lib/share/worker-template.js';
|
|
9
|
+
import { analyticsEnabled } from '../lib/share/analytics.js';
|
|
10
|
+
import { resolveGitHubUsername } from '../lib/git.js';
|
|
11
|
+
export function formatSharePublishResult(result, json = false) {
|
|
12
|
+
if (json)
|
|
13
|
+
return JSON.stringify(result, null, 2);
|
|
14
|
+
const lines = [chalk.green(result.url)];
|
|
15
|
+
if (result.coverUrl)
|
|
16
|
+
lines.push(chalk.dim(` cover ${result.coverUrl}`));
|
|
17
|
+
if (result.expiresAt)
|
|
18
|
+
lines.push(chalk.dim(` expires ${new Date(result.expiresAt).toLocaleString()}`));
|
|
19
|
+
return lines.join('\n');
|
|
20
|
+
}
|
|
9
21
|
export function registerShareCommands(program) {
|
|
10
22
|
const shareCmd = program
|
|
11
23
|
.command('share')
|
|
12
24
|
.description('Publish an HTML file to your own Cloudflare R2 and get a shareable link (~$0).')
|
|
13
25
|
.argument('[file]', 'file to publish (HTML or any static asset)')
|
|
14
|
-
.option('--slug <slug>', 'custom URL slug (default: <project>-<feature>-<hash>)')
|
|
26
|
+
.option('--slug <slug>', 'custom URL slug under your namespace (default: <project>-<feature>-<hash>)')
|
|
27
|
+
.option('--github-user <user>', 'GitHub username for the share namespace (default: resolved from gh/git config)')
|
|
15
28
|
.option('--expire <spec>', 'auto-expire, e.g. 30d, 12h, or 2026-08-01')
|
|
16
29
|
.option('--no-cover', 'skip the OG preview image (HTML pages get one by default)')
|
|
30
|
+
.option('--no-analytics', 'skip injecting the Cloudflare Web Analytics beacon')
|
|
31
|
+
.option('--json', 'emit machine-readable publish result for plan-render hooks and scripts')
|
|
17
32
|
.action(async (file, opts) => {
|
|
18
33
|
if (!file) {
|
|
19
34
|
shareCmd.help();
|
|
@@ -27,14 +42,12 @@ export function registerShareCommands(program) {
|
|
|
27
42
|
try {
|
|
28
43
|
const { url, expiresAt, coverUrl } = await publishFile(file, {
|
|
29
44
|
slug: opts.slug,
|
|
45
|
+
githubUser: opts.githubUser,
|
|
30
46
|
expire: opts.expire,
|
|
31
47
|
cover: opts.cover,
|
|
48
|
+
analytics: opts.analytics,
|
|
32
49
|
});
|
|
33
|
-
console.log(
|
|
34
|
-
if (coverUrl)
|
|
35
|
-
console.log(chalk.dim(` cover ${coverUrl}`));
|
|
36
|
-
if (expiresAt)
|
|
37
|
-
console.log(chalk.dim(` expires ${new Date(expiresAt).toLocaleString()}`));
|
|
50
|
+
console.log(formatSharePublishResult({ url, expiresAt, coverUrl }, Boolean(opts.json)));
|
|
38
51
|
}
|
|
39
52
|
catch (e) {
|
|
40
53
|
console.error(chalk.red(e.message));
|
|
@@ -49,7 +62,8 @@ export function registerShareCommands(program) {
|
|
|
49
62
|
.option('--bucket <name>', 'R2 bucket name', DEFAULT_BUCKET_NAME)
|
|
50
63
|
.option('--account <id>', 'Cloudflare account id (else read from the bundle / prompt)')
|
|
51
64
|
.option('--token <t>', 'Cloudflare API token (else read from the --bundle)')
|
|
52
|
-
.option('--domain <host>',
|
|
65
|
+
.option('--domain <host>', `custom domain to map (default: ${DEFAULT_SHARE_DOMAIN}; workers.dev if zone is not visible)`)
|
|
66
|
+
.option('--analytics-token <token>', 'Cloudflare Web Analytics token to inject into published HTML pages')
|
|
53
67
|
.action(async (opts) => {
|
|
54
68
|
try {
|
|
55
69
|
await runShareProvision(opts);
|
|
@@ -61,11 +75,12 @@ export function registerShareCommands(program) {
|
|
|
61
75
|
});
|
|
62
76
|
shareCmd
|
|
63
77
|
.command('join')
|
|
64
|
-
.description('Use an existing share endpoint (no provisioning)
|
|
65
|
-
.argument('
|
|
66
|
-
.
|
|
78
|
+
.description('Use an existing synced share endpoint and write token (no provisioning).')
|
|
79
|
+
.argument('[baseUrl]', 'base URL of the endpoint, e.g. https://share.agents-cli.sh')
|
|
80
|
+
.option('--token <token>', 'write token (else SHARE_WRITE_TOKEN env, existing bundle, or prompt)')
|
|
81
|
+
.action(async (baseUrl, opts) => {
|
|
67
82
|
try {
|
|
68
|
-
await runShareJoin(baseUrl);
|
|
83
|
+
await runShareJoin(baseUrl, opts);
|
|
69
84
|
}
|
|
70
85
|
catch (e) {
|
|
71
86
|
console.error(chalk.red(e.message));
|
|
@@ -74,8 +89,8 @@ export function registerShareCommands(program) {
|
|
|
74
89
|
});
|
|
75
90
|
shareCmd
|
|
76
91
|
.command('status')
|
|
77
|
-
.description('Show the configured share endpoint.')
|
|
78
|
-
.action(() => {
|
|
92
|
+
.description('Show the configured share endpoint and namespace.')
|
|
93
|
+
.action(async () => {
|
|
79
94
|
const cfg = readShareConfig();
|
|
80
95
|
if (!cfg) {
|
|
81
96
|
console.log(chalk.dim("Not configured. Run 'agents share setup' or 'agents share join'."));
|
|
@@ -83,6 +98,34 @@ export function registerShareCommands(program) {
|
|
|
83
98
|
}
|
|
84
99
|
console.log(`${chalk.bold('endpoint')} ${chalk.green(cfg.baseUrl)}`);
|
|
85
100
|
console.log(chalk.dim(`worker ${cfg.workerName} · bucket ${cfg.bucketName} · account ${cfg.accountId}`));
|
|
101
|
+
const user = await resolveGitHubUsername();
|
|
102
|
+
console.log(`${chalk.bold('namespace')} ${user ? chalk.cyan(`${cfg.baseUrl}/${user}`) : chalk.yellow('unknown — set gh auth or github.user')}`);
|
|
103
|
+
console.log(`${chalk.bold('analytics')} ${analyticsEnabled(cfg) ? chalk.green('enabled') : chalk.dim('not configured')}`);
|
|
104
|
+
});
|
|
105
|
+
shareCmd
|
|
106
|
+
.command('analytics')
|
|
107
|
+
.description('Show the Cloudflare Web Analytics status for this share endpoint.')
|
|
108
|
+
.action(async () => {
|
|
109
|
+
const cfg = readShareConfig();
|
|
110
|
+
if (!cfg) {
|
|
111
|
+
console.log(chalk.dim("Not configured. Run 'agents share setup' or 'agents share join'."));
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (!analyticsEnabled(cfg)) {
|
|
115
|
+
console.log(chalk.yellow('Cloudflare Web Analytics is not configured.'));
|
|
116
|
+
console.log(chalk.dim("Re-run setup with --analytics-token <token> or add analyticsToken to agents.yaml share:."));
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const dashboard = cfg.domain
|
|
120
|
+
? `https://dash.cloudflare.com/${cfg.accountId}/web-analytics/${cfg.domain}`
|
|
121
|
+
: `https://dash.cloudflare.com/${cfg.accountId}/web-analytics`;
|
|
122
|
+
console.log(`${chalk.bold('analytics')} ${chalk.green('enabled')}`);
|
|
123
|
+
console.log(`${chalk.bold('token')} ${chalk.dim(cfg.analyticsToken.slice(0, 8) + '…')}`);
|
|
124
|
+
console.log(`${chalk.bold('dashboard')} ${chalk.cyan(dashboard)}`);
|
|
125
|
+
const user = await resolveGitHubUsername();
|
|
126
|
+
if (user) {
|
|
127
|
+
console.log(chalk.dim(`Per-page breakdown is available under Paths in the dashboard (filter by /${user}/).`));
|
|
128
|
+
}
|
|
86
129
|
});
|
|
87
130
|
}
|
|
88
131
|
/** Provision a fresh R2 bucket + Worker on the user's Cloudflare and persist the
|
|
@@ -101,29 +144,35 @@ export async function runShareProvision(opts) {
|
|
|
101
144
|
const workerName = opts.worker;
|
|
102
145
|
const bucketName = opts.bucket;
|
|
103
146
|
const token = generateWriteToken();
|
|
147
|
+
const requestedDomain = cleanHostname(opts.domain) ?? DEFAULT_SHARE_DOMAIN;
|
|
104
148
|
const spin = ora('Provisioning on Cloudflare…').start();
|
|
105
149
|
try {
|
|
106
|
-
|
|
150
|
+
const provisionOpts = opts.request ? { request: opts.request } : {};
|
|
151
|
+
await createBucket(apiToken, accountId, bucketName, provisionOpts);
|
|
107
152
|
spin.text = `R2 bucket '${bucketName}' ready`;
|
|
108
|
-
await
|
|
153
|
+
await configureBucketLifecycle(apiToken, accountId, bucketName, provisionOpts);
|
|
154
|
+
spin.text = `R2 bucket '${bucketName}' lifecycle ready`;
|
|
155
|
+
await deployWorker(apiToken, accountId, workerName, renderWorkerScript(), bucketName, provisionOpts);
|
|
109
156
|
spin.text = `Worker '${workerName}' deployed`;
|
|
110
|
-
|
|
157
|
+
await setWorkerSecret(apiToken, accountId, workerName, token, provisionOpts);
|
|
158
|
+
spin.text = `Worker '${workerName}' write token set`;
|
|
159
|
+
const subdomain = await enableWorkersDev(apiToken, accountId, workerName, provisionOpts);
|
|
111
160
|
let baseUrl = `https://${workerName}.${subdomain}.workers.dev`;
|
|
112
161
|
let domain;
|
|
113
|
-
if (
|
|
114
|
-
spin.text = `Mapping ${
|
|
115
|
-
const zoneId = await findZoneId(apiToken,
|
|
162
|
+
if (requestedDomain) {
|
|
163
|
+
spin.text = `Mapping ${requestedDomain}…`;
|
|
164
|
+
const zoneId = await findZoneId(apiToken, requestedDomain, provisionOpts);
|
|
116
165
|
if (zoneId) {
|
|
117
|
-
await addCustomDomain(apiToken, accountId, workerName, zoneId,
|
|
118
|
-
baseUrl = `https://${
|
|
119
|
-
domain =
|
|
166
|
+
await addCustomDomain(apiToken, accountId, workerName, zoneId, requestedDomain, provisionOpts);
|
|
167
|
+
baseUrl = `https://${requestedDomain}`;
|
|
168
|
+
domain = requestedDomain;
|
|
120
169
|
}
|
|
121
170
|
else {
|
|
122
|
-
spin.warn(`Zone for ${
|
|
171
|
+
spin.warn(`Zone for ${requestedDomain} not visible to this token — staying on workers.dev`);
|
|
123
172
|
}
|
|
124
173
|
}
|
|
125
174
|
spin.succeed('Provisioned');
|
|
126
|
-
const cfg = { baseUrl, accountId, workerName, bucketName, domain };
|
|
175
|
+
const cfg = { baseUrl, accountId, workerName, bucketName, domain, analyticsToken: opts.analyticsToken };
|
|
127
176
|
writeShareConfig(cfg);
|
|
128
177
|
storeWriteToken(token);
|
|
129
178
|
console.log(chalk.green(`\nShare endpoint ready → ${chalk.bold(baseUrl)}`));
|
|
@@ -135,22 +184,58 @@ export async function runShareProvision(opts) {
|
|
|
135
184
|
throw e;
|
|
136
185
|
}
|
|
137
186
|
}
|
|
187
|
+
function cleanHostname(domain) {
|
|
188
|
+
const raw = domain?.trim().replace(/\/+$/, '');
|
|
189
|
+
if (!raw)
|
|
190
|
+
return undefined;
|
|
191
|
+
try {
|
|
192
|
+
const url = new URL(raw.includes('://') ? raw : `https://${raw}`);
|
|
193
|
+
return url.hostname || undefined;
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
return raw;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
138
199
|
/** Join an existing share endpoint (no provisioning): prompt for the endpoint
|
|
139
200
|
* details + write token and persist them. Shared by `agents share join` and the
|
|
140
201
|
* unified `agents setup share` wizard. */
|
|
141
|
-
export async function runShareJoin(baseUrl) {
|
|
202
|
+
export async function runShareJoin(baseUrl, opts = {}) {
|
|
142
203
|
const { password, input } = await import('@inquirer/prompts');
|
|
143
|
-
const
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
204
|
+
const existing = readShareConfig();
|
|
205
|
+
const clean = baseUrl?.replace(/\/+$/, '');
|
|
206
|
+
if (!clean && !existing) {
|
|
207
|
+
throw new Error("No synced share endpoint found. Pull config first with 'agents repo pull', or pass the endpoint URL: agents share join <baseUrl>.");
|
|
208
|
+
}
|
|
209
|
+
let cfg;
|
|
210
|
+
if (existing && (!clean || clean === existing.baseUrl)) {
|
|
211
|
+
cfg = existing;
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
if (!clean)
|
|
215
|
+
throw new Error('Share endpoint URL is required.');
|
|
216
|
+
const workerName = await input({ message: 'Worker name', default: DEFAULT_WORKER_NAME });
|
|
217
|
+
const bucketName = await input({ message: 'Bucket name', default: DEFAULT_BUCKET_NAME });
|
|
218
|
+
const accountId = await input({ message: 'Cloudflare account id' });
|
|
219
|
+
const domain = clean.startsWith('https://') && !clean.includes('.workers.dev')
|
|
220
|
+
? clean.replace(/^https:\/\//, '')
|
|
221
|
+
: undefined;
|
|
222
|
+
cfg = { baseUrl: clean, accountId, workerName, bucketName, domain };
|
|
223
|
+
}
|
|
224
|
+
let token = opts.token?.trim() || readWriteTokenEnv() || '';
|
|
225
|
+
if (!token) {
|
|
226
|
+
try {
|
|
227
|
+
token = readWriteTokenFromBundle();
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
token = '';
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (!token) {
|
|
234
|
+
token = await password({ message: 'Write token (from the endpoint owner)', mask: true });
|
|
235
|
+
}
|
|
148
236
|
if (!token)
|
|
149
237
|
throw new Error('A write token is required to join.');
|
|
150
|
-
|
|
151
|
-
? clean.replace(/^https:\/\//, '')
|
|
152
|
-
: undefined;
|
|
153
|
-
writeShareConfig({ baseUrl: clean, accountId, workerName, bucketName, domain });
|
|
238
|
+
writeShareConfig(cfg);
|
|
154
239
|
storeWriteToken(token);
|
|
155
|
-
console.log(chalk.green(`Joined ${chalk.bold(
|
|
240
|
+
console.log(chalk.green(`Joined ${chalk.bold(cfg.baseUrl)} — publish with `) + chalk.cyan('agents share <file>'));
|
|
156
241
|
}
|
package/dist/commands/ssh.d.ts
CHANGED
|
@@ -10,5 +10,14 @@
|
|
|
10
10
|
* rsync / `agents sessions --host` resolve the same logical names.
|
|
11
11
|
*/
|
|
12
12
|
import type { Command } from 'commander';
|
|
13
|
+
import { type CrabboxBox } from '../lib/crabbox/cli.js';
|
|
14
|
+
/**
|
|
15
|
+
* Live "Leased boxes" section for `agents devices` (F4, RUSH-1923), computed
|
|
16
|
+
* from `crabboxList()` — these are ephemeral crabbox leases, NEVER written into
|
|
17
|
+
* the device registry. Returns [] when crabbox is unavailable / has no creds /
|
|
18
|
+
* reports no boxes, so the section is simply omitted. `nowSecs` is injected so
|
|
19
|
+
* the row formatting is deterministic in tests.
|
|
20
|
+
*/
|
|
21
|
+
export declare function renderLeasedBoxesSection(boxes: CrabboxBox[], nowSecs: number): string[];
|
|
13
22
|
/** Register both `agents ssh` and `agents devices`. */
|
|
14
23
|
export declare function registerSshCommands(program: Command): void;
|