@skrr-ai/cli 0.1.8 → 0.1.10

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 (170) hide show
  1. package/dist/base-command.d.ts +27 -0
  2. package/dist/base-command.js +83 -11
  3. package/dist/commands/agent/message/send.js +1 -1
  4. package/dist/commands/agents/chat.d.ts +1 -1
  5. package/dist/commands/agents/chat.js +1 -1
  6. package/dist/commands/browser/install.d.ts +1 -1
  7. package/dist/commands/browser/install.js +10 -2
  8. package/dist/commands/browser/mcp-config.js +3 -1
  9. package/dist/commands/browser/skill/show.js +1 -1
  10. package/dist/commands/browser/status.js +4 -1
  11. package/dist/commands/browser/uninstall.d.ts +1 -1
  12. package/dist/commands/browser/uninstall.js +10 -2
  13. package/dist/commands/browser.d.ts +1 -1
  14. package/dist/commands/browser.js +3 -3
  15. package/dist/commands/code/index.js +6 -3
  16. package/dist/commands/code/install.d.ts +61 -0
  17. package/dist/commands/code/install.js +247 -0
  18. package/dist/commands/code/oversky-agent.d.ts +2 -1
  19. package/dist/commands/code/oversky-agent.js +12 -8
  20. package/dist/commands/commands.js +1 -1
  21. package/dist/commands/context.js +1 -1
  22. package/dist/commands/create-token.js +1 -1
  23. package/dist/commands/daemon/byok.d.ts +1 -0
  24. package/dist/commands/daemon/byok.js +14 -1
  25. package/dist/commands/daemon/index.js +18 -7
  26. package/dist/commands/daemon/install.d.ts +1 -0
  27. package/dist/commands/daemon/install.js +22 -3
  28. package/dist/commands/daemon/logs.d.ts +1 -0
  29. package/dist/commands/daemon/logs.js +4 -0
  30. package/dist/commands/daemon/start.d.ts +1 -0
  31. package/dist/commands/daemon/start.js +15 -2
  32. package/dist/commands/daemon/status.d.ts +1 -0
  33. package/dist/commands/daemon/status.js +14 -1
  34. package/dist/commands/daemon/stop.d.ts +1 -0
  35. package/dist/commands/daemon/stop.js +14 -1
  36. package/dist/commands/daemon/uninstall.d.ts +1 -0
  37. package/dist/commands/daemon/uninstall.js +15 -2
  38. package/dist/commands/daemon/usage.d.ts +1 -0
  39. package/dist/commands/daemon/usage.js +5 -1
  40. package/dist/commands/doctor.js +2 -2
  41. package/dist/commands/github/allow-tools.d.ts +1 -0
  42. package/dist/commands/github/app/install.d.ts +1 -0
  43. package/dist/commands/github/app/status.d.ts +1 -0
  44. package/dist/commands/github/connect.d.ts +1 -0
  45. package/dist/commands/github/connections.d.ts +1 -0
  46. package/dist/commands/github/disconnect.d.ts +1 -0
  47. package/dist/commands/github/finalize.d.ts +1 -0
  48. package/dist/commands/github/reconnect.d.ts +1 -0
  49. package/dist/commands/github/run.d.ts +1 -0
  50. package/dist/commands/github/tools.d.ts +1 -0
  51. package/dist/commands/goals/create.js +2 -2
  52. package/dist/commands/goals/show.js +5 -0
  53. package/dist/commands/harnesses/list.js +14 -3
  54. package/dist/commands/harnesses/show.js +14 -0
  55. package/dist/commands/instructions/activate.js +1 -1
  56. package/dist/commands/instructions/archive-version.js +1 -1
  57. package/dist/commands/instructions/delete.js +1 -1
  58. package/dist/commands/instructions/diff.js +1 -1
  59. package/dist/commands/instructions/install.js +7 -1
  60. package/dist/commands/instructions/restore.js +1 -1
  61. package/dist/commands/instructions/show.js +17 -1
  62. package/dist/commands/instructions/update.js +1 -1
  63. package/dist/commands/integrations/connections/connect.d.ts +1 -0
  64. package/dist/commands/integrations/connections/disconnect.d.ts +1 -0
  65. package/dist/commands/integrations/connections/finalize.d.ts +1 -0
  66. package/dist/commands/integrations/connections/list.d.ts +1 -0
  67. package/dist/commands/integrations/connections/reconnect.d.ts +1 -0
  68. package/dist/commands/integrations/execute.d.ts +1 -0
  69. package/dist/commands/integrations/search.d.ts +1 -0
  70. package/dist/commands/integrations/toolkits.d.ts +1 -0
  71. package/dist/commands/integrations/tools/allow.d.ts +1 -0
  72. package/dist/commands/integrations/tools/list.d.ts +1 -0
  73. package/dist/commands/list-daemons.d.ts +2 -7
  74. package/dist/commands/list-daemons.js +13 -13
  75. package/dist/commands/login.js +78 -33
  76. package/dist/commands/logout.js +52 -1
  77. package/dist/commands/machines/hosted/start.js +1 -1
  78. package/dist/commands/pair.js +2 -2
  79. package/dist/commands/projects/create.js +6 -1
  80. package/dist/commands/projects/tasks.js +6 -1
  81. package/dist/commands/revoke-daemon.js +6 -2
  82. package/dist/commands/set-capabilities.js +6 -2
  83. package/dist/commands/skills/install.js +1 -1
  84. package/dist/commands/skills/library.js +2 -2
  85. package/dist/commands/spaces/create.js +6 -2
  86. package/dist/commands/tasks/complete.d.ts +1 -1
  87. package/dist/commands/tasks/complete.js +21 -8
  88. package/dist/commands/tasks/create.js +4 -1
  89. package/dist/commands/tasks/current.js +1 -1
  90. package/dist/commands/tasks/delete.d.ts +1 -0
  91. package/dist/commands/tasks/delete.js +9 -0
  92. package/dist/commands/tasks/export.js +5 -1
  93. package/dist/commands/tasks/follow-up.js +2 -1
  94. package/dist/commands/tasks/list.js +5 -1
  95. package/dist/commands/tasks/pr.js +1 -1
  96. package/dist/commands/tasks/show.js +10 -1
  97. package/dist/commands/tasks/triage.js +2 -1
  98. package/dist/commands/tasks/update.js +4 -1
  99. package/dist/commands/tasks/upsert.js +4 -1
  100. package/dist/commands/usage.js +1 -1
  101. package/dist/commands/whoami.js +4 -1
  102. package/dist/lib/agentic-stream.js +21 -1
  103. package/dist/lib/api-fetch.d.ts +1 -1
  104. package/dist/lib/api-fetch.js +1 -1
  105. package/dist/lib/auth-core-init.js +23 -3
  106. package/dist/lib/auth-storage.d.ts +0 -12
  107. package/dist/lib/auth-storage.js +37 -2
  108. package/dist/lib/config.d.ts +43 -3
  109. package/dist/lib/config.js +391 -31
  110. package/dist/lib/created-line.d.ts +22 -0
  111. package/dist/lib/created-line.js +25 -0
  112. package/dist/lib/daemon-binding.d.ts +29 -0
  113. package/dist/lib/daemon-binding.js +63 -0
  114. package/dist/lib/daemon-ref.d.ts +31 -0
  115. package/dist/lib/daemon-ref.js +47 -0
  116. package/dist/lib/daemonBroker.js +1 -1
  117. package/dist/lib/delegated-cli.js +3 -3
  118. package/dist/lib/exec-oversky.d.ts +18 -1
  119. package/dist/lib/exec-oversky.js +21 -4
  120. package/dist/lib/html-text.d.ts +15 -0
  121. package/dist/lib/html-text.js +40 -0
  122. package/dist/lib/keychain.d.ts +43 -0
  123. package/dist/lib/keychain.js +145 -4
  124. package/dist/lib/login.js +3 -3
  125. package/dist/lib/node-adapter.js +1 -1
  126. package/dist/lib/oauthLogin.js +17 -6
  127. package/dist/lib/sky-code-agent.d.ts +1 -1
  128. package/dist/lib/sky-code-agent.js +8 -8
  129. package/dist/lib/sky-code-broker.js +18 -2
  130. package/dist/lib/sky-code-doctor.js +120 -4
  131. package/dist/lib/sky-code-managed.d.ts +12 -0
  132. package/dist/lib/sky-code-managed.js +21 -7
  133. package/dist/lib/sky-code.d.ts +16 -1
  134. package/dist/lib/sky-code.js +110 -7
  135. package/dist/lib/task-execution.js +4 -11
  136. package/dist/lib/tasks.d.ts +1 -0
  137. package/dist/lib/tasks.js +9 -6
  138. package/dist/lib/update-check.js +1 -1
  139. package/dist/lib/usage-discovery.js +1 -1
  140. package/dist/lib/web-url.js +12 -1
  141. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialResolver.d.ts +1 -1
  142. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialResolver.js +2 -2
  143. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +1 -0
  144. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +13 -1
  145. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/linux.js +16 -3
  146. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/legacyStatePreflight.d.ts +0 -9
  147. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/legacyStatePreflight.js +18 -1
  148. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/loginLocalhost.js +3 -3
  149. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/messages.js +3 -3
  150. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/runtime.d.ts +7 -3
  151. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/skyCodeChannels.d.ts +96 -0
  152. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/skyCodeChannels.js +115 -0
  153. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialResolver.d.ts +1 -1
  154. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialResolver.js +2 -2
  155. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +1 -0
  156. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +1 -0
  157. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/linux.js +16 -3
  158. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/legacyStatePreflight.d.ts +0 -9
  159. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/legacyStatePreflight.js +18 -1
  160. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/loginLocalhost.js +3 -3
  161. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/messages.js +3 -3
  162. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/runtime.d.ts +7 -3
  163. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/skyCodeChannels.d.ts +96 -0
  164. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/skyCodeChannels.js +107 -0
  165. package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
  166. package/dist/node_modules/@skrr-ai/data-provider/index.js +4206 -4191
  167. package/dist/node_modules/@skrr-ai/inference-broker/dist/cjs/managed-inference-broker.js +2 -2
  168. package/dist/node_modules/@skrr-ai/inference-broker/dist/esm/managed-inference-broker.js +2 -2
  169. package/oclif.manifest.json +7969 -1397
  170. package/package.json +22 -19
@@ -35,11 +35,11 @@ const auth_storage_1 = require("../lib/auth-storage");
35
35
  * `cliLoginWithRefreshToken` for the full rationale.
36
36
  */
37
37
  class Login extends base_command_1.BaseCommand {
38
- static description = 'Sign in to an skrr instance (PKCE localhost callback; device-code fallback)';
38
+ static description = 'Sign in to a skrr instance (PKCE localhost callback; device-code fallback)';
39
39
  static examples = [
40
40
  '<%= config.bin %> login',
41
41
  '<%= config.bin %> login --env prod',
42
- '<%= config.bin %> login --base-url https://oversky.ai',
42
+ '<%= config.bin %> login --base-url https://skrr.ai',
43
43
  '<%= config.bin %> login --server http://localhost:3090',
44
44
  '<%= config.bin %> login --device-code',
45
45
  '<%= config.bin %> login --port 1455',
@@ -49,15 +49,15 @@ class Login extends base_command_1.BaseCommand {
49
49
  static flags = {
50
50
  env: core_1.Flags.string({
51
51
  description: 'Deployment to sign in to. Shorthand for the matching --base-url, and the same ' +
52
- 'environment names the oversky daemon accepts.',
52
+ 'environment names the skrrd runtime CLI accepts.',
53
53
  options: Object.keys(config_1.ENVIRONMENT_BASE_URLS),
54
54
  }),
55
55
  'base-url': core_1.Flags.string({
56
56
  char: 'u',
57
- description: 'API base URL to save and use (e.g. https://oversky.ai)',
57
+ description: 'API base URL to save and use (e.g. https://skrr.ai)',
58
58
  }),
59
59
  server: core_1.Flags.string({
60
- description: 'Alias for --base-url, matching the oversky daemon CLI.',
60
+ description: 'Alias for --base-url, matching the skrrd runtime CLI.',
61
61
  }),
62
62
  'device-code': core_1.Flags.boolean({
63
63
  description: 'Force the device-code flow (skip the PKCE localhost callback).',
@@ -90,41 +90,84 @@ class Login extends base_command_1.BaseCommand {
90
90
  `(${explicitBaseUrl}). Pass one of them.`, { exit: 2 });
91
91
  }
92
92
  const requestedBaseUrl = envBaseUrl ?? explicitBaseUrl;
93
+ /**
94
+ * Undo the base-URL write if this login does not complete.
95
+ *
96
+ * The write has to happen FIRST — every path below reads `baseURL` to know
97
+ * which deployment it is authenticating against — and it used to be kept
98
+ * whatever happened next. So a login that refused left the CLI pointed at a
99
+ * deployment it holds no credential for, while correctly ignoring the
100
+ * credential it does hold, and every subsequent command answered
101
+ * `NOT_SIGNED_IN`. Including the ones that would explain why.
102
+ *
103
+ * Dogfooded as OSK-286: `skrr login --env dev` from a non-TTY wrote the new
104
+ * URL and then refused for want of a terminal. Recovery was editing
105
+ * `~/.skrr/cli-config.json` by hand, and nothing in the output said so.
106
+ *
107
+ * Hoisting the interactivity check ahead of the write would NOT have fixed
108
+ * it and would have broken something real: `cliLogin` can complete without a
109
+ * terminal through the daemon broker, which `lib/login.ts` calls out as the
110
+ * case that matters most on a headless box. The defect was never the order
111
+ * of the check — it was keeping a pointer the login never earned.
112
+ */
113
+ let undoBaseURL = null;
93
114
  if (requestedBaseUrl) {
94
115
  const existing = (0, config_1.loadConfig)();
116
+ const previousBaseURL = existing.baseURL;
95
117
  const nextBaseURL = (0, config_1.canonicalizeKnownBaseURL)(requestedBaseUrl);
118
+ if (previousBaseURL && previousBaseURL !== nextBaseURL) {
119
+ undoBaseURL = () => {
120
+ // Re-read rather than reusing `existing`: the flow may have persisted
121
+ // other fields (cliId, migration markers) before failing, and this
122
+ // must put back the POINTER without discarding those.
123
+ (0, config_1.saveConfig)({ ...(0, config_1.loadConfig)(), baseURL: previousBaseURL });
124
+ (0, data_provider_1.setBaseURL)(previousBaseURL);
125
+ };
126
+ }
96
127
  (0, config_1.saveConfig)({ ...existing, baseURL: nextBaseURL });
97
128
  (0, data_provider_1.setBaseURL)(nextBaseURL);
98
129
  this.cliConfig = { ...this.cliConfig, baseURL: nextBaseURL };
99
130
  }
100
- // Recovery-code path: skip interactive flow entirely.
101
- if (flags['recovery-code']) {
102
- await this.runRecoveryCodeLogin(flags['recovery-code']);
103
- return;
104
- }
105
- // L13 — OVERSKY_REFRESH_TOKEN env-var bootstrap. Skipped when the user
106
- // explicitly asked for `--device-code`; explicit flags always win
107
- // over env vars. The recovery-code path above already returned, so
108
- // we know we're not on that branch.
109
- const envRefreshToken = process.env.OVERSKY_REFRESH_TOKEN;
110
- if (envRefreshToken && !flags['device-code']) {
111
- await this.runRefreshTokenLogin(envRefreshToken);
112
- return;
113
- }
114
131
  try {
115
- const result = await (0, login_1.cliLogin)({
116
- serverUrl: this.cliConfig.baseURL,
117
- scope: flags.scope ?? 'cli',
118
- forceDeviceCode: flags['device-code'],
119
- port: flags.port,
120
- });
121
- this.log('');
122
- this.log(`Signed in via ${result.flow}. Run \`${this.config.bin} whoami\` to confirm your identity.`);
132
+ // Recovery-code path: skip interactive flow entirely.
133
+ if (flags['recovery-code']) {
134
+ await this.runRecoveryCodeLogin(flags['recovery-code']);
135
+ undoBaseURL = null;
136
+ return;
137
+ }
138
+ // L13 — OVERSKY_REFRESH_TOKEN env-var bootstrap. Skipped when the user
139
+ // explicitly asked for `--device-code`; explicit flags always win
140
+ // over env vars. The recovery-code path above already returned, so
141
+ // we know we're not on that branch.
142
+ const envRefreshToken = process.env.OVERSKY_REFRESH_TOKEN;
143
+ if (envRefreshToken && !flags['device-code']) {
144
+ await this.runRefreshTokenLogin(envRefreshToken);
145
+ undoBaseURL = null;
146
+ return;
147
+ }
148
+ try {
149
+ const result = await (0, login_1.cliLogin)({
150
+ serverUrl: this.cliConfig.baseURL,
151
+ scope: flags.scope ?? 'cli',
152
+ forceDeviceCode: flags['device-code'],
153
+ port: flags.port,
154
+ });
155
+ // Only now is the new pointer earned.
156
+ undoBaseURL = null;
157
+ this.log('');
158
+ this.log(`Signed in via ${result.flow} on ${(0, config_1.describeDeployment)(this.cliConfig.baseURL)}. ` +
159
+ `Run \`${this.config.bin} whoami\` to confirm your identity.`);
160
+ }
161
+ catch (err) {
162
+ // Everything structured in login.ts throws Error; surface the
163
+ // message through the standard handler.
164
+ this.handleApiError(err);
165
+ }
123
166
  }
124
- catch (err) {
125
- // Everything structured in login.ts throws Error; surface the
126
- // message through the standard handler.
127
- this.handleApiError(err);
167
+ finally {
168
+ // Runs for a thrown error and for oclif's own exit signals alike, which is
169
+ // why the restore lives here rather than in the catch above.
170
+ undoBaseURL?.();
128
171
  }
129
172
  }
130
173
  /**
@@ -159,7 +202,8 @@ class Login extends base_command_1.BaseCommand {
159
202
  cliId,
160
203
  });
161
204
  this.log('');
162
- this.log(`Signed in via ${result.flow} (OVERSKY_REFRESH_TOKEN). ` +
205
+ this.log(`Signed in via ${result.flow} (OVERSKY_REFRESH_TOKEN) on ` +
206
+ `${(0, config_1.describeDeployment)(this.cliConfig.baseURL)}. ` +
163
207
  `Run \`${this.config.bin} whoami\` to confirm your identity.`);
164
208
  }
165
209
  catch (err) {
@@ -236,7 +280,8 @@ class Login extends base_command_1.BaseCommand {
236
280
  : undefined,
237
281
  }, { serverOrigin: this.cliConfig.baseURL, clearReauth: true });
238
282
  this.log('');
239
- this.log(`Signed in as ${result.user.email} via recovery code.`);
283
+ this.log(`Signed in as ${result.user.email} via recovery code on ` +
284
+ `${(0, config_1.describeDeployment)(this.cliConfig.baseURL)}.`);
240
285
  this.log(`Run \`${this.config.bin} whoami\` to confirm your identity.`);
241
286
  }
242
287
  }
@@ -1,4 +1,37 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.shouldSkipLocalLogout = shouldSkipLocalLogout;
4
37
  const core_1 = require("@oclif/core");
@@ -9,6 +42,7 @@ const refresh_1 = require("../lib/refresh");
9
42
  const api_fetch_1 = require("../lib/api-fetch");
10
43
  const cred_envelope_1 = require("../lib/cred-envelope");
11
44
  const device_identity_1 = require("../lib/device-identity");
45
+ const keychain = __importStar(require("../lib/keychain"));
12
46
  function shouldSkipLocalLogout(input) {
13
47
  return (!input.hasAnyStoredToken &&
14
48
  !input.hasUsableLocalToken &&
@@ -135,6 +169,18 @@ class Logout extends base_command_1.BaseCommand {
135
169
  // when the API host is unreachable.
136
170
  }
137
171
  (0, auth_storage_1.clearAllBackends)();
172
+ // Sweep the credentials this product wrote under its PREVIOUS brand.
173
+ //
174
+ // Without this, logout removed only the current service and still reported
175
+ // an unqualified "Signed out." — leaving the pre-rename CLI credential, the
176
+ // pre-rename daemon credentials and BOTH KEKs on the machine, so the sealed
177
+ // envelope and the key that unwraps it were both still there. `--all-devices`
178
+ // is documented for "a stolen-laptop incident", which is precisely when that
179
+ // is the wrong outcome.
180
+ //
181
+ // Reported rather than silent: this destroys credentials, and one of them
182
+ // may belong to a still-installed `oversky` binary.
183
+ const sweptLegacy = keychain.deleteLegacyBrandEntries();
138
184
  // L11/L12 — also wipe shared device-identity + envelope artifacts.
139
185
  // These files live under ~/.skrr/profiles/default/ and are shared
140
186
  // with the daemon, so a `skrr logout` here also rotates the daemon's
@@ -176,7 +222,7 @@ class Logout extends base_command_1.BaseCommand {
176
222
  // not the same as safe: if two people share one OS account and the second
177
223
  // holds EDIT on the agent the first pinned, the config branch is deliberately
178
224
  // ungated (naming a shared agent is a deliberate act) and their sessions
179
- // would bill it. `skrr code oversky-agent --show` reports the resolved agent
225
+ // would bill it. `skrr code skrr-agent --show` reports the resolved agent
180
226
  // and where it came from, which is the intended way to notice.
181
227
  const cfg = (0, config_1.loadConfig)();
182
228
  (0, config_1.saveConfig)({
@@ -192,6 +238,11 @@ class Logout extends base_command_1.BaseCommand {
192
238
  : 'Signed out from all devices.'
193
239
  : 'Signed out.';
194
240
  this.log(finalMessage);
241
+ if (sweptLegacy.length > 0) {
242
+ this.log(`Also removed ${sweptLegacy.length} credential${sweptLegacy.length === 1 ? '' : 's'} left by the previous product identity:`);
243
+ for (const service of sweptLegacy)
244
+ this.log(` ${service}`);
245
+ }
195
246
  }
196
247
  /**
197
248
  * Iterate the user's daemon resources and revoke each one. Honors
@@ -5,7 +5,7 @@ const node_crypto_1 = require("node:crypto");
5
5
  const base_command_1 = require("../../../base-command");
6
6
  const hosted_machines_1 = require("../../../lib/hosted-machines");
7
7
  class HostedMachinesStart extends base_command_1.BaseCommand {
8
- static description = 'Start an skrr Hosted Machine';
8
+ static description = 'Start a skrr Hosted Machine';
9
9
  static examples = [
10
10
  '<%= config.bin %> machines hosted start --name scratch --wait',
11
11
  '<%= config.bin %> machines hosted start --repo acme/app --installation-id 123 --branch main --wait',
@@ -39,8 +39,8 @@ function buildPairAad(daemonId, responseUserId) {
39
39
  }
40
40
  class Pair extends base_command_1.BaseCommand {
41
41
  static description = PAIR_FEATURE_ENABLED
42
- ? 'Pair this daemon to an skrr account via the mobile app.'
43
- : "Pair this daemon to an skrr account via the mobile app (mobile app integration pending; use 'oversky login' for now).";
42
+ ? 'Pair this daemon to a skrr account via the mobile app.'
43
+ : "Pair this daemon to a skrr account via the mobile app (mobile app integration pending; use 'skrr login' for now).";
44
44
  // H16 — hide from `--help` output unless the feature flag is on at
45
45
  // module load. oclif consults this static field when generating the
46
46
  // top-level command list.
@@ -6,6 +6,7 @@ const base_command_1 = require("../../base-command");
6
6
  const space_argument_1 = require("../../lib/space-argument");
7
7
  const projects_1 = require("../../lib/projects");
8
8
  const web_url_1 = require("../../lib/web-url");
9
+ const created_line_1 = require("../../lib/created-line");
9
10
  class ProjectsCreate extends base_command_1.BaseCommand {
10
11
  static description = 'Create a project in a space';
11
12
  static examples = [
@@ -68,7 +69,11 @@ class ProjectsCreate extends base_command_1.BaseCommand {
68
69
  this.log(JSON.stringify({ ...p, url }, null, 2));
69
70
  return;
70
71
  }
71
- this.log(`Created project ${p.identifier ?? p.id ?? p._id ?? ''} — ${p.title ?? flags.title}`);
72
+ this.log((0, created_line_1.createdLine)('project', {
73
+ ref: p.identifier,
74
+ id: (p.id ?? p._id),
75
+ title: (p.title ?? flags.title),
76
+ }));
72
77
  if (url)
73
78
  this.log(`View it at ${url}`);
74
79
  }
@@ -4,6 +4,7 @@ const core_1 = require("@oclif/core");
4
4
  const data_provider_1 = require("@skrr-ai/data-provider");
5
5
  const base_command_1 = require("../../base-command");
6
6
  const format_1 = require("../../lib/format");
7
+ const web_url_1 = require("../../lib/web-url");
7
8
  /**
8
9
  * `skrr projects tasks <project>` — the tasks in a project.
9
10
  *
@@ -60,7 +61,11 @@ class ProjectsTasks extends base_command_1.BaseCommand {
60
61
  this.handleApiError(err, { subject: `project ${args.id}` });
61
62
  }
62
63
  if (flags.json) {
63
- this.log(JSON.stringify(result, null, 2));
64
+ // The same task carries a `url` via `tasks list` and `spaces tasks`, and
65
+ // did not here — so whether a row was linkable depended on which command
66
+ // you happened to list it from. `withDataUrls` is the same helper those
67
+ // two use, and it leaves a non-list response untouched.
68
+ this.log(JSON.stringify((0, web_url_1.withDataUrls)(this.cliConfig.baseURL, result, web_url_1.taskUrlFrom), null, 2));
64
69
  return;
65
70
  }
66
71
  const items = result?.data ?? [];
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const core_1 = require("@oclif/core");
4
4
  const base_command_1 = require("../base-command");
5
5
  const api_fetch_1 = require("../lib/api-fetch");
6
+ const daemon_ref_1 = require("../lib/daemon-ref");
6
7
  /**
7
8
  * `skrr revoke-daemon <id-or-prefix>`
8
9
  *
@@ -45,7 +46,10 @@ class RevokeDaemon extends base_command_1.BaseCommand {
45
46
  async run() {
46
47
  this.requireAuth();
47
48
  const { args, flags } = await this.parse(RevokeDaemon);
48
- const input = args.idOrPrefix.trim();
49
+ // Accept what `list-daemons` prints, decoration and all — the DAEMON REF
50
+ // column is the obvious place to copy an id from, and it was the one
51
+ // value this command refused.
52
+ const input = (0, daemon_ref_1.normalizeDaemonRef)(args.idOrPrefix);
49
53
  // Resolve the full daemon ID (possibly from a prefix lookup).
50
54
  let resolvedId;
51
55
  let resolvedDaemon;
@@ -130,7 +134,7 @@ class RevokeDaemon extends base_command_1.BaseCommand {
130
134
  const any = list.daemons.find((d) => d.id.startsWith(prefix));
131
135
  if (any)
132
136
  return { id: any.id, daemon: any };
133
- this.error(`No daemon matches prefix "${prefix}".`, { exit: 1 });
137
+ this.error(`No daemon matches "${prefix}". Run \`skrr list-daemons\` to see the ids on this account.`, { exit: 1 });
134
138
  }
135
139
  if (active.length > 1) {
136
140
  const ids = active.map((d) => ` ${d.id} (${d.name})`).join('\n');
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const core_1 = require("@oclif/core");
4
4
  const base_command_1 = require("../base-command");
5
5
  const api_fetch_1 = require("../lib/api-fetch");
6
+ const daemon_ref_1 = require("../lib/daemon-ref");
6
7
  /**
7
8
  * `skrr set-capabilities <id-or-prefix> <cap>[,<cap>…]`
8
9
  *
@@ -39,7 +40,10 @@ class SetCapabilities extends base_command_1.BaseCommand {
39
40
  async run() {
40
41
  this.requireAuth();
41
42
  const { args, flags } = await this.parse(SetCapabilities);
42
- const input = args.idOrPrefix.trim();
43
+ // Accept what `list-daemons` prints, decoration and all — the DAEMON REF
44
+ // column is the obvious place to copy an id from, and it was the one
45
+ // value this command refused.
46
+ const input = (0, daemon_ref_1.normalizeDaemonRef)(args.idOrPrefix);
43
47
  const capabilities = args.capabilities
44
48
  .split(',')
45
49
  .map((s) => s.trim())
@@ -118,7 +122,7 @@ class SetCapabilities extends base_command_1.BaseCommand {
118
122
  const any = list.daemons.find((d) => d.id.startsWith(prefix));
119
123
  if (any)
120
124
  return any.id;
121
- this.error(`No daemon matches prefix "${prefix}".`, { exit: 2 });
125
+ this.error(`No daemon matches "${prefix}". Run \`skrr list-daemons\` to see the ids on this account.`, { exit: 2 });
122
126
  }
123
127
  if (active.length > 1) {
124
128
  const ids = active.map((d) => ` ${d.id} (${d.name})`).join('\n');
@@ -30,7 +30,7 @@ class SkillsInstall extends base_command_1.BaseCommand {
30
30
  const { args, flags } = await this.parse(SkillsInstall);
31
31
  if (flags.service && !flags.agent) {
32
32
  // One-line stderr warning; doesn't break --json consumers on stdout.
33
- process.stderr.write('[sky] --service is deprecated for `skills install`; use --agent instead.\n');
33
+ process.stderr.write('[skrr] --service is deprecated for `skills install`; use --agent instead.\n');
34
34
  }
35
35
  const targetAgentId = flags.agent ?? flags.service ?? null;
36
36
  let result;
@@ -28,10 +28,10 @@ class SkillsLibrary extends base_command_1.BaseCommand {
28
28
  this.requireAuth();
29
29
  const { flags } = await this.parse(SkillsLibrary);
30
30
  if (flags.agent && flags.service) {
31
- process.stderr.write('[sky] both --agent and --service given; using --agent and ignoring --service.\n');
31
+ process.stderr.write('[skrr] both --agent and --service given; using --agent and ignoring --service.\n');
32
32
  }
33
33
  else if (flags.service && !flags.agent) {
34
- process.stderr.write('[sky] --service is deprecated for `skills library`; use --agent instead.\n');
34
+ process.stderr.write('[skrr] --service is deprecated for `skills library`; use --agent instead.\n');
35
35
  }
36
36
  const agentId = flags.agent ?? flags.service;
37
37
  let response;
@@ -6,6 +6,7 @@ const api_fetch_1 = require("../../lib/api-fetch");
6
6
  const base_command_1 = require("../../base-command");
7
7
  const web_url_1 = require("../../lib/web-url");
8
8
  const prompt_1 = require("../../lib/prompt");
9
+ const created_line_1 = require("../../lib/created-line");
9
10
  class SpacesCreate extends base_command_1.BaseCommand {
10
11
  static description = 'Create a new space';
11
12
  static examples = [
@@ -112,8 +113,11 @@ class SpacesCreate extends base_command_1.BaseCommand {
112
113
  this.log(JSON.stringify({ ...s, url }, null, 2));
113
114
  return;
114
115
  }
115
- const parentNote = s.parentSpaceId ? ` (subspace of ${s.parentSpaceId})` : '';
116
- this.log(`Created space ${s.id ?? s._id ?? '?'} - ${s.title ?? '(no title)'}${parentNote}`);
116
+ this.log((0, created_line_1.createdLine)('space', {
117
+ ref: s.identifier,
118
+ id: (s.id ?? s._id),
119
+ title: s.title,
120
+ }));
117
121
  if (url)
118
122
  this.log(`View it at ${url}`);
119
123
  }
@@ -92,7 +92,7 @@ export default class TasksComplete extends BaseCommand {
92
92
  'from-json': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
93
93
  status: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
94
94
  summary: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
95
- artifacts: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
95
+ artifacts: import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
96
96
  artifact: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
97
97
  verdict: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
98
98
  outcome: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
@@ -151,10 +151,18 @@ class TasksComplete extends base_command_1.BaseCommand {
151
151
  }),
152
152
  summary: core_1.Flags.string({ description: 'Completion summary' }),
153
153
  artifacts: core_1.Flags.string({
154
- description: 'Artifacts produced, or "none". Repeat --artifact for a list. The whole ' +
155
- `TASK_OUTPUT block (status + summary + artifacts + verdict) must fit in ${data_provider_1.TASK_OUTPUT_BODY_MAX} ` +
154
+ description: 'Artifacts produced, or "none". Repeatable, and interchangeable with --artifact. ' +
155
+ `The whole TASK_OUTPUT block (status + summary + artifacts + verdict) must fit in ${data_provider_1.TASK_OUTPUT_BODY_MAX} ` +
156
156
  'characters — link to commits, PRs, or file paths rather than pasting content.',
157
- default: 'none',
157
+ // Repeatable, even though `--artifact` already is. The two spellings sit
158
+ // one letter apart and both read as "the artifacts go here", so the wrong
159
+ // one gets typed — and oclif answered that with "Flag --artifacts can only
160
+ // be specified once", which names the flag you used and not the sibling
161
+ // that does what you wanted. Dogfooded (OSK-266) by losing a completion
162
+ // call to exactly that, then re-running with the two references pre-joined
163
+ // into one string, which is the workaround rather than the shape.
164
+ multiple: true,
165
+ default: ['none'],
158
166
  }),
159
167
  artifact: core_1.Flags.string({
160
168
  description: 'A single artifact reference (repeatable); joined with commas. Prefer this ' +
@@ -201,11 +209,16 @@ class TasksComplete extends base_command_1.BaseCommand {
201
209
  const input = (0, prompt_1.mergeDefined)(jsonBody, {
202
210
  status: flags.status,
203
211
  summary: flags.summary,
204
- // Repeated --artifact wins over the single --artifacts string; both
205
- // normalize to the same one-line form the server stores.
206
- artifacts: flags.artifact?.length
207
- ? (0, data_provider_1.normalizeTaskOutputArtifacts)(flags.artifact)
208
- : flags.artifacts,
212
+ // Both spellings, pooled, then normalized to the one-line form the server
213
+ // stores. Pooling rather than letting one win: someone who passes both has
214
+ // named artifacts in each, and silently dropping half of them is worse
215
+ // than either flag being unavailable.
216
+ artifacts: (0, data_provider_1.normalizeTaskOutputArtifacts)([
217
+ ...(flags.artifact ?? []),
218
+ // The literal default is dropped when it is only the default; a user
219
+ // who typed `--artifacts none` alongside a real one meant the real one.
220
+ ...(flags.artifacts ?? []).filter((value) => value !== 'none'),
221
+ ]) || 'none',
209
222
  verdict: flags.verdict,
210
223
  });
211
224
  let taskIdentity;
@@ -47,7 +47,10 @@ class TasksCreate extends base_command_1.BaseCommand {
47
47
  '(OVERSKY_SESSION_AGENT_ID), to you when --execution-mode is human, or to nobody. ' +
48
48
  'Cannot be combined with --execution-mode human.',
49
49
  }),
50
- priority: core_1.Flags.string({ description: 'Task priority' }),
50
+ priority: core_1.Flags.string({
51
+ description: 'Task priority',
52
+ options: [...tasks_1.TASK_PRIORITIES],
53
+ }),
51
54
  parent: core_1.Flags.string({ description: 'Parent task ID' }),
52
55
  'spawned-by': core_1.Flags.string({
53
56
  description: 'Task whose execution produced this one (lineage). Distinct from --parent (containment) and blockers (ordering).',
@@ -18,7 +18,7 @@ class TasksCurrent extends base_command_1.BaseCommand {
18
18
  const current = (0, git_task_1.currentGitTaskBranch)();
19
19
  if (!current) {
20
20
  this.failWithCliError({
21
- message: 'The current git branch does not identify an skrr task.',
21
+ message: 'The current git branch does not identify a skrr task.',
22
22
  code: 'TASK_BRANCH_CONTEXT_MISSING',
23
23
  exit: 2,
24
24
  retryable: false,
@@ -7,6 +7,7 @@ export default class TasksDelete extends BaseCommand {
7
7
  };
8
8
  static flags: {
9
9
  yes: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
11
  };
11
12
  run(): Promise<void>;
12
13
  }
@@ -15,6 +15,11 @@ class TasksDelete extends base_command_1.BaseCommand {
15
15
  };
16
16
  static flags = {
17
17
  yes: core_1.Flags.boolean({ char: 'y', description: 'Skip confirmation prompt' }),
18
+ // Every sibling here takes --json, and a script that batches deletes
19
+ // reasonably passes it to all of them. This command rejected it with
20
+ // CLI_PARSE_ERROR, so a loop that discarded output — the normal shape for a
21
+ // cleanup loop — deleted nothing and reported nothing.
22
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
18
23
  };
19
24
  async run() {
20
25
  this.requireAuth();
@@ -30,6 +35,8 @@ class TasksDelete extends base_command_1.BaseCommand {
30
35
  throw err;
31
36
  }
32
37
  if (!confirmed) {
38
+ if (flags.json)
39
+ return this.log(JSON.stringify({ deleted: false, id: args.id }, null, 2));
33
40
  this.log('Cancelled.');
34
41
  return;
35
42
  }
@@ -39,6 +46,8 @@ class TasksDelete extends base_command_1.BaseCommand {
39
46
  catch (err) {
40
47
  this.handleApiError(err);
41
48
  }
49
+ if (flags.json)
50
+ return this.log(JSON.stringify({ deleted: true, id: args.id }, null, 2));
42
51
  this.log(`Deleted task ${args.id}`);
43
52
  }
44
53
  }
@@ -5,6 +5,7 @@ const core_1 = require("@oclif/core");
5
5
  const data_provider_1 = require("@skrr-ai/data-provider");
6
6
  const base_command_1 = require("../../base-command");
7
7
  const list_1 = require("./list");
8
+ const tasks_1 = require("../../lib/tasks");
8
9
  const task_transfer_1 = require("../../lib/task-transfer");
9
10
  /** The list filter vocabulary is intentionally mirrored here; request construction stays shared. */
10
11
  const FILTER_FLAGS = {
@@ -25,7 +26,10 @@ const FILTER_FLAGS = {
25
26
  'actionability-state': core_1.Flags.string({ description: 'Filter by readiness state' }),
26
27
  'actionability-reason': core_1.Flags.string({ description: 'Filter by readiness reason code' }),
27
28
  'needs-me': core_1.Flags.boolean({ description: 'Filter to human-actionable work addressed to you' }),
28
- priority: core_1.Flags.string({ description: 'Filter by task priority' }),
29
+ priority: core_1.Flags.string({
30
+ description: 'Filter by task priority',
31
+ options: [...tasks_1.TASK_PRIORITIES],
32
+ }),
29
33
  'assignee-agent': core_1.Flags.string({ description: 'Filter by assigned agent ID' }),
30
34
  'assignee-user': core_1.Flags.string({ description: 'Filter by assigned user ID' }),
31
35
  mine: core_1.Flags.boolean({ description: 'Filter to tasks assigned to you' }),
@@ -4,6 +4,7 @@ const core_1 = require("@oclif/core");
4
4
  const base_command_1 = require("../../base-command");
5
5
  const task_extras_1 = require("../../lib/task-extras");
6
6
  const prompt_1 = require("../../lib/prompt");
7
+ const tasks_1 = require("../../lib/tasks");
7
8
  function parsePointers(values) {
8
9
  if (!values?.length)
9
10
  return undefined;
@@ -77,7 +78,7 @@ class TasksFollowUp extends base_command_1.BaseCommand {
77
78
  }),
78
79
  priority: core_1.Flags.string({
79
80
  description: 'Follow-up task priority',
80
- options: ['low', 'medium', 'high', 'critical'],
81
+ options: [...tasks_1.TASK_PRIORITIES],
81
82
  }),
82
83
  tag: core_1.Flags.string({ description: 'Tag to add to the follow-up task', multiple: true }),
83
84
  'assignee-agent': core_1.Flags.string({
@@ -6,6 +6,7 @@ const data_provider_1 = require("@skrr-ai/data-provider");
6
6
  const base_command_1 = require("../../base-command");
7
7
  const web_url_1 = require("../../lib/web-url");
8
8
  const format_1 = require("../../lib/format");
9
+ const tasks_1 = require("../../lib/tasks");
9
10
  /**
10
11
  * The task-list request bag is shared with import/export so every CLI list
11
12
  * surface serializes the same server-side filters. Keep user-id resolution in
@@ -156,7 +157,10 @@ class TasksList extends base_command_1.BaseCommand {
156
157
  'actionability-reason': core_1.Flags.string({
157
158
  description: 'Filter by machine-readable readiness reason code',
158
159
  }),
159
- priority: core_1.Flags.string({ description: 'Filter by task priority' }),
160
+ priority: core_1.Flags.string({
161
+ description: 'Filter by task priority',
162
+ options: [...tasks_1.TASK_PRIORITIES],
163
+ }),
160
164
  estimate: core_1.Flags.integer({ description: 'Filter by an exact estimate value' }),
161
165
  'min-estimate': core_1.Flags.integer({
162
166
  description: 'Filter to tasks estimated at or above this value',
@@ -32,7 +32,7 @@ class TasksPr extends base_command_1.BaseCommand {
32
32
  const current = (0, git_task_1.currentGitTaskBranch)();
33
33
  if (!current) {
34
34
  this.failWithCliError({
35
- message: 'The current git branch does not identify an skrr task.',
35
+ message: 'The current git branch does not identify a skrr task.',
36
36
  code: 'TASK_BRANCH_CONTEXT_MISSING',
37
37
  exit: 2,
38
38
  retryable: false,