@skrr-ai/cli 0.1.94 → 0.1.95

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.
Files changed (120) hide show
  1. package/README.md +153 -165
  2. package/bin/run.js +32 -0
  3. package/bin/update-npm-runner.cjs +33 -0
  4. package/bin/update-session.cjs +194 -0
  5. package/bin/update-worker.cjs +208 -0
  6. package/dist/base-command.js +0 -15
  7. package/dist/commands/code/doctor.d.ts +1 -0
  8. package/dist/commands/code/doctor.js +6 -0
  9. package/dist/commands/code/index.js +4 -0
  10. package/dist/commands/code/install.d.ts +5 -62
  11. package/dist/commands/code/install.js +86 -279
  12. package/dist/commands/code/rollback.d.ts +8 -0
  13. package/dist/commands/code/rollback.js +20 -0
  14. package/dist/commands/code/update.d.ts +8 -37
  15. package/dist/commands/code/update.js +134 -213
  16. package/dist/commands/daemon/install.js +4 -0
  17. package/dist/commands/generate-recovery-code.d.ts +13 -1
  18. package/dist/commands/generate-recovery-code.js +146 -13
  19. package/dist/commands/instructions/guide.d.ts +20 -0
  20. package/dist/commands/instructions/guide.js +84 -0
  21. package/dist/commands/instructions/install.js +57 -33
  22. package/dist/commands/instructions/setup.d.ts +14 -0
  23. package/dist/commands/instructions/setup.js +72 -0
  24. package/dist/commands/integrations/execute.js +1 -1
  25. package/dist/commands/login.d.ts +5 -6
  26. package/dist/commands/login.js +27 -11
  27. package/dist/commands/logout.js +7 -7
  28. package/dist/commands/security/overview.d.ts +11 -0
  29. package/dist/commands/security/overview.js +158 -0
  30. package/dist/commands/spaces/claim.d.ts +12 -0
  31. package/dist/commands/spaces/claim.js +42 -0
  32. package/dist/commands/spaces/ownership.d.ts +12 -0
  33. package/dist/commands/spaces/ownership.js +46 -0
  34. package/dist/commands/tasks/cancel-cascade.js +1 -1
  35. package/dist/commands/tasks/create-tree.d.ts +5 -1
  36. package/dist/commands/tasks/create-tree.js +35 -7
  37. package/dist/commands/tasks/interrupt.js +2 -2
  38. package/dist/commands/tasks/pause-schedule.js +1 -1
  39. package/dist/commands/token/list.d.ts +3 -5
  40. package/dist/commands/token/list.js +99 -57
  41. package/dist/commands/update.d.ts +14 -0
  42. package/dist/commands/update.js +61 -0
  43. package/dist/generated/managed-instruction-guides.json +9 -0
  44. package/dist/hooks/init.d.ts +5 -0
  45. package/dist/hooks/init.js +27 -0
  46. package/dist/lib/commitments.d.ts +0 -8
  47. package/dist/lib/commitments.js +0 -52
  48. package/dist/lib/daemon-installer.d.ts +2 -0
  49. package/dist/lib/daemon-installer.js +100 -24
  50. package/dist/lib/first-party-harness-doctor.js +31 -1
  51. package/dist/lib/first-party-harness-remote-install.d.ts +71 -0
  52. package/dist/lib/first-party-harness-remote-install.js +310 -0
  53. package/dist/lib/first-party-harness-remote-update.d.ts +46 -0
  54. package/dist/lib/first-party-harness-remote-update.js +242 -0
  55. package/dist/lib/first-party-harness-startup-update.d.ts +26 -0
  56. package/dist/lib/first-party-harness-startup-update.js +166 -0
  57. package/dist/lib/first-party-harness-update.d.ts +46 -0
  58. package/dist/lib/first-party-harness-update.js +289 -0
  59. package/dist/lib/first-party-harness.js +7 -4
  60. package/dist/lib/managed-instruction-local.d.ts +12 -0
  61. package/dist/lib/managed-instruction-local.js +58 -0
  62. package/dist/lib/managed-instruction-setup.d.ts +35 -0
  63. package/dist/lib/managed-instruction-setup.js +306 -0
  64. package/dist/lib/memory-sync.d.ts +1 -0
  65. package/dist/lib/memory-sync.js +279 -68
  66. package/dist/lib/platform-update-local.d.ts +2 -0
  67. package/dist/lib/platform-update-local.js +113 -0
  68. package/dist/lib/platform-update.d.ts +39 -0
  69. package/dist/lib/platform-update.js +84 -0
  70. package/dist/lib/profile-machine-identity-guard.d.ts +2 -0
  71. package/dist/lib/profile-machine-identity-guard.js +13 -0
  72. package/dist/lib/prompt.d.ts +1 -0
  73. package/dist/lib/prompt.js +4 -3
  74. package/dist/lib/task-batch.d.ts +9 -0
  75. package/dist/lib/task-batch.js +94 -17
  76. package/dist/lib/task-instruction-offer.d.ts +1 -4
  77. package/dist/lib/task-instruction-offer.js +3 -129
  78. package/dist/lib/update-check.d.ts +61 -53
  79. package/dist/lib/update-check.js +453 -314
  80. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessChannels.d.ts +3 -4
  81. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessChannels.js +3 -4
  82. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessReleaseKeys.d.ts +82 -0
  83. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessReleaseKeys.js +105 -0
  84. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessUpdater.d.ts +110 -0
  85. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessUpdater.js +945 -0
  86. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessPermissionControls.d.ts +32 -0
  87. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessPermissionControls.js +62 -0
  88. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +2 -0
  89. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +4 -1
  90. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.js +35 -5
  91. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releasePolicy.d.ts +63 -0
  92. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releasePolicy.js +169 -0
  93. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releaseVersions.d.ts +2 -0
  94. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releaseVersions.js +44 -0
  95. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessChannels.d.ts +3 -4
  96. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessChannels.js +3 -4
  97. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessReleaseKeys.d.ts +82 -0
  98. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessReleaseKeys.js +102 -0
  99. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessUpdater.d.ts +110 -0
  100. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessUpdater.js +923 -0
  101. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessPermissionControls.d.ts +32 -0
  102. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessPermissionControls.js +59 -0
  103. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +2 -0
  104. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +2 -0
  105. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.js +35 -5
  106. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releasePolicy.d.ts +63 -0
  107. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releasePolicy.js +163 -0
  108. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releaseVersions.d.ts +2 -0
  109. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releaseVersions.js +41 -0
  110. package/dist/node_modules/@skrr-ai/auth-core/package.json +31 -1
  111. package/dist/node_modules/@skrr-ai/data-provider/index.js +6584 -6567
  112. package/docs/v1/README.md +28 -0
  113. package/docs/v1/api.md +55 -0
  114. package/docs/v1/changelog.md +16 -0
  115. package/docs/v1/check-examples.mjs +178 -0
  116. package/docs/v1/examples/api-readonly.mjs +144 -0
  117. package/docs/v1/operations.md +87 -0
  118. package/docs/v1/quickstart.md +71 -0
  119. package/oclif.manifest.json +46007 -45462
  120. package/package.json +13 -11
package/README.md CHANGED
@@ -2,6 +2,83 @@
2
2
 
3
3
  Command-line interface for OverSky, wrapping the `@skrr-ai/data-provider` client.
4
4
 
5
+
6
+ ## Start here
7
+
8
+ The supported executable is `skrr`. These [versioned developer guides](docs/v1/README.md) are included with the npm package; they do not require access to the private source repository. This guide set was checked against CLI **0.1.95** source on **2026-10-10**. Run `skrr --version` to identify your installed artifact; source availability is not evidence of a published release.
9
+
10
+ ```bash
11
+ npm install -g @skrr-ai/cli
12
+ skrr --version
13
+ skrr login --base-url https://skrr.ai
14
+ skrr whoami
15
+ skrr spaces list --json
16
+ ```
17
+
18
+ `login` first tries a signed-in local daemon, then browser PKCE, then a device code when the callback cannot run. With SSH or no local browser, use `skrr login --device-code`; approve it in a browser on another device. Password, MFA, passkey and configured federation challenges remain on the web sign-in page. The CLI has no password flag.
19
+
20
+ To create your first Task in an existing Space, copy its ID from `spaces list` and run:
21
+
22
+ ```bash
23
+ skrr tasks create --space <space-id> --title "My first CLI task" --execution-mode human --external-key onboarding/first-task --json
24
+ ```
25
+
26
+ This creates a Task; it does not start an agent run. Use a Space whose automation is disabled if you are exploring. See the [quickstart](docs/v1/quickstart.md) for scope selection and safe retries, the [public API guide](docs/v1/api.md) for a read-only first API call, and [operations and recovery](docs/v1/operations.md) for credentials, errors, request IDs, quotas and upgrades. `skrr code` runs a coding agent in the current repository and can incur model/compute usage; run it only after choosing that execution context.
27
+
28
+ After installing the CLI, run `skrr login`. On an interactive sign-in, skrr can help set up
29
+ removable managed instructions for the coding agents on your computer. You select each
30
+ provider and choose automatic updates or a fixed current version; installing the CLI alone
31
+ does not change agent instruction files.
32
+
33
+ Run `skrr instructions setup` at any time to revisit provider choices. The setup verifies
34
+ the local daemon's account, server and profile, then previews the real file paths and checks
35
+ whether the agent can read them. Use `--provider codex --review` to inspect the exact content
36
+ without installing. To choose a different machine explicitly, pass `--daemon <id>`.
37
+
38
+ Automation never prompts. For an explicit installation, use
39
+ `skrr instructions setup --provider codex --update-policy latest --yes --json`.
40
+ Use `--update-policy pinned` to keep the current version, or `--review --json` to get a
41
+ read-only preflight. `skrr instructions status` confirms application by the daemon.
42
+ `skrr instructions guide task-management` loads the detailed workflow on demand.
43
+ It works offline and without sign-in, using a canonical guide generated into the CLI release.
44
+
45
+ ## Local updates
46
+
47
+ These commands work without a cloud login or connected daemon:
48
+
49
+ ```bash
50
+ skrr update --check # CLI, Code and daemon offered versions
51
+ skrr update --status --json # local versions and recorded results; no network
52
+ skrr update # update installed components through their owners
53
+ skrr update --component daemon --restart
54
+ skrr code install # install the signed local Code engine
55
+ skrr code update # update it; existing sessions keep their release
56
+ skrr code update --check
57
+ skrr code rollback # restore the previous verified release
58
+ skrr code update --startup-checks off
59
+ skrr code update --startup-checks on
60
+ ```
61
+
62
+ Interactive `skrr code` sessions offer **Update and start**, **Skip once**,
63
+ **Skip this version** and **Disable startup checks** when a newer signed release is available. ACP, scripts,
64
+ JSON output, help and noninteractive launches do not display that prompt.
65
+ `SKRR_CODE_UPDATE_CHECK=0` disables startup checks; explicit update commands remain
66
+ available. Use `--daemon <id>` with `code install` or `code update` to target a
67
+ remote machine instead; that path uses account authentication.
68
+
69
+ The CLI automatically queues updates for private, writable, user-owned npm global
70
+ installations and waits for active CLI invocations to finish. Set
71
+ `OVERSKY_CLI_AUTO_UPDATE=0` to keep discovery while disabling automatic application.
72
+ Shared prefixes, Windows npm installations, project dependencies, source checkouts,
73
+ app bundles and runtime images show their owner's update command. Daemon automatic
74
+ updates require an eligible supervised installation with its update monitor enabled;
75
+ the unified status reports the live daemon's recorded posture.
76
+
77
+ Code and daemon rollback obey retained signed minimum versions. Unsigned or tampered
78
+ rollback artifacts cannot be used as verified releases. See the
79
+ [update lifecycle design](../docs/architecture/component-update-lifecycle-2026-10-10.md)
80
+ and the [release runbook](../docs/runbooks/cli-daemon-release.md) for storage and rollout.
81
+
5
82
  ## Status
6
83
 
7
84
  **Comprehensive CRUD + workflow surface across the OverSky public API.**
@@ -38,7 +115,7 @@ observability), and shared links.
38
115
  | **spaces widgets** | `list`, `add`, `remove` |
39
116
  | **spaces skills** | `list`, `add`, `remove`, `pin` |
40
117
  | **spaces labels** | `list`, `add`, `remove` (attach/detach; filter with `spaces list --label`) |
41
- | **labels** | `list`, `palette`, `create`, `update`, `archive`, `restore`, `delete`, `reorder` (unified labels across `user` and `workspace` scopes) |
118
+ | **labels** | `list`, `palette`, `create`, `update`, `archive`, `restore`, `delete`, `reorder` (unified labels across `user` and `workspace` scopes) |
42
119
  | **chats triggers** | `show`, `set` |
43
120
  | **dm** | `list`, `show`, `messages`, `threads`, `thread show/messages/follow/mute/share`, `send` (agent 1:1 main chat and Slack-style Thread controls) |
44
121
  | **diagnostics** | `context`, `doctor`, `usage`, `commands` (agent-friendly runtime identity, readiness, progressive token-budgeted discovery, and complete machine-readable schemas) |
@@ -53,7 +130,7 @@ observability), and shared links.
53
130
  | **tasks result** | `submit`, `show` (immutable Result versions and exact Review state) |
54
131
  | **tasks resource** | `add`, `list` (versioned inputs, references, evidence, attachments, and Deliverables) |
55
132
  | **tasks deliverable** | `add`, `list`, `confirm` (the user-facing produced-Resource workflow) |
56
- | **tasks labels** | `list`, `create`, `delete`, `attach`, `detach`, `suggest` (label vocabulary + per-task attachment; `suggest` asks the model to pick from the declared vocabulary, advisory only) |
133
+ | **tasks labels** | `list`, `create`, `delete`, `attach`, `detach`, `suggest` (label vocabulary + per-task attachment; `suggest` asks the model to pick from the declared vocabulary, advisory only) |
57
134
  | **tasks approvals** | `list`, `create`, `delete`, `resolve` |
58
135
  | **tasks attachments** | `list`, `delete`, `upload`, `download` |
59
136
  | **integrations** | `toolkits`, `search`, `execute`, `tools list`, `tools allow`, `connections connect`, `connections list`, `connections finalize`, `connections disconnect`, `connections reconnect` |
@@ -66,27 +143,27 @@ observability), and shared links.
66
143
  Recent conversations, optionally scoped to one agent, then the transcript:
67
144
 
68
145
  ```bash
69
- sky convos list --limit 10 # id, title, agent, updated
70
- sky convos list --agent <agent-id> # server-side agent scope
71
- sky convos list --search "login bug" --json # Meilisearch-backed
72
- sky messages list -c <convo-id> --limit 20 # newest 20 (default: whole transcript)
73
- sky messages show <convo-id> <message-id> # one message, full body
146
+ skrr convos list --limit 10 # id, title, agent, updated
147
+ skrr convos list --agent <agent-id> # server-side agent scope
148
+ skrr convos list --search "login bug" --json # Meilisearch-backed
149
+ skrr messages list -c <convo-id> --limit 20 # newest 20 (default: whole transcript)
150
+ skrr messages show <convo-id> <message-id> # one message, full body
74
151
  ```
75
152
 
76
153
  Tasks, and what the agent actually produced:
77
154
 
78
155
  ```bash
79
- sky tasks list --assignee-agent <agent-id> # what this agent is working on
80
- sky tasks show <task-id> # includes the Convo: pointer
81
- sky tasks result show <task-id> # current Result + exact Review
82
- sky tasks transcript <task-id> --assistant-only # full agent transcript, no prompt
83
- sky tasks comments list <task-id> # raw comment thread
156
+ skrr tasks list --assignee-agent <agent-id> # what this agent is working on
157
+ skrr tasks show <task-id> # includes the Convo: pointer
158
+ skrr tasks result show <task-id> # current Result + exact Review
159
+ skrr tasks transcript <task-id> --assistant-only # full agent transcript, no prompt
160
+ skrr tasks comments list <task-id> # raw comment thread
84
161
  ```
85
162
 
86
163
  One agent's recent work across all three surfaces:
87
164
 
88
165
  ```bash
89
- sky agents activity <agent-id> --limit 10 # merged DM + conversations + tasks feed
166
+ skrr agents activity <agent-id> --limit 10 # merged DM + conversations + tasks feed
90
167
  ```
91
168
 
92
169
  `--agent` / `agents activity` need a server that implements `?agentId=` on
@@ -96,7 +173,7 @@ conversations, and `agents activity` filters locally with a printed caveat.
96
173
 
97
174
  ### Production CLI Contract
98
175
 
99
- Sky CLI is designed for both humans and daemon agents. New commands should
176
+ skrr CLI is designed for both humans and daemon agents. New commands should
100
177
  preserve these contracts:
101
178
 
102
179
  - Positional args never read from stdin implicitly. Every `Args.string` must
@@ -107,21 +184,21 @@ preserve these contracts:
107
184
  in JSON mode.
108
185
  - Commands that accept `--from-json` also expose `--json`; typed flags override
109
186
  JSON fields on conflict.
110
- - Agent runtime scripts start with `sky context --json`, then `sky usage --json`.
187
+ - Agent runtime scripts start with `skrr context --json`, then `skrr usage --json`.
111
188
  It is the recommended command-discovery bootstrap: the overview is generated
112
189
  from the oclif manifest and stays within a small token budget. Read exactly
113
- the relevant reference next with `sky usage tasks --json` (or the convenient
114
- `sky tasks usage --json` form), then use `sky commands --schema "tasks list"`
190
+ the relevant reference next with `skrr usage tasks --json` (or the convenient
191
+ `skrr tasks usage --json` form), then use `skrr commands --schema "tasks list"`
115
192
  only when the selected command needs its complete flag contract. Use
116
- `sky doctor --json` for auth/build readiness and `sky commands --audit --json`
193
+ `skrr doctor --json` for auth/build readiness and `skrr commands --audit --json`
117
194
  for command-surface hygiene.
118
195
  - Side-effecting commands use explicit idempotency keys only when the caller
119
196
  owns retry coordination. Daemon session commands derive stable defaults when
120
- possible, such as `sky agent message send --text "..."`.
197
+ possible, such as `skrr agent message send --text "..."`.
121
198
 
122
199
  ### Agent-initiated app voice calls
123
200
 
124
- `sky agent call` is a session-only consent flow, not a phone dialer. It reads
201
+ `skrr agent call` is a session-only consent flow, not a phone dialer. It reads
125
202
  the Agent identity and owner target from `OVERSKY_SESSION_TOKEN`,
126
203
  `OVERSKY_SESSION_ID`, and `OVERSKY_SESSION_AGENT_ID`; no flag or JSON field can
127
204
  select another person. The user receives an in-app/push invitation and must
@@ -129,14 +206,14 @@ accept it before the normal LiveKit call is created.
129
206
 
130
207
  ```bash
131
208
  # From an autonomous daemon session
132
- sky agent call request \
209
+ skrr agent call request \
133
210
  --reason "The production rollback decision needs you." \
134
211
  --conversation <conversation-id> \
135
212
  --expires-in 120 \
136
213
  --json
137
214
 
138
- sky agent call show <call-id> --json
139
- sky agent call cancel <call-id> --json
215
+ skrr agent call show <call-id> --json
216
+ skrr agent call cancel <call-id> --json
140
217
  ```
141
218
 
142
219
  The request is idempotent. With no explicit `--idempotency-key`, Sky derives a
@@ -152,12 +229,12 @@ default Sky CLI capability.
152
229
  Run the hygiene audit before publishing CLI changes:
153
230
 
154
231
  ```bash
155
- sky commands --audit --json
232
+ skrr commands --audit --json
156
233
  ```
157
234
 
158
235
  ### PSTN phone calls (Phase 2)
159
236
 
160
- `sky agent phone-call request --purpose "…"` is an explicit, autonomous-
237
+ `skrr agent phone-call request --purpose "…"` is an explicit, autonomous-
161
238
  session-only command. It does not accept a phone number, carrier setting,
162
239
  caller ID, or recording option; the server derives the owner and agent and
163
240
  uses only that owner's verified endpoint plus active, renewable consent.
@@ -179,9 +256,8 @@ or intentionally not exposed as request/response APIs:
179
256
  has no SSE/WebSocket adapter — the node-adapter is pure request/response.
180
257
  Chat streaming would need a separate client layer (Socket.io client + event
181
258
  plumbing). This does not include persistent main-chat DM sends; use
182
- `sky agent message send --text "..." --json` for that agent-facing path.
183
- - **2FA / OAuth / SAML / LDAP sign-in**: `sky login` exits code 6 on
184
- `twoFAPending`. The server supports these; the CLI does not.
259
+ `skrr agent message send --text "..." --json` for that agent-facing path.
260
+ - **Authentication**: browser/device-code sign-in delegates configured MFA, passkey and federation to the web sign-in page. There is no CLI password flow. See [authentication and revocation](docs/v1/operations.md#authentication-and-revocation).
185
261
  - **Message delete**: `DELETE /api/messages/:convoId/:messageId` — server
186
262
  only.
187
263
  - **Tests**: the CLI has focused Jest coverage, but broader command/API
@@ -193,13 +269,15 @@ or intentionally not exposed as request/response APIs:
193
269
  ## Prerequisites
194
270
 
195
271
  - Node.js 20+
196
- - A running OverSky API (default target: `http://localhost:3080`)
272
+ - An account on your deployment (default: `https://skrr.ai`; `--env local` selects the configured local API)
197
273
  - `@skrr-ai/data-provider` must be built — it's a workspace dep and the CLI
198
274
  imports from its `dist/`
199
275
 
200
276
  ## Install
201
277
 
202
- From the repo root (the CLI is a workspace, so there's no separate install):
278
+ For end users: `npm install -g @skrr-ai/cli`. The package vendors its private workspace dependencies.
279
+
280
+ For contributors with a checkout, build from the repository root:
203
281
 
204
282
  ```bash
205
283
  # 1. Install workspace deps (picks up cli/ because it was added to the root
@@ -228,8 +306,8 @@ From `cli/`:
228
306
  Or globally, after `npm link` from `cli/`:
229
307
 
230
308
  ```bash
231
- sky login
232
- sky convos list --json
309
+ skrr login
310
+ skrr convos list --json
233
311
  ```
234
312
 
235
313
  ## GitHub tools from local runtimes
@@ -348,142 +426,48 @@ to `dist/` and the next invocation picks up the change.
348
426
 
349
427
  ## Commands
350
428
 
351
- ### `sky login`
352
-
353
- Sign in to an OverSky instance.
354
-
355
- **You probably don't need to run this at all.** If the local `oversky`
356
- daemon is authenticated, every `sky` command silently auto-brokers a
357
- sibling cli-scope token on first use — no `sky login`, no browser, no
358
- device code, no user interaction whatsoever. See
359
- [Auto-broker on first use](#auto-broker-on-first-use) below.
360
-
361
- **When `sky login` is still useful:**
429
+ ### `skrr login`
362
430
 
363
- - You want to log in to a DIFFERENT account than the daemon
364
- - You want to log in to a DIFFERENT server (`--base-url <url>`)
365
- - The daemon isn't installed / isn't running, and you want sky alone
366
- - You want to force a re-authentication (e.g. revoked refresh family)
367
-
368
- **Behavior when invoked explicitly:**
369
-
370
- - If the daemon is authed for the same server, `sky login` brokers the
371
- handoff (still no browser).
372
- - If the daemon is not running or not authed, the CLI runs its own
373
- PKCE-localhost OAuth flow (popping your browser); device-code is the
374
- secondary fallback (SSH, port-bind failure, `--device-code`).
431
+ Sign in to a deployment and profile. The order is a local daemon broker, browser PKCE with a localhost callback, then device code when the browser callback cannot run. `--device-code` skips both the broker and callback. A declined sign-in is not automatically retried through a different flow.
375
432
 
376
433
  ```bash
377
- sky login
378
- sky login --base-url https://oversky.ai
379
- sky login --device-code # skip broker + PKCE; use device-code directly
434
+ skrr login --base-url https://skrr.ai
435
+ skrr login --device-code
436
+ skrr login --profile reviewer --env dev
380
437
  ```
381
438
 
382
- On first run, pass `--base-url` to target your API host. It is saved to
383
- `~/.sky/config.json` and reused until you override it again.
384
-
385
- Flags:
439
+ Configuration lives in `~/.skrr/cli-config.json`, or `~/.skrr/profiles/<name>/cli-config.json`. `SKRR_CONFIG_DIR` / `OVERSKY_CONFIG_DIR` can set a different root. Credentials live in the macOS Keychain or `cli-auth.json` (0600), not the legacy `~/.sky/config.json`; that path is read only for migration. Sessions are bound to their issuing server.
386
440
 
387
- - `-u, --base-url <url>` — API base URL to save and use
388
- - `--device-code` — force the device-code flow (also skips the
389
- daemon broker pre-flight)
390
- - `--port <n>` — pin the localhost callback port (PKCE flow)
391
- - `--scope <cli|daemon>` — token scope (default `cli`)
392
- - `--recovery-code <code>` — non-interactive sign-in with a printable
393
- recovery code
441
+ The web sign-in page handles password, two-factor, passkey and configured federation. The CLI never receives the password. `--recovery-code` redeems a printable recovery code; it can still require a confirmation step and is not an unattended CI credential. For a saved refresh family use `OVERSKY_REFRESH_TOKEN` with its matching `OVERSKY_CLI_ID`; a successful restore rotates the token, so do not reuse a bundle across machines or jobs.
394
442
 
395
- Env overrides:
396
-
397
- - `OVERSKY_SKIP_DAEMON_BROKER=1` — disable the broker pre-flight
398
- - `OVERSKY_FORCE_DEVICE_CODE=1` — same as `--device-code`
399
- - `OVERSKY_REFRESH_TOKEN=...` + `OVERSKY_CLI_ID=...` — non-interactive
400
- restore from a backed-up refresh token
401
-
402
- 2FA, OAuth, SAML, and LDAP are not yet supported via the interactive
403
- PKCE / device-code flows. (The recovery-code path is unaffected.)
443
+ `OVERSKY_SKIP_DAEMON_BROKER=1` skips the broker. `SKRR_SKIP_DAEMON_HANDOFF=1` skips the optional post-login daemon setup. They control different steps. Login does not require installing the daemon for workspace/API management.
404
444
 
405
445
  ### Auto-broker on first use
406
446
 
407
- Every `sky` command (except `login`, `logout`,
408
- `generate-recovery-code`) runs the daemon-broker handoff transparently
409
- when no token is in the keychain. So:
410
-
411
- ```bash
412
- oversky login # authenticate the daemon, once
413
- sky tasks list # silently auto-brokers, persists, runs
414
- sky tasks list --json # uses the persisted token, no broker call
415
- sky whoami # confirms identity from the persisted token
416
- ```
417
-
418
- There is no opt-in flag. The mechanism is the long-term default.
419
-
420
- **Skip rules** — auto-broker does NOT fire when any of these hold:
447
+ A human command with no stored session may adopt a durable CLI family through a signed-in daemon on the same deployment. It is stored and renews independently, so a daemon restart does not sign out the CLI. Revoking that daemon also revokes the families delegated through it. If durable adoption is unavailable, the command can borrow a short-lived token for that invocation.
421
448
 
422
- - `--bare` flag is set (operator opted out of keychain/file persistence)
423
- - `OVERSKY_TOKEN` or `OVERSKY_REFRESH_TOKEN` env vars are set (operator
424
- controls auth out-of-band — CI runners, ephemeral containers)
425
- - `OVERSKY_SKIP_DAEMON_BROKER=1` (explicit escape hatch for debugging
426
- or testing the PKCE flow itself)
427
- - The command is one of `login`, `logout`,
428
- `generate-recovery-code` — these manage their own auth lifecycle
449
+ `--bare`, injected `OVERSKY_TOKEN` / `SKRR_TOKEN` / `OVERSKY_REFRESH_TOKEN`, and `OVERSKY_SKIP_DAEMON_BROKER=1` disable automatic brokering. `SKRR_NO_CLI_SESSION_ADOPTION=1` disables durable adoption. Agent/tool children only borrow and never read or persist the person's session. Their login/logout commands are refused.
429
450
 
430
- **Failure handling.** If the broker can't reach the daemon, can't read
431
- its bootstrap file, or the daemon isn't authenticated, the auto-broker
432
- fails quietly and the command's normal `requireAuth()` produces the
433
- familiar "Not signed in. Run `sky login` first." error. The one case
434
- that gets a louder hint is baseURL mismatch, since the fix is precise:
435
-
436
- ```
437
- [sky] Local oversky daemon is logged in to http://localhost:3080, but sky
438
- is configured for https://oversky.ai. Run `sky login --base-url http://localhost:3080`
439
- to use the daemon.
440
- Not signed in. Run `sky login` first.
441
- ```
451
+ After `skrr logout`, durable adoption remains off until explicit login, although the daemon can still lend a short-lived token. On a Dedicated Runtime, the platform-managed hand-off can continue providing access after the person's own local credential is cleared.
442
452
 
443
- ### Daemon-as-broker handoff
444
-
445
- Mechanism for "logged-in daemon implies logged-in sky":
446
-
447
- 1. `sky login` reads the daemon's bootstrap file:
448
- - macOS: `~/Library/Application Support/OverSky/daemon-island.<profile>.json`
449
- - Linux/Windows: `~/.oversky/profiles/<profile>/daemon-island.json`
450
- (pre-Phase-K fallback: `~/.oversky/daemon-island.json`)
451
- 2. CLI POSTs to `http://127.0.0.1:<port>/v1/auth/cli-handoff` with the
452
- bootstrap secret as `Authorization: Bearer ...` and the requested
453
- cliId in the body.
454
- 3. Daemon's loopback handler (`daemon/src/auth/cliHandoff.ts`) forwards
455
- to the server's `POST /api/daemons/cli-handoff` using the daemon's
456
- own bearer as proof of "this user is already authenticated here".
457
- 4. Server mints a **fresh cli-scope refresh family** (independent
458
- rotation, distinct revocation, blast-radius isolated from the
459
- daemon) bound to the supplied cliId.
460
- 5. CLI persists via the canonical `writeToBackend()` — Keychain on
461
- macOS, `cli-auth.json` elsewhere.
462
-
463
- Trust model is the same same-UID loopback fence the Socket.IO server
464
- uses: any attacker who can read the 0600 bootstrap file can already
465
- read the daemon's keychain. CI tokens are refused at the server
466
- (daemon bootstrapped from `osk_ci_*` cannot auto-elevate to CLI).
467
-
468
- ### `sky logout`
469
-
470
- Sign out and clear the saved token. The `baseURL` is preserved so the next
471
- `sky login` defaults to the same host.
453
+ ### `skrr logout`
472
454
 
473
455
  ```bash
474
- sky logout
456
+ skrr logout
457
+ skrr logout --all-devices
475
458
  ```
476
459
 
477
- The server-side logout call is best-effort — if the network is down, the
478
- local token is still cleared.
460
+ The first command revokes this CLI refresh family best-effort and clears its local Keychain/file credential. It keeps the server, CLI identity and daemon's separate sign-in. The second also enumerates and revokes registered daemon resources, including their delegated CLI families. Independent CLI families created by browser/device code on other machines, and personal access tokens, require their own session/token revocation controls; this flag does not promise account-wide revocation of every credential type. If remote revocation fails, local cleanup still runs and the CLI reports the incomplete sweep.
461
+
462
+ For CI, use expiring `osk_pat_*` personal access tokens through `SKRR_TOKEN`. `osk_ci_*` tokens only bootstrap a daemon. Space-scoped `osk_live_*` / `osk_test_*` keys authenticate the public `/v1` API, a different API from the workspace CLI's `/api` routes. See [operations and recovery](docs/v1/operations.md).
479
463
 
480
- ### `sky whoami`
464
+ ### `skrr whoami`
481
465
 
482
466
  Show the currently signed-in user.
483
467
 
484
468
  ```bash
485
- sky whoami
486
- sky whoami --json
469
+ skrr whoami
470
+ skrr whoami --json
487
471
  ```
488
472
 
489
473
  ### `sky convos list`
@@ -892,6 +876,17 @@ sky spaces unarchive <space-id>
892
876
  sky spaces archive <space-id> --json
893
877
  ```
894
878
 
879
+ ### `sky spaces claim <id>`
880
+
881
+ An eligible editor can claim an ownerless Space. The longest-standing editor
882
+ can claim immediately; any editor can claim after seven days. The server
883
+ enforces eligibility at claim time.
884
+
885
+ ```bash
886
+ sky spaces claim <space-id>
887
+ sky spaces claim OSK-S-12 --json
888
+ ```
889
+
895
890
  ### `sky spaces` — subspaces (parent / child hierarchy)
896
891
 
897
892
  Spaces form a tree. Each space tracks `parentSpaceId`, the materialized
@@ -1908,25 +1903,20 @@ delete commands refuse to prompt and exit with code 7 unless `--yes` is
1908
1903
  passed. This prevents the CLI from hanging forever waiting on input that
1909
1904
  will never arrive.
1910
1905
 
1911
- ## Config file
1906
+ ## Configuration and credentials
1912
1907
 
1913
- Credentials and host state live at `~/.sky/config.json`. The directory is
1914
- created with mode `0700` and the file with mode `0600`, so it's readable only
1915
- by your user account.
1908
+ The active config root is `~/.skrr`, with `cli-config.json` for the default profile and `profiles/<name>/cli-config.json` for a named profile. `SKRR_CONFIG_DIR` (preferred) / `OVERSKY_CONFIG_DIR` can override it. The legacy `~/.sky/config.json` is read only as a migration input.
1916
1909
 
1917
- | Field | Description |
1918
- | -------------- | ------------------------------------------------------------ |
1919
- | `baseURL` | API host (e.g. `https://oversky.ai`) |
1920
- | `token` | JWT bearer token from `/api/auth/login` |
1921
- | `refreshToken` | Refresh token for silent rotation (if the server issued one) |
1922
- | `userId` | Signed-in user ID |
1923
- | `email` | Signed-in user email, cached for display |
1910
+ | Field | Description |
1911
+ | --- | --- |
1912
+ | `baseURL` | Issuing deployment, e.g. `https://skrr.ai` |
1913
+ | `cliId` / `profileCliId` | Machine/profile identity used to bind refresh sessions |
1914
+ | `credentials.store` | Credential backend posture, such as automatic Keychain/file or env-only |
1915
+ | `adoptDaemonSession` | Whether human commands may durably adopt a session through the daemon |
1924
1916
 
1925
- Delete the file to fully reset CLI state:
1917
+ Session secrets live in the macOS Keychain or profile-local `cli-auth.json` (0600), not normal config fields. Environment/flag/helper credentials outrank stored sessions and do not refresh. Agent children never read the person's stored session. Use `skrr whoami` to inspect the actual source.
1926
1918
 
1927
- ```bash
1928
- rm ~/.sky/config.json
1929
- ```
1919
+ Use `skrr logout` to revoke and clear the local CLI session, and explicit session/token management for broader revocation. Deleting a legacy config file does not clear Keychain credentials, revoke a remote family, or stop daemon-provided access. See [authentication and revocation](docs/v1/operations.md#authentication-and-revocation).
1930
1920
 
1931
1921
  ## Architecture notes
1932
1922
 
@@ -1935,11 +1925,9 @@ code is a Node-native HttpAdapter that satisfies the `HttpAdapter` interface
1935
1925
  the data-provider exposes for non-browser consumers.
1936
1926
 
1937
1927
  - **`src/base-command.ts`** — every command extends `BaseCommand`, which in
1938
- `init()` loads `~/.sky/config.json`, calls `setBaseURL()` and
1939
- `setHttpAdapter()` on the data-provider, and exposes `requireAuth()` and
1940
- `handleApiError()` for subclasses.
1928
+ `init()` loads profile configuration, resolves the effective credential, calls `setBaseURL()` and `setHttpAdapter()` on the data-provider, and exposes `requireAuth()` and `handleApiError()` for subclasses.
1941
1929
  - **`src/lib/node-adapter.ts`** — implements `HttpAdapter` using Node 20's
1942
- global `fetch`. Injects the bearer token from disk on every request,
1930
+ global `fetch`. Injects the resolved credential on every request,
1943
1931
  transparently handles 401 → refresh → retry (mirroring the browser
1944
1932
  interceptor minus the `window.location` redirect), and surfaces server
1945
1933
  errors as `Error` instances with `status` and `body` properties.
package/bin/run.js CHANGED
@@ -13,6 +13,38 @@ try {
13
13
 
14
14
  const path = require('node:path');
15
15
  const { spawnSync } = require('node:child_process');
16
+
17
+ // Enter the installation's session gate before loading any package modules.
18
+ // The copy outside node_modules remains available while npm replaces files.
19
+ // npm still owns the executable itself; its one-time initial migration and
20
+ // clients from older releases cannot participate in this cooperative gate.
21
+ try {
22
+ const fs = require('node:fs');
23
+ const os = require('node:os');
24
+ const crypto = require('node:crypto');
25
+ const packageRoot = path.resolve(__dirname, '..');
26
+ const key = crypto.createHash('sha256').update(packageRoot).digest('hex').slice(0, 24);
27
+ const runtimeDirectory = path.join(os.homedir(), '.skrr', 'cli-update-runtime', key);
28
+ const bootstrap = path.join(runtimeDirectory, 'bootstrap-v1.cjs');
29
+ if (!fs.existsSync(bootstrap)) {
30
+ fs.mkdirSync(runtimeDirectory, { recursive: true, mode: 0o700 });
31
+ const temporary = `${bootstrap}.${process.pid}.tmp`;
32
+ fs.copyFileSync(path.join(__dirname, 'update-session.cjs'), temporary);
33
+ fs.chmodSync(temporary, 0o600);
34
+ fs.renameSync(temporary, bootstrap);
35
+ }
36
+ require(bootstrap).registerSession(packageRoot);
37
+ process.env.SKRR_CLI_UPDATE_SESSION_REGISTERED = String(process.pid);
38
+ } catch (error) {
39
+ if (error && error.code === 'CLI_UPDATE_BUSY') {
40
+ console.error(`[skrr] ${error.message}`);
41
+ process.exit(75);
42
+ }
43
+ // Failure to record a session disables the automatic updater in this
44
+ // invocation. A read-only home must not break ordinary CLI commands.
45
+ process.env.SKRR_CLI_UPDATE_SESSION_UNAVAILABLE = '1';
46
+ }
47
+
16
48
  const { findAlternateCli, missingLocalCommandBuild } = require('./dev-fallback');
17
49
 
18
50
  /**
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ // Park before npm executes. The parent publishes this process group's durable
4
+ // mutation ownership before authorizing execution, closing its crash window.
5
+ const fs = require('node:fs');
6
+ const { spawn } = require('node:child_process');
7
+ const requestFile = process.argv[2];
8
+ const request = JSON.parse(fs.readFileSync(requestFile, 'utf8'));
9
+ const deadline = Date.now() + 30000;
10
+ const timer = setInterval(() => {
11
+ let authorization;
12
+ try {
13
+ authorization = JSON.parse(fs.readFileSync(`${requestFile}.go`, 'utf8'));
14
+ } catch {
15
+ /* still parked */
16
+ }
17
+ if (authorization?.pid === process.pid && authorization?.token === request.token) {
18
+ clearInterval(timer);
19
+ const child = spawn(request.npmPath, ['install', '-g', `@skrr-ai/cli@${request.version}`], {
20
+ stdio: 'inherit',
21
+ shell: process.platform === 'win32',
22
+ });
23
+ child.once('error', () => {
24
+ process.exitCode = 1;
25
+ });
26
+ child.once('exit', (code) => {
27
+ process.exitCode = code ?? 1;
28
+ });
29
+ } else if (Date.now() >= deadline) {
30
+ clearInterval(timer);
31
+ process.exitCode = 1;
32
+ }
33
+ }, 20);