@skrr-ai/cli 0.1.9 → 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.
@@ -155,7 +155,8 @@ class Login extends base_command_1.BaseCommand {
155
155
  // Only now is the new pointer earned.
156
156
  undoBaseURL = null;
157
157
  this.log('');
158
- this.log(`Signed in via ${result.flow}. Run \`${this.config.bin} whoami\` to confirm your identity.`);
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.`);
159
160
  }
160
161
  catch (err) {
161
162
  // Everything structured in login.ts throws Error; surface the
@@ -201,7 +202,8 @@ class Login extends base_command_1.BaseCommand {
201
202
  cliId,
202
203
  });
203
204
  this.log('');
204
- 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)}. ` +
205
207
  `Run \`${this.config.bin} whoami\` to confirm your identity.`);
206
208
  }
207
209
  catch (err) {
@@ -278,7 +280,8 @@ class Login extends base_command_1.BaseCommand {
278
280
  : undefined,
279
281
  }, { serverOrigin: this.cliConfig.baseURL, clearReauth: true });
280
282
  this.log('');
281
- 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)}.`);
282
285
  this.log(`Run \`${this.config.bin} whoami\` to confirm your identity.`);
283
286
  }
284
287
  }
@@ -130,7 +130,10 @@ class Whoami extends base_command_1.BaseCommand {
130
130
  : '-';
131
131
  this.log(`Workspace: ${workspaceLabel}`);
132
132
  this.log(`Daemon ID: ${daemonId ?? '-'}`);
133
- this.log(`Server: ${this.cliConfig.baseURL}`);
133
+ // Named, not just spelled: `oversky.dev` and `skrr.ai` do not read as a
134
+ // dev/prod pair to anyone who has not seen the constants, and `whoami` is
135
+ // where the login message sends you to find out where you are (OSK-301).
136
+ this.log(`Server: ${(0, config_1.describeDeployment)(this.cliConfig.baseURL)}`);
134
137
  this.log(`Profile: ${(0, keychain_1.getActiveProfile)()}`);
135
138
  if (this.cliConfig.cliId) {
136
139
  this.log(`CLI ID: ${this.cliConfig.cliId}`);
@@ -119,6 +119,19 @@ export declare function environmentForBaseURL(value: string): 'dev' | 'prod' | '
119
119
  * display and not harmless for routing, because two spellings of prod are two
120
120
  * different keys to anything comparing base URLs.
121
121
  */
122
+ /**
123
+ * A deployment, written so a human can tell which one it is.
124
+ *
125
+ * A published `npm i -g @skrr-ai/cli` defaults to the DEV deployment, and nothing
126
+ * in the login flow said so — you got "Signed in via browser" and no indication
127
+ * of which backend now holds your account (OSK-301). Naming the environment as
128
+ * well as the URL matters because `oversky.dev` and `skrr.ai` do not look like a
129
+ * dev/prod pair to anyone who has not read this file.
130
+ *
131
+ * Falls back to the bare URL for a deployment we do not recognise — a
132
+ * self-hosted or local server is legitimate, and labelling it would be a guess.
133
+ */
134
+ export declare function describeDeployment(baseURL: string): string;
122
135
  export declare function canonicalizeKnownBaseURL(value: string): string;
123
136
  /**
124
137
  * True when any auth-carrying env var is set. In this mode credentials are
@@ -127,6 +140,33 @@ export declare function canonicalizeKnownBaseURL(value: string): string;
127
140
  * us persist a rotated pair that the next `loadConfig()` would shadow.
128
141
  */
129
142
  export declare function isEnvAuthOverride(): boolean;
143
+ /**
144
+ * Storage layout (Phase H+).
145
+ *
146
+ * Canonical: ~/.skrr/cli-config.json (metadata only)
147
+ * ~/.skrr/cli-auth.json (file-backend auth storage)
148
+ * Keychain (darwin-preferred auth storage)
149
+ * Legacy: ~/.sky/config.json (read-only fallback, copied forward once)
150
+ *
151
+ * The CLI shares the daemon's config root so `auth.lock` and
152
+ * `needs-reauth.json` are coordinated across binaries.
153
+ */
154
+ /**
155
+ * The skrr root for this process — the ONE place every root-derived path comes
156
+ * from.
157
+ *
158
+ * It is exported and takes `env` because the alternative is what this replaced:
159
+ * two functions each deriving the root themselves, one honouring the override
160
+ * and one not, disagreeing only when someone relocated their root (OSK-300).
161
+ * Fixing that by teaching the second function the same two variable names would
162
+ * have re-created the split the moment a third name appeared — and did, briefly,
163
+ * when `SKRR_CONFIG_DIR` was added to one side only.
164
+ *
165
+ * `SKRR_CONFIG_DIR` is the spelling for anything new (root CLAUDE.md) and wins
166
+ * when both are set. `OVERSKY_CONFIG_DIR` keeps working: the daemon, the engine
167
+ * resolver and every existing install read it.
168
+ */
169
+ export declare function configRoot(env?: NodeJS.ProcessEnv): string;
130
170
  /**
131
171
  * Read the config file. Returns defaults if missing. Throws on corrupt JSON.
132
172
  * Performs a one-shot legacy → new copy when only the legacy file exists, so
@@ -35,8 +35,10 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.ENVIRONMENT_BASE_URLS = exports.LEGACY_PROD_BASE_URL = exports.LEGACY_DEV_BASE_URL = exports.CANONICAL_PROD_BASE_URL = exports.CANONICAL_DEV_BASE_URL = void 0;
37
37
  exports.environmentForBaseURL = environmentForBaseURL;
38
+ exports.describeDeployment = describeDeployment;
38
39
  exports.canonicalizeKnownBaseURL = canonicalizeKnownBaseURL;
39
40
  exports.isEnvAuthOverride = isEnvAuthOverride;
41
+ exports.configRoot = configRoot;
40
42
  exports.loadConfig = loadConfig;
41
43
  exports.saveConfig = saveConfig;
42
44
  exports.getConfigPath = getConfigPath;
@@ -97,6 +99,22 @@ function environmentForBaseURL(value) {
97
99
  * display and not harmless for routing, because two spellings of prod are two
98
100
  * different keys to anything comparing base URLs.
99
101
  */
102
+ /**
103
+ * A deployment, written so a human can tell which one it is.
104
+ *
105
+ * A published `npm i -g @skrr-ai/cli` defaults to the DEV deployment, and nothing
106
+ * in the login flow said so — you got "Signed in via browser" and no indication
107
+ * of which backend now holds your account (OSK-301). Naming the environment as
108
+ * well as the URL matters because `oversky.dev` and `skrr.ai` do not look like a
109
+ * dev/prod pair to anyone who has not read this file.
110
+ *
111
+ * Falls back to the bare URL for a deployment we do not recognise — a
112
+ * self-hosted or local server is legitimate, and labelling it would be a guess.
113
+ */
114
+ function describeDeployment(baseURL) {
115
+ const env = environmentForBaseURL(baseURL);
116
+ return env ? `${env} (${baseURL})` : baseURL;
117
+ }
100
118
  function canonicalizeKnownBaseURL(value) {
101
119
  const trimmed = value.trim().replace(/\/+$/, '');
102
120
  const normalized = trimmed.toLowerCase().replace(/^http:\/\//, 'https://');
@@ -113,10 +131,27 @@ function canonicalizeKnownBaseURL(value) {
113
131
  return value;
114
132
  }
115
133
  const DEFAULT_CONFIG = {
116
- // Dev remains the default for an unconfigured CLI, matching the daemon
117
- // (daemon/src/config.ts → ENVIRONMENT_URLS.dev). Reach prod with
118
- // `skrr login --env prod`, `--base-url https://oversky.ai`, or OVERSKY_BASE_URL.
119
- baseURL: exports.CANONICAL_DEV_BASE_URL,
134
+ // PROD for an unconfigured CLI, matching the daemon
135
+ // (daemon/src/config.ts → ENVIRONMENT_URLS.prod). Reach dev with
136
+ // `skrr login --env dev`, `--base-url https://oversky.dev`, or OVERSKY_BASE_URL.
137
+ //
138
+ // This was dev, which was right when the CLI was something the team installed
139
+ // from the repo. `@skrr-ai/cli` is a PUBLIC npm package now, and the default
140
+ // decides where a stranger's first `skrr login` creates their account,
141
+ // workspace and agents. `oversky.dev` is the integration environment: it
142
+ // deploys on every push to `dev` and, by design, without waiting for the api or
143
+ // client suites. A reasonable place for the team to live, a poor place to send
144
+ // someone who typed `npm install` (OSK-301).
145
+ //
146
+ // It moves with the daemon or not at all. The two defaults are ONE decision:
147
+ // changing this alone would put every fresh machine into the CLI-on-prod /
148
+ // daemon-on-dev split that OSK-279 exists to prevent — which is exactly the
149
+ // state this machine was found in. `cli/src/__tests__/default-deployment.spec.ts`
150
+ // reads the daemon's own source and fails if they diverge.
151
+ //
152
+ // Nobody's existing setup moves: a stored `cli-config.json` wins over this, so
153
+ // only an install with no configuration at all is affected.
154
+ baseURL: exports.CANONICAL_PROD_BASE_URL,
120
155
  };
121
156
  /**
122
157
  * Environment-variable overlay for headless use (CI, Secrets Manager, EC2
@@ -205,8 +240,27 @@ function isEnvAuthOverride() {
205
240
  * The CLI shares the daemon's config root so `auth.lock` and
206
241
  * `needs-reauth.json` are coordinated across binaries.
207
242
  */
243
+ /**
244
+ * The skrr root for this process — the ONE place every root-derived path comes
245
+ * from.
246
+ *
247
+ * It is exported and takes `env` because the alternative is what this replaced:
248
+ * two functions each deriving the root themselves, one honouring the override
249
+ * and one not, disagreeing only when someone relocated their root (OSK-300).
250
+ * Fixing that by teaching the second function the same two variable names would
251
+ * have re-created the split the moment a third name appeared — and did, briefly,
252
+ * when `SKRR_CONFIG_DIR` was added to one side only.
253
+ *
254
+ * `SKRR_CONFIG_DIR` is the spelling for anything new (root CLAUDE.md) and wins
255
+ * when both are set. `OVERSKY_CONFIG_DIR` keeps working: the daemon, the engine
256
+ * resolver and every existing install read it.
257
+ */
258
+ function configRoot(env = process.env) {
259
+ const root = (env.SKRR_CONFIG_DIR || env.OVERSKY_CONFIG_DIR)?.trim();
260
+ return root || path.join(os.homedir(), '.skrr');
261
+ }
208
262
  function newConfigDir() {
209
- return path.join(os.homedir(), '.skrr');
263
+ return configRoot();
210
264
  }
211
265
  /**
212
266
  * Fields that belong to the MACHINE, not to a profile.
@@ -288,10 +342,15 @@ function readMachineScoped() {
288
342
  * This was missing from the fallback chain, which went straight from `.skrr` to
289
343
  * `.sky` and skipped the directory that every current install actually has.
290
344
  * The effect is not a missing preference: with no config found, `loadConfig`
291
- * returns DEFAULT_CONFIG, whose baseURL is the production apex — so a CLI that
292
- * had been pointed at the dev deployment silently starts addressing PRODUCTION,
293
- * and its `workspaceId` is gone. Nothing errors; commands just answer about a
294
- * different backend.
345
+ * returns DEFAULT_CONFIG, whose baseURL is the DEV deployment — so a CLI that
346
+ * had been pointed at production silently starts addressing dev, and its
347
+ * `workspaceId` is gone. Nothing errors; commands just answer about a different
348
+ * backend.
349
+ *
350
+ * This read "the production apex", and said the drift ran the other way. It did
351
+ * not: DEFAULT_CONFIG has been dev since it was written, forty lines further up.
352
+ * The direction matters here more than most stale comments, because it is the
353
+ * difference between a lost session and one that silently addresses production.
295
354
  *
296
355
  * Note the filename differs by generation: `.sky` used `config.json`, `.oversky`
297
356
  * and `.skrr` use `cli-config.json`.
@@ -35,6 +35,7 @@ const node_fs_1 = require("node:fs");
35
35
  const node_os_1 = require("node:os");
36
36
  const node_path_1 = __importDefault(require("node:path"));
37
37
  const auth_core_1 = require("@skrr-ai/auth-core");
38
+ const config_1 = require("./config");
38
39
  // Deliberately does NOT import the managed marker any more. This module used to
39
40
  // read it to decide whether a run was managed; that decision now arrives as a
40
41
  // declared `credentialMode`, and re-introducing the import here would be the first
@@ -51,14 +52,18 @@ exports.ENGINE_PATH_ENV = 'OVERSKY_SKY_CODE_PATH';
51
52
  * ordering below exists to prevent.
52
53
  */
53
54
  function engineHome(env = process.env) {
54
- const root = env.OVERSKY_CONFIG_DIR?.trim();
55
- return node_path_1.default.join(root || node_path_1.default.join((0, node_os_1.homedir)(), '.skrr'), 'sky-code');
55
+ // `configRoot` and not a second reading of the environment: deriving the root
56
+ // twice is what let this function and `getConfigPath()` disagree (OSK-300).
57
+ return node_path_1.default.join((0, config_1.configRoot)(env), 'sky-code');
56
58
  }
57
59
  /** The user-level instruction root owned by skrr Code. */
58
60
  function skyCodeInstructionHome(env = process.env) {
59
61
  const configured = env.SKY_CODE_HOME?.trim();
62
+ // Falls through to `engineHome()` rather than re-deriving `~/.skrr` — the two
63
+ // describe the same root, and re-deriving it is what made them disagree under
64
+ // `OVERSKY_CONFIG_DIR` (OSK-300).
60
65
  if (!configured)
61
- return node_path_1.default.join((0, node_os_1.homedir)(), '.skrr', 'sky-code');
66
+ return engineHome(env);
62
67
  if (configured === '~')
63
68
  return (0, node_os_1.homedir)();
64
69
  if (configured.startsWith('~/'))