@agentage/cli 0.37.2 → 0.38.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/README.md +53 -83
- package/dist/cli.js +5 -8
- package/dist/commands/auth/setup.d.ts +6 -16
- package/dist/commands/auth/setup.js +9 -139
- package/dist/commands/status/status.d.ts +4 -3
- package/dist/commands/status/status.js +4 -27
- package/dist/commands/update/update.d.ts +3 -10
- package/dist/commands/update/update.js +24 -41
- package/dist/core/flag.d.ts +1 -0
- package/dist/core/flag.js +1 -0
- package/dist/lib/auth/api.d.ts +3 -2
- package/dist/lib/auth/api.js +50 -56
- package/dist/lib/auth/env-match.js +1 -0
- package/dist/lib/auth/introspect.js +10 -11
- package/dist/lib/auth/oauth.d.ts +2 -0
- package/dist/lib/auth/oauth.js +30 -28
- package/dist/lib/auth/sign-in.d.ts +20 -0
- package/dist/lib/auth/sign-in.js +95 -0
- package/dist/lib/fs/config.d.ts +1 -0
- package/dist/lib/fs/config.js +14 -21
- package/dist/lib/fs/file-lock.d.ts +7 -2
- package/dist/lib/fs/file-lock.js +64 -74
- package/dist/lib/fs/json-file.d.ts +3 -0
- package/dist/lib/fs/json-file.js +43 -0
- package/dist/lib/net/fetch.d.ts +10 -0
- package/dist/lib/net/fetch.js +13 -0
- package/dist/lib/net/http.js +51 -23
- package/dist/lib/net/origins.d.ts +0 -2
- package/dist/lib/net/origins.js +1 -5
- package/dist/lib/net/user-agent.d.ts +1 -6
- package/dist/lib/net/user-agent.js +3 -4
- package/dist/lib/npm/npm-cli.d.ts +17 -0
- package/dist/lib/npm/npm-cli.js +77 -0
- package/dist/lib/status/status-info.d.ts +0 -18
- package/dist/lib/status/status-info.js +2 -42
- package/dist/lib/update/update-cache.d.ts +1 -0
- package/dist/lib/update/update-cache.js +7 -11
- package/dist/lib/update/update-check.js +1 -4
- package/dist/plugin.d.ts +1 -0
- package/dist/plugin.js +2 -0
- package/dist/program.d.ts +18 -1
- package/dist/program.js +75 -44
- package/package.json +17 -12
- package/dist/commands/daemon/daemon-cmd.d.ts +0 -2
- package/dist/commands/daemon/daemon-cmd.js +0 -107
- package/dist/commands/memory/memory-verbs.d.ts +0 -21
- package/dist/commands/memory/memory-verbs.js +0 -98
- package/dist/commands/memory/memory.d.ts +0 -2
- package/dist/commands/memory/memory.js +0 -54
- package/dist/commands/vault/vault-sync.d.ts +0 -13
- package/dist/commands/vault/vault-sync.js +0 -90
- package/dist/commands/vault/vault.d.ts +0 -22
- package/dist/commands/vault/vault.js +0 -129
- package/dist/daemon/actions.d.ts +0 -5
- package/dist/daemon/actions.js +0 -22
- package/dist/daemon/client-provider.d.ts +0 -2
- package/dist/daemon/client-provider.js +0 -16
- package/dist/daemon/entry.d.ts +0 -8
- package/dist/daemon/entry.js +0 -113
- package/dist/daemon/guards.d.ts +0 -3
- package/dist/daemon/guards.js +0 -13
- package/dist/daemon/lifecycle.d.ts +0 -17
- package/dist/daemon/lifecycle.js +0 -151
- package/dist/daemon/mcp-http.d.ts +0 -3
- package/dist/daemon/mcp-http.js +0 -34
- package/dist/daemon/server.d.ts +0 -23
- package/dist/daemon/server.js +0 -135
- package/dist/daemon-entry.d.ts +0 -1
- package/dist/daemon-entry.js +0 -9
- package/dist/lib/auth/provision.d.ts +0 -14
- package/dist/lib/auth/provision.js +0 -49
- package/dist/lib/daemon/daemon-client.d.ts +0 -37
- package/dist/lib/daemon/daemon-client.js +0 -136
- package/dist/lib/daemon/daemon-pref.d.ts +0 -2
- package/dist/lib/daemon/daemon-pref.js +0 -10
- package/dist/lib/memory/memory-client.d.ts +0 -30
- package/dist/lib/memory/memory-client.js +0 -98
- package/dist/lib/status/format.d.ts +0 -1
- package/dist/lib/status/format.js +0 -12
- package/dist/lib/status/vaults-format.d.ts +0 -2
- package/dist/lib/status/vaults-format.js +0 -49
- package/dist/lib/status/vaults-status.d.ts +0 -12
- package/dist/lib/status/vaults-status.js +0 -54
- package/dist/lib/update/update-lock.d.ts +0 -2
- package/dist/lib/update/update-lock.js +0 -109
- package/dist/lib/vault/vault-registry.d.ts +0 -12
- package/dist/lib/vault/vault-registry.js +0 -81
- package/dist/lib/vault/vaults.d.ts +0 -10
- package/dist/lib/vault/vaults.js +0 -66
- package/dist/lib/vault/vaults.schema.d.ts +0 -2
- package/dist/lib/vault/vaults.schema.js +0 -10
- package/dist/mcp/local-server.d.ts +0 -4
- package/dist/mcp/local-server.js +0 -26
- package/dist/observability.d.ts +0 -4
- package/dist/observability.js +0 -35
- package/dist/sync/discover/watcher.d.ts +0 -26
- package/dist/sync/discover/watcher.js +0 -159
- package/dist/sync/git/conflict.d.ts +0 -1
- package/dist/sync/git/conflict.js +0 -16
- package/dist/sync/git/cycle.d.ts +0 -18
- package/dist/sync/git/cycle.js +0 -158
- package/dist/sync/git/git-exec.d.ts +0 -22
- package/dist/sync/git/git-exec.js +0 -56
- package/dist/sync/git/manager.d.ts +0 -28
- package/dist/sync/git/manager.js +0 -114
- package/dist/sync/git/planner.d.ts +0 -15
- package/dist/sync/git/planner.js +0 -46
- package/dist/sync/git/remote-url.d.ts +0 -3
- package/dist/sync/git/remote-url.js +0 -30
package/README.md
CHANGED
|
@@ -1,122 +1,92 @@
|
|
|
1
1
|
# @agentage/cli
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[](https://badge.fury.io/js/%40agentage%2Fcli)
|
|
3
|
+

|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
Connect this machine to your [agentage](https://agentage.io) account from the terminal. One
|
|
6
|
+
command signs you in through your browser, and from then on the machine is known to your account.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
CLI gives them a single shared one. It lives on your disk as ordinary markdown files
|
|
10
|
-
you can open, edit, and back up like any other folder. Your AI tools read and write
|
|
11
|
-
those same files, so they all remember the same things. Connect a free account and your
|
|
12
|
-
memory follows you to every device - and nothing is locked in, because the files are
|
|
13
|
-
always just markdown you can export.
|
|
8
|
+
## What is this?
|
|
14
9
|
|
|
15
|
-
|
|
10
|
+
agentage gives your AI tools a shared, account-backed home. Every machine you use needs to be
|
|
11
|
+
connected to that account once: this package does that connection. It keeps your sign-in on
|
|
12
|
+
the machine (OAuth 2.1 with PKCE, nothing typed into the terminal), tells you whether the
|
|
13
|
+
machine is connected, and keeps itself up to date.
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
It is intentionally **small**: sign-in, status and update. Everything else arrives as plugins
|
|
16
|
+
that the CLI installs for you.
|
|
18
17
|
|
|
19
|
-
##
|
|
18
|
+
## Get started
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
**1. Install it.** Needs Node.js 22 or newer.
|
|
20
|
+
Needs Node.js 22 or newer.
|
|
24
21
|
|
|
25
22
|
```bash
|
|
26
23
|
npm install -g @agentage/cli
|
|
24
|
+
agentage setup
|
|
27
25
|
```
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
No sign-in needed.
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
agentage vault add notes --local
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
**3. Connect your AI.** This example wires up Claude Code over MCP, the open protocol AI
|
|
37
|
-
tools use to call tools. Any AI tool that speaks MCP connects the same way.
|
|
27
|
+
`setup` opens your browser, you sign in, and the session is stored in `~/.agentage`. Then:
|
|
38
28
|
|
|
39
29
|
```bash
|
|
40
|
-
|
|
30
|
+
agentage status
|
|
41
31
|
```
|
|
42
32
|
|
|
43
|
-
|
|
44
|
-
folder as a markdown file you own.
|
|
45
|
-
|
|
46
|
-
## What your AI can do
|
|
47
|
-
|
|
48
|
-
Once connected, your AI can:
|
|
49
|
-
|
|
50
|
-
- Remember things you tell it, saved as a note.
|
|
51
|
-
- Find them again later by keyword.
|
|
52
|
-
- Read back a specific note in full.
|
|
53
|
-
- Update a note in place, or add to it.
|
|
54
|
-
- Browse the folders your notes are organized into.
|
|
55
|
-
- Remove a note it no longer needs (deletes are recoverable).
|
|
56
|
-
|
|
57
|
-
You can do all of this from the terminal too - run `agentage memory --help` to see how.
|
|
58
|
-
|
|
59
|
-
## Sync across devices
|
|
60
|
-
|
|
61
|
-
Want the same memory on your laptop, desktop, and phone? Connect a free account:
|
|
33
|
+
### On a server or in CI (no browser)
|
|
62
34
|
|
|
63
35
|
```bash
|
|
64
|
-
agentage setup
|
|
36
|
+
agentage setup --no-browser # prints the sign-in URL to open elsewhere
|
|
37
|
+
AGENTAGE_TOKEN=aga_... agentage status # or use a personal access token
|
|
65
38
|
```
|
|
66
39
|
|
|
67
|
-
|
|
68
|
-
terminal. After that, sync runs quietly in the background and the same memory follows
|
|
69
|
-
you everywhere. Your files always stay yours: they remain plain markdown on your disk,
|
|
70
|
-
and you can export them any time.
|
|
71
|
-
|
|
72
|
-
Prefer to host it yourself? You can point a memory at your own git remote instead with
|
|
73
|
-
`agentage vault add <name> --git <remote>` - see [`docs/reference.md`](docs/reference.md)
|
|
74
|
-
for details.
|
|
40
|
+
### Then
|
|
75
41
|
|
|
76
|
-
|
|
42
|
+
- `agentage status --json` in scripts to check the machine is connected.
|
|
43
|
+
- `agentage update` whenever a newer version is published; `status` tells you when.
|
|
77
44
|
|
|
78
|
-
|
|
79
|
-
personal access token. Mint one in the dashboard under **Settings -> API tokens**
|
|
80
|
-
(scopes `memory:read` / `memory:write`), then set it in the environment:
|
|
45
|
+
## Commands
|
|
81
46
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
agentage status
|
|
85
|
-
|
|
47
|
+
| Command | What it does |
|
|
48
|
+
| ----------------------------- | ----------------------------------------------------------------------- |
|
|
49
|
+
| `agentage setup` | Sign in through your browser, then show status |
|
|
50
|
+
| `agentage setup --no-browser` | Print the sign-in URL instead of opening a browser |
|
|
51
|
+
| `agentage setup --reauth` | Force a fresh sign-in |
|
|
52
|
+
| `agentage setup --disconnect` | Sign out and remove local credentials |
|
|
53
|
+
| `agentage status` | Version, update, target, sign-in state, endpoint (`--json` for scripts) |
|
|
54
|
+
| `agentage update` | Install the latest published version (`--check` only reports) |
|
|
86
55
|
|
|
87
|
-
|
|
88
|
-
too. Account-channel provisioning still needs an interactive `agentage setup` session.
|
|
56
|
+
Flags, exit codes and token auth are in [`docs/reference.md`](docs/reference.md).
|
|
89
57
|
|
|
90
|
-
##
|
|
58
|
+
## How it works
|
|
91
59
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
60
|
+
This is the **terminal client for an agentage account**. `setup` registers a one-off OAuth
|
|
61
|
+
client, opens the authorization page in your browser and waits on a localhost callback; the
|
|
62
|
+
tokens land in `~/.agentage/auth.json` with owner-only permissions and are refreshed
|
|
63
|
+
automatically. `status` validates the session against the account's introspection endpoint
|
|
64
|
+
and reports version, update, target host and connectivity. Nothing runs in the background and
|
|
65
|
+
nothing is installed beyond this package.
|
|
96
66
|
|
|
97
|
-
##
|
|
67
|
+
## Configuration
|
|
98
68
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
69
|
+
| Env | Default | Purpose |
|
|
70
|
+
| --------------------- | ------------- | -------------------------------------------------- |
|
|
71
|
+
| `AGENTAGE_SITE_FQDN` | `agentage.io` | Target host |
|
|
72
|
+
| `AGENTAGE_CONFIG_DIR` | `~/.agentage` | Config and credentials directory |
|
|
73
|
+
| `AGENTAGE_TOKEN` | - | Personal access token for CI and headless machines |
|
|
74
|
+
| `NO_COLOR` | - | Disable colored output |
|
|
104
75
|
|
|
105
|
-
##
|
|
76
|
+
## Develop
|
|
106
77
|
|
|
107
78
|
```bash
|
|
108
79
|
npm ci
|
|
109
|
-
npm run verify
|
|
80
|
+
npm run verify
|
|
81
|
+
npm run build && npm run test:e2e -- --grep @offline
|
|
110
82
|
```
|
|
111
83
|
|
|
112
|
-
|
|
113
|
-
account. See [`docs/reference.md`](docs/reference.md) for more.
|
|
84
|
+
## Release
|
|
114
85
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
```
|
|
86
|
+
Releases publish to npm via GitHub Actions when a `chore(release): X.Y.Z` commit that touches
|
|
87
|
+
`package.json` lands on `master` (the squash-merge subject of a release PR). The workflow skips
|
|
88
|
+
any version already on npm.
|
|
119
89
|
|
|
120
90
|
## License
|
|
121
91
|
|
|
122
|
-
MIT
|
|
92
|
+
MIT - see [LICENSE](./LICENSE).
|
package/dist/cli.js
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// The bin is a loader, nothing else. @agentage/observability instruments node:http, fetch and MCP
|
|
3
|
-
// tool registration through module hooks, and a hook only sees a module imported after it is
|
|
4
|
-
// registered - so the bootstrap runs first and the program is imported dynamically behind it.
|
|
5
2
|
// Dependency-free guard so the message survives even if deps fail to parse on old Node.
|
|
6
3
|
const nodeMajor = Number(process.versions.node.split('.')[0]);
|
|
7
4
|
if (nodeMajor < 22) {
|
|
8
5
|
process.stderr.write(`agentage requires Node.js >= 22 (you have v${process.versions.node})\n`);
|
|
9
|
-
process.
|
|
6
|
+
process.exitCode = 1;
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
const { run } = await import('./program.js');
|
|
10
|
+
process.exitCode = await run();
|
|
10
11
|
}
|
|
11
|
-
const { CLI_SERVICE, startObservability } = await import('./observability.js');
|
|
12
|
-
await startObservability(CLI_SERVICE);
|
|
13
|
-
const { run } = await import('./program.js');
|
|
14
|
-
await run();
|
|
15
12
|
export {};
|
|
@@ -1,22 +1,12 @@
|
|
|
1
1
|
import { type Command } from 'commander';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import { introspectToken } from '../../lib/auth/api.js';
|
|
5
|
-
import { exchangeCode, registerClient, revokeToken } from '../../lib/auth/oauth.js';
|
|
6
|
-
export interface SetupOptions {
|
|
2
|
+
import { type SignInOptions, type SignInResult } from '../../lib/auth/sign-in.js';
|
|
3
|
+
export interface SetupOptions extends SignInOptions {
|
|
7
4
|
disconnect?: boolean;
|
|
8
|
-
reauth?: boolean;
|
|
9
|
-
browser?: boolean;
|
|
10
5
|
}
|
|
11
6
|
export interface SetupDeps {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
revoke: typeof revokeToken;
|
|
15
|
-
startServer: typeof startCallbackServer;
|
|
16
|
-
openBrowser: (url: string) => Promise<void>;
|
|
7
|
+
ensureSignedIn: (opts: SignInOptions) => Promise<SignInResult>;
|
|
8
|
+
signOut: () => Promise<void>;
|
|
17
9
|
printStatus: () => Promise<void>;
|
|
18
|
-
ensureDaemon: typeof ensureDaemon;
|
|
19
|
-
introspect: typeof introspectToken;
|
|
20
10
|
}
|
|
21
|
-
export declare const runSetup: (opts: SetupOptions, deps
|
|
22
|
-
export declare const registerSetup: (program: Command) => void;
|
|
11
|
+
export declare const runSetup: (opts: SetupOptions, deps: SetupDeps) => Promise<void>;
|
|
12
|
+
export declare const registerSetup: (program: Command, action: (opts: SetupOptions) => Promise<void>) => void;
|
|
@@ -1,147 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import { buildAuthorizeUrl, exchangeCode, pkcePair, randomState, registerClient, revokeToken, } from '../../lib/auth/oauth.js';
|
|
9
|
-
import { links, siteFqdn } from '../../lib/net/origins.js';
|
|
10
|
-
import { ensureVaultsConfig } from '../../lib/vault/vaults.js';
|
|
11
|
-
import { runStatus } from '../status/status.js';
|
|
12
|
-
const defaultDeps = {
|
|
13
|
-
register: registerClient,
|
|
14
|
-
exchange: exchangeCode,
|
|
15
|
-
revoke: revokeToken,
|
|
16
|
-
startServer: startCallbackServer,
|
|
17
|
-
openBrowser: async (url) => {
|
|
18
|
-
const { default: open } = await import('open');
|
|
19
|
-
await open(url);
|
|
20
|
-
},
|
|
21
|
-
printStatus: () => runStatus({}),
|
|
22
|
-
ensureDaemon,
|
|
23
|
-
introspect: introspectToken,
|
|
1
|
+
import {} from 'commander';
|
|
2
|
+
import {} from '../../lib/auth/sign-in.js';
|
|
3
|
+
export const runSetup = async (opts, deps) => {
|
|
4
|
+
if (opts.disconnect)
|
|
5
|
+
return deps.signOut();
|
|
6
|
+
await deps.ensureSignedIn({ reauth: opts.reauth, browser: opts.browser });
|
|
7
|
+
await deps.printStatus();
|
|
24
8
|
};
|
|
25
|
-
const
|
|
26
|
-
siteFqdn: fqdn,
|
|
27
|
-
clientId,
|
|
28
|
-
tokens: {
|
|
29
|
-
accessToken: tokens.access_token,
|
|
30
|
-
refreshToken: tokens.refresh_token,
|
|
31
|
-
expiresAt: tokens.expires_in ? Date.now() + tokens.expires_in * 1000 : undefined,
|
|
32
|
-
},
|
|
33
|
-
});
|
|
34
|
-
// After sign-in, bring the daemon up so account sync starts immediately; ensureDaemon reuses a
|
|
35
|
-
// live daemon and starts a stopped one (idempotent). Honor the --no-daemon / AGENTAGE_NO_DAEMON
|
|
36
|
-
// disable switches.
|
|
37
|
-
const startDaemon = async (deps) => {
|
|
38
|
-
if (daemonDisabled()) {
|
|
39
|
-
console.log('Daemon disabled - account sync will run in-process on demand.');
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
const client = await deps.ensureDaemon();
|
|
43
|
-
const fail = 'Could not start the daemon - run: agentage daemon start';
|
|
44
|
-
console.log(client ? 'Daemon running.' : fail);
|
|
45
|
-
};
|
|
46
|
-
const disconnect = async (deps) => {
|
|
47
|
-
const auth = readAuth();
|
|
48
|
-
if (!auth) {
|
|
49
|
-
console.log('Nothing to disconnect.');
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
await deps.revoke(links(auth.siteFqdn).auth, auth.tokens.accessToken);
|
|
53
|
-
await deleteAuth();
|
|
54
|
-
console.log('Disconnected - local credentials removed.');
|
|
55
|
-
};
|
|
56
|
-
// Validate the stored session instead of trusting mere token presence. Returns true to short-circuit
|
|
57
|
-
// (valid or a transient blip - creds intact), false to proceed into a fresh sign-in (truly expired or
|
|
58
|
-
// the credential belongs to a different target than the current run).
|
|
59
|
-
const alreadySignedIn = async (auth, deps) => {
|
|
60
|
-
const mismatch = detectEnvMismatch(auth, siteFqdn());
|
|
61
|
-
if (mismatch) {
|
|
62
|
-
console.log(`Signed in to ${mismatch.credentialFqdn} (${mismatch.credentialEnv}), but this run targets ` +
|
|
63
|
-
`${mismatch.targetFqdn} (${mismatch.targetEnv}) - signing you into ${mismatch.targetEnv}.\n`);
|
|
64
|
-
return false; // proceed to a fresh sign-in against the current target
|
|
65
|
-
}
|
|
66
|
-
try {
|
|
67
|
-
await deps.introspect(auth, links(auth.siteFqdn));
|
|
68
|
-
console.log(`Already signed in. Run ${chalk.white('agentage setup --reauth')} to sign in again.\n`);
|
|
69
|
-
await deps.printStatus();
|
|
70
|
-
return true;
|
|
71
|
-
}
|
|
72
|
-
catch (err) {
|
|
73
|
-
if (err instanceof AuthRequiredError) {
|
|
74
|
-
console.log('Session expired - signing you in again.\n');
|
|
75
|
-
return false; // fall through to the sign-in flow, no --reauth needed
|
|
76
|
-
}
|
|
77
|
-
// Transient: do not force reauth on a blip; keep credentials and show status.
|
|
78
|
-
console.log('You appear signed in (could not fully verify - temporary).\n');
|
|
79
|
-
await deps.printStatus();
|
|
80
|
-
return true;
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
export const runSetup = async (opts, deps = defaultDeps) => {
|
|
84
|
-
if (opts.disconnect) {
|
|
85
|
-
await disconnect(deps);
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
const stored = readAuth();
|
|
89
|
-
if (stored && !opts.reauth && (await alreadySignedIn(stored, deps)))
|
|
90
|
-
return;
|
|
91
|
-
const fqdn = siteFqdn();
|
|
92
|
-
const target = links(fqdn);
|
|
93
|
-
ensureConfigDir();
|
|
94
|
-
ensureVaultsConfig();
|
|
95
|
-
const { verifier, challenge } = pkcePair();
|
|
96
|
-
const state = randomState();
|
|
97
|
-
const server = await deps.startServer(state);
|
|
98
|
-
try {
|
|
99
|
-
const clientId = await deps.register(target.auth, server.redirectUri);
|
|
100
|
-
const url = buildAuthorizeUrl(target.auth, {
|
|
101
|
-
clientId,
|
|
102
|
-
redirectUri: server.redirectUri,
|
|
103
|
-
challenge,
|
|
104
|
-
state,
|
|
105
|
-
});
|
|
106
|
-
console.log(`\nSign in to agentage (${fqdn}):\n\n ${url}\n`);
|
|
107
|
-
if (opts.browser === false)
|
|
108
|
-
console.log('Open the URL above in a browser to continue.');
|
|
109
|
-
else
|
|
110
|
-
await deps
|
|
111
|
-
.openBrowser(url)
|
|
112
|
-
.catch(() => console.log('Could not open a browser - use the URL above.'));
|
|
113
|
-
console.log('Waiting for sign-in to complete...');
|
|
114
|
-
const code = await server.waitForCode();
|
|
115
|
-
const tokens = await deps.exchange(target.auth, {
|
|
116
|
-
clientId,
|
|
117
|
-
code,
|
|
118
|
-
redirectUri: server.redirectUri,
|
|
119
|
-
verifier,
|
|
120
|
-
});
|
|
121
|
-
await mutateAuth(() => toAuthState(fqdn, clientId, tokens));
|
|
122
|
-
console.log(chalk.green('\nSigned in.\n'));
|
|
123
|
-
await startDaemon(deps);
|
|
124
|
-
await deps.printStatus();
|
|
125
|
-
}
|
|
126
|
-
finally {
|
|
127
|
-
server.close();
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
export const registerSetup = (program) => {
|
|
9
|
+
export const registerSetup = (program, action) => {
|
|
131
10
|
program
|
|
132
11
|
.command('setup')
|
|
133
12
|
.description('Sign in and connect this machine to your agentage account')
|
|
134
13
|
.option('--disconnect', 'sign out and remove local credentials')
|
|
135
14
|
.option('--reauth', 'force a fresh sign-in')
|
|
136
15
|
.option('--no-browser', 'print the sign-in URL instead of opening a browser')
|
|
137
|
-
.action(
|
|
138
|
-
try {
|
|
139
|
-
await runSetup(opts);
|
|
140
|
-
}
|
|
141
|
-
catch (err) {
|
|
142
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
143
|
-
console.error(chalk.red(`Setup failed: ${message}`));
|
|
144
|
-
process.exitCode = 1;
|
|
145
|
-
}
|
|
146
|
-
});
|
|
16
|
+
.action(action);
|
|
147
17
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { type Command } from 'commander';
|
|
2
2
|
import { type StatusReport } from '../../lib/status/status-info.js';
|
|
3
3
|
export declare const printStatus: (report: StatusReport) => void;
|
|
4
|
-
export
|
|
4
|
+
export interface StatusOptions {
|
|
5
5
|
json?: boolean;
|
|
6
6
|
token?: string;
|
|
7
|
-
}
|
|
8
|
-
export declare const
|
|
7
|
+
}
|
|
8
|
+
export declare const runStatus: (opts?: StatusOptions) => Promise<void>;
|
|
9
|
+
export declare const registerStatus: (program: Command, action: (opts: StatusOptions) => Promise<void>) => void;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
+
import {} from 'commander';
|
|
2
3
|
import { resolveAuth } from '../../lib/auth/credentials.js';
|
|
3
4
|
import { siteFqdn } from '../../lib/net/origins.js';
|
|
4
|
-
import {
|
|
5
|
-
import { gatherStatus, } from '../../lib/status/status-info.js';
|
|
6
|
-
import { vaultLines } from '../../lib/status/vaults-format.js';
|
|
5
|
+
import { gatherStatus } from '../../lib/status/status-info.js';
|
|
7
6
|
import { INSTALL_HINT } from '../../lib/update/update-check.js';
|
|
8
7
|
const mark = (good) => (good ? chalk.green('✓') : chalk.red('✗'));
|
|
9
8
|
const row = (label, value) => {
|
|
@@ -36,24 +35,6 @@ const updateLine = (update) => {
|
|
|
36
35
|
return chalk.dim('- update check unavailable');
|
|
37
36
|
}
|
|
38
37
|
};
|
|
39
|
-
const daemonLine = (d, cliVersion) => {
|
|
40
|
-
if (!d.running)
|
|
41
|
-
return `${mark(false)} stopped - run: agentage daemon start`;
|
|
42
|
-
const up = d.uptimeSeconds !== undefined ? `, up ${formatUptime(d.uptimeSeconds)}` : '';
|
|
43
|
-
const stale = d.daemonVersion && d.daemonVersion !== cliVersion
|
|
44
|
-
? chalk.yellow(` (version ${d.daemonVersion} != cli ${cliVersion})`)
|
|
45
|
-
: '';
|
|
46
|
-
return `${mark(true)} running (pid ${d.pid ?? '?'}, port ${d.port}${up})${stale}`;
|
|
47
|
-
};
|
|
48
|
-
const mcpLine = (d) => d.mcp ? `${mark(true)} serving at http://127.0.0.1:${d.port}/mcp` : `${mark(false)} off`;
|
|
49
|
-
// Daemon rows honor version-mismatch inline (appended to the daemon row) and print mcp only when
|
|
50
|
-
// running; the per-vault sync breakdown now lives in its own `vaults` block (printStatus).
|
|
51
|
-
const printDaemon = (d, cliVersion) => {
|
|
52
|
-
row('daemon', daemonLine(d, cliVersion));
|
|
53
|
-
if (!d.running)
|
|
54
|
-
return;
|
|
55
|
-
row('mcp', mcpLine(d));
|
|
56
|
-
};
|
|
57
38
|
export const printStatus = (report) => {
|
|
58
39
|
row('version', report.version);
|
|
59
40
|
row('update', updateLine(report.update));
|
|
@@ -63,10 +44,6 @@ export const printStatus = (report) => {
|
|
|
63
44
|
row('auth', authLine(report.auth));
|
|
64
45
|
row('endpoint', `${mark(report.endpoint.reachable)} ${report.endpoint.url} ` +
|
|
65
46
|
(report.endpoint.reachable ? 'reachable' : 'unreachable'));
|
|
66
|
-
if (report.daemon)
|
|
67
|
-
printDaemon(report.daemon, report.version);
|
|
68
|
-
for (const line of vaultLines(report.vaults))
|
|
69
|
-
console.log(line);
|
|
70
47
|
if (report.update.message)
|
|
71
48
|
console.log(chalk.yellow(`\n${report.update.message}`));
|
|
72
49
|
};
|
|
@@ -78,11 +55,11 @@ export const runStatus = async (opts = {}) => {
|
|
|
78
55
|
}
|
|
79
56
|
printStatus(report);
|
|
80
57
|
};
|
|
81
|
-
export const registerStatus = (program) => {
|
|
58
|
+
export const registerStatus = (program, action) => {
|
|
82
59
|
program
|
|
83
60
|
.command('status')
|
|
84
61
|
.description('Show CLI, account, and endpoint status')
|
|
85
62
|
.option('--json', 'machine-readable output')
|
|
86
63
|
.option('--token <token>', 'authenticate with a personal access token (aga_...); or set AGENTAGE_TOKEN')
|
|
87
|
-
.action(
|
|
64
|
+
.action(action);
|
|
88
65
|
};
|
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
import { type Command } from 'commander';
|
|
2
|
-
import {
|
|
2
|
+
import { requireNpm10, runNpm } from '../../lib/npm/npm-cli.js';
|
|
3
3
|
import { type UpdateInfo } from '../../lib/update/update-check.js';
|
|
4
|
-
export
|
|
5
|
-
export interface RestartDeps {
|
|
6
|
-
running?: () => boolean;
|
|
7
|
-
stop?: () => Promise<boolean>;
|
|
8
|
-
start?: (port: number) => Promise<SpawnOutcome>;
|
|
9
|
-
}
|
|
10
|
-
export declare const restartDaemonIfRunning: (deps?: RestartDeps) => Promise<RestartOutcome>;
|
|
4
|
+
export declare const installLatest: (run?: typeof runNpm, check?: typeof requireNpm10) => Promise<void>;
|
|
11
5
|
export interface UpdateDeps {
|
|
12
6
|
check: (installed: string) => Promise<UpdateInfo>;
|
|
13
7
|
install: () => Promise<void>;
|
|
14
|
-
restartDaemon: () => Promise<RestartOutcome>;
|
|
15
8
|
acquireLock: () => boolean;
|
|
16
9
|
releaseLock: () => void;
|
|
17
10
|
log: (msg: string) => void;
|
|
@@ -20,4 +13,4 @@ export interface UpdateOptions {
|
|
|
20
13
|
check?: boolean;
|
|
21
14
|
}
|
|
22
15
|
export declare const runUpdate: (opts: UpdateOptions, deps?: UpdateDeps) => Promise<void>;
|
|
23
|
-
export declare const registerUpdate: (program: Command) => void;
|
|
16
|
+
export declare const registerUpdate: (program: Command, action: (opts: UpdateOptions) => Promise<void>) => void;
|
|
@@ -1,31 +1,30 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { promisify } from 'node:util';
|
|
1
|
+
import { join } from 'node:path';
|
|
3
2
|
import chalk from 'chalk';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import {} from 'commander';
|
|
4
|
+
import { getConfigDir } from '../../lib/fs/config.js';
|
|
5
|
+
import { acquireFileLock, releaseFileLock } from '../../lib/fs/file-lock.js';
|
|
6
|
+
import { requireNpm10, runNpm } from '../../lib/npm/npm-cli.js';
|
|
6
7
|
import { checkForUpdate, INSTALL_HINT } from '../../lib/update/update-check.js';
|
|
7
|
-
import { acquireUpdateLock, releaseUpdateLock } from '../../lib/update/update-lock.js';
|
|
8
8
|
import { VERSION } from '../../utils/version.js';
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
//
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
await (
|
|
18
|
-
|
|
19
|
-
|
|
9
|
+
const INSTALL_TIMEOUT_MS = 5 * 60_000;
|
|
10
|
+
const NPM_TAIL_LINES = 10;
|
|
11
|
+
// An install takes minutes, so the crashed-holder ages scale up from the config-write defaults.
|
|
12
|
+
const UPDATE_LOCK = { ttlMs: 10 * 60_000, hardStaleMs: 30 * 60_000 };
|
|
13
|
+
const updateLockTarget = () => join(getConfigDir(), 'update');
|
|
14
|
+
const tail = (text) => text.trimEnd().split('\n').slice(-NPM_TAIL_LINES).join('\n');
|
|
15
|
+
export const installLatest = async (run = runNpm, check = requireNpm10) => {
|
|
16
|
+
await check(run);
|
|
17
|
+
const res = await run(['install', '-g', '@agentage/cli@latest'], {
|
|
18
|
+
timeoutMs: INSTALL_TIMEOUT_MS,
|
|
19
|
+
});
|
|
20
|
+
if (res.code !== 0)
|
|
21
|
+
throw new Error(`npm install failed (exit ${res.code}):\n${tail(res.stderr || res.stdout)}`);
|
|
20
22
|
};
|
|
21
23
|
const defaultDeps = {
|
|
22
24
|
check: checkForUpdate,
|
|
23
|
-
install:
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
restartDaemon: () => restartDaemonIfRunning(),
|
|
27
|
-
acquireLock: () => acquireUpdateLock(),
|
|
28
|
-
releaseLock: releaseUpdateLock,
|
|
25
|
+
install: () => installLatest(),
|
|
26
|
+
acquireLock: () => acquireFileLock(updateLockTarget(), Date.now(), UPDATE_LOCK),
|
|
27
|
+
releaseLock: () => releaseFileLock(updateLockTarget()),
|
|
29
28
|
log: (msg) => console.log(msg),
|
|
30
29
|
};
|
|
31
30
|
const describe = (info) => {
|
|
@@ -41,20 +40,12 @@ const describe = (info) => {
|
|
|
41
40
|
return chalk.yellow(`Couldn't reach the registry - try again later. ${INSTALL_HINT}`);
|
|
42
41
|
}
|
|
43
42
|
};
|
|
44
|
-
// Install, then restart a running daemon so its in-process engine runs the new version.
|
|
45
43
|
const install = async (deps) => {
|
|
46
44
|
deps.log('Installing the latest @agentage/cli...');
|
|
47
45
|
await deps.install();
|
|
48
46
|
deps.log(chalk.green('Updated. Run `agentage status` to confirm.'));
|
|
49
|
-
const outcome = await deps.restartDaemon();
|
|
50
|
-
if (outcome === 'restarted')
|
|
51
|
-
deps.log(chalk.green('Restarted the daemon on the new version.'));
|
|
52
|
-
if (outcome === 'failed')
|
|
53
|
-
deps.log(chalk.yellow('Daemon did not restart cleanly - run `agentage daemon start`.'));
|
|
54
47
|
};
|
|
55
|
-
// --check
|
|
56
|
-
// we're behind (available/unsupported), guarded by a single-writer lock; current/unreachable just
|
|
57
|
-
// report.
|
|
48
|
+
// --check never installs; otherwise install only when behind, under a single-writer lock.
|
|
58
49
|
export const runUpdate = async (opts, deps = defaultDeps) => {
|
|
59
50
|
const info = await deps.check(VERSION);
|
|
60
51
|
deps.log(describe(info));
|
|
@@ -72,18 +63,10 @@ export const runUpdate = async (opts, deps = defaultDeps) => {
|
|
|
72
63
|
deps.releaseLock();
|
|
73
64
|
}
|
|
74
65
|
};
|
|
75
|
-
export const registerUpdate = (program) => {
|
|
66
|
+
export const registerUpdate = (program, action) => {
|
|
76
67
|
program
|
|
77
68
|
.command('update')
|
|
78
69
|
.description('Update @agentage/cli to the latest published version')
|
|
79
70
|
.option('--check', 'report whether an update is available, without installing')
|
|
80
|
-
.action(
|
|
81
|
-
try {
|
|
82
|
-
await runUpdate(opts);
|
|
83
|
-
}
|
|
84
|
-
catch (err) {
|
|
85
|
-
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
86
|
-
process.exitCode = 1;
|
|
87
|
-
}
|
|
88
|
-
});
|
|
71
|
+
.action(action);
|
|
89
72
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const pluginsEnabled: () => boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const pluginsEnabled = () => process.env['AGENTAGE_PLUGINS'] === '1';
|
package/dist/lib/auth/api.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type AuthState } from '../fs/config.js';
|
|
2
|
+
import { type CliRequestInit } from '../net/fetch.js';
|
|
2
3
|
import { type Links } from '../net/origins.js';
|
|
3
4
|
export { AuthRequiredError, TransientAuthError } from './auth-errors.js';
|
|
4
5
|
export declare const refreshOrThrow: (auth: AuthState, links: Links) => Promise<void>;
|
|
5
|
-
export declare const
|
|
6
|
-
export declare const
|
|
6
|
+
export declare const authedFetch: (auth: AuthState, links: Links, url: string, init?: CliRequestInit) => Promise<Response>;
|
|
7
|
+
export declare const authedJson: <T>(auth: AuthState, links: Links, url: string, init?: CliRequestInit) => Promise<T>;
|
|
7
8
|
export { introspectToken, type TokenSession } from './introspect.js';
|