@skrr-ai/cli 0.1.32 → 0.1.34

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 (114) hide show
  1. package/bin/run.js +2 -2
  2. package/dist/base-command.js +5 -0
  3. package/dist/commands/agents/list.d.ts +2 -1
  4. package/dist/commands/agents/list.js +2 -1
  5. package/dist/commands/agents/show.js +2 -1
  6. package/dist/commands/balance/statement.js +8 -4
  7. package/dist/commands/browser/install.js +6 -2
  8. package/dist/commands/browser/uninstall.js +6 -2
  9. package/dist/commands/code/acp.js +2 -1
  10. package/dist/commands/code/doctor.d.ts +1 -1
  11. package/dist/commands/code/doctor.js +6 -5
  12. package/dist/commands/code/handover.d.ts +2 -2
  13. package/dist/commands/code/handover.js +2 -2
  14. package/dist/commands/code/index.d.ts +2 -2
  15. package/dist/commands/code/index.js +18 -17
  16. package/dist/commands/code/install.d.ts +3 -3
  17. package/dist/commands/code/install.js +18 -11
  18. package/dist/commands/code/migrate.js +3 -2
  19. package/dist/commands/code/oversky-agent.d.ts +5 -4
  20. package/dist/commands/code/oversky-agent.js +24 -22
  21. package/dist/commands/code/run.js +2 -1
  22. package/dist/commands/harnesses/list.d.ts +9 -1
  23. package/dist/commands/harnesses/list.js +28 -7
  24. package/dist/commands/harnesses/show.js +7 -2
  25. package/dist/commands/instructions/install.js +16 -6
  26. package/dist/commands/learning/delete.d.ts +9 -0
  27. package/dist/commands/learning/delete.js +40 -0
  28. package/dist/commands/learning/export.d.ts +9 -0
  29. package/dist/commands/learning/export.js +56 -0
  30. package/dist/commands/learning/reset.d.ts +9 -0
  31. package/dist/commands/learning/reset.js +36 -0
  32. package/dist/commands/learning/set.d.ts +10 -0
  33. package/dist/commands/learning/set.js +52 -0
  34. package/dist/commands/learning/status.d.ts +8 -0
  35. package/dist/commands/learning/status.js +35 -0
  36. package/dist/commands/logout.js +10 -5
  37. package/dist/commands/machines/dedicated/attach.js +2 -1
  38. package/dist/commands/tasks/runs.js +3 -1
  39. package/dist/commands/workspaces/use.js +2 -1
  40. package/dist/lib/adaptive-learning.d.ts +37 -0
  41. package/dist/lib/adaptive-learning.js +39 -0
  42. package/dist/lib/auth-core-init.d.ts +23 -0
  43. package/dist/lib/auth-core-init.js +61 -0
  44. package/dist/lib/code-handover.d.ts +1 -1
  45. package/dist/lib/code-handover.js +3 -2
  46. package/dist/lib/config.d.ts +30 -4
  47. package/dist/lib/config.js +2 -1
  48. package/dist/lib/daemon-installer.d.ts +1 -1
  49. package/dist/lib/daemon-target.js +2 -2
  50. package/dist/lib/dedicated-machines.d.ts +2 -2
  51. package/dist/lib/dedicated-machines.js +11 -4
  52. package/dist/lib/exec-runtime-binary.d.ts +2 -2
  53. package/dist/lib/exec-runtime-binary.js +2 -2
  54. package/dist/lib/{sky-code-agent.d.ts → first-party-harness-agent.d.ts} +20 -19
  55. package/dist/lib/{sky-code-agent.js → first-party-harness-agent.js} +85 -47
  56. package/dist/lib/{sky-code-broker.d.ts → first-party-harness-broker.d.ts} +6 -6
  57. package/dist/lib/{sky-code-broker.js → first-party-harness-broker.js} +23 -23
  58. package/dist/lib/{sky-code-doctor.d.ts → first-party-harness-doctor.d.ts} +12 -2
  59. package/dist/lib/{sky-code-doctor.js → first-party-harness-doctor.js} +181 -94
  60. package/dist/lib/{sky-code-managed.d.ts → first-party-harness-managed.d.ts} +55 -30
  61. package/dist/lib/{sky-code-managed.js → first-party-harness-managed.js} +92 -35
  62. package/dist/lib/{sky-code.d.ts → first-party-harness.d.ts} +107 -36
  63. package/dist/lib/{sky-code.js → first-party-harness.js} +172 -73
  64. package/dist/lib/harness-provider-input.d.ts +35 -0
  65. package/dist/lib/harness-provider-input.js +57 -0
  66. package/dist/lib/harness-tiers.d.ts +8 -2
  67. package/dist/lib/harness-tiers.js +11 -6
  68. package/dist/lib/task-instruction-offer.js +10 -4
  69. package/dist/lib/worklogs.js +2 -2
  70. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/configRoot.d.ts +2 -2
  71. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/configRoot.js +2 -2
  72. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.d.ts +248 -0
  73. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.js +361 -0
  74. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessChannels.d.ts +147 -0
  75. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessChannels.js +180 -0
  76. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessHome.d.ts +111 -0
  77. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessHome.js +314 -0
  78. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessTrust.d.ts +11 -5
  79. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessTrust.js +14 -7
  80. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +3 -1
  81. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +51 -14
  82. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releaseManifest.js +1 -1
  83. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/spawnEnv.d.ts +4 -4
  84. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/spawnEnv.js +4 -4
  85. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/configRoot.d.ts +2 -2
  86. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/configRoot.js +2 -2
  87. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.d.ts +248 -0
  88. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.js +332 -0
  89. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessChannels.d.ts +147 -0
  90. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessChannels.js +170 -0
  91. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessHome.d.ts +111 -0
  92. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessHome.js +303 -0
  93. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessTrust.d.ts +11 -5
  94. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessTrust.js +14 -7
  95. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +3 -1
  96. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +12 -2
  97. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releaseManifest.js +1 -1
  98. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/spawnEnv.d.ts +4 -4
  99. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/spawnEnv.js +4 -4
  100. package/dist/node_modules/@skrr-ai/auth-core/package.json +11 -1
  101. package/dist/node_modules/@skrr-ai/data-provider/index.js +4816 -4782
  102. package/dist/node_modules/@skrr-ai/inference-broker/dist/cjs/index.d.ts +1 -1
  103. package/dist/node_modules/@skrr-ai/inference-broker/dist/cjs/index.js +1 -1
  104. package/dist/node_modules/@skrr-ai/inference-broker/dist/cjs/managed-inference-broker.js +1 -1
  105. package/dist/node_modules/@skrr-ai/inference-broker/dist/esm/index.d.ts +1 -1
  106. package/dist/node_modules/@skrr-ai/inference-broker/dist/esm/index.js +1 -1
  107. package/dist/node_modules/@skrr-ai/inference-broker/dist/esm/managed-inference-broker.js +1 -1
  108. package/dist/node_modules/@skrr-ai/inference-broker/package.json +1 -1
  109. package/oclif.manifest.json +34286 -33962
  110. package/package.json +5 -2
  111. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/skyCodeChannels.d.ts +0 -96
  112. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/skyCodeChannels.js +0 -115
  113. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/skyCodeChannels.d.ts +0 -96
  114. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/skyCodeChannels.js +0 -107
@@ -10,7 +10,7 @@
10
10
  * - The CLI's engine path honoured `OVERSKY_CONFIG_DIR` while its config did
11
11
  * not, so a relocated root moved the engine and left the credentials in
12
12
  * `$HOME`. Fixed by teaching `config.ts` the variable — which promptly
13
- * re-created the split in the mirror image, because `sky-code.ts` still read
13
+ * re-created the split in the mirror image, because the engine resolver still read
14
14
  * only the old name.
15
15
  * - The daemon then had the same shape, and fixing the CLI's half turned it
16
16
  * into a CLI/daemon divergence: with the variable set, the two halves of one
@@ -32,7 +32,7 @@
32
32
  * child process it is about to spawn, and so tests need no process-wide mutation.
33
33
  */
34
34
  export declare function resolveConfigRoot(env?: NodeJS.ProcessEnv): string;
35
- /** A path under the skrr root, e.g. `configRootPath(env, 'sky-code', 'bin')`. */
35
+ /** A path under the skrr root, e.g. `configRootPath(env, 'daemon', 'logs')`. */
36
36
  export declare function configRootPath(env: NodeJS.ProcessEnv, ...segments: string[]): string;
37
37
  /**
38
38
  * Has the operator explicitly relocated the root?
@@ -20,7 +20,7 @@ const node_path_1 = __importDefault(require("node:path"));
20
20
  * - The CLI's engine path honoured `OVERSKY_CONFIG_DIR` while its config did
21
21
  * not, so a relocated root moved the engine and left the credentials in
22
22
  * `$HOME`. Fixed by teaching `config.ts` the variable — which promptly
23
- * re-created the split in the mirror image, because `sky-code.ts` still read
23
+ * re-created the split in the mirror image, because the engine resolver still read
24
24
  * only the old name.
25
25
  * - The daemon then had the same shape, and fixing the CLI's half turned it
26
26
  * into a CLI/daemon divergence: with the variable set, the two halves of one
@@ -45,7 +45,7 @@ function resolveConfigRoot(env = process.env) {
45
45
  const override = (env.SKRR_CONFIG_DIR || env.OVERSKY_CONFIG_DIR)?.trim();
46
46
  return override || node_path_1.default.join((0, node_os_1.homedir)(), '.skrr');
47
47
  }
48
- /** A path under the skrr root, e.g. `configRootPath(env, 'sky-code', 'bin')`. */
48
+ /** A path under the skrr root, e.g. `configRootPath(env, 'daemon', 'logs')`. */
49
49
  function configRootPath(env, ...segments) {
50
50
  return node_path_1.default.join(resolveConfigRoot(env), ...segments);
51
51
  }
@@ -0,0 +1,248 @@
1
+ /**
2
+ * The first-party harness identity — the ONLY place its product name is written.
3
+ *
4
+ * "First-party harness" is the harness provider this platform builds, signs,
5
+ * distributes and installs itself: today a fork of OpenCode sold as skrr Code.
6
+ * It is a different axis from trust Tier 1 in `harnessTrust.ts`, whose
7
+ * "first-party" means an audited VENDOR harness such as Claude Code.
8
+ *
9
+ * ── Why a module, not a find/replace ──────────────────────────────────────
10
+ *
11
+ * The product was renamed twice ("OverSky" engine → "Sky Code" → "skrr Code"),
12
+ * and because its name was used as an IDENTIFIER — in file names, function
13
+ * names, env vars, workflow inputs, Mongo values, wire events — the second
14
+ * rename left 2,826 occurrences in 361 files spelled eleven ways. Every one was
15
+ * a place the next rename would have to find again.
16
+ *
17
+ * So the rule is: the product name is a VALUE held here, and every NAME in the
18
+ * codebase is brand-neutral and reads it. Renaming the product again is:
19
+ *
20
+ * 1. set `displayName` and `provider`;
21
+ * 2. move the old `provider` to the front of `aliases`;
22
+ * 3. leave `wireProvider` on the spelling installed daemons still speak;
23
+ * 4. regenerate `first-party-harness.json`
24
+ * (`node --import tsx scripts/emit-first-party-harness-json.mjs`);
25
+ * 5. ship the data migration, which is generic over `aliases`.
26
+ *
27
+ * No identifier, file, env var name or workflow input moves.
28
+ *
29
+ * ── Three spellings, kept apart on purpose ────────────────────────────────
30
+ *
31
+ * `provider` CANONICAL. What the platform stores, returns and renders.
32
+ * `aliases` ACCEPTED on every ingress until contract, and normalised to
33
+ * canonical at the edge. Nothing new is ever written with one.
34
+ * `wireProvider` What the server and a daemon say to EACH OTHER — the
35
+ * capability a daemon advertises, `daemon:<p>:request|response`,
36
+ * the `provider` of a session RPC. It moves LAST, because a
37
+ * daemon on a user's machine may be any version and the server
38
+ * cannot tell which one sent a request.
39
+ *
40
+ * The old code treated those three as one string, which is why no single
41
+ * change could rename it safely. See
42
+ * `docs/architecture/skrr-code-identifier-rename-2026-09-13.md`.
43
+ *
44
+ * ── Constraints on this file ──────────────────────────────────────────────
45
+ *
46
+ * Pure: no `node:` imports, no `process` at module load. It is published as the
47
+ * `@skrr-ai/auth-core/first-party-harness` subpath so the browser client and
48
+ * the React Native app can read it, and a Node-only import here would break
49
+ * both bundles at a distance.
50
+ */
51
+ export interface FirstPartyHarnessIdentity {
52
+ /** What a person reads. Lowercase brand inside a compound (naming map §1). */
53
+ readonly displayName: string;
54
+ /** The command a person types, as it appears in prose. */
55
+ readonly command: string;
56
+ /** Canonical provider slug: stored, returned by the API, rendered. */
57
+ readonly provider: string;
58
+ /** Older spellings still ACCEPTED on every ingress, newest first. */
59
+ readonly aliases: readonly string[];
60
+ /** The spelling daemons and the server exchange on the wire. */
61
+ readonly wireProvider: string;
62
+ }
63
+ /**
64
+ * THE identity — the only literal product name in the codebase.
65
+ *
66
+ * Phase: EXPAND. `provider` is still the spelling every stored row carries;
67
+ * `skrr-code` is accepted everywhere so the flip can follow once every reader
68
+ * has shipped.
69
+ */
70
+ declare const IDENTITY: {
71
+ readonly displayName: "skrr Code";
72
+ readonly command: "skrr code";
73
+ readonly provider: "sky-code";
74
+ readonly aliases: readonly ["skrr-code"];
75
+ readonly wireProvider: "sky-code";
76
+ };
77
+ /** The canonical slug, as a literal type. */
78
+ export type FirstPartyHarnessCanonicalProvider = typeof IDENTITY.provider;
79
+ /** Any accepted spelling, as a literal type — for unions that must admit an alias. */
80
+ export type FirstPartyHarnessProvider = typeof IDENTITY.provider | (typeof IDENTITY.aliases)[number];
81
+ /** `local-<spelling>` for every accepted spelling. */
82
+ export type FirstPartyHarnessEnvironmentName = `local-${FirstPartyHarnessProvider}`;
83
+ /** `<spelling>_session` for every accepted spelling. */
84
+ export type FirstPartyHarnessCapabilityName = `${FirstPartyHarnessProvider}_session`;
85
+ export declare const FIRST_PARTY_HARNESS: FirstPartyHarnessIdentity;
86
+ /** The canonical slug with its literal type, for `as const` tuples and keyed tables. */
87
+ export declare const FIRST_PARTY_HARNESS_PROVIDER: FirstPartyHarnessCanonicalProvider;
88
+ /** Every spelling, canonical first. The order is the resolution order. */
89
+ export declare function firstPartyHarnessSpellings(): readonly string[];
90
+ /** True for the canonical provider or any alias (case- and whitespace-insensitive). */
91
+ export declare function isFirstPartyHarnessProvider(value: unknown): boolean;
92
+ /**
93
+ * The canonical provider for any spelling of the first-party harness; every
94
+ * other value is returned UNCHANGED (this is not a general normaliser — the
95
+ * caller's own normalisation still owns case and shape for other providers).
96
+ */
97
+ export declare function canonicalHarnessProvider<T>(value: T): T | string;
98
+ /**
99
+ * Every spelling a stored row for this provider may carry, canonical first —
100
+ * for a Mongo `$in` filter while rows written before a flip still exist. Any
101
+ * other provider is returned as a one-element list.
102
+ */
103
+ export declare function harnessProviderSpellings(value: string): string[];
104
+ /** The spelling to put ON THE WIRE to a daemon; other providers pass through. */
105
+ export declare function wireHarnessProvider(value: string): string;
106
+ /** True when two provider values name the same harness, whatever spelling each uses. */
107
+ export declare function isSameHarnessProvider(a: unknown, b: unknown): boolean;
108
+ export declare function firstPartyHarnessCapability(provider?: string): string;
109
+ /** Every capability spelling, canonical first. */
110
+ export declare function firstPartyHarnessCapabilities(): readonly string[];
111
+ /** The capability a daemon advertises. */
112
+ export declare function firstPartyHarnessWireCapability(): string;
113
+ export declare function isFirstPartyHarnessCapability(value: unknown): boolean;
114
+ /** `<alias>_session` → `<provider>_session`; every other value unchanged. */
115
+ export declare function canonicalSessionCapability<T>(value: T): T | string;
116
+ /**
117
+ * Whether a capability list contains `capability` under ANY accepted spelling.
118
+ *
119
+ * A daemon advertises the capability it was built with, and a daemon on a user's
120
+ * machine may be any version, so around a rename the same harness arrives as
121
+ * more than one `<provider>_session`. An exact `includes` against the canonical
122
+ * spelling reads the older one as "not installed" — a card that never lights up,
123
+ * a dispatch refused — with no error. Every other capability compares exactly.
124
+ */
125
+ export declare function advertisesSessionCapability(capabilities: readonly unknown[] | null | undefined, capability: string): boolean;
126
+ export declare function firstPartyHarnessEnvironment(provider?: string): string;
127
+ /** Every environment spelling, canonical first. */
128
+ export declare function firstPartyHarnessEnvironments(): readonly string[];
129
+ export declare function isFirstPartyHarnessEnvironment(value: unknown): boolean;
130
+ /** `local-<alias>` → `local-<provider>`; every other value unchanged. */
131
+ export declare function canonicalExecutionEnvironment<T>(value: T): T | string;
132
+ /** Binary file name. `platform` is a `process.platform` value; only `win32` differs. */
133
+ export declare function firstPartyHarnessBinaryName(provider?: string, platform?: string): string;
134
+ /** Every binary file name, canonical first — the lookup order. */
135
+ export declare function firstPartyHarnessBinaryNames(platform?: string): readonly string[];
136
+ /**
137
+ * The engine home directory name under the skrr config root.
138
+ *
139
+ * It follows the ENGINE's namespace (`FIRST_PARTY_HARNESS_ENGINE.appName`), not
140
+ * the provider slug, because it is one directory with two owners: the platform
141
+ * installs the binary into `<home>/bin`, and the engine reads its own config and
142
+ * the managed `AGENTS.md` from `<home>`. Deriving it from the provider would, on
143
+ * a fresh install after a provider rename, create a second directory the engine
144
+ * never reads — managed instructions would stop applying with no error. It moves
145
+ * when the engine's namespace moves, and not before.
146
+ */
147
+ export declare function firstPartyHarnessHomeDirname(): string;
148
+ /** Signed release manifest file name. */
149
+ export declare function firstPartyHarnessManifestFile(provider?: string): string;
150
+ /**
151
+ * The update feed ORIGIN. Not a product name, and not moved by this identity:
152
+ * a feed host sits inside signed manifests (naming map §2 "Update feed").
153
+ */
154
+ export declare const FIRST_PARTY_HARNESS_FEED_ORIGIN = "https://updates.oversky.ai";
155
+ /** Object-key prefix for one spelling's feed, e.g. `skrr-code/`. */
156
+ export declare function firstPartyHarnessFeedPrefix(provider?: string): string;
157
+ /** Every feed prefix, canonical first. Publishing writes all of them. */
158
+ export declare function firstPartyHarnessFeedPrefixes(): readonly string[];
159
+ /** Object-key prefix the fork stages unsigned builds under, e.g. `skrr-code-staging/`. */
160
+ export declare function firstPartyHarnessStagingPrefix(provider?: string): string;
161
+ /** Default feed base URL for one spelling. */
162
+ export declare function firstPartyHarnessDefaultFeedBase(provider?: string): string;
163
+ export interface FirstPartyHarnessEnvName {
164
+ /** Brand-neutral name. Set this one. */
165
+ readonly name: string;
166
+ /** Older names still read, in precedence order, until contract. */
167
+ readonly legacy: readonly string[];
168
+ }
169
+ /**
170
+ * Every environment variable the platform reads for the first-party harness,
171
+ * by purpose. The neutral name wins; a legacy name is read only when the neutral
172
+ * one is unset or blank, because a variable set in an ECS task definition, a
173
+ * user's shell or a LaunchAgent does not change when the code does.
174
+ */
175
+ export declare const FIRST_PARTY_HARNESS_ENV: Readonly<{
176
+ /** Absolute path to an engine binary, overriding resolution. */
177
+ path: FirstPartyHarnessEnvName;
178
+ /** Forces the CLI's managed-inference mode. */
179
+ managed: FirstPartyHarnessEnvName;
180
+ /** Update channel. */
181
+ channel: FirstPartyHarnessEnvName;
182
+ /** Update-feed base URL override. */
183
+ updateFeedBase: FirstPartyHarnessEnvName;
184
+ /** Path to a file of development release keys. */
185
+ devKeys: FirstPartyHarnessEnvName;
186
+ /** Engine version the desktop build bundles. */
187
+ bundleVersion: FirstPartyHarnessEnvName;
188
+ /** Engine home override (the engine reads its own name too — see ENGINE env below). */
189
+ home: FirstPartyHarnessEnvName;
190
+ /** Engine version baked into the cloud-coding image. */
191
+ cloudCodingVersion: FirstPartyHarnessEnvName;
192
+ /** Engine version baked into the Dedicated Runtime AMI. */
193
+ dedicatedRuntimeVersion: FirstPartyHarnessEnvName;
194
+ /** Engine version the desktop release workflow bundles. */
195
+ desktopBundledVersion: FirstPartyHarnessEnvName;
196
+ /** Update-feed bucket used by publish and promote. */
197
+ updatesBucket: FirstPartyHarnessEnvName;
198
+ /** Release signing key (CI secret). */
199
+ signingKey: FirstPartyHarnessEnvName;
200
+ /** Release signing key id (CI secret). */
201
+ signingKeyId: FirstPartyHarnessEnvName;
202
+ }>;
203
+ export type FirstPartyHarnessEnvKey = keyof typeof FIRST_PARTY_HARNESS_ENV;
204
+ export interface FirstPartyHarnessEnvReading {
205
+ /** Trimmed, non-empty value, or undefined when nothing is set. */
206
+ readonly value: string | undefined;
207
+ /** The variable that supplied `value`. */
208
+ readonly name: string | undefined;
209
+ /** True when the value came from a legacy name — worth telling the operator. */
210
+ readonly legacy: boolean;
211
+ }
212
+ /** Every name for one purpose, neutral first — for spawn-env forwarding and sanitisers. */
213
+ export declare function firstPartyHarnessEnvNames(key: FirstPartyHarnessEnvKey): readonly string[];
214
+ /** Read one purpose's variable: neutral name first, legacy names after. */
215
+ export declare function readFirstPartyHarnessEnv(env: Readonly<Record<string, string | undefined>>, key: FirstPartyHarnessEnvKey): FirstPartyHarnessEnvReading;
216
+ /**
217
+ * Names the ENGINE itself defines and reads. The platform sets or reads them
218
+ * across the daemon↔engine boundary, so they are recorded here as values rather
219
+ * than scattered as literals — but they are the fork's to change, and moving
220
+ * one is a two-sided change (contract §6). Not part of this identity's rename.
221
+ */
222
+ export declare const FIRST_PARTY_HARNESS_ENGINE: Readonly<{
223
+ /**
224
+ * The engine's state namespace: XDG dirs, project marker, config basename, and
225
+ * the engine home under the skrr root (`firstPartyHarnessHomeDirname`).
226
+ */
227
+ appName: "sky-code";
228
+ /**
229
+ * Earlier `appName`s whose home directory `migrateFirstPartyHarnessHome` moves
230
+ * onto the current one. Empty until the engine's namespace is renamed.
231
+ */
232
+ legacyAppNames: readonly string[];
233
+ /** Project-local configuration directory inside a user's repository. */
234
+ projectDirectory: ".sky-code";
235
+ /** Environment variables the engine reads. */
236
+ env: Readonly<{
237
+ serverPassword: "SKY_CODE_SERVER_PASSWORD";
238
+ serverUsername: "SKY_CODE_SERVER_USERNAME";
239
+ home: "SKY_CODE_HOME";
240
+ config: "SKY_CODE_CONFIG";
241
+ appName: "SKY_CODE_APP_NAME";
242
+ scriptName: "SKY_CODE_SCRIPT_NAME";
243
+ allowUpstreamEgress: "SKY_CODE_ALLOW_UPSTREAM_EGRESS";
244
+ compatOpencode: "SKY_CODE_COMPAT_OPENCODE";
245
+ noCompatPrompts: "SKY_CODE_NO_COMPAT_PROMPTS";
246
+ }>;
247
+ }>;
248
+ export {};
@@ -0,0 +1,361 @@
1
+ "use strict";
2
+ /**
3
+ * The first-party harness identity — the ONLY place its product name is written.
4
+ *
5
+ * "First-party harness" is the harness provider this platform builds, signs,
6
+ * distributes and installs itself: today a fork of OpenCode sold as skrr Code.
7
+ * It is a different axis from trust Tier 1 in `harnessTrust.ts`, whose
8
+ * "first-party" means an audited VENDOR harness such as Claude Code.
9
+ *
10
+ * ── Why a module, not a find/replace ──────────────────────────────────────
11
+ *
12
+ * The product was renamed twice ("OverSky" engine → "Sky Code" → "skrr Code"),
13
+ * and because its name was used as an IDENTIFIER — in file names, function
14
+ * names, env vars, workflow inputs, Mongo values, wire events — the second
15
+ * rename left 2,826 occurrences in 361 files spelled eleven ways. Every one was
16
+ * a place the next rename would have to find again.
17
+ *
18
+ * So the rule is: the product name is a VALUE held here, and every NAME in the
19
+ * codebase is brand-neutral and reads it. Renaming the product again is:
20
+ *
21
+ * 1. set `displayName` and `provider`;
22
+ * 2. move the old `provider` to the front of `aliases`;
23
+ * 3. leave `wireProvider` on the spelling installed daemons still speak;
24
+ * 4. regenerate `first-party-harness.json`
25
+ * (`node --import tsx scripts/emit-first-party-harness-json.mjs`);
26
+ * 5. ship the data migration, which is generic over `aliases`.
27
+ *
28
+ * No identifier, file, env var name or workflow input moves.
29
+ *
30
+ * ── Three spellings, kept apart on purpose ────────────────────────────────
31
+ *
32
+ * `provider` CANONICAL. What the platform stores, returns and renders.
33
+ * `aliases` ACCEPTED on every ingress until contract, and normalised to
34
+ * canonical at the edge. Nothing new is ever written with one.
35
+ * `wireProvider` What the server and a daemon say to EACH OTHER — the
36
+ * capability a daemon advertises, `daemon:<p>:request|response`,
37
+ * the `provider` of a session RPC. It moves LAST, because a
38
+ * daemon on a user's machine may be any version and the server
39
+ * cannot tell which one sent a request.
40
+ *
41
+ * The old code treated those three as one string, which is why no single
42
+ * change could rename it safely. See
43
+ * `docs/architecture/skrr-code-identifier-rename-2026-09-13.md`.
44
+ *
45
+ * ── Constraints on this file ──────────────────────────────────────────────
46
+ *
47
+ * Pure: no `node:` imports, no `process` at module load. It is published as the
48
+ * `@skrr-ai/auth-core/first-party-harness` subpath so the browser client and
49
+ * the React Native app can read it, and a Node-only import here would break
50
+ * both bundles at a distance.
51
+ */
52
+ Object.defineProperty(exports, "__esModule", { value: true });
53
+ exports.FIRST_PARTY_HARNESS_ENGINE = exports.FIRST_PARTY_HARNESS_ENV = exports.FIRST_PARTY_HARNESS_FEED_ORIGIN = exports.FIRST_PARTY_HARNESS_PROVIDER = exports.FIRST_PARTY_HARNESS = void 0;
54
+ exports.firstPartyHarnessSpellings = firstPartyHarnessSpellings;
55
+ exports.isFirstPartyHarnessProvider = isFirstPartyHarnessProvider;
56
+ exports.canonicalHarnessProvider = canonicalHarnessProvider;
57
+ exports.harnessProviderSpellings = harnessProviderSpellings;
58
+ exports.wireHarnessProvider = wireHarnessProvider;
59
+ exports.isSameHarnessProvider = isSameHarnessProvider;
60
+ exports.firstPartyHarnessCapability = firstPartyHarnessCapability;
61
+ exports.firstPartyHarnessCapabilities = firstPartyHarnessCapabilities;
62
+ exports.firstPartyHarnessWireCapability = firstPartyHarnessWireCapability;
63
+ exports.isFirstPartyHarnessCapability = isFirstPartyHarnessCapability;
64
+ exports.canonicalSessionCapability = canonicalSessionCapability;
65
+ exports.advertisesSessionCapability = advertisesSessionCapability;
66
+ exports.firstPartyHarnessEnvironment = firstPartyHarnessEnvironment;
67
+ exports.firstPartyHarnessEnvironments = firstPartyHarnessEnvironments;
68
+ exports.isFirstPartyHarnessEnvironment = isFirstPartyHarnessEnvironment;
69
+ exports.canonicalExecutionEnvironment = canonicalExecutionEnvironment;
70
+ exports.firstPartyHarnessBinaryName = firstPartyHarnessBinaryName;
71
+ exports.firstPartyHarnessBinaryNames = firstPartyHarnessBinaryNames;
72
+ exports.firstPartyHarnessHomeDirname = firstPartyHarnessHomeDirname;
73
+ exports.firstPartyHarnessManifestFile = firstPartyHarnessManifestFile;
74
+ exports.firstPartyHarnessFeedPrefix = firstPartyHarnessFeedPrefix;
75
+ exports.firstPartyHarnessFeedPrefixes = firstPartyHarnessFeedPrefixes;
76
+ exports.firstPartyHarnessStagingPrefix = firstPartyHarnessStagingPrefix;
77
+ exports.firstPartyHarnessDefaultFeedBase = firstPartyHarnessDefaultFeedBase;
78
+ exports.firstPartyHarnessEnvNames = firstPartyHarnessEnvNames;
79
+ exports.readFirstPartyHarnessEnv = readFirstPartyHarnessEnv;
80
+ /** A slug usable as a directory name, a capability prefix and an event segment. */
81
+ const SLUG = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
82
+ function defineIdentity(identity) {
83
+ const spellings = [identity.provider, ...identity.aliases];
84
+ for (const spelling of spellings) {
85
+ if (!SLUG.test(spelling)) {
86
+ throw new Error(`first-party harness spelling ${JSON.stringify(spelling)} is not a slug; it becomes a ` +
87
+ `directory name, a capability prefix and a wire event segment`);
88
+ }
89
+ }
90
+ if (new Set(spellings).size !== spellings.length) {
91
+ throw new Error('first-party harness provider and aliases must be distinct');
92
+ }
93
+ if (!spellings.includes(identity.wireProvider)) {
94
+ throw new Error(`first-party harness wireProvider ${JSON.stringify(identity.wireProvider)} must be the ` +
95
+ 'provider or one of its aliases — a peer can only accept a spelling it knows');
96
+ }
97
+ return Object.freeze({ ...identity, aliases: Object.freeze([...identity.aliases]) });
98
+ }
99
+ /**
100
+ * THE identity — the only literal product name in the codebase.
101
+ *
102
+ * Phase: EXPAND. `provider` is still the spelling every stored row carries;
103
+ * `skrr-code` is accepted everywhere so the flip can follow once every reader
104
+ * has shipped.
105
+ */
106
+ const IDENTITY = {
107
+ displayName: 'skrr Code',
108
+ command: 'skrr code',
109
+ provider: 'sky-code',
110
+ aliases: ['skrr-code'],
111
+ wireProvider: 'sky-code',
112
+ };
113
+ exports.FIRST_PARTY_HARNESS = defineIdentity(IDENTITY);
114
+ /** The canonical slug with its literal type, for `as const` tuples and keyed tables. */
115
+ exports.FIRST_PARTY_HARNESS_PROVIDER = IDENTITY.provider;
116
+ const SPELLINGS = Object.freeze([
117
+ exports.FIRST_PARTY_HARNESS.provider,
118
+ ...exports.FIRST_PARTY_HARNESS.aliases,
119
+ ]);
120
+ const SPELLING_SET = new Set(SPELLINGS);
121
+ const SESSION_SUFFIX = '_session';
122
+ const ENVIRONMENT_PREFIX = 'local-';
123
+ function asSlug(value) {
124
+ if (typeof value !== 'string')
125
+ return null;
126
+ const slug = value.trim().toLowerCase();
127
+ return slug ? slug : null;
128
+ }
129
+ /** Every spelling, canonical first. The order is the resolution order. */
130
+ function firstPartyHarnessSpellings() {
131
+ return SPELLINGS;
132
+ }
133
+ /** True for the canonical provider or any alias (case- and whitespace-insensitive). */
134
+ function isFirstPartyHarnessProvider(value) {
135
+ const slug = asSlug(value);
136
+ return slug !== null && SPELLING_SET.has(slug);
137
+ }
138
+ /**
139
+ * The canonical provider for any spelling of the first-party harness; every
140
+ * other value is returned UNCHANGED (this is not a general normaliser — the
141
+ * caller's own normalisation still owns case and shape for other providers).
142
+ */
143
+ function canonicalHarnessProvider(value) {
144
+ return isFirstPartyHarnessProvider(value) ? exports.FIRST_PARTY_HARNESS.provider : value;
145
+ }
146
+ /**
147
+ * Every spelling a stored row for this provider may carry, canonical first —
148
+ * for a Mongo `$in` filter while rows written before a flip still exist. Any
149
+ * other provider is returned as a one-element list.
150
+ */
151
+ function harnessProviderSpellings(value) {
152
+ return isFirstPartyHarnessProvider(value) ? [...SPELLINGS] : [value];
153
+ }
154
+ /** The spelling to put ON THE WIRE to a daemon; other providers pass through. */
155
+ function wireHarnessProvider(value) {
156
+ return isFirstPartyHarnessProvider(value) ? exports.FIRST_PARTY_HARNESS.wireProvider : value;
157
+ }
158
+ /** True when two provider values name the same harness, whatever spelling each uses. */
159
+ function isSameHarnessProvider(a, b) {
160
+ if (typeof a !== 'string' || typeof b !== 'string')
161
+ return false;
162
+ return (canonicalHarnessProvider(a.trim().toLowerCase()) ===
163
+ canonicalHarnessProvider(b.trim().toLowerCase()));
164
+ }
165
+ /* ── Derived: session capability ─────────────────────────────────────────── */
166
+ function firstPartyHarnessCapability(provider = exports.FIRST_PARTY_HARNESS.provider) {
167
+ return `${provider}${SESSION_SUFFIX}`;
168
+ }
169
+ /** Every capability spelling, canonical first. */
170
+ function firstPartyHarnessCapabilities() {
171
+ return SPELLINGS.map((spelling) => firstPartyHarnessCapability(spelling));
172
+ }
173
+ /** The capability a daemon advertises. */
174
+ function firstPartyHarnessWireCapability() {
175
+ return firstPartyHarnessCapability(exports.FIRST_PARTY_HARNESS.wireProvider);
176
+ }
177
+ function isFirstPartyHarnessCapability(value) {
178
+ const slug = asSlug(value);
179
+ if (slug === null || !slug.endsWith(SESSION_SUFFIX))
180
+ return false;
181
+ return SPELLING_SET.has(slug.slice(0, -SESSION_SUFFIX.length));
182
+ }
183
+ /** `<alias>_session` → `<provider>_session`; every other value unchanged. */
184
+ function canonicalSessionCapability(value) {
185
+ return isFirstPartyHarnessCapability(value) ? firstPartyHarnessCapability() : value;
186
+ }
187
+ /**
188
+ * Whether a capability list contains `capability` under ANY accepted spelling.
189
+ *
190
+ * A daemon advertises the capability it was built with, and a daemon on a user's
191
+ * machine may be any version, so around a rename the same harness arrives as
192
+ * more than one `<provider>_session`. An exact `includes` against the canonical
193
+ * spelling reads the older one as "not installed" — a card that never lights up,
194
+ * a dispatch refused — with no error. Every other capability compares exactly.
195
+ */
196
+ function advertisesSessionCapability(capabilities, capability) {
197
+ if (!Array.isArray(capabilities) || capabilities.length === 0)
198
+ return false;
199
+ const wanted = canonicalSessionCapability(capability);
200
+ return capabilities.some((advertised) => canonicalSessionCapability(advertised) === wanted);
201
+ }
202
+ /* ── Derived: pinned execution environment ───────────────────────────────── */
203
+ function firstPartyHarnessEnvironment(provider = exports.FIRST_PARTY_HARNESS.provider) {
204
+ return `${ENVIRONMENT_PREFIX}${provider}`;
205
+ }
206
+ /** Every environment spelling, canonical first. */
207
+ function firstPartyHarnessEnvironments() {
208
+ return SPELLINGS.map((spelling) => firstPartyHarnessEnvironment(spelling));
209
+ }
210
+ function isFirstPartyHarnessEnvironment(value) {
211
+ const slug = asSlug(value);
212
+ if (slug === null || !slug.startsWith(ENVIRONMENT_PREFIX))
213
+ return false;
214
+ return SPELLING_SET.has(slug.slice(ENVIRONMENT_PREFIX.length));
215
+ }
216
+ /** `local-<alias>` → `local-<provider>`; every other value unchanged. */
217
+ function canonicalExecutionEnvironment(value) {
218
+ return isFirstPartyHarnessEnvironment(value) ? firstPartyHarnessEnvironment() : value;
219
+ }
220
+ /* ── Derived: on-disk and distribution names ─────────────────────────────── */
221
+ /** Binary file name. `platform` is a `process.platform` value; only `win32` differs. */
222
+ function firstPartyHarnessBinaryName(provider = exports.FIRST_PARTY_HARNESS.provider, platform) {
223
+ return platform === 'win32' ? `${provider}.exe` : provider;
224
+ }
225
+ /** Every binary file name, canonical first — the lookup order. */
226
+ function firstPartyHarnessBinaryNames(platform) {
227
+ return SPELLINGS.map((spelling) => firstPartyHarnessBinaryName(spelling, platform));
228
+ }
229
+ /**
230
+ * The engine home directory name under the skrr config root.
231
+ *
232
+ * It follows the ENGINE's namespace (`FIRST_PARTY_HARNESS_ENGINE.appName`), not
233
+ * the provider slug, because it is one directory with two owners: the platform
234
+ * installs the binary into `<home>/bin`, and the engine reads its own config and
235
+ * the managed `AGENTS.md` from `<home>`. Deriving it from the provider would, on
236
+ * a fresh install after a provider rename, create a second directory the engine
237
+ * never reads — managed instructions would stop applying with no error. It moves
238
+ * when the engine's namespace moves, and not before.
239
+ */
240
+ function firstPartyHarnessHomeDirname() {
241
+ return exports.FIRST_PARTY_HARNESS_ENGINE.appName;
242
+ }
243
+ /** Signed release manifest file name. */
244
+ function firstPartyHarnessManifestFile(provider = exports.FIRST_PARTY_HARNESS.provider) {
245
+ return `${provider}-version.json`;
246
+ }
247
+ /**
248
+ * The update feed ORIGIN. Not a product name, and not moved by this identity:
249
+ * a feed host sits inside signed manifests (naming map §2 "Update feed").
250
+ */
251
+ exports.FIRST_PARTY_HARNESS_FEED_ORIGIN = 'https://updates.oversky.ai';
252
+ /** Object-key prefix for one spelling's feed, e.g. `skrr-code/`. */
253
+ function firstPartyHarnessFeedPrefix(provider = exports.FIRST_PARTY_HARNESS.provider) {
254
+ return `${provider}/`;
255
+ }
256
+ /** Every feed prefix, canonical first. Publishing writes all of them. */
257
+ function firstPartyHarnessFeedPrefixes() {
258
+ return SPELLINGS.map((spelling) => firstPartyHarnessFeedPrefix(spelling));
259
+ }
260
+ /** Object-key prefix the fork stages unsigned builds under, e.g. `skrr-code-staging/`. */
261
+ function firstPartyHarnessStagingPrefix(provider = exports.FIRST_PARTY_HARNESS.provider) {
262
+ return `${provider}-staging/`;
263
+ }
264
+ /** Default feed base URL for one spelling. */
265
+ function firstPartyHarnessDefaultFeedBase(provider = exports.FIRST_PARTY_HARNESS.provider) {
266
+ return `${exports.FIRST_PARTY_HARNESS_FEED_ORIGIN}/${provider}`;
267
+ }
268
+ function envName(name, legacy) {
269
+ return Object.freeze({ name, legacy: Object.freeze([...legacy]) });
270
+ }
271
+ /**
272
+ * Every environment variable the platform reads for the first-party harness,
273
+ * by purpose. The neutral name wins; a legacy name is read only when the neutral
274
+ * one is unset or blank, because a variable set in an ECS task definition, a
275
+ * user's shell or a LaunchAgent does not change when the code does.
276
+ */
277
+ exports.FIRST_PARTY_HARNESS_ENV = Object.freeze({
278
+ /** Absolute path to an engine binary, overriding resolution. */
279
+ path: envName('SKRR_FIRST_PARTY_HARNESS_PATH', ['OVERSKY_SKY_CODE_PATH']),
280
+ /** Forces the CLI's managed-inference mode. */
281
+ managed: envName('SKRR_FIRST_PARTY_HARNESS_MANAGED', ['OVERSKY_SKY_CODE_MANAGED']),
282
+ /** Update channel. */
283
+ channel: envName('SKRR_FIRST_PARTY_HARNESS_CHANNEL', ['OVERSKY_SKY_CODE_CHANNEL']),
284
+ /** Update-feed base URL override. */
285
+ updateFeedBase: envName('SKRR_FIRST_PARTY_HARNESS_UPDATE_FEED_BASE', [
286
+ 'OVERSKY_SKY_CODE_UPDATE_FEED_BASE',
287
+ ]),
288
+ /** Path to a file of development release keys. */
289
+ devKeys: envName('SKRR_FIRST_PARTY_HARNESS_DEV_KEYS', ['OVERSKY_SKY_CODE_DEV_KEYS']),
290
+ /** Engine version the desktop build bundles. */
291
+ bundleVersion: envName('SKRR_FIRST_PARTY_HARNESS_BUNDLE_VERSION', ['OVERSKY_BUNDLE_SKY_CODE']),
292
+ /** Engine home override (the engine reads its own name too — see ENGINE env below). */
293
+ home: envName('SKRR_FIRST_PARTY_HARNESS_HOME', ['SKY_CODE_HOME']),
294
+ /** Engine version baked into the cloud-coding image. */
295
+ cloudCodingVersion: envName('CLOUD_CODING_FIRST_PARTY_HARNESS_VERSION', [
296
+ 'CLOUD_CODING_SKY_CODE_VERSION',
297
+ ]),
298
+ /** Engine version baked into the Dedicated Runtime AMI. */
299
+ dedicatedRuntimeVersion: envName('SKRR_DEDICATED_RUNTIME_FIRST_PARTY_HARNESS_VERSION', [
300
+ 'SKRR_DEDICATED_RUNTIME_SKY_CODE_VERSION',
301
+ ]),
302
+ /** Engine version the desktop release workflow bundles. */
303
+ desktopBundledVersion: envName('DESKTOP_BUNDLED_FIRST_PARTY_HARNESS_VERSION', [
304
+ 'DESKTOP_BUNDLED_SKY_CODE_VERSION',
305
+ ]),
306
+ /** Update-feed bucket used by publish and promote. */
307
+ updatesBucket: envName('FIRST_PARTY_HARNESS_UPDATES_BUCKET', ['SKY_CODE_UPDATES_BUCKET']),
308
+ /** Release signing key (CI secret). */
309
+ signingKey: envName('FIRST_PARTY_HARNESS_SIGNING_KEY', ['SKY_CODE_SIGNING_KEY']),
310
+ /** Release signing key id (CI secret). */
311
+ signingKeyId: envName('FIRST_PARTY_HARNESS_SIGNING_KEY_ID', ['SKY_CODE_SIGNING_KEY_ID']),
312
+ });
313
+ /** Every name for one purpose, neutral first — for spawn-env forwarding and sanitisers. */
314
+ function firstPartyHarnessEnvNames(key) {
315
+ const entry = exports.FIRST_PARTY_HARNESS_ENV[key];
316
+ return [entry.name, ...entry.legacy];
317
+ }
318
+ /** Read one purpose's variable: neutral name first, legacy names after. */
319
+ function readFirstPartyHarnessEnv(env, key) {
320
+ const entry = exports.FIRST_PARTY_HARNESS_ENV[key];
321
+ for (const name of [entry.name, ...entry.legacy]) {
322
+ const raw = env[name];
323
+ if (typeof raw === 'string' && raw.trim() !== '') {
324
+ return { value: raw.trim(), name, legacy: name !== entry.name };
325
+ }
326
+ }
327
+ return { value: undefined, name: undefined, legacy: false };
328
+ }
329
+ /* ── The ENGINE's own namespace (defined inside the fork) ───────────────── */
330
+ /**
331
+ * Names the ENGINE itself defines and reads. The platform sets or reads them
332
+ * across the daemon↔engine boundary, so they are recorded here as values rather
333
+ * than scattered as literals — but they are the fork's to change, and moving
334
+ * one is a two-sided change (contract §6). Not part of this identity's rename.
335
+ */
336
+ exports.FIRST_PARTY_HARNESS_ENGINE = Object.freeze({
337
+ /**
338
+ * The engine's state namespace: XDG dirs, project marker, config basename, and
339
+ * the engine home under the skrr root (`firstPartyHarnessHomeDirname`).
340
+ */
341
+ appName: 'sky-code',
342
+ /**
343
+ * Earlier `appName`s whose home directory `migrateFirstPartyHarnessHome` moves
344
+ * onto the current one. Empty until the engine's namespace is renamed.
345
+ */
346
+ legacyAppNames: Object.freeze([]),
347
+ /** Project-local configuration directory inside a user's repository. */
348
+ projectDirectory: '.sky-code',
349
+ /** Environment variables the engine reads. */
350
+ env: Object.freeze({
351
+ serverPassword: 'SKY_CODE_SERVER_PASSWORD',
352
+ serverUsername: 'SKY_CODE_SERVER_USERNAME',
353
+ home: 'SKY_CODE_HOME',
354
+ config: 'SKY_CODE_CONFIG',
355
+ appName: 'SKY_CODE_APP_NAME',
356
+ scriptName: 'SKY_CODE_SCRIPT_NAME',
357
+ allowUpstreamEgress: 'SKY_CODE_ALLOW_UPSTREAM_EGRESS',
358
+ compatOpencode: 'SKY_CODE_COMPAT_OPENCODE',
359
+ noCompatPrompts: 'SKY_CODE_NO_COMPAT_PROMPTS',
360
+ }),
361
+ });