@letta-ai/dreams 0.0.1 → 0.0.3
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 +74 -20
- package/dist/auth/commands.js +46 -4
- package/dist/auth/credentials.js +28 -8
- package/dist/cli.js +198 -8
- package/dist/cloud/client.js +89 -5
- package/dist/cloud/upload.js +150 -70
- package/dist/development-reset.js +359 -0
- package/dist/launcher.js +311 -0
- package/dist/local/backfill.js +608 -0
- package/dist/local/bindings.js +30 -0
- package/dist/local/claude.js +61 -163
- package/dist/local/codex.js +313 -0
- package/dist/local/commands.js +129 -10
- package/dist/local/db.js +64 -0
- package/dist/local/detect.js +144 -0
- package/dist/local/discovered.js +6 -0
- package/dist/local/leases.js +3 -1
- package/dist/local/scan.js +99 -17
- package/dist/local/source-adapter.js +8 -0
- package/dist/local/source-adapters.js +58 -0
- package/dist/local/state-lock.js +88 -0
- package/dist/local/sync-control.js +381 -0
- package/dist/local/transcript-bytes.js +204 -0
- package/dist/managed-install.js +74 -86
- package/dist/onboard.js +26 -72
- package/dist/skill.js +281 -16
- package/dist/snapshots.js +210 -0
- package/dist/sync.js +790 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,38 +15,77 @@ npx @letta-ai/dreams@latest onboard --json
|
|
|
15
15
|
|
|
16
16
|
1. verifies Node >= 22.13 through the bin preflight
|
|
17
17
|
2. installs the exact CLI version under `~/.dreams/cli/<version>/`
|
|
18
|
-
3.
|
|
18
|
+
3. activates it through the stable launcher at `~/.dreams/bin/dreams`
|
|
19
19
|
4. creates or preserves the installation id in `~/.dreams/installation.json`
|
|
20
|
-
5. installs `~/.claude/skills/dreams-setup
|
|
20
|
+
5. installs `~/.claude/skills/dreams-setup/` (skill + init snapshot template)
|
|
21
21
|
6. initializes and migrates `~/.dreams/dreams.db`
|
|
22
|
-
7. returns
|
|
22
|
+
7. returns a skill handoff (`status: "ready"`) with absolute `cli_path` and skill path
|
|
23
23
|
|
|
24
|
-
It does not
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
It does **not** check authentication or choose login/orient next steps. The
|
|
25
|
+
installed `dreams-setup` skill owns sequencing (authenticate → detect source →
|
|
26
|
+
init snapshot → activate → test connection). Repeated `onboard` calls are safe
|
|
27
|
+
and repair local setup only.
|
|
28
28
|
|
|
29
29
|
### Commands
|
|
30
30
|
|
|
31
|
-
- `dreams onboard [--json]` — install or repair local setup and
|
|
32
|
-
setup
|
|
33
|
-
- `dreams
|
|
34
|
-
|
|
31
|
+
- `dreams onboard [--json]` — install or repair local setup and hand off to the
|
|
32
|
+
setup skill.
|
|
33
|
+
- `dreams rollback [--json]` — reactivate the previous completed CLI version.
|
|
34
|
+
- `dreams status [--json]` — installation, active and previous CLI versions,
|
|
35
|
+
SQLite, setup skill, and authentication state.
|
|
35
36
|
- `dreams auth login [--json]` — OAuth device code sign-in (see Auth below).
|
|
36
37
|
- `dreams auth status [--json]` — authentication state; tokens are masked
|
|
37
38
|
(`at-let-…abcd`), never printed.
|
|
38
39
|
- `dreams auth logout [--json]` — best-effort revoke of Dreams' refresh token,
|
|
39
40
|
then clear stored credentials.
|
|
41
|
+
- `dreams dev reset local [--confirm] [--json]` — preview or remove only local
|
|
42
|
+
SQLite and blob state.
|
|
43
|
+
- `dreams dev reset identity [--confirm] [--json]` — preview or remove local
|
|
44
|
+
state, stored Dreams credentials, and the installation identity.
|
|
40
45
|
|
|
41
46
|
Local state lives in `~/.dreams/`. Requires Node >= 22.13, where built-in
|
|
42
47
|
`node:sqlite` no longer requires the `--experimental-sqlite` flag.
|
|
43
48
|
|
|
49
|
+
### CLI upgrades and rollback
|
|
50
|
+
|
|
51
|
+
Installed CLI versions are immutable under `~/.dreams/cli/<version>/`. The
|
|
52
|
+
atomic `~/.dreams/cli/activation.json` record selects the active version and
|
|
53
|
+
retains one previous version. The stable launcher reads that record rather than
|
|
54
|
+
pointing directly at a version.
|
|
55
|
+
|
|
56
|
+
Run `dreams rollback` to reactivate the previous completed version. The launcher
|
|
57
|
+
also rolls back automatically when an active CLI cannot reach its startup
|
|
58
|
+
readiness marker, then retries the original command once. Normal command errors
|
|
59
|
+
after readiness, including invalid arguments, authentication failures, and
|
|
60
|
+
network failures, never trigger rollback.
|
|
61
|
+
|
|
62
|
+
### Development reset
|
|
63
|
+
|
|
64
|
+
Development resets are preview-only until `--confirm` is provided. `local`
|
|
65
|
+
removes `dreams.db`, its SQLite sidecars, and `~/.dreams/blobs/`; it preserves
|
|
66
|
+
credentials and the installation identity. `identity` removes those local files
|
|
67
|
+
plus Dreams' stored credentials and `installation.json`, so the next `onboard`
|
|
68
|
+
mints a new device identity. Both scopes preserve installed CLI versions, the
|
|
69
|
+
stable launcher, the setup skill, and every Cloud resource. Confirmed resets
|
|
70
|
+
hold the same local-state lock as onboarding, auth, source, and upload commands,
|
|
71
|
+
so they fail instead of deleting files another process is using. If
|
|
72
|
+
`DREAMS_CREDENTIALS_BACKEND=file` is forced, identity reset clears the file and
|
|
73
|
+
explicitly reports that the OS keychain was not checked.
|
|
74
|
+
|
|
75
|
+
Test-workspace cleanup is intentionally not available through this local CLI.
|
|
76
|
+
It is a separate internal Cloud operation with different credentials and data
|
|
77
|
+
cleanup semantics. `dreams dev reset test-workspace` fails without deleting
|
|
78
|
+
anything.
|
|
79
|
+
|
|
44
80
|
## Local sources (Claude Code)
|
|
45
81
|
|
|
46
82
|
The CLI maintains a crash-safe local SQLite store (`~/.dreams/dreams.db`) that
|
|
47
83
|
discovers Claude Code transcripts and prepares immutable upload segments before
|
|
48
84
|
they are sent to Letta Cloud.
|
|
49
85
|
|
|
86
|
+
- `dreams source detect [--json]` — detect Claude Code from harness filesystem
|
|
87
|
+
facts under `~/.claude` (no transcript reads) and register an installation-scoped
|
|
88
|
+
Cloud source in status `detected`. Idempotent; does not scan or upload.
|
|
50
89
|
- `dreams source approve-root <path> [--json]` — approve a work root. Sources
|
|
51
90
|
are **deny-by-default**: no transcript bytes are queued until their working
|
|
52
91
|
directory is under an approved root.
|
|
@@ -57,8 +96,23 @@ they are sent to Letta Cloud.
|
|
|
57
96
|
before anything is enqueued.
|
|
58
97
|
- `dreams source list [--json]` — show the DB path, approved roots, sources, and
|
|
59
98
|
the pending upload queue.
|
|
60
|
-
- `dreams
|
|
61
|
-
|
|
99
|
+
- `dreams snapshots create --type <type> --file <path> --client-request-id <id> [--workspace-id <id>] [--json]`
|
|
100
|
+
— submit a skill-authored JSON snapshot (256 KiB UTF-8 object cap) to
|
|
101
|
+
`POST /v1/dreams/workspaces/{workspaceId}/snapshots`. Workspace defaults to the
|
|
102
|
+
local binding from `source detect`.
|
|
103
|
+
- `dreams upload [--json]` — authenticate, refresh source registration, and
|
|
104
|
+
upload due queue entries. Upload accepts `detected` sources; Cloud promotes to
|
|
105
|
+
`active` after durable acceptance.
|
|
106
|
+
- `dreams sync [--force] [--json]` — hook-safe scheduler: records a durable sync
|
|
107
|
+
trigger and runs a detached worker that live-scans tracked sessions and uploads
|
|
108
|
+
with a per-pass budget (~3h cadence unless `--force` or retry-due).
|
|
109
|
+
- `dreams sync pause|resume|status [--json]` — pause makes hook wakes no-ops;
|
|
110
|
+
resume clears pause and requests one immediate sync.
|
|
111
|
+
- `dreams backfill start --since <RFC3339> [--json]` — approve a frozen
|
|
112
|
+
`[since, until=now]` historical window and run one bounded local scan/queue
|
|
113
|
+
pass (session frontier, newest unfinished sessions first; no upload).
|
|
114
|
+
Re-running the same active `--since` is idempotent; a different active policy
|
|
115
|
+
fails closed. Sync drains live first, then backfill by newest session mtime.
|
|
62
116
|
|
|
63
117
|
Local cursors track a `queued_through_offset` (advanced as segments are queued)
|
|
64
118
|
separately from an `acked_offset` (advanced only after durable Cloud
|
|
@@ -127,20 +181,20 @@ npm test # build + node:test suite (uses a temp HOME)
|
|
|
127
181
|
## Testing the npx bootstrap via tarball (no publish)
|
|
128
182
|
|
|
129
183
|
```sh
|
|
130
|
-
npm pack # produces letta-ai-dreams-0.0.
|
|
184
|
+
npm pack # produces letta-ai-dreams-0.0.3.tgz
|
|
131
185
|
cd "$(mktemp -d)"
|
|
132
|
-
npx -y -p /absolute/path/to/dreams/letta-ai-dreams-0.0.
|
|
186
|
+
npx -y -p /absolute/path/to/dreams/letta-ai-dreams-0.0.3.tgz dreams onboard
|
|
133
187
|
```
|
|
134
188
|
|
|
135
189
|
(The `-p <tarball> dreams` form is required: a bare `npx <tarball>` treats the
|
|
136
190
|
path as a script to execute, not a package to install.)
|
|
137
191
|
|
|
138
192
|
`onboard` writes to `~/.dreams/` and installs
|
|
139
|
-
`~/.claude/skills/dreams-setup
|
|
140
|
-
for a sandboxed run.
|
|
193
|
+
`~/.claude/skills/dreams-setup/` (including the init snapshot template). Set
|
|
194
|
+
`HOME` to a temporary directory for a sandboxed run.
|
|
141
195
|
|
|
142
196
|
## Deferred
|
|
143
197
|
|
|
144
|
-
-
|
|
145
|
-
-
|
|
146
|
-
-
|
|
198
|
+
- Shared-memory repository generation and review
|
|
199
|
+
- Hook installation and default Dream schedule creation
|
|
200
|
+
- `dreams backfill start` (skill optional background history import)
|
package/dist/auth/commands.js
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* {"status":"authenticated",…} object once the user approves in the browser.
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.commandAuthLogin = commandAuthLogin;
|
|
11
10
|
exports.renderAuthStatus = renderAuthStatus;
|
|
11
|
+
exports.commandAuthLogin = commandAuthLogin;
|
|
12
12
|
exports.commandAuthStatus = commandAuthStatus;
|
|
13
13
|
exports.commandAuthLogout = commandAuthLogout;
|
|
14
14
|
const browser_1 = require("./browser");
|
|
@@ -17,12 +17,13 @@ const index_1 = require("./index");
|
|
|
17
17
|
const credentials_1 = require("./credentials");
|
|
18
18
|
const oauth_refresh_1 = require("./oauth-refresh");
|
|
19
19
|
const oauth_1 = require("./oauth");
|
|
20
|
+
const state_lock_1 = require("../local/state-lock");
|
|
20
21
|
/** `auth login` short-circuits when the stored token is valid for >7 days. */
|
|
21
22
|
const REAUTH_MARGIN_MS = 7 * 24 * 60 * 60 * 1000;
|
|
22
23
|
function printJsonLine(value) {
|
|
23
24
|
console.log(JSON.stringify(value));
|
|
24
25
|
}
|
|
25
|
-
async function
|
|
26
|
+
async function commandAuthLoginUnlocked(json) {
|
|
26
27
|
const stored = (0, credentials_1.loadCredentials)();
|
|
27
28
|
if (stored && stored.credentials.access_token && !(0, credentials_1.expiresWithin)(stored.credentials, REAUTH_MARGIN_MS)) {
|
|
28
29
|
if (json) {
|
|
@@ -111,7 +112,7 @@ function renderAuthStatus(info) {
|
|
|
111
112
|
` Device id: ${info.device_id}`,
|
|
112
113
|
].join("\n");
|
|
113
114
|
}
|
|
114
|
-
function
|
|
115
|
+
function commandAuthStatusUnlocked(json) {
|
|
115
116
|
const info = (0, index_1.authStatusInfo)();
|
|
116
117
|
if (json) {
|
|
117
118
|
console.log(JSON.stringify(info, null, 2));
|
|
@@ -121,7 +122,7 @@ function commandAuthStatus(json) {
|
|
|
121
122
|
}
|
|
122
123
|
return 0;
|
|
123
124
|
}
|
|
124
|
-
async function
|
|
125
|
+
async function commandAuthLogoutUnlocked(json) {
|
|
125
126
|
const stored = (0, credentials_1.loadCredentials)();
|
|
126
127
|
if (!stored) {
|
|
127
128
|
if (json)
|
|
@@ -139,3 +140,44 @@ async function commandAuthLogout(json) {
|
|
|
139
140
|
console.log("Logged out: refresh token revoked and local credentials cleared.");
|
|
140
141
|
return 0;
|
|
141
142
|
}
|
|
143
|
+
function stateBusy(json) {
|
|
144
|
+
const message = "Another Dreams command is using local state. Try again after it finishes.";
|
|
145
|
+
if (json)
|
|
146
|
+
printJsonLine({ status: "error", code: "local_state_busy", message });
|
|
147
|
+
else
|
|
148
|
+
process.stderr.write(message + "\n");
|
|
149
|
+
return 1;
|
|
150
|
+
}
|
|
151
|
+
async function commandAuthLogin(json) {
|
|
152
|
+
const lock = (0, state_lock_1.acquireLocalStateLock)();
|
|
153
|
+
if (lock === null)
|
|
154
|
+
return stateBusy(json);
|
|
155
|
+
try {
|
|
156
|
+
return await commandAuthLoginUnlocked(json);
|
|
157
|
+
}
|
|
158
|
+
finally {
|
|
159
|
+
(0, state_lock_1.releaseLocalStateLock)(lock);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function commandAuthStatus(json) {
|
|
163
|
+
const lock = (0, state_lock_1.acquireLocalStateLock)();
|
|
164
|
+
if (lock === null)
|
|
165
|
+
return stateBusy(json);
|
|
166
|
+
try {
|
|
167
|
+
return commandAuthStatusUnlocked(json);
|
|
168
|
+
}
|
|
169
|
+
finally {
|
|
170
|
+
(0, state_lock_1.releaseLocalStateLock)(lock);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async function commandAuthLogout(json) {
|
|
174
|
+
const lock = (0, state_lock_1.acquireLocalStateLock)();
|
|
175
|
+
if (lock === null)
|
|
176
|
+
return stateBusy(json);
|
|
177
|
+
try {
|
|
178
|
+
return await commandAuthLogoutUnlocked(json);
|
|
179
|
+
}
|
|
180
|
+
finally {
|
|
181
|
+
(0, state_lock_1.releaseLocalStateLock)(lock);
|
|
182
|
+
}
|
|
183
|
+
}
|
package/dist/auth/credentials.js
CHANGED
|
@@ -108,15 +108,26 @@ function keychainRead(account) {
|
|
|
108
108
|
return null; // no entry, or keychain unusable — fall through to file
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
|
-
function keychainDelete(account) {
|
|
111
|
+
function keychainDelete(account, strict) {
|
|
112
112
|
const ctor = keyringCtor();
|
|
113
|
-
if (!ctor)
|
|
114
|
-
|
|
113
|
+
if (!ctor) {
|
|
114
|
+
if (backendOverride() === "file")
|
|
115
|
+
return "not_checked_file_backend";
|
|
116
|
+
if (strict) {
|
|
117
|
+
throw new Error("Could not verify OS keychain cleanup because @napi-rs/keyring is unavailable. " +
|
|
118
|
+
"Rerun where keychain support is available.");
|
|
119
|
+
}
|
|
120
|
+
return "unavailable";
|
|
121
|
+
}
|
|
115
122
|
try {
|
|
116
123
|
new ctor(KEYCHAIN_SERVICE, account).deleteCredential();
|
|
124
|
+
return "cleared";
|
|
117
125
|
}
|
|
118
|
-
catch {
|
|
119
|
-
|
|
126
|
+
catch (error) {
|
|
127
|
+
if (strict) {
|
|
128
|
+
throw new Error(`Could not clear Dreams credentials from the OS keychain: ${error instanceof Error ? error.message : String(error)}`);
|
|
129
|
+
}
|
|
130
|
+
return "unavailable";
|
|
120
131
|
}
|
|
121
132
|
}
|
|
122
133
|
// --- file backend ------------------------------------------------------------
|
|
@@ -202,10 +213,19 @@ function saveCredentials(credentials) {
|
|
|
202
213
|
fileWrite(credentials);
|
|
203
214
|
}
|
|
204
215
|
/** Clear both backends (login/logout/invalid_grant paths). */
|
|
205
|
-
function clearCredentials() {
|
|
206
|
-
|
|
207
|
-
keychainDelete(
|
|
216
|
+
function clearCredentials(options = {}) {
|
|
217
|
+
const strict = options.strictKeychain === true;
|
|
218
|
+
const refresh = keychainDelete(REFRESH_ACCOUNT, strict);
|
|
219
|
+
const access = keychainDelete(ACCESS_ACCOUNT, strict);
|
|
208
220
|
fs.rmSync(credentialsFilePath(), { force: true });
|
|
221
|
+
return {
|
|
222
|
+
file: "cleared",
|
|
223
|
+
keychain: refresh === "not_checked_file_backend" || access === "not_checked_file_backend"
|
|
224
|
+
? "not_checked_file_backend"
|
|
225
|
+
: refresh === "cleared" && access === "cleared"
|
|
226
|
+
? "cleared"
|
|
227
|
+
: "unavailable",
|
|
228
|
+
};
|
|
209
229
|
}
|
|
210
230
|
function expiresWithin(credentials, marginMs = exports.EXPIRY_MARGIN_MS) {
|
|
211
231
|
const at = Date.parse(credentials.expires_at);
|
package/dist/cli.js
CHANGED
|
@@ -4,47 +4,146 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
exports.main = main;
|
|
5
5
|
const index_1 = require("./auth/index");
|
|
6
6
|
const commands_1 = require("./auth/commands");
|
|
7
|
+
const development_reset_1 = require("./development-reset");
|
|
7
8
|
const commands_2 = require("./local/commands");
|
|
8
9
|
const db_1 = require("./local/db");
|
|
10
|
+
const state_lock_1 = require("./local/state-lock");
|
|
11
|
+
const launcher_1 = require("./launcher");
|
|
9
12
|
const managed_install_1 = require("./managed-install");
|
|
10
13
|
const onboard_1 = require("./onboard");
|
|
14
|
+
const snapshots_1 = require("./snapshots");
|
|
11
15
|
const skill_1 = require("./skill");
|
|
12
16
|
const store_1 = require("./store");
|
|
17
|
+
const backfill_1 = require("./local/backfill");
|
|
18
|
+
const sync_1 = require("./sync");
|
|
13
19
|
const version_1 = require("./version");
|
|
14
20
|
const USAGE = `Usage: dreams <command> [options]
|
|
15
21
|
|
|
16
22
|
Commands:
|
|
17
|
-
onboard Install Dreams locally and
|
|
23
|
+
onboard Install Dreams locally and hand off to the setup skill
|
|
24
|
+
rollback Reactivate the previous installed CLI version
|
|
18
25
|
status Show installation, skill, CLI, database, and auth state
|
|
19
26
|
auth login Connect this device to Letta (OAuth device code flow)
|
|
20
27
|
auth status Show authentication state (never prints tokens)
|
|
21
28
|
auth logout Revoke Dreams' refresh token and clear stored credentials
|
|
29
|
+
dev reset local Preview/reset local SQLite and blob state
|
|
30
|
+
dev reset identity Preview/reset local state, credentials, and device identity
|
|
31
|
+
source detect Detect Claude Code and register a detected Cloud source
|
|
22
32
|
source scan Discover Claude Code sessions and build the local upload queue
|
|
23
33
|
source approve-root <path> Approve a work root so its transcripts become eligible
|
|
24
34
|
source list Show local sources, approved roots, and the pending queue
|
|
35
|
+
snapshots create Submit a skill-authored snapshot JSON file to Cloud
|
|
36
|
+
sync Schedule a hook-safe sync worker (live then active backfill)
|
|
37
|
+
sync pause|resume|status Pause/resume hooks or show sync diagnostics
|
|
38
|
+
backfill start Queue a bounded historical backfill window (local only)
|
|
25
39
|
upload Upload pending queued objects to Letta Cloud
|
|
26
40
|
|
|
27
41
|
Options:
|
|
28
|
-
--json
|
|
29
|
-
--
|
|
30
|
-
--
|
|
42
|
+
--json Machine-readable JSON output
|
|
43
|
+
--confirm Apply a development reset preview
|
|
44
|
+
--force Bypass sync cadence (never bypasses pause/privacy)
|
|
45
|
+
--source <type> Sync source adapter (claude-code default; codex)
|
|
46
|
+
--since <RFC3339> Backfill window start (with backfill start)
|
|
47
|
+
--type <type> Snapshot type (with snapshots create)
|
|
48
|
+
--file <path> Snapshot JSON file (with snapshots create)
|
|
49
|
+
--client-request-id <id> Idempotency key (with snapshots create)
|
|
50
|
+
--workspace-id <id> Override workspace id (defaults to local binding)
|
|
51
|
+
--version Print the CLI version
|
|
52
|
+
--help Show this help
|
|
31
53
|
`;
|
|
32
|
-
const COMMANDS_WITH_SUBCOMMANDS = new Set(["auth", "source"]);
|
|
54
|
+
const COMMANDS_WITH_SUBCOMMANDS = new Set(["auth", "dev", "source", "snapshots", "sync", "backfill"]);
|
|
33
55
|
function parseArgs(argv) {
|
|
34
56
|
const parsed = {
|
|
35
57
|
positionals: [],
|
|
36
58
|
json: false,
|
|
59
|
+
confirm: false,
|
|
37
60
|
help: false,
|
|
38
61
|
version: false,
|
|
62
|
+
force: false,
|
|
63
|
+
worker: false,
|
|
64
|
+
source: undefined,
|
|
65
|
+
since: undefined,
|
|
66
|
+
type: undefined,
|
|
67
|
+
file: undefined,
|
|
68
|
+
clientRequestId: undefined,
|
|
69
|
+
workspaceId: undefined,
|
|
39
70
|
unknown: [],
|
|
40
71
|
};
|
|
41
|
-
for (
|
|
72
|
+
for (let i = 0; i < argv.length; i++) {
|
|
73
|
+
const arg = argv[i];
|
|
42
74
|
if (arg === "--json")
|
|
43
75
|
parsed.json = true;
|
|
76
|
+
else if (arg === "--confirm")
|
|
77
|
+
parsed.confirm = true;
|
|
78
|
+
else if (arg === "--force")
|
|
79
|
+
parsed.force = true;
|
|
80
|
+
else if (arg === "--worker")
|
|
81
|
+
parsed.worker = true;
|
|
82
|
+
else if (arg === "--source") {
|
|
83
|
+
const value = argv[++i];
|
|
84
|
+
if (value === undefined || value.trim() === "")
|
|
85
|
+
parsed.unknown.push("--source");
|
|
86
|
+
else
|
|
87
|
+
parsed.source = value;
|
|
88
|
+
}
|
|
89
|
+
else if (arg.startsWith("--source=")) {
|
|
90
|
+
const value = arg.slice("--source=".length);
|
|
91
|
+
if (value.trim() === "")
|
|
92
|
+
parsed.unknown.push("--source=");
|
|
93
|
+
else
|
|
94
|
+
parsed.source = value;
|
|
95
|
+
}
|
|
44
96
|
else if (arg === "--help" || arg === "-h")
|
|
45
97
|
parsed.help = true;
|
|
46
98
|
else if (arg === "--version" || arg === "-v")
|
|
47
99
|
parsed.version = true;
|
|
100
|
+
else if (arg === "--since") {
|
|
101
|
+
const value = argv[++i];
|
|
102
|
+
if (value === undefined)
|
|
103
|
+
parsed.unknown.push("--since");
|
|
104
|
+
else
|
|
105
|
+
parsed.since = value;
|
|
106
|
+
}
|
|
107
|
+
else if (arg.startsWith("--since="))
|
|
108
|
+
parsed.since = arg.slice("--since=".length);
|
|
109
|
+
else if (arg === "--type") {
|
|
110
|
+
const value = argv[++i];
|
|
111
|
+
if (value === undefined)
|
|
112
|
+
parsed.unknown.push("--type");
|
|
113
|
+
else
|
|
114
|
+
parsed.type = value;
|
|
115
|
+
}
|
|
116
|
+
else if (arg.startsWith("--type="))
|
|
117
|
+
parsed.type = arg.slice("--type=".length);
|
|
118
|
+
else if (arg === "--file") {
|
|
119
|
+
const value = argv[++i];
|
|
120
|
+
if (value === undefined)
|
|
121
|
+
parsed.unknown.push("--file");
|
|
122
|
+
else
|
|
123
|
+
parsed.file = value;
|
|
124
|
+
}
|
|
125
|
+
else if (arg.startsWith("--file="))
|
|
126
|
+
parsed.file = arg.slice("--file=".length);
|
|
127
|
+
else if (arg === "--client-request-id") {
|
|
128
|
+
const value = argv[++i];
|
|
129
|
+
if (value === undefined)
|
|
130
|
+
parsed.unknown.push("--client-request-id");
|
|
131
|
+
else
|
|
132
|
+
parsed.clientRequestId = value;
|
|
133
|
+
}
|
|
134
|
+
else if (arg.startsWith("--client-request-id=")) {
|
|
135
|
+
parsed.clientRequestId = arg.slice("--client-request-id=".length);
|
|
136
|
+
}
|
|
137
|
+
else if (arg === "--workspace-id") {
|
|
138
|
+
const value = argv[++i];
|
|
139
|
+
if (value === undefined)
|
|
140
|
+
parsed.unknown.push("--workspace-id");
|
|
141
|
+
else
|
|
142
|
+
parsed.workspaceId = value;
|
|
143
|
+
}
|
|
144
|
+
else if (arg.startsWith("--workspace-id=")) {
|
|
145
|
+
parsed.workspaceId = arg.slice("--workspace-id=".length);
|
|
146
|
+
}
|
|
48
147
|
else if (arg.startsWith("-"))
|
|
49
148
|
parsed.unknown.push(arg);
|
|
50
149
|
else
|
|
@@ -52,14 +151,17 @@ function parseArgs(argv) {
|
|
|
52
151
|
}
|
|
53
152
|
return parsed;
|
|
54
153
|
}
|
|
55
|
-
function
|
|
154
|
+
function commandStatusUnlocked(json) {
|
|
56
155
|
const installation = (0, store_1.loadOrCreateInstallation)();
|
|
57
156
|
const auth = (0, index_1.authStatusInfo)();
|
|
157
|
+
const activation = (0, launcher_1.readActivation)();
|
|
58
158
|
const status = {
|
|
59
159
|
installation_id: installation.installation_id,
|
|
60
160
|
installation_created_at: installation.created_at,
|
|
61
161
|
state: auth.authenticated ? "authenticated" : "unauthenticated",
|
|
62
162
|
cli_path: (0, managed_install_1.stableCliPath)(),
|
|
163
|
+
active_cli_version: activation?.active_version ?? null,
|
|
164
|
+
previous_cli_version: activation?.previous_version ?? null,
|
|
63
165
|
database_path: (0, db_1.dbFilePath)(),
|
|
64
166
|
skill_version: (0, skill_1.installedSkillVersion)(),
|
|
65
167
|
skill_path: (0, skill_1.skillFilePath)(),
|
|
@@ -72,7 +174,7 @@ function commandStatus(json) {
|
|
|
72
174
|
else {
|
|
73
175
|
const authLine = auth.authenticated
|
|
74
176
|
? `yes (via ${auth.source}, token ${auth.access_token ?? "pending refresh"}${auth.expires_at ? `, expires ${auth.expires_at}` : ""})`
|
|
75
|
-
: "no (run `dreams
|
|
177
|
+
: "no (run `dreams auth login`)";
|
|
76
178
|
console.log([
|
|
77
179
|
"Dreams status",
|
|
78
180
|
"",
|
|
@@ -80,6 +182,8 @@ function commandStatus(json) {
|
|
|
80
182
|
` Created at: ${status.installation_created_at}`,
|
|
81
183
|
` State: ${status.state}`,
|
|
82
184
|
` Durable CLI: ${status.cli_path}`,
|
|
185
|
+
` Active version: ${status.active_cli_version ?? "(not activated)"}`,
|
|
186
|
+
` Previous version:${status.previous_cli_version ? ` ${status.previous_cli_version}` : " (none)"}`,
|
|
83
187
|
` Skill installed: ${status.skill_version ? `v${status.skill_version} at ${status.skill_path}` : "no"}`,
|
|
84
188
|
` Authenticated: ${authLine}`,
|
|
85
189
|
` Database: ${status.database_path}`,
|
|
@@ -88,6 +192,23 @@ function commandStatus(json) {
|
|
|
88
192
|
}
|
|
89
193
|
return 0;
|
|
90
194
|
}
|
|
195
|
+
async function commandStatus(json) {
|
|
196
|
+
const lock = await (0, state_lock_1.waitForLocalStateLock)();
|
|
197
|
+
if (lock === null) {
|
|
198
|
+
const message = "Another Dreams command is using local state. Try again after it finishes.";
|
|
199
|
+
if (json)
|
|
200
|
+
console.log(JSON.stringify({ status: "error", code: "local_state_busy", message }));
|
|
201
|
+
else
|
|
202
|
+
process.stderr.write(message + "\n");
|
|
203
|
+
return 1;
|
|
204
|
+
}
|
|
205
|
+
try {
|
|
206
|
+
return commandStatusUnlocked(json);
|
|
207
|
+
}
|
|
208
|
+
finally {
|
|
209
|
+
(0, state_lock_1.releaseLocalStateLock)(lock);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
91
212
|
function commandAuth(subcommand, json) {
|
|
92
213
|
switch (subcommand) {
|
|
93
214
|
case "login":
|
|
@@ -101,6 +222,17 @@ function commandAuth(subcommand, json) {
|
|
|
101
222
|
return 1;
|
|
102
223
|
}
|
|
103
224
|
}
|
|
225
|
+
function commandDevelopment(positionals, confirmed, json) {
|
|
226
|
+
if (positionals[1] !== "reset") {
|
|
227
|
+
process.stderr.write(`Unknown dev subcommand: ${positionals[1] ?? "(none)"} — expected reset\n\n${USAGE}`);
|
|
228
|
+
return 1;
|
|
229
|
+
}
|
|
230
|
+
if (positionals.length > 3) {
|
|
231
|
+
process.stderr.write(`Unexpected argument(s): ${positionals.slice(3).join(", ")}\n\n${USAGE}`);
|
|
232
|
+
return 1;
|
|
233
|
+
}
|
|
234
|
+
return (0, development_reset_1.commandDevelopmentReset)(positionals[2], confirmed, json);
|
|
235
|
+
}
|
|
104
236
|
async function runCli() {
|
|
105
237
|
const args = parseArgs(process.argv.slice(2));
|
|
106
238
|
const command = args.positionals[0];
|
|
@@ -113,6 +245,26 @@ async function runCli() {
|
|
|
113
245
|
process.stdout.write(USAGE);
|
|
114
246
|
return args.help ? 0 : 1;
|
|
115
247
|
}
|
|
248
|
+
if (args.confirm && (command !== "dev" || subcommand !== "reset")) {
|
|
249
|
+
process.stderr.write(`--confirm is only valid with \`dreams dev reset\`\n\n${USAGE}`);
|
|
250
|
+
return 1;
|
|
251
|
+
}
|
|
252
|
+
if ((args.type || args.file || args.clientRequestId || args.workspaceId) && command !== "snapshots") {
|
|
253
|
+
process.stderr.write(`Snapshot options are only valid with \`dreams snapshots create\`\n\n${USAGE}`);
|
|
254
|
+
return 1;
|
|
255
|
+
}
|
|
256
|
+
if ((args.force || args.worker) && command !== "sync") {
|
|
257
|
+
process.stderr.write(`--force/--worker are only valid with \`dreams sync\`\n\n${USAGE}`);
|
|
258
|
+
return 1;
|
|
259
|
+
}
|
|
260
|
+
if (args.source && command !== "sync") {
|
|
261
|
+
process.stderr.write(`--source is only valid with \`dreams sync\`\n\n${USAGE}`);
|
|
262
|
+
return 1;
|
|
263
|
+
}
|
|
264
|
+
if (args.since && command !== "backfill") {
|
|
265
|
+
process.stderr.write(`--since is only valid with \`dreams backfill start\`\n\n${USAGE}`);
|
|
266
|
+
return 1;
|
|
267
|
+
}
|
|
116
268
|
if (args.unknown.length > 0) {
|
|
117
269
|
process.stderr.write(`Unknown argument(s): ${args.unknown.join(", ")}\n\n${USAGE}`);
|
|
118
270
|
return 1;
|
|
@@ -122,15 +274,52 @@ async function runCli() {
|
|
|
122
274
|
process.stderr.write(`Unexpected argument(s): ${args.positionals.slice(1).join(", ")}\n\n${USAGE}`);
|
|
123
275
|
return 1;
|
|
124
276
|
}
|
|
277
|
+
if (command === "snapshots" && args.positionals.length > 2) {
|
|
278
|
+
process.stderr.write(`Unexpected argument(s): ${args.positionals.slice(2).join(", ")}\n\n${USAGE}`);
|
|
279
|
+
return 1;
|
|
280
|
+
}
|
|
281
|
+
if (command === "sync" && args.positionals.length > 2) {
|
|
282
|
+
process.stderr.write(`Unexpected argument(s): ${args.positionals.slice(2).join(", ")}\n\n${USAGE}`);
|
|
283
|
+
return 1;
|
|
284
|
+
}
|
|
285
|
+
if (command === "backfill" && args.positionals.length > 2) {
|
|
286
|
+
process.stderr.write(`Unexpected argument(s): ${args.positionals.slice(2).join(", ")}\n\n${USAGE}`);
|
|
287
|
+
return 1;
|
|
288
|
+
}
|
|
125
289
|
switch (command) {
|
|
126
290
|
case "onboard":
|
|
127
291
|
return (0, onboard_1.commandOnboard)(args.json);
|
|
292
|
+
case "rollback":
|
|
293
|
+
return (0, launcher_1.commandRollback)(args.json);
|
|
128
294
|
case "status":
|
|
129
295
|
return commandStatus(args.json);
|
|
130
296
|
case "auth":
|
|
131
297
|
return commandAuth(subcommand, args.json);
|
|
298
|
+
case "dev":
|
|
299
|
+
return commandDevelopment(args.positionals, args.confirm, args.json);
|
|
132
300
|
case "source":
|
|
133
301
|
return (0, commands_2.commandSource)(subcommand, args.positionals[2], args.json);
|
|
302
|
+
case "snapshots":
|
|
303
|
+
return (0, snapshots_1.commandSnapshots)(subcommand, {
|
|
304
|
+
type: args.type,
|
|
305
|
+
file: args.file,
|
|
306
|
+
clientRequestId: args.clientRequestId,
|
|
307
|
+
workspaceId: args.workspaceId,
|
|
308
|
+
json: args.json,
|
|
309
|
+
});
|
|
310
|
+
case "sync":
|
|
311
|
+
return (0, sync_1.commandSync)(subcommand, {
|
|
312
|
+
json: args.json,
|
|
313
|
+
force: args.force,
|
|
314
|
+
worker: args.worker,
|
|
315
|
+
sourceType: args.source,
|
|
316
|
+
});
|
|
317
|
+
case "backfill":
|
|
318
|
+
if (subcommand !== "start") {
|
|
319
|
+
process.stderr.write(`Unknown backfill subcommand: ${subcommand ?? "(none)"} — expected start\n\n${USAGE}`);
|
|
320
|
+
return 1;
|
|
321
|
+
}
|
|
322
|
+
return (0, backfill_1.commandBackfillStart)({ since: args.since, json: args.json });
|
|
134
323
|
case "upload":
|
|
135
324
|
return (0, commands_2.commandUpload)(args.json);
|
|
136
325
|
default:
|
|
@@ -139,6 +328,7 @@ async function runCli() {
|
|
|
139
328
|
}
|
|
140
329
|
}
|
|
141
330
|
function main() {
|
|
331
|
+
(0, launcher_1.signalLauncherReady)();
|
|
142
332
|
runCli().then((code) => process.exit(code), (error) => {
|
|
143
333
|
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
144
334
|
process.exit(1);
|