@skrr-ai/cli 0.1.43 → 0.1.44
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.
- package/dist/base-command.d.ts +2 -0
- package/dist/base-command.js +1 -0
- package/dist/commands/balance/index.js +1 -1
- package/dist/commands/balance/show.d.ts +32 -0
- package/dist/commands/balance/show.js +74 -3
- package/dist/commands/code/handover.d.ts +1 -0
- package/dist/commands/code/handover.js +4 -0
- package/dist/commands/code/jobs/run.d.ts +1 -0
- package/dist/commands/code/jobs/run.js +4 -0
- package/dist/commands/daemon/install.js +7 -0
- package/dist/commands/harnesses/leases/show.js +14 -0
- package/dist/commands/instructions/install.d.ts +22 -0
- package/dist/commands/instructions/install.js +83 -7
- package/dist/commands/instructions/list.js +5 -0
- package/dist/commands/instructions/show.d.ts +6 -0
- package/dist/commands/instructions/show.js +34 -1
- package/dist/commands/instructions/status.js +17 -1
- package/dist/commands/payments/wallet.js +2 -2
- package/dist/commands/tasks/create.d.ts +6 -0
- package/dist/commands/tasks/create.js +26 -3
- package/dist/commands/tasks/labels/attach.js +4 -0
- package/dist/commands/tasks/list.d.ts +1 -0
- package/dist/commands/tasks/list.js +9 -0
- package/dist/commands/tasks/show.d.ts +23 -0
- package/dist/commands/tasks/show.js +61 -1
- package/dist/commands/tasks/update.js +12 -0
- package/dist/commands/views/create.js +12 -2
- package/dist/commands/views/list.js +3 -2
- package/dist/commands/views/show.js +2 -0
- package/dist/lib/agentic-stream.d.ts +10 -4
- package/dist/lib/agentic-stream.js +25 -11
- package/dist/lib/cli-installers.js +9 -1
- package/dist/lib/daemon-setup.d.ts +18 -1
- package/dist/lib/daemon-setup.js +33 -1
- package/dist/lib/first-party-harness-agent.d.ts +16 -1
- package/dist/lib/first-party-harness-agent.js +41 -12
- package/dist/lib/first-party-harness-doctor.js +34 -16
- package/dist/lib/first-party-harness.d.ts +18 -11
- package/dist/lib/first-party-harness.js +26 -21
- package/dist/lib/harnesses.d.ts +6 -0
- package/dist/lib/instruction-input.d.ts +21 -0
- package/dist/lib/instruction-input.js +30 -0
- package/dist/lib/instruction-provenance.d.ts +54 -0
- package/dist/lib/instruction-provenance.js +84 -0
- package/dist/lib/task-view-render.d.ts +14 -0
- package/dist/lib/task-view-render.js +55 -0
- package/dist/lib/tasks.d.ts +18 -0
- package/dist/lib/tasks.js +22 -1
- package/dist/lib/views/vocabulary.d.ts +1 -1
- package/dist/lib/views/vocabulary.js +3 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.d.ts +75 -24
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.js +143 -34
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/legacyStatePreflight.d.ts +21 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/legacyStatePreflight.js +75 -19
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.d.ts +75 -24
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.js +138 -34
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/legacyStatePreflight.d.ts +21 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/legacyStatePreflight.js +74 -19
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +3516 -3513
- package/dist/node_modules/@skrr-ai/data-provider/package.json +1 -1
- package/oclif.manifest.json +21649 -21626
- package/package.json +3 -3
|
@@ -213,7 +213,8 @@ export declare function firstPartyHarnessBinaryNames(platform?: string): readonl
|
|
|
213
213
|
* the managed `AGENTS.md` from `<home>`. Deriving it from the provider would, on
|
|
214
214
|
* a fresh install after a provider rename, create a second directory the engine
|
|
215
215
|
* never reads — managed instructions would stop applying with no error. It moves
|
|
216
|
-
* when the engine's namespace moves, and not before
|
|
216
|
+
* when the engine's namespace moves, and not before; it did in OSK-8674, and
|
|
217
|
+
* `migrateFirstPartyHarnessHome` moves a home under a legacy name onto it.
|
|
217
218
|
*/
|
|
218
219
|
export declare function firstPartyHarnessHomeDirname(): string;
|
|
219
220
|
/** Signed release manifest file name. */
|
|
@@ -250,7 +251,8 @@ export interface FirstPartyHarnessEnvName {
|
|
|
250
251
|
* (OSK-8663) and are not read at all now. The ENGINE's own variables are a
|
|
251
252
|
* different namespace (`FIRST_PARTY_HARNESS_ENGINE.env`): the fork reads them,
|
|
252
253
|
* so a platform reader that must agree with the engine consults the engine's
|
|
253
|
-
*
|
|
254
|
+
* names explicitly (`readFirstPartyHarnessEngineEnv`) — the engine home is the
|
|
255
|
+
* one case (`home` below).
|
|
254
256
|
*/
|
|
255
257
|
export declare const FIRST_PARTY_HARNESS_ENV: Readonly<{
|
|
256
258
|
/** Absolute path to an engine binary, overriding resolution. */
|
|
@@ -266,10 +268,11 @@ export declare const FIRST_PARTY_HARNESS_ENV: Readonly<{
|
|
|
266
268
|
/** Engine version the desktop build bundles. */
|
|
267
269
|
bundleVersion: FirstPartyHarnessEnvName;
|
|
268
270
|
/**
|
|
269
|
-
* Engine home override. The engine reads only its own variable
|
|
270
|
-
* (`
|
|
271
|
-
* the engine will use reads
|
|
272
|
-
* the resolved path under
|
|
271
|
+
* Engine home override. The engine reads only its own variable, under every
|
|
272
|
+
* name it has had (`readFirstPartyHarnessEngineEnv(env, 'home')`), so a reader
|
|
273
|
+
* that resolves the home the engine will use reads those second, and a
|
|
274
|
+
* launcher hands the engine the resolved path under every one of them
|
|
275
|
+
* (`firstPartyHarnessEngineEnvEntries`).
|
|
273
276
|
*/
|
|
274
277
|
home: FirstPartyHarnessEnvName;
|
|
275
278
|
/** Engine version baked into the cloud-coding image. */
|
|
@@ -294,36 +297,84 @@ export interface FirstPartyHarnessEnvReading {
|
|
|
294
297
|
}
|
|
295
298
|
/** Read one purpose's variable. A blank value counts as unset. */
|
|
296
299
|
export declare function readFirstPartyHarnessEnv(env: Readonly<Record<string, string | undefined>>, key: FirstPartyHarnessEnvKey): FirstPartyHarnessEnvReading;
|
|
300
|
+
/**
|
|
301
|
+
* Every variable the engine reads, by purpose, as the suffix after the app
|
|
302
|
+
* name's prefix (`skrr-code` → `SKRR_CODE_<suffix>`). The fork names all of its
|
|
303
|
+
* own variables this way, so the names follow the namespace rather than being
|
|
304
|
+
* written out once per spelling.
|
|
305
|
+
*/
|
|
306
|
+
declare const ENGINE_ENV_SUFFIXES: Readonly<{
|
|
307
|
+
serverPassword: "SERVER_PASSWORD";
|
|
308
|
+
serverUsername: "SERVER_USERNAME";
|
|
309
|
+
home: "HOME";
|
|
310
|
+
config: "CONFIG";
|
|
311
|
+
appName: "APP_NAME";
|
|
312
|
+
scriptName: "SCRIPT_NAME";
|
|
313
|
+
allowUpstreamEgress: "ALLOW_UPSTREAM_EGRESS";
|
|
314
|
+
compatOpencode: "COMPAT_OPENCODE";
|
|
315
|
+
noCompatPrompts: "NO_COMPAT_PROMPTS";
|
|
316
|
+
}>;
|
|
317
|
+
export type FirstPartyHarnessEngineEnvKey = keyof typeof ENGINE_ENV_SUFFIXES;
|
|
297
318
|
/**
|
|
298
319
|
* Names the ENGINE itself defines and reads. The platform sets or reads them
|
|
299
320
|
* across the daemon↔engine boundary, so they are recorded here as values rather
|
|
300
|
-
* than scattered as literals
|
|
301
|
-
*
|
|
321
|
+
* than scattered as literals. They are the fork's names, and moving one is a
|
|
322
|
+
* two-sided change: the engine reads the new name first and every legacy name
|
|
323
|
+
* second, and while engine and platform releases can arrive in either order the
|
|
324
|
+
* platform SETS every name and READS new-then-legacy (contract §6, OSK-8674).
|
|
302
325
|
*/
|
|
303
326
|
export declare const FIRST_PARTY_HARNESS_ENGINE: Readonly<{
|
|
304
327
|
/**
|
|
305
328
|
* The engine's state namespace: XDG dirs, project marker, config basename, and
|
|
306
329
|
* the engine home under the skrr root (`firstPartyHarnessHomeDirname`).
|
|
307
330
|
*/
|
|
308
|
-
appName:
|
|
331
|
+
appName: string;
|
|
309
332
|
/**
|
|
310
|
-
* Earlier `appName`s
|
|
311
|
-
* onto the current
|
|
333
|
+
* Earlier `appName`s, newest first. `migrateFirstPartyHarnessHome` moves a home
|
|
334
|
+
* under one of them onto the current name and leaves a symlink; readers of
|
|
335
|
+
* engine state look under them after the current name.
|
|
312
336
|
*/
|
|
313
337
|
legacyAppNames: readonly string[];
|
|
314
338
|
/** Project-local configuration directory inside a user's repository. */
|
|
315
|
-
projectDirectory:
|
|
316
|
-
/**
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
339
|
+
projectDirectory: `.${string}`;
|
|
340
|
+
/**
|
|
341
|
+
* Earlier project directories, newest first. The engine still reads them and
|
|
342
|
+
* the platform never rewrites a user's repository to move one, so a reader
|
|
343
|
+
* looks here after `projectDirectory`, and a writer adopts an existing file
|
|
344
|
+
* here rather than creating a second one beside it.
|
|
345
|
+
*/
|
|
346
|
+
legacyProjectDirectories: readonly string[];
|
|
347
|
+
/**
|
|
348
|
+
* Environment variables the engine reads, under the CURRENT namespace. The
|
|
349
|
+
* engine also reads each one under every legacy namespace, second — use
|
|
350
|
+
* `readFirstPartyHarnessEngineEnv` to read one the way the engine does and
|
|
351
|
+
* `firstPartyHarnessEngineEnvEntries` to set one every engine build honours.
|
|
352
|
+
*/
|
|
353
|
+
env: Readonly<Record<"appName" | "serverPassword" | "serverUsername" | "home" | "config" | "scriptName" | "allowUpstreamEgress" | "compatOpencode" | "noCompatPrompts", string>>;
|
|
328
354
|
}>;
|
|
355
|
+
/**
|
|
356
|
+
* Every name the engine reads for one purpose, current namespace first — the
|
|
357
|
+
* engine's own lookup order.
|
|
358
|
+
*/
|
|
359
|
+
export declare function firstPartyHarnessEngineEnvNames(key: FirstPartyHarnessEngineEnvKey): readonly string[];
|
|
360
|
+
/**
|
|
361
|
+
* Read one engine variable the way the engine reads it: the current name, then
|
|
362
|
+
* every legacy name. A blank value counts as unset.
|
|
363
|
+
*/
|
|
364
|
+
export declare function readFirstPartyHarnessEngineEnv(env: Readonly<Record<string, string | undefined>>, key: FirstPartyHarnessEngineEnvKey): FirstPartyHarnessEnvReading;
|
|
365
|
+
/**
|
|
366
|
+
* One engine variable set under EVERY name the engine has read, for a process
|
|
367
|
+
* that spawns the engine. An engine binary is installed on its own schedule, so
|
|
368
|
+
* a launcher cannot know whether the one it starts reads the current name or a
|
|
369
|
+
* legacy one; setting both means either build receives the value.
|
|
370
|
+
*/
|
|
371
|
+
export declare function firstPartyHarnessEngineEnvEntries(key: FirstPartyHarnessEngineEnvKey, value: string): Record<string, string>;
|
|
372
|
+
/** Every engine project directory, current first — the engine's read order. */
|
|
373
|
+
export declare function firstPartyHarnessEngineProjectDirectories(): readonly string[];
|
|
374
|
+
/**
|
|
375
|
+
* Every engine home directory name under a config root, current first: where an
|
|
376
|
+
* engine home may exist on disk. `firstPartyHarnessHomeDirname` is the one the
|
|
377
|
+
* platform writes.
|
|
378
|
+
*/
|
|
379
|
+
export declare function firstPartyHarnessEngineHomeDirnames(): readonly string[];
|
|
329
380
|
export {};
|
|
@@ -290,7 +290,8 @@ export function firstPartyHarnessBinaryNames(platform) {
|
|
|
290
290
|
* the managed `AGENTS.md` from `<home>`. Deriving it from the provider would, on
|
|
291
291
|
* a fresh install after a provider rename, create a second directory the engine
|
|
292
292
|
* never reads — managed instructions would stop applying with no error. It moves
|
|
293
|
-
* when the engine's namespace moves, and not before
|
|
293
|
+
* when the engine's namespace moves, and not before; it did in OSK-8674, and
|
|
294
|
+
* `migrateFirstPartyHarnessHome` moves a home under a legacy name onto it.
|
|
294
295
|
*/
|
|
295
296
|
export function firstPartyHarnessHomeDirname() {
|
|
296
297
|
return FIRST_PARTY_HARNESS_ENGINE.appName;
|
|
@@ -338,7 +339,8 @@ function envName(name) {
|
|
|
338
339
|
* (OSK-8663) and are not read at all now. The ENGINE's own variables are a
|
|
339
340
|
* different namespace (`FIRST_PARTY_HARNESS_ENGINE.env`): the fork reads them,
|
|
340
341
|
* so a platform reader that must agree with the engine consults the engine's
|
|
341
|
-
*
|
|
342
|
+
* names explicitly (`readFirstPartyHarnessEngineEnv`) — the engine home is the
|
|
343
|
+
* one case (`home` below).
|
|
342
344
|
*/
|
|
343
345
|
export const FIRST_PARTY_HARNESS_ENV = Object.freeze({
|
|
344
346
|
/** Absolute path to an engine binary, overriding resolution. */
|
|
@@ -354,10 +356,11 @@ export const FIRST_PARTY_HARNESS_ENV = Object.freeze({
|
|
|
354
356
|
/** Engine version the desktop build bundles. */
|
|
355
357
|
bundleVersion: envName('SKRR_FIRST_PARTY_HARNESS_BUNDLE_VERSION'),
|
|
356
358
|
/**
|
|
357
|
-
* Engine home override. The engine reads only its own variable
|
|
358
|
-
* (`
|
|
359
|
-
* the engine will use reads
|
|
360
|
-
* the resolved path under
|
|
359
|
+
* Engine home override. The engine reads only its own variable, under every
|
|
360
|
+
* name it has had (`readFirstPartyHarnessEngineEnv(env, 'home')`), so a reader
|
|
361
|
+
* that resolves the home the engine will use reads those second, and a
|
|
362
|
+
* launcher hands the engine the resolved path under every one of them
|
|
363
|
+
* (`firstPartyHarnessEngineEnvEntries`).
|
|
361
364
|
*/
|
|
362
365
|
home: envName('SKRR_FIRST_PARTY_HARNESS_HOME'),
|
|
363
366
|
/** Engine version baked into the cloud-coding image. */
|
|
@@ -383,35 +386,136 @@ export function readFirstPartyHarnessEnv(env, key) {
|
|
|
383
386
|
return { value: undefined, name: undefined };
|
|
384
387
|
}
|
|
385
388
|
/* ── The ENGINE's own namespace (defined inside the fork) ───────────────── */
|
|
389
|
+
/**
|
|
390
|
+
* The engine's state namespace today. Moved from `sky-code` by OSK-8674: XDG
|
|
391
|
+
* dirs, project directory, config basename, the engine home under the skrr
|
|
392
|
+
* root, and every variable the engine reads all derive from it.
|
|
393
|
+
*/
|
|
394
|
+
const ENGINE_APP_NAME = 'skrr-code';
|
|
395
|
+
/**
|
|
396
|
+
* Earlier engine namespaces, newest first. Still READ on both sides of the
|
|
397
|
+
* daemon↔engine boundary: an engine binary, a daemon, a CLI and a desktop app
|
|
398
|
+
* each ship on their own schedule, and a machine holds state written under
|
|
399
|
+
* every name it has run.
|
|
400
|
+
*/
|
|
401
|
+
const ENGINE_LEGACY_APP_NAMES = ['sky-code'];
|
|
402
|
+
/**
|
|
403
|
+
* Every variable the engine reads, by purpose, as the suffix after the app
|
|
404
|
+
* name's prefix (`skrr-code` → `SKRR_CODE_<suffix>`). The fork names all of its
|
|
405
|
+
* own variables this way, so the names follow the namespace rather than being
|
|
406
|
+
* written out once per spelling.
|
|
407
|
+
*/
|
|
408
|
+
const ENGINE_ENV_SUFFIXES = Object.freeze({
|
|
409
|
+
serverPassword: 'SERVER_PASSWORD',
|
|
410
|
+
serverUsername: 'SERVER_USERNAME',
|
|
411
|
+
home: 'HOME',
|
|
412
|
+
config: 'CONFIG',
|
|
413
|
+
appName: 'APP_NAME',
|
|
414
|
+
scriptName: 'SCRIPT_NAME',
|
|
415
|
+
allowUpstreamEgress: 'ALLOW_UPSTREAM_EGRESS',
|
|
416
|
+
compatOpencode: 'COMPAT_OPENCODE',
|
|
417
|
+
noCompatPrompts: 'NO_COMPAT_PROMPTS',
|
|
418
|
+
});
|
|
419
|
+
function engineEnvName(appName, key) {
|
|
420
|
+
return `${appName.toUpperCase().replace(/-/g, '_')}_${ENGINE_ENV_SUFFIXES[key]}`;
|
|
421
|
+
}
|
|
422
|
+
function engineEnvTable(appName) {
|
|
423
|
+
return Object.freeze(Object.fromEntries(Object.keys(ENGINE_ENV_SUFFIXES).map((key) => [
|
|
424
|
+
key,
|
|
425
|
+
engineEnvName(appName, key),
|
|
426
|
+
])));
|
|
427
|
+
}
|
|
428
|
+
function defineEngineNamespace(appName, legacyAppNames) {
|
|
429
|
+
const every = [appName, ...legacyAppNames];
|
|
430
|
+
for (const name of every) {
|
|
431
|
+
if (!SLUG.test(name)) {
|
|
432
|
+
throw new Error(`first-party harness engine app name ${JSON.stringify(name)} is not a slug; it becomes a ` +
|
|
433
|
+
'directory name and a variable prefix');
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
if (new Set(every).size !== every.length) {
|
|
437
|
+
throw new Error('first-party harness engine appName and legacyAppNames must be distinct');
|
|
438
|
+
}
|
|
439
|
+
return Object.freeze({
|
|
440
|
+
/**
|
|
441
|
+
* The engine's state namespace: XDG dirs, project marker, config basename, and
|
|
442
|
+
* the engine home under the skrr root (`firstPartyHarnessHomeDirname`).
|
|
443
|
+
*/
|
|
444
|
+
appName,
|
|
445
|
+
/**
|
|
446
|
+
* Earlier `appName`s, newest first. `migrateFirstPartyHarnessHome` moves a home
|
|
447
|
+
* under one of them onto the current name and leaves a symlink; readers of
|
|
448
|
+
* engine state look under them after the current name.
|
|
449
|
+
*/
|
|
450
|
+
legacyAppNames: Object.freeze([...legacyAppNames]),
|
|
451
|
+
/** Project-local configuration directory inside a user's repository. */
|
|
452
|
+
projectDirectory: `.${appName}`,
|
|
453
|
+
/**
|
|
454
|
+
* Earlier project directories, newest first. The engine still reads them and
|
|
455
|
+
* the platform never rewrites a user's repository to move one, so a reader
|
|
456
|
+
* looks here after `projectDirectory`, and a writer adopts an existing file
|
|
457
|
+
* here rather than creating a second one beside it.
|
|
458
|
+
*/
|
|
459
|
+
legacyProjectDirectories: Object.freeze(legacyAppNames.map((name) => `.${name}`)),
|
|
460
|
+
/**
|
|
461
|
+
* Environment variables the engine reads, under the CURRENT namespace. The
|
|
462
|
+
* engine also reads each one under every legacy namespace, second — use
|
|
463
|
+
* `readFirstPartyHarnessEngineEnv` to read one the way the engine does and
|
|
464
|
+
* `firstPartyHarnessEngineEnvEntries` to set one every engine build honours.
|
|
465
|
+
*/
|
|
466
|
+
env: engineEnvTable(appName),
|
|
467
|
+
});
|
|
468
|
+
}
|
|
386
469
|
/**
|
|
387
470
|
* Names the ENGINE itself defines and reads. The platform sets or reads them
|
|
388
471
|
* across the daemon↔engine boundary, so they are recorded here as values rather
|
|
389
|
-
* than scattered as literals
|
|
390
|
-
*
|
|
472
|
+
* than scattered as literals. They are the fork's names, and moving one is a
|
|
473
|
+
* two-sided change: the engine reads the new name first and every legacy name
|
|
474
|
+
* second, and while engine and platform releases can arrive in either order the
|
|
475
|
+
* platform SETS every name and READS new-then-legacy (contract §6, OSK-8674).
|
|
391
476
|
*/
|
|
392
|
-
export const FIRST_PARTY_HARNESS_ENGINE =
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
477
|
+
export const FIRST_PARTY_HARNESS_ENGINE = defineEngineNamespace(ENGINE_APP_NAME, ENGINE_LEGACY_APP_NAMES);
|
|
478
|
+
/**
|
|
479
|
+
* Every name the engine reads for one purpose, current namespace first — the
|
|
480
|
+
* engine's own lookup order.
|
|
481
|
+
*/
|
|
482
|
+
export function firstPartyHarnessEngineEnvNames(key) {
|
|
483
|
+
return [FIRST_PARTY_HARNESS_ENGINE.appName, ...FIRST_PARTY_HARNESS_ENGINE.legacyAppNames].map((appName) => engineEnvName(appName, key));
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Read one engine variable the way the engine reads it: the current name, then
|
|
487
|
+
* every legacy name. A blank value counts as unset.
|
|
488
|
+
*/
|
|
489
|
+
export function readFirstPartyHarnessEngineEnv(env, key) {
|
|
490
|
+
for (const name of firstPartyHarnessEngineEnvNames(key)) {
|
|
491
|
+
const raw = env[name];
|
|
492
|
+
if (typeof raw === 'string' && raw.trim() !== '') {
|
|
493
|
+
return { value: raw.trim(), name };
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
return { value: undefined, name: undefined };
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* One engine variable set under EVERY name the engine has read, for a process
|
|
500
|
+
* that spawns the engine. An engine binary is installed on its own schedule, so
|
|
501
|
+
* a launcher cannot know whether the one it starts reads the current name or a
|
|
502
|
+
* legacy one; setting both means either build receives the value.
|
|
503
|
+
*/
|
|
504
|
+
export function firstPartyHarnessEngineEnvEntries(key, value) {
|
|
505
|
+
return Object.fromEntries(firstPartyHarnessEngineEnvNames(key).map((name) => [name, value]));
|
|
506
|
+
}
|
|
507
|
+
/** Every engine project directory, current first — the engine's read order. */
|
|
508
|
+
export function firstPartyHarnessEngineProjectDirectories() {
|
|
509
|
+
return [
|
|
510
|
+
FIRST_PARTY_HARNESS_ENGINE.projectDirectory,
|
|
511
|
+
...FIRST_PARTY_HARNESS_ENGINE.legacyProjectDirectories,
|
|
512
|
+
];
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Every engine home directory name under a config root, current first: where an
|
|
516
|
+
* engine home may exist on disk. `firstPartyHarnessHomeDirname` is the one the
|
|
517
|
+
* platform writes.
|
|
518
|
+
*/
|
|
519
|
+
export function firstPartyHarnessEngineHomeDirnames() {
|
|
520
|
+
return [FIRST_PARTY_HARNESS_ENGINE.appName, ...FIRST_PARTY_HARNESS_ENGINE.legacyAppNames];
|
|
521
|
+
}
|
|
@@ -55,4 +55,24 @@ export interface LegacyStateReport {
|
|
|
55
55
|
* real `~` passes or fails based on who runs it.
|
|
56
56
|
*/
|
|
57
57
|
export declare function findLegacyLocalState(home?: string): LegacyStateReport;
|
|
58
|
-
|
|
58
|
+
/**
|
|
59
|
+
* Where the full procedure lives, by repository path. The refusal used to say
|
|
60
|
+
* "follow the team cutover runbook" without naming one, which stopped a person
|
|
61
|
+
* at a pointer they could not follow (OSK-6895). The steps the refusal prints
|
|
62
|
+
* are the runbook's own, so the path is for the parts a terminal message cannot
|
|
63
|
+
* carry: Linux and Windows service removal, Keychain entries, the old app.
|
|
64
|
+
*/
|
|
65
|
+
export declare const LEGACY_CUTOVER_RUNBOOK = "docs/runbooks/skrr-cutover-dev-machine.md";
|
|
66
|
+
/**
|
|
67
|
+
* The message shown when preflight refuses.
|
|
68
|
+
*
|
|
69
|
+
* Written for someone who has just been stopped and wants to know why and what
|
|
70
|
+
* to do — so it names the exact paths, says explicitly that nothing was touched,
|
|
71
|
+
* and prints the cutover as commands to run rather than a pointer to follow. It
|
|
72
|
+
* does NOT offer a `--force`: the operator's next step is the backup, and a flag
|
|
73
|
+
* that skips a safety check is the flag everyone learns to paste.
|
|
74
|
+
*
|
|
75
|
+
* `command` is what the operator re-runs to install — `skrrd` when the runtime
|
|
76
|
+
* refused, `skrr daemon` when the CLI refused before fetching one.
|
|
77
|
+
*/
|
|
78
|
+
export declare function describeLegacyState(report: LegacyStateReport, command: string, platform?: NodeJS.Platform): string;
|
|
@@ -43,22 +43,69 @@ export function findLegacyLocalState(home = os.homedir()) {
|
|
|
43
43
|
return { findings, hasLegacyState: findings.length > 0 };
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
|
-
* The
|
|
47
|
-
*
|
|
48
|
-
* Written for someone who has just been stopped and wants to know why and what
|
|
49
|
-
* to do — so it names the exact paths, says explicitly that nothing was touched,
|
|
50
|
-
* and points at the runbook rather than improvising a fix. It does NOT offer a
|
|
51
|
-
* `--force`: the operator's next step is the backup the runbook specifies, and
|
|
52
|
-
* a flag that skips a safety check is the flag everyone learns to paste.
|
|
53
|
-
*/
|
|
54
|
-
/**
|
|
55
|
-
* The pre-rename runtime binary. Named in the refusal above because deregistering
|
|
46
|
+
* The pre-rename runtime binary. Named in the refusal below because deregistering
|
|
56
47
|
* the OLD service is the one step the NEW binary cannot do: `uninstall` resolves
|
|
57
48
|
* the current profile's label (`ai.skrr.daemon.*`), and the legacy sweep is wired
|
|
58
49
|
* only into the install path.
|
|
59
50
|
*/
|
|
60
51
|
const LEGACY_BINARY_NAME = 'oversky';
|
|
61
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Where the full procedure lives, by repository path. The refusal used to say
|
|
54
|
+
* "follow the team cutover runbook" without naming one, which stopped a person
|
|
55
|
+
* at a pointer they could not follow (OSK-6895). The steps the refusal prints
|
|
56
|
+
* are the runbook's own, so the path is for the parts a terminal message cannot
|
|
57
|
+
* carry: Linux and Windows service removal, Keychain entries, the old app.
|
|
58
|
+
*/
|
|
59
|
+
export const LEGACY_CUTOVER_RUNBOOK = 'docs/runbooks/skrr-cutover-dev-machine.md';
|
|
60
|
+
/** Credential file patterns the runbook strips from its backup (§5.5). */
|
|
61
|
+
const BACKUP_CREDENTIAL_PATTERNS = ['auth.json', 'cli-auth.json', '*token*'];
|
|
62
|
+
function posixQuote(value) {
|
|
63
|
+
return `'${value.split("'").join(`'\\''`)}'`;
|
|
64
|
+
}
|
|
65
|
+
function powershellQuote(value) {
|
|
66
|
+
return `'${value.split("'").join("''")}'`;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The commands for the three steps a person runs by hand, in the shell they are
|
|
70
|
+
* actually in. A POSIX `rm -rf` pasted into PowerShell is not an instruction.
|
|
71
|
+
*/
|
|
72
|
+
function cutoverCommands(paths, platform) {
|
|
73
|
+
if (platform === 'win32') {
|
|
74
|
+
const backupDir = '"$HOME\\skrr-cutover-backup"';
|
|
75
|
+
return {
|
|
76
|
+
backup: [
|
|
77
|
+
`New-Item -ItemType Directory -Force ${backupDir} | Out-Null`,
|
|
78
|
+
...paths.map((p) => `Copy-Item -Recurse ${powershellQuote(p)} ${backupDir}`),
|
|
79
|
+
`Get-ChildItem -Recurse -File ${backupDir} -Include ${BACKUP_CREDENTIAL_PATTERNS.join(',')} | Remove-Item`,
|
|
80
|
+
],
|
|
81
|
+
remove: paths.map((p) => `Remove-Item -Recurse -Force ${powershellQuote(p)}`),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const names = BACKUP_CREDENTIAL_PATTERNS.map((n) => `-name '${n}'`).join(' -o ');
|
|
85
|
+
return {
|
|
86
|
+
backup: [
|
|
87
|
+
'mkdir -p ~/skrr-cutover-backup && chmod 700 ~/skrr-cutover-backup',
|
|
88
|
+
`cp -a ${paths.map(posixQuote).join(' ')} ~/skrr-cutover-backup/`,
|
|
89
|
+
`find ~/skrr-cutover-backup -type f \\( ${names} \\) -delete`,
|
|
90
|
+
],
|
|
91
|
+
remove: [`rm -rf ${paths.map(posixQuote).join(' ')}`],
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The message shown when preflight refuses.
|
|
96
|
+
*
|
|
97
|
+
* Written for someone who has just been stopped and wants to know why and what
|
|
98
|
+
* to do — so it names the exact paths, says explicitly that nothing was touched,
|
|
99
|
+
* and prints the cutover as commands to run rather than a pointer to follow. It
|
|
100
|
+
* does NOT offer a `--force`: the operator's next step is the backup, and a flag
|
|
101
|
+
* that skips a safety check is the flag everyone learns to paste.
|
|
102
|
+
*
|
|
103
|
+
* `command` is what the operator re-runs to install — `skrrd` when the runtime
|
|
104
|
+
* refused, `skrr daemon` when the CLI refused before fetching one.
|
|
105
|
+
*/
|
|
106
|
+
export function describeLegacyState(report, command, platform = process.platform) {
|
|
107
|
+
const paths = report.findings.map((f) => f.path);
|
|
108
|
+
const { backup, remove } = cutoverCommands(paths, platform);
|
|
62
109
|
const lines = [];
|
|
63
110
|
lines.push('Found state from the previous product identity on this machine:');
|
|
64
111
|
lines.push('');
|
|
@@ -69,20 +116,28 @@ export function describeLegacyState(report, binaryName) {
|
|
|
69
116
|
lines.push('Installing beside it risks two runtimes holding two different service');
|
|
70
117
|
lines.push('labels, each believing it owns the single-instance lock.');
|
|
71
118
|
lines.push('');
|
|
72
|
-
lines.push('Nothing above has been read, copied or removed
|
|
73
|
-
lines.push('
|
|
119
|
+
lines.push('Nothing above has been read, copied or removed, and no service was registered.');
|
|
120
|
+
lines.push('To finish the cutover:');
|
|
74
121
|
lines.push('');
|
|
122
|
+
lines.push(' 1. Keep a copy, with its credentials removed, in case you need an old setting:');
|
|
123
|
+
for (const line of backup)
|
|
124
|
+
lines.push(` ${line}`);
|
|
75
125
|
// The OLD binary, deliberately: it is the one that knows the old service
|
|
76
126
|
// label. `<current> uninstall` resolves the CURRENT profile's label and would
|
|
77
127
|
// report success while leaving the pre-rename service registered. Guarded by
|
|
78
128
|
// "only if" rather than omitted, because this module inspects directories and
|
|
79
129
|
// has no way to know whether that binary is still on PATH.
|
|
80
|
-
lines.push(
|
|
81
|
-
lines.push(
|
|
82
|
-
lines.push(
|
|
130
|
+
lines.push(' 2. If the old runtime is still installed, deregister it with the old binary —');
|
|
131
|
+
lines.push(' it is the one that knows the old service label:');
|
|
132
|
+
lines.push(` ${LEGACY_BINARY_NAME} uninstall`);
|
|
133
|
+
lines.push(' 3. Remove the directories listed above:');
|
|
134
|
+
for (const line of remove)
|
|
135
|
+
lines.push(` ${line}`);
|
|
136
|
+
lines.push(' 4. Run this again:');
|
|
137
|
+
lines.push(` ${command} install`);
|
|
83
138
|
lines.push('');
|
|
84
|
-
lines.push(`Any pre-rename service still registered is swept by \`${
|
|
85
|
-
lines.push('once those directories are gone, so
|
|
86
|
-
lines.push(
|
|
139
|
+
lines.push(`Any pre-rename service still registered is swept by \`${command} install\``);
|
|
140
|
+
lines.push('once those directories are gone, so step 4 completes the cutover either way.');
|
|
141
|
+
lines.push(`Full runbook, including Keychain entries and the old app: ${LEGACY_CUTOVER_RUNBOOK}`);
|
|
87
142
|
return lines.join('\n');
|
|
88
143
|
}
|