@skrr-ai/cli 0.1.123 → 0.1.124

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 (85) hide show
  1. package/dist/commands/agents/delete.d.ts +8 -0
  2. package/dist/commands/agents/delete.js +16 -0
  3. package/dist/commands/context.js +7 -0
  4. package/dist/commands/search/workspace.js +1 -1
  5. package/dist/commands/store/gallery-admissions/approve.js +1 -1
  6. package/dist/commands/store/gallery-admissions/preview.js +1 -1
  7. package/dist/commands/store/gallery-admissions/refuse.js +1 -1
  8. package/dist/commands/store/gallery-admissions/show.js +1 -1
  9. package/dist/lib/auth-core-init.d.ts +15 -2
  10. package/dist/lib/auth-core-init.js +47 -6
  11. package/dist/lib/command-hygiene.js +30 -1
  12. package/dist/lib/daemonBrokerRefusal.js +5 -1
  13. package/dist/lib/keychain.js +41 -4
  14. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/cliHandoffWire.d.ts +5 -1
  15. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/cliHandoffWire.js +1 -1
  16. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialEnvelopeBridge.js +13 -28
  17. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.d.ts +133 -4
  18. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.js +387 -90
  19. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceKey.d.ts +106 -7
  20. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceKey.js +77 -19
  21. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceKeyHandle.d.ts +33 -0
  22. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceKeyHandle.js +77 -0
  23. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceKeyHardware.d.ts +68 -0
  24. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceKeyHardware.js +264 -0
  25. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceKeyServerSupport.d.ts +31 -0
  26. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceKeyServerSupport.js +90 -0
  27. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/dpop.js +2 -0
  28. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/independentMachineReservation.js +2 -0
  29. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +7 -3
  30. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +102 -0
  31. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/index.d.ts +1 -1
  32. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/index.js +6 -0
  33. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/linux.d.ts +18 -0
  34. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/linux.js +8 -0
  35. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/macos.d.ts +22 -0
  36. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/macos.js +11 -0
  37. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/masterKekService.d.ts +43 -3
  38. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/masterKekService.js +33 -3
  39. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/liveState.d.ts +154 -0
  40. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/liveState.js +281 -0
  41. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineId.js +6 -3
  42. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.js +8 -5
  43. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/profileStateDir.js +7 -27
  44. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refresh.d.ts +1 -1
  45. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refresh.js +12 -10
  46. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/stateFiles.d.ts +31 -0
  47. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/stateFiles.js +89 -0
  48. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/cliHandoffWire.d.ts +5 -1
  49. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/cliHandoffWire.js +4 -1
  50. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialEnvelopeBridge.js +15 -37
  51. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.d.ts +133 -4
  52. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.js +536 -101
  53. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceKey.d.ts +106 -7
  54. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceKey.js +131 -27
  55. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceKeyHandle.d.ts +33 -0
  56. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceKeyHandle.js +81 -0
  57. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceKeyHardware.d.ts +68 -0
  58. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceKeyHardware.js +317 -0
  59. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceKeyServerSupport.d.ts +31 -0
  60. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceKeyServerSupport.js +86 -0
  61. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/dpop.js +4 -0
  62. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/independentMachineReservation.js +4 -0
  63. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +7 -3
  64. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +13 -3
  65. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/index.d.ts +1 -1
  66. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/index.js +1 -1
  67. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/linux.d.ts +18 -0
  68. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/linux.js +15 -0
  69. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/macos.d.ts +22 -0
  70. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/macos.js +20 -0
  71. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/masterKekService.d.ts +43 -3
  72. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/masterKekService.js +104 -8
  73. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/liveState.d.ts +154 -0
  74. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/liveState.js +386 -0
  75. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineId.js +6 -3
  76. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.js +11 -5
  77. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/profileStateDir.js +6 -35
  78. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refresh.d.ts +1 -1
  79. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refresh.js +14 -10
  80. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/stateFiles.d.ts +31 -0
  81. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/stateFiles.js +73 -0
  82. package/dist/node_modules/@skrr-ai/auth-core/package.json +11 -1
  83. package/dist/node_modules/@skrr-ai/data-provider/index.js +25 -7
  84. package/oclif.manifest.json +1 -1
  85. package/package.json +4 -1
@@ -1,4 +1,34 @@
1
- import { type DeviceKeyPair, type Ed25519PublicJwk } from './deviceKey.js';
1
+ import { type DeviceKeyAlg, type DevicePublicJwk } from './deviceKey.js';
2
+ import { type DeviceKeyCustody, type DeviceKeyHandle } from './deviceKeyHandle.js';
3
+ import { type HardwareKeyCapability, type HardwareKeyRecord } from './deviceKeyHardware.js';
4
+ /**
5
+ * The `cred_envelope.read.decrypt_failed` hint for the device PRIVATE key
6
+ * (OSK-20506).
7
+ *
8
+ * The envelope's default hint says "signing in again rebuilds it", which is true
9
+ * of a credential and false of this: `skrr login` never creates or replaces a
10
+ * device key, and only an interactive daemon sign-in does (it re-pins the new key
11
+ * on the server). `loadKeypair` hands this to `maybeDecryptOnRead` so the
12
+ * producer says WHAT failed; a presenter that already prints one device-key line
13
+ * (the CLI's `recovery_required` notice) recognises it by identity and prints
14
+ * nothing for the decrypt failure, instead of two lines with two remedies. A
15
+ * logger that prints every warning, the daemon's, shows this one as written.
16
+ *
17
+ * Compared by value by the CLI presenter: change the text and the CLI prints the
18
+ * credential line again, which `auth-core-init.device-key.spec.ts` catches.
19
+ */
20
+ export declare const DEVICE_KEY_UNREADABLE_CREDENTIAL_HINT = "stored device key is unreadable on this machine \u2014 only an interactive daemon sign-in replaces it";
21
+ /**
22
+ * `key` is a handle, never a keypair: nothing in this module (or any caller of
23
+ * it) can read a private scalar once a key is active, which is what lets a
24
+ * hardware key stand in for a software one without a second code path.
25
+ *
26
+ * `envelopeProtected` is about the PRIVATE KEY FILE being sealed under the
27
+ * credential envelope. A hardware record is deliberately not sealed (it is
28
+ * useless off this machine, and sealing it would tie the device identity's life
29
+ * to the envelope key again), so it is always `false` for hardware and says
30
+ * nothing about how well that key is protected: read `key.custody` for that.
31
+ */
2
32
  type DeviceIdentityState = {
3
33
  kind: 'uninit';
4
34
  } | {
@@ -6,7 +36,7 @@ type DeviceIdentityState = {
6
36
  reason: DisabledReason;
7
37
  } | {
8
38
  kind: 'active';
9
- keypair: DeviceKeyPair;
39
+ key: DeviceKeyHandle;
10
40
  profile: string;
11
41
  envelopeProtected: boolean;
12
42
  };
@@ -69,6 +99,69 @@ export declare function resetDeviceIdentity(opts?: {
69
99
  profile?: string;
70
100
  clearOnDisk?: boolean;
71
101
  }): Promise<void>;
102
+ /**
103
+ * A hardware key that exists only in memory. It is not this machine's identity
104
+ * until `commitDeviceKeyCandidate`, and it leaves nothing behind if it is
105
+ * dropped: a Secure Enclave key lives in the blob and nowhere else.
106
+ *
107
+ * That is the whole safety argument for an upgrade. The server learns the new key
108
+ * from a proof signed with it (an interactive sign-in re-pins the row), so the
109
+ * order has to be: create the candidate, sign the sign-in with it, and only after
110
+ * the server has accepted that sign-in make it the identity. The software key
111
+ * stays on disk, untouched and active, through every step before the last one.
112
+ */
113
+ export interface DeviceKeyCandidate {
114
+ readonly key: DeviceKeyHandle;
115
+ /** @internal what `commitDeviceKeyCandidate` persists. */
116
+ readonly record: HardwareKeyRecord;
117
+ }
118
+ export type DeviceKeyCandidateResult = {
119
+ ok: true;
120
+ candidate: DeviceKeyCandidate;
121
+ } | {
122
+ ok: false;
123
+ reason: 'already_hardware' | 'independent_profile' | 'unavailable' | 'create_failed';
124
+ capability?: HardwareKeyCapability;
125
+ message?: string;
126
+ };
127
+ /**
128
+ * Create a hardware key candidate if this machine can hold one and does not
129
+ * already. Never throws and never touches disk, so an interactive sign-in can
130
+ * call it unconditionally and fall back to the key it has on any answer but ok.
131
+ */
132
+ export declare function prepareHardwareKeyCandidate(profile: string): Promise<DeviceKeyCandidateResult>;
133
+ /** Sign a request with a candidate (the upgrade's sign-in proof). Null on failure, like `signServerRequest`. */
134
+ export declare function signWithCandidate(candidate: DeviceKeyCandidate, opts: {
135
+ method: string;
136
+ url: string;
137
+ refreshToken?: string;
138
+ accessToken?: string;
139
+ }): Promise<string | null>;
140
+ /**
141
+ * Make a candidate this profile's device identity. Call it only after the
142
+ * server has accepted a sign-in proven with `candidate`: until then the software
143
+ * key is the identity the server pins, and replacing it early is the failure
144
+ * this API exists to prevent.
145
+ *
146
+ * Under the identity lock, in the order that survives a crash: retire the old
147
+ * key, write the hardware record (authoritative), then the public file, then
148
+ * clear the enrollment marker (it records the OLD thumbprint and would otherwise
149
+ * short-circuit every later enrollment as already done).
150
+ */
151
+ export declare function commitDeviceKeyCandidate(profile: string, candidate: DeviceKeyCandidate): Promise<void>;
152
+ /** A sign-in that takes longer than this has been abandoned; its pending key is not committed. */
153
+ export declare const PENDING_HARDWARE_KEY_MAX_AGE_MS: number;
154
+ /** Park a candidate so a later process can commit or discard it. Replaces any earlier one. */
155
+ export declare function persistPendingHardwareKey(profile: string, candidate: DeviceKeyCandidate): Promise<void>;
156
+ export type PendingHardwareKeyOutcome = 'committed' | 'no_pending' | 'mismatch' | 'expired' | 'unreadable';
157
+ /**
158
+ * Make the parked candidate this profile's identity, if it is the one the caller
159
+ * proved the sign-in with (`thumbprint`) and it is not stale. Anything else
160
+ * commits nothing: the software key stays the identity, and the answer says why.
161
+ */
162
+ export declare function commitPendingHardwareKey(profile: string, thumbprint: string): Promise<PendingHardwareKeyOutcome>;
163
+ /** Drop the parked candidate (the sign-in failed or was refused). Idempotent. */
164
+ export declare function discardPendingHardwareKey(profile: string): Promise<void>;
72
165
  /** True iff init has completed and a keypair is in memory. */
73
166
  export declare function isDeviceIdentityActive(): boolean;
74
167
  /**
@@ -77,8 +170,10 @@ export declare function isDeviceIdentityActive(): boolean;
77
170
  * on the in-flight request.
78
171
  */
79
172
  export declare function getDevicePublicKey(): {
80
- jwk: Ed25519PublicJwk;
173
+ jwk: DevicePublicJwk;
81
174
  thumbprint: string;
175
+ alg: DeviceKeyAlg;
176
+ custody: DeviceKeyCustody;
82
177
  } | null;
83
178
  /**
84
179
  * Operator-readable summary of device-identity state. Used by
@@ -90,13 +185,47 @@ export declare function describeDeviceIdentityState(): {
90
185
  thumbprint?: string;
91
186
  profile?: string;
92
187
  envelopeProtected?: boolean;
188
+ alg?: DeviceKeyAlg;
189
+ /** Whether the private half can be copied off this machine. Absent unless active. */
190
+ custody?: DeviceKeyCustody;
191
+ /**
192
+ * For a hardware key: can THIS process sign with it right now? False means the
193
+ * key exists and is intact but the helper that signs with it is not installed
194
+ * where this process can find it (a CLI without the desktop app's helper, an
195
+ * app update that has not landed). It is a different fact from an unreadable
196
+ * key, and it must never lead to replacing the key.
197
+ */
198
+ canSign?: boolean;
199
+ };
200
+ export type StoredDeviceKeyDescription = {
201
+ stored: false;
202
+ } | {
203
+ stored: true;
204
+ alg: DeviceKeyAlg;
205
+ custody: DeviceKeyCustody;
206
+ thumbprint: string;
207
+ /** A hardware key needs the helper to sign; a software key never does. */
208
+ canSign: boolean;
93
209
  };
210
+ /**
211
+ * What a profile's device key IS, read from its plaintext public record alone. For
212
+ * `status`, which is a different process from the daemon and may run while the
213
+ * daemon is stopped: it opens nothing, needs no envelope key and writes nothing, so
214
+ * it answers even when the private half is unreadable. Not evidence the key can be
215
+ * used (only `describeDeviceIdentityState` in the process that loaded it says that);
216
+ * evidence of what kind of key the profile has, which nothing else showed.
217
+ */
218
+ export declare function describeStoredDeviceKey(profile: string): StoredDeviceKeyDescription;
94
219
  /**
95
220
  * Sign an outgoing request with the device key. Returns the JWS Compact
96
221
  * Serialization, or null when device identity is not active. NEVER
97
222
  * throws — a failed sign returns null and emits a telemetry event so
98
223
  * the caller can fall back to bearer-only auth without an outage.
99
224
  *
225
+ * Asynchronous because a hardware key signs in a helper process. A software key
226
+ * resolves on the next microtask, so a caller that awaits pays nothing it can
227
+ * measure; a caller that could not await could not have a hardware key.
228
+ *
100
229
  * Shape matches `DeviceProofSigner` from `./refresh.ts` so the function
101
230
  * passes directly into `refreshDaemonToken`'s `signRequestProof` slot.
102
231
  */
@@ -105,7 +234,7 @@ export declare function signServerRequest(opts: {
105
234
  url: string;
106
235
  refreshToken?: string;
107
236
  accessToken?: string;
108
- }): string | null;
237
+ }): Promise<string | null>;
109
238
  /** @internal Test seams — file path resolvers. */
110
239
  export declare function __publicKeyPathForTest(profile: string): string;
111
240
  export declare function __privateKeyPathForTest(profile: string): string;