@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
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The two halves of the daemon-reference contract: how a daemon id is DISPLAYED
3
+ * and how a displayed one is READ BACK.
4
+ *
5
+ * `list-daemons` prints a decorated short form — `d_6a323ae4...` — and the two
6
+ * commands that consume a daemon reference (`revoke-daemon`,
7
+ * `set-capabilities`) matched the raw argument against `id.startsWith(prefix)`.
8
+ * So the value the product printed in a column literally headed DAEMON REF was
9
+ * rejected by every command that takes one, and the failure looked like "no such
10
+ * daemon" rather than "that is not the format I want". The sibling
11
+ * `machines show` accepts what `machines list` prints, which is the behaviour
12
+ * people reasonably expect here too.
13
+ *
14
+ * Keeping the decoration and accepting it back is the right trade: the `d_`
15
+ * prefix and the ellipsis are what tell a reader the value is truncated, and
16
+ * dropping them would make an 8-character fragment look like a full id.
17
+ */
18
+ /**
19
+ * Format a full daemon ObjectId as a short readable label:
20
+ * `d_xY3p...` — prefix + first 8 hex chars + an ellipsis.
21
+ */
22
+ export declare function formatDaemonRef(id: string): string;
23
+ /**
24
+ * Read back anything `formatDaemonRef` may have produced, plus what a person
25
+ * plausibly pastes: with or without the `d_`, with or without a trailing `...`
26
+ * or a real ellipsis character, and with surrounding whitespace.
27
+ *
28
+ * A value that was never decorated passes through untouched, so a full id and a
29
+ * hand-typed prefix keep working exactly as before.
30
+ */
31
+ export declare function normalizeDaemonRef(input: string): string;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ /**
3
+ * The two halves of the daemon-reference contract: how a daemon id is DISPLAYED
4
+ * and how a displayed one is READ BACK.
5
+ *
6
+ * `list-daemons` prints a decorated short form — `d_6a323ae4...` — and the two
7
+ * commands that consume a daemon reference (`revoke-daemon`,
8
+ * `set-capabilities`) matched the raw argument against `id.startsWith(prefix)`.
9
+ * So the value the product printed in a column literally headed DAEMON REF was
10
+ * rejected by every command that takes one, and the failure looked like "no such
11
+ * daemon" rather than "that is not the format I want". The sibling
12
+ * `machines show` accepts what `machines list` prints, which is the behaviour
13
+ * people reasonably expect here too.
14
+ *
15
+ * Keeping the decoration and accepting it back is the right trade: the `d_`
16
+ * prefix and the ellipsis are what tell a reader the value is truncated, and
17
+ * dropping them would make an 8-character fragment look like a full id.
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.formatDaemonRef = formatDaemonRef;
21
+ exports.normalizeDaemonRef = normalizeDaemonRef;
22
+ /** Prefix the short form carries so a truncated id is visibly truncated. */
23
+ const DISPLAY_PREFIX = 'd_';
24
+ /**
25
+ * Format a full daemon ObjectId as a short readable label:
26
+ * `d_xY3p...` — prefix + first 8 hex chars + an ellipsis.
27
+ */
28
+ function formatDaemonRef(id) {
29
+ if (!id || id.length < 8)
30
+ return id || '—';
31
+ return `${DISPLAY_PREFIX}${id.slice(0, 8)}...`;
32
+ }
33
+ /**
34
+ * Read back anything `formatDaemonRef` may have produced, plus what a person
35
+ * plausibly pastes: with or without the `d_`, with or without a trailing `...`
36
+ * or a real ellipsis character, and with surrounding whitespace.
37
+ *
38
+ * A value that was never decorated passes through untouched, so a full id and a
39
+ * hand-typed prefix keep working exactly as before.
40
+ */
41
+ function normalizeDaemonRef(input) {
42
+ let out = input.trim();
43
+ if (out.toLowerCase().startsWith(DISPLAY_PREFIX))
44
+ out = out.slice(DISPLAY_PREFIX.length);
45
+ out = out.replace(/(?:\.{3}|…)$/, '');
46
+ return out.trim();
47
+ }
@@ -286,7 +286,7 @@ async function attemptDaemonBrokerLogin(opts) {
286
286
  return {
287
287
  ok: false,
288
288
  reason: 'base_url_mismatch',
289
- detail: `No local oversky daemon is logged in to ${opts.baseURL}; available daemon is logged in to ${mismatchedBootstrap.serverUrl}.`,
289
+ detail: `No local skrr runtime is logged in to ${opts.baseURL}; available daemon is logged in to ${mismatchedBootstrap.serverUrl}.`,
290
290
  daemonServerUrl: mismatchedBootstrap.serverUrl,
291
291
  };
292
292
  }
@@ -22,7 +22,7 @@ function isDelegatedCliSession(env = process.env) {
22
22
  function trustedLoopbackUrl(raw) {
23
23
  const url = new URL(raw);
24
24
  if (url.protocol !== 'http:' || !['127.0.0.1', 'localhost', '::1'].includes(url.hostname)) {
25
- throw new Error('Delegated Sky CLI broker must be a loopback HTTP URL.');
25
+ throw new Error('Delegated skrr CLI broker must be a loopback HTTP URL.');
26
26
  }
27
27
  return url.toString();
28
28
  }
@@ -82,11 +82,11 @@ async function fetchDelegatedCliCredential(env = process.env, options = {}) {
82
82
  if (body?.code === 'DELEGATED_CLI_CAPABILITY_REJECTED')
83
83
  return null;
84
84
  }
85
- throw new Error(`Delegated Sky CLI credential broker returned HTTP ${res.status}.`);
85
+ throw new Error(`Delegated skrr CLI credential broker returned HTTP ${res.status}.`);
86
86
  }
87
87
  const body = (await res.json());
88
88
  if (typeof body.accessToken !== 'string' || body.accessToken.length === 0) {
89
- throw new Error('Delegated Sky CLI credential broker returned no access token.');
89
+ throw new Error('Delegated skrr CLI credential broker returned no access token.');
90
90
  }
91
91
  const credential = {
92
92
  token: body.accessToken,
@@ -3,8 +3,25 @@ export declare const RUNTIME_BINARY_NAMES: readonly ["skrrd", "oversky"];
3
3
  /** Resolve the absolute path of `oversky` if it exists, else return null. */
4
4
  export declare function findOverskyBinary(): string | null;
5
5
  /**
6
- * Pretty hint shown when `oversky` isn't installed. Kept short — points
6
+ * Pretty hint shown when the runtime isn't installed. Kept short — points
7
7
  * users at the canonical install paths rather than enumerating them.
8
+ *
9
+ * THE ADDRESSES BELOW STILL SAY `oversky`, ON PURPOSE.
10
+ * ---------------------------------------------------
11
+ * The rename moved this text to `skrr` and pointed it at
12
+ * `dush1023/skrr/skrrd`, `raw.githubusercontent.com/dush1023/skrr/...` and
13
+ * `github.com/dush1023/skrr` — none of which exist. The tap
14
+ * `dush1023/homebrew-skrr` 404s; only `dush1023/homebrew-oversky` is
15
+ * published, and the repository is still `dush1023/OverSky`.
16
+ *
17
+ * An install instruction is only worth what it installs. Renaming these
18
+ * before the tap and repository move produces a message that reads correct
19
+ * and fails when followed — the same defect as the "install it with
20
+ * `sky code install`" hint, which named a command that never existed.
21
+ *
22
+ * They move when the Homebrew tap is published (that work is tracked
23
+ * separately) and when the repository is renamed — not before, and not as
24
+ * part of a copy sweep.
8
25
  */
9
26
  export declare function notInstalledMessage(): string;
10
27
  /**
@@ -76,17 +76,34 @@ function isExecutable(p) {
76
76
  }
77
77
  }
78
78
  /**
79
- * Pretty hint shown when `oversky` isn't installed. Kept short — points
79
+ * Pretty hint shown when the runtime isn't installed. Kept short — points
80
80
  * users at the canonical install paths rather than enumerating them.
81
+ *
82
+ * THE ADDRESSES BELOW STILL SAY `oversky`, ON PURPOSE.
83
+ * ---------------------------------------------------
84
+ * The rename moved this text to `skrr` and pointed it at
85
+ * `dush1023/skrr/skrrd`, `raw.githubusercontent.com/dush1023/skrr/...` and
86
+ * `github.com/dush1023/skrr` — none of which exist. The tap
87
+ * `dush1023/homebrew-skrr` 404s; only `dush1023/homebrew-oversky` is
88
+ * published, and the repository is still `dush1023/OverSky`.
89
+ *
90
+ * An install instruction is only worth what it installs. Renaming these
91
+ * before the tap and repository move produces a message that reads correct
92
+ * and fails when followed — the same defect as the "install it with
93
+ * `sky code install`" hint, which named a command that never existed.
94
+ *
95
+ * They move when the Homebrew tap is published (that work is tracked
96
+ * separately) and when the repository is renamed — not before, and not as
97
+ * part of a copy sweep.
81
98
  */
82
99
  function notInstalledMessage() {
83
100
  return [
84
101
  'The skrr local runtime is not installed on this machine.',
85
102
  '',
86
103
  'Install:',
87
- ' macOS: brew install dush1023/skrr/skrrd',
88
- ' Linux: curl -fsSL https://raw.githubusercontent.com/dush1023/skrr/main/scripts/install-daemon.sh | bash',
89
- ' Other: https://github.com/dush1023/skrr#installation',
104
+ ' macOS: brew install dush1023/oversky/oversky',
105
+ ' Linux: curl -fsSL https://raw.githubusercontent.com/dush1023/OverSky/main/scripts/install-daemon.sh | bash',
106
+ ' Other: https://github.com/dush1023/OverSky#installation',
90
107
  '',
91
108
  'Once installed, re-run your command.',
92
109
  ].join('\n');
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Render server-stored rich text as something a terminal can read.
3
+ *
4
+ * Task, goal and project descriptions are persisted as HTML — `--description
5
+ * -format markdown` is converted on the way in — so a CLI that prints the field
6
+ * verbatim shows the user `<p>…</p>` and `<code>…</code>` around their own
7
+ * words. They wrote markdown and got tags back.
8
+ *
9
+ * Deliberately NOT a general HTML renderer. It converts the block boundaries
10
+ * that carry meaning in a paragraph of prose, drops the rest of the tags, and
11
+ * decodes the entity set the server actually emits. Anything that does not look
12
+ * like markup is returned untouched, so a plain-text description keeps its own
13
+ * whitespace instead of being reflowed by a converter it never needed.
14
+ */
15
+ export declare function htmlToDisplayText(value: string): string;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ /**
3
+ * Render server-stored rich text as something a terminal can read.
4
+ *
5
+ * Task, goal and project descriptions are persisted as HTML — `--description
6
+ * -format markdown` is converted on the way in — so a CLI that prints the field
7
+ * verbatim shows the user `<p>…</p>` and `<code>…</code>` around their own
8
+ * words. They wrote markdown and got tags back.
9
+ *
10
+ * Deliberately NOT a general HTML renderer. It converts the block boundaries
11
+ * that carry meaning in a paragraph of prose, drops the rest of the tags, and
12
+ * decodes the entity set the server actually emits. Anything that does not look
13
+ * like markup is returned untouched, so a plain-text description keeps its own
14
+ * whitespace instead of being reflowed by a converter it never needed.
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.htmlToDisplayText = htmlToDisplayText;
18
+ /** Cheap, deliberate: a tag-shaped substring is the only trigger. */
19
+ function looksLikeHtml(value) {
20
+ return /<\/?[a-z][^>]*>/i.test(value);
21
+ }
22
+ function htmlToDisplayText(value) {
23
+ if (!looksLikeHtml(value))
24
+ return value;
25
+ return (value
26
+ .replace(/<br\s*\/?>/gi, '\n')
27
+ .replace(/<\/(p|div|li|h[1-6])>/gi, '\n')
28
+ .replace(/<li[^>]*>/gi, ' - ')
29
+ .replace(/<[^>]+>/g, '')
30
+ .replace(/&nbsp;/g, ' ')
31
+ .replace(/&#39;/g, "'")
32
+ .replace(/&quot;/g, '"')
33
+ .replace(/&lt;/g, '<')
34
+ .replace(/&gt;/g, '>')
35
+ // `&amp;` LAST, or `&amp;lt;` would decode twice into a bare `<`.
36
+ .replace(/&amp;/g, '&')
37
+ .replace(/[ \t]+/g, ' ')
38
+ .replace(/\n{3,}/g, '\n\n')
39
+ .trim());
40
+ }
@@ -1,4 +1,15 @@
1
+ /** Pre-Phase-K namespace; reserved for a future migration helper. */
2
+ export declare const DEFAULT_PROFILE = "default";
1
3
  export declare function setActiveProfile(profile: string): void;
4
+ /**
5
+ * Whether the profile has been chosen for this process.
6
+ *
7
+ * Borrowed from `daemon/src/config.ts`, which warns when a writer runs before
8
+ * `setActiveProfile()` and says why: such a caller "is a bug — they're writing
9
+ * to the legacy single-tenant root instead of the active profile's dir". The
10
+ * failure is silent and permanent, so it needs to be noisy once.
11
+ */
12
+ export declare function isProfileResolved(): boolean;
2
13
  export declare function getActiveProfile(): string;
3
14
  /** @internal exposed for tests / diagnostics. */
4
15
  export declare function __currentServiceForTest(): string;
@@ -38,8 +49,40 @@ export declare function writeServerOrigin(origin: string): boolean;
38
49
  export declare function deleteServerOrigin(): void;
39
50
  export declare function deleteToken(): void;
40
51
  export declare function deleteRefreshToken(): void;
52
+ /**
53
+ * Remove the credentials this product wrote under its previous brand.
54
+ *
55
+ * `logout` used to delete only the CURRENT service and report an unqualified
56
+ * "Signed out." On a machine carried through the rename that left the
57
+ * pre-rename CLI credential, the pre-rename daemon credentials, and BOTH KEKs
58
+ * in place — so the sealed envelope and the key that unwraps it were still
59
+ * sitting there after the product said you were signed out. `logout --help`
60
+ * offers `--all-devices` for "a stolen-laptop incident", which is the one
61
+ * situation where that is exactly wrong.
62
+ *
63
+ * Returns the services it actually removed something from, so the caller can
64
+ * say what happened instead of destroying credentials silently.
65
+ *
66
+ * NOTE this also signs out the retired `oversky` binary, if one is still
67
+ * installed. That is the intent — same account, same machine — and the cutover
68
+ * runbook already lists these items for removal.
69
+ */
70
+ export declare function deleteLegacyBrandEntries(): string[];
41
71
  /**
42
72
  * Remove every CLI keychain slot for the active profile. Used by `skrr logout`.
43
73
  * Safe to call on a clean system — missing items are not an error.
44
74
  */
45
75
  export declare function deleteAll(): void;
76
+ /**
77
+ * Pull `--profile` out of raw argv.
78
+ *
79
+ * Deliberately minimal: it recognises `--profile x` and `--profile=x` and
80
+ * nothing else. This runs before any validation, so it must not throw, must not
81
+ * consume anything it does not own, and must not care about flag ordering —
82
+ * anything it gets wrong is corrected microseconds later when oclif parses the
83
+ * same argv properly and rejects a malformed invocation.
84
+ *
85
+ * Returns null rather than the default, so the caller can fall through to
86
+ * `OVERSKY_PROFILE` without a flag having to out-rank an env var it never saw.
87
+ */
88
+ export declare function resolveProfileFromArgv(argv: readonly string[] | undefined): string | null;
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_PROFILE = void 0;
3
4
  exports.setActiveProfile = setActiveProfile;
5
+ exports.isProfileResolved = isProfileResolved;
4
6
  exports.getActiveProfile = getActiveProfile;
5
7
  exports.__currentServiceForTest = __currentServiceForTest;
6
8
  exports.isAvailable = isAvailable;
@@ -14,7 +16,9 @@ exports.writeServerOrigin = writeServerOrigin;
14
16
  exports.deleteServerOrigin = deleteServerOrigin;
15
17
  exports.deleteToken = deleteToken;
16
18
  exports.deleteRefreshToken = deleteRefreshToken;
19
+ exports.deleteLegacyBrandEntries = deleteLegacyBrandEntries;
17
20
  exports.deleteAll = deleteAll;
21
+ exports.resolveProfileFromArgv = resolveProfileFromArgv;
18
22
  /**
19
23
  * keychain.ts — macOS Keychain-backed token storage for the Sky CLI.
20
24
  *
@@ -44,10 +48,11 @@ exports.deleteAll = deleteAll;
44
48
  */
45
49
  const node_child_process_1 = require("node:child_process");
46
50
  const cred_envelope_1 = require("./cred-envelope");
51
+ const auth_core_1 = require("@skrr-ai/auth-core");
47
52
  /** Service-name prefix. Always followed by `.<profile>`. */
48
53
  const SERVICE_BASE = 'ai.skrr.cli';
49
54
  /** Pre-Phase-K namespace; reserved for a future migration helper. */
50
- const DEFAULT_PROFILE = 'default';
55
+ exports.DEFAULT_PROFILE = 'default';
51
56
  const ACCOUNT_TOKEN = 'cli-token';
52
57
  const ACCOUNT_EXPIRES = 'cli-token-expires';
53
58
  const ACCOUNT_REFRESH = 'cli-refresh';
@@ -58,14 +63,35 @@ const SECURITY_ITEM_NOT_FOUND = 44;
58
63
  /** Cached availability — probed once at first call. */
59
64
  let _availability = null;
60
65
  /**
61
- * Active profile for this process. Phase K will wire `setActiveProfile('work')`
62
- * onto a `--profile` flag; today everything resolves to `default`.
66
+ * Active profile for this process.
67
+ *
68
+ * Wired from `--profile` / `OVERSKY_PROFILE` in `BaseCommand.init()`, before
69
+ * anything reads a credential. The comment here used to say "Phase K will wire
70
+ * `setActiveProfile('work')` onto a `--profile` flag; today everything resolves
71
+ * to `default`" — and that stayed true long enough to cost something: with one
72
+ * slot, signing into a second deployment EVICTED the first, so a round trip
73
+ * meant two interactive logins and an agent could not make one at all
74
+ * (OSK-290).
63
75
  */
64
- let _activeProfile = DEFAULT_PROFILE;
76
+ let _activeProfile = exports.DEFAULT_PROFILE;
77
+ /** True once a caller has chosen, so a writer can tell "default" from "unset". */
78
+ let _profileResolved = false;
65
79
  function setActiveProfile(profile) {
80
+ _profileResolved = true;
66
81
  if (profile && profile.length > 0)
67
82
  _activeProfile = profile;
68
83
  }
84
+ /**
85
+ * Whether the profile has been chosen for this process.
86
+ *
87
+ * Borrowed from `daemon/src/config.ts`, which warns when a writer runs before
88
+ * `setActiveProfile()` and says why: such a caller "is a bug — they're writing
89
+ * to the legacy single-tenant root instead of the active profile's dir". The
90
+ * failure is silent and permanent, so it needs to be noisy once.
91
+ */
92
+ function isProfileResolved() {
93
+ return _profileResolved;
94
+ }
69
95
  function getActiveProfile() {
70
96
  return _activeProfile;
71
97
  }
@@ -307,6 +333,88 @@ function deleteRefreshToken() {
307
333
  deleteSlot(ACCOUNT_REFRESH);
308
334
  deleteSlot(ACCOUNT_REFRESH_EXPIRES);
309
335
  }
336
+ /**
337
+ * Every Keychain service this product wrote under its PREVIOUS brand.
338
+ *
339
+ * Discovered rather than enumerated, because the daemon's services carry a
340
+ * per-profile hash (`ai.oversky.daemon.dev-f00ad7c1`) that cannot be
341
+ * reconstructed from a name. Metadata only — `dump-keychain` without `-d`
342
+ * prints service names and does not prompt for or reveal any secret.
343
+ *
344
+ * Filtered to `LEGACY_NATIVE_ID_PREFIXES` followed by a dot, so a third-party
345
+ * item that merely starts with the same letters is never in scope.
346
+ */
347
+ function discoverLegacyBrandServices() {
348
+ let dump;
349
+ try {
350
+ dump = (0, node_child_process_1.execFileSync)('security', ['dump-keychain'], {
351
+ encoding: 'utf-8',
352
+ stdio: ['ignore', 'pipe', 'ignore'],
353
+ });
354
+ }
355
+ catch {
356
+ return [];
357
+ }
358
+ const found = new Set();
359
+ for (const match of dump.matchAll(/"svce"<blob>="([^"]*)"/g)) {
360
+ const service = match[1];
361
+ if (auth_core_1.LEGACY_NATIVE_ID_PREFIXES.some((prefix) => service.startsWith(`${prefix}.`))) {
362
+ found.add(service);
363
+ }
364
+ }
365
+ return [...found].sort();
366
+ }
367
+ /**
368
+ * Delete every item under one service, without needing its account names.
369
+ *
370
+ * `delete-generic-password -s <svc>` removes ONE matching item, so a service
371
+ * holding a token, its expiry and a refresh pair needs several passes. Bounded,
372
+ * because a delete that never reports "not found" would otherwise spin.
373
+ */
374
+ function deleteEntireService(service) {
375
+ let removedAny = false;
376
+ for (let i = 0; i < 32; i += 1) {
377
+ try {
378
+ (0, node_child_process_1.execFileSync)('security', ['delete-generic-password', '-s', service], {
379
+ stdio: ['ignore', 'ignore', 'ignore'],
380
+ });
381
+ removedAny = true;
382
+ }
383
+ catch (err) {
384
+ const status = err.status;
385
+ if (status === SECURITY_ITEM_NOT_FOUND)
386
+ return removedAny;
387
+ if (process.env.DEBUG) {
388
+ console.error(`[cli/keychain] legacy sweep failed for ${service} (status=${status ?? 'unknown'})`);
389
+ }
390
+ return removedAny;
391
+ }
392
+ }
393
+ return removedAny;
394
+ }
395
+ /**
396
+ * Remove the credentials this product wrote under its previous brand.
397
+ *
398
+ * `logout` used to delete only the CURRENT service and report an unqualified
399
+ * "Signed out." On a machine carried through the rename that left the
400
+ * pre-rename CLI credential, the pre-rename daemon credentials, and BOTH KEKs
401
+ * in place — so the sealed envelope and the key that unwraps it were still
402
+ * sitting there after the product said you were signed out. `logout --help`
403
+ * offers `--all-devices` for "a stolen-laptop incident", which is the one
404
+ * situation where that is exactly wrong.
405
+ *
406
+ * Returns the services it actually removed something from, so the caller can
407
+ * say what happened instead of destroying credentials silently.
408
+ *
409
+ * NOTE this also signs out the retired `oversky` binary, if one is still
410
+ * installed. That is the intent — same account, same machine — and the cutover
411
+ * runbook already lists these items for removal.
412
+ */
413
+ function deleteLegacyBrandEntries() {
414
+ if (!isAvailable())
415
+ return [];
416
+ return discoverLegacyBrandServices().filter((service) => deleteEntireService(service));
417
+ }
310
418
  /**
311
419
  * Remove every CLI keychain slot for the active profile. Used by `skrr logout`.
312
420
  * Safe to call on a clean system — missing items are not an error.
@@ -316,3 +424,36 @@ function deleteAll() {
316
424
  deleteRefreshToken();
317
425
  deleteServerOrigin();
318
426
  }
427
+ /**
428
+ * Pull `--profile` out of raw argv.
429
+ *
430
+ * Deliberately minimal: it recognises `--profile x` and `--profile=x` and
431
+ * nothing else. This runs before any validation, so it must not throw, must not
432
+ * consume anything it does not own, and must not care about flag ordering —
433
+ * anything it gets wrong is corrected microseconds later when oclif parses the
434
+ * same argv properly and rejects a malformed invocation.
435
+ *
436
+ * Returns null rather than the default, so the caller can fall through to
437
+ * `OVERSKY_PROFILE` without a flag having to out-rank an env var it never saw.
438
+ */
439
+ function resolveProfileFromArgv(argv) {
440
+ // `undefined` is a real input, not a defensive flourish: a command
441
+ // constructed directly — as several suites do — has no argv yet when `init()`
442
+ // runs. The contract above says this must not throw, and it did.
443
+ if (!Array.isArray(argv))
444
+ return null;
445
+ for (let i = 0; i < argv.length; i += 1) {
446
+ const token = argv[i];
447
+ if (token === '--')
448
+ break;
449
+ if (token === '--profile') {
450
+ const value = argv[i + 1];
451
+ return value && !value.startsWith('-') ? value : null;
452
+ }
453
+ if (token.startsWith('--profile=')) {
454
+ const value = token.slice('--profile='.length);
455
+ return value.length > 0 ? value : null;
456
+ }
457
+ }
458
+ return null;
459
+ }
package/dist/lib/login.js CHANGED
@@ -82,7 +82,7 @@ async function cliLogin(opts = {}) {
82
82
  });
83
83
  if (brokerResult.ok) {
84
84
  console.log('');
85
- console.log(' Authorized via the local oversky daemon (no browser needed).');
85
+ console.log(' Authorized via the local skrr runtime (no browser needed).');
86
86
  return {
87
87
  token: brokerResult.accessToken,
88
88
  refreshToken: brokerResult.refreshToken,
@@ -105,7 +105,7 @@ async function cliLogin(opts = {}) {
105
105
  // broker failures — missing bootstrap, network blip, server 5xx —
106
106
  // silently fall through to PKCE / device-code below.
107
107
  if (brokerResult.reason === 'ci_token_refused') {
108
- throw new Error('The local oversky daemon is bootstrapped from a CI token, which cannot broker an interactive CLI login. ' +
108
+ throw new Error('The local skrr runtime is bootstrapped from a CI token, which cannot broker an interactive CLI login. ' +
109
109
  'Use `skrr create-token --name <name>` to mint a long-lived CI credential directly, ' +
110
110
  'or run `skrr login` on a machine where the daemon was authenticated interactively.');
111
111
  }
@@ -116,7 +116,7 @@ async function cliLogin(opts = {}) {
116
116
  // "I'm logging into a different server than the daemon".
117
117
  if (brokerResult.reason === 'base_url_mismatch' && brokerResult.daemonServerUrl) {
118
118
  console.log('');
119
- console.log(` The local oversky daemon is logged in to ${brokerResult.daemonServerUrl}, but skrr is configured for ${serverUrl}.`);
119
+ console.log(` The local skrr runtime is logged in to ${brokerResult.daemonServerUrl}, but skrr is configured for ${serverUrl}.`);
120
120
  console.log(` Skipping the daemon-broker handoff. Run \`skrr login --base-url ${brokerResult.daemonServerUrl}\` to use the daemon instead.`);
121
121
  }
122
122
  }
@@ -298,7 +298,7 @@ function createNodeAdapter(opts = {}) {
298
298
  else {
299
299
  // Refresh-token rotation rejected (revoked / family burned /
300
300
  // passwordChangedAt cutover). As a last resort, ask the local
301
- // oversky daemon to broker a fresh cli-scope family — covers
301
+ // skrr runtime to broker a fresh cli-scope family — covers
302
302
  // "user reset their account but daemon is still authed",
303
303
  // "stale pre-broker keychain token", and similar drift cases.
304
304
  const brokered = await tryDaemonBrokerRecovery();
@@ -45,6 +45,7 @@ const node_child_process_1 = require("node:child_process");
45
45
  const auth_storage_1 = require("./auth-storage");
46
46
  const config_1 = require("./config");
47
47
  const device_id_1 = require("./device-id");
48
+ const publicEndpoints_generated_1 = require("./publicEndpoints.generated");
48
49
  // ---------------------------------------------------------------------------
49
50
  // PKCE helpers
50
51
  // ---------------------------------------------------------------------------
@@ -64,17 +65,27 @@ function generateState() {
64
65
  // ---------------------------------------------------------------------------
65
66
  const CLIENT_ID = 'oversky-cli';
66
67
  const DEFAULT_SCOPES = Object.freeze(['cli']);
68
+ // Both directions are DERIVED from config/public-endpoints.json via the
69
+ // generated constant rather than hand-listed. The hand-listed pair predated the
70
+ // domain cutover and knew only `oversky.*`, so the CURRENT prod apex
71
+ // (`skrr.ai`) resolved to itself: a login against it would exchange tokens on
72
+ // the app origin instead of the API one. Mirrors the same derivation in
73
+ // `web-url.ts`, which needs the inverse map for exactly the same reason.
67
74
  const OAUTH_API_URL_FROM_WEB = {
75
+ ...Object.fromEntries(Object.values(publicEndpoints_generated_1.OVERSKY_ENVIRONMENT_ENDPOINTS).map((e) => [
76
+ e.appUrl.toLowerCase(),
77
+ e.realtimeUrl,
78
+ ])),
79
+ // Prod's retained previous origin, and the `www.` spelling of it.
68
80
  'https://oversky.ai': 'https://api.oversky.ai',
69
81
  'https://www.oversky.ai': 'https://api.oversky.ai',
70
- // Dev split onto its own apex (oversky.dev) with an ALB-direct api. subdomain.
71
- // Mirrors config/public-endpoints.json so `skrr login` against dev exchanges
72
- // tokens on the same origin family prod uses.
73
- 'https://oversky.dev': 'https://api.oversky.dev',
74
82
  };
75
83
  const OAUTH_WEB_URL_FROM_API = {
84
+ ...Object.fromEntries(Object.values(publicEndpoints_generated_1.OVERSKY_ENVIRONMENT_ENDPOINTS).map((e) => [
85
+ e.realtimeUrl.toLowerCase(),
86
+ e.appUrl,
87
+ ])),
76
88
  'https://api.oversky.ai': 'https://oversky.ai',
77
- 'https://api.oversky.dev': 'https://oversky.dev',
78
89
  };
79
90
  function resolveOAuthEndpoints(serverUrl) {
80
91
  const normalized = serverUrl.replace(/\/+$/, '');
@@ -351,7 +362,7 @@ async function runOAuthLogin(opts) {
351
362
  // refresh.ts:169 and :296. So the credential was rejected by its
352
363
  // own issuer check the instant it was written:
353
364
  //
354
- // [sky] Ignoring stored credentials issued by
365
+ // [skrr] Ignoring stored credentials issued by
355
366
  // https://api.oversky.ai; skrr is configured for
356
367
  // https://oversky.ai.
357
368
  //
@@ -113,7 +113,7 @@ export interface SkyCodeAgentOptions {
113
113
  * May resolution CREATE the default agent when nothing else answers?
114
114
  *
115
115
  * Defaults to true, because a session that cannot name an agent cannot run.
116
- * `skrr code oversky-agent` (with no `--create`) passes false: a command whose
116
+ * `skrr code skrr-agent` (with no `--create`) passes false: a command whose
117
117
  * job is to report what would happen must not make it happen.
118
118
  */
119
119
  createDefault?: boolean;
@@ -96,7 +96,7 @@ exports.SkyCodeAgentError = SkyCodeAgentError;
96
96
  */
97
97
  async function resolveSkyCodeAgent(explicit, deps = {}, options = {}) {
98
98
  const configured = deps.configuredAgentId ?? (() => (0, config_1.loadConfig)().skyCodeAgentId);
99
- const explicitLabel = options.explicitLabel ?? sky_code_managed_1.OVERSKY_AGENT_FLAG;
99
+ const explicitLabel = options.explicitLabel ?? sky_code_managed_1.SKRR_AGENT_FLAG;
100
100
  let cached = null;
101
101
  const roster = async () => {
102
102
  if (cached)
@@ -123,7 +123,7 @@ async function resolveSkyCodeAgent(explicit, deps = {}, options = {}) {
123
123
  }
124
124
  if (byName.length > 1) {
125
125
  throw new SkyCodeAgentError('agent-ambiguous', `${describeSource(source, ref, explicitLabel)} matches ${byName.length} agents. ` +
126
- `Pass ${sky_code_managed_1.OVERSKY_AGENT_FLAG} with an id instead: ${candidates(byName)}`);
126
+ `Pass ${sky_code_managed_1.SKRR_AGENT_FLAG} with an id instead: ${candidates(byName)}`);
127
127
  }
128
128
  // Not in the bounded roster. It may still be a real id belonging to a user with
129
129
  // more agents than the roster shows, so ask directly before refusing.
@@ -186,7 +186,7 @@ async function resolveSkyCodeAgent(explicit, deps = {}, options = {}) {
186
186
  // exactly this and belongs to nobody else.
187
187
  // `createDefault: false` makes this a READ: the endpoint is get-or-create
188
188
  // and has no read-only mode, so a caller that is only ASKING
189
- // (`skrr code oversky-agent`) recognises an existing default from the roster
189
+ // (`skrr code skrr-agent`) recognises an existing default from the roster
190
190
  // it has already fetched instead. `defaultForHarness` rides the same
191
191
  // summary projection `author` does, so this costs no extra request.
192
192
  //
@@ -220,8 +220,8 @@ async function resolveSkyCodeAgent(explicit, deps = {}, options = {}) {
220
220
  if (isAbortError(err))
221
221
  throw err;
222
222
  throw new SkyCodeAgentError('agent-unset', `could not establish your default skrr Code agent — ${message(err)}. ` +
223
- `Pass ${sky_code_managed_1.OVERSKY_AGENT_FLAG} <id-or-name>, or set one with ` +
224
- '`skrr code oversky-agent --set <id>`' +
223
+ `Pass ${sky_code_managed_1.SKRR_AGENT_FLAG} <id-or-name>, or set one with ` +
224
+ '`skrr code skrr-agent --set <id>`' +
225
225
  (rows.length ? `. Yours: ${candidates(rows)}` : ''));
226
226
  }
227
227
  // Asked, not told: the caller opted out of creation, so "no default" is a fact
@@ -229,14 +229,14 @@ async function resolveSkyCodeAgent(explicit, deps = {}, options = {}) {
229
229
  if (options.createDefault === false) {
230
230
  throw new SkyCodeAgentError('agent-unset', 'nothing is configured and you have no skrr Code default agent yet. ' +
231
231
  'One is created automatically the first time you run a managed session — ' +
232
- 'or make it now with `skrr code oversky-agent --create`' +
232
+ 'or make it now with `skrr code skrr-agent --create`' +
233
233
  (rows.length ? `. Yours: ${candidates(rows)}` : ''));
234
234
  }
235
235
  // The endpoint answered without an agent. Nothing here can repair that, but
236
236
  // the user still has every ordinary way to name one.
237
237
  throw new SkyCodeAgentError('agent-unset', rows.length
238
238
  ? `skrr Code has no default agent for you and will not pick one of your ${rows.length}. ` +
239
- `Pass ${sky_code_managed_1.OVERSKY_AGENT_FLAG} <id-or-name>, or set "${sky_code_managed_1.AGENT_CONFIG_KEY}" in ` +
239
+ `Pass ${sky_code_managed_1.SKRR_AGENT_FLAG} <id-or-name>, or set "${sky_code_managed_1.AGENT_CONFIG_KEY}" in ` +
240
240
  `${configPathHint()}. Yours: ${candidates(rows)}`
241
241
  : 'you have no agents and no default could be created, yet a managed skrr Code session ' +
242
242
  'runs as one. Create an agent in the skrr app first');
@@ -278,7 +278,7 @@ async function setConfiguredAgentId(ref, deps = {}, options = {}) {
278
278
  // Name the thing the user actually typed. Without this a bad `--set` value
279
279
  // is refused with "--oversky-agent \"typo\" is not an agent you can run",
280
280
  // pointing at a flag that was never on the command line.
281
- explicitLabel: 'skrr code oversky-agent --set',
281
+ explicitLabel: 'skrr code skrr-agent --set',
282
282
  ...options,
283
283
  });
284
284
  writeConfigKey(resolved.id);