@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
package/dist/lib/tasks.d.ts
CHANGED
|
@@ -7,6 +7,24 @@ import type { ParsedDeliverableCoordinate, ParsedExpectationSpec } from '@skrr-a
|
|
|
7
7
|
* Undefined means the flag was not passed.
|
|
8
8
|
*/
|
|
9
9
|
export declare function resolveTaskGoalFlag(value: string | undefined): string | null | undefined;
|
|
10
|
+
export declare const TASK_GOAL_NOT_FOUND = "TASK_GOAL_NOT_FOUND";
|
|
11
|
+
/**
|
|
12
|
+
* The refusal for a goal id that names no goal, in CLI terms.
|
|
13
|
+
*
|
|
14
|
+
* The server's sentence carries the API's remedy — "detach the goal with
|
|
15
|
+
* goalId: null" on update, "leave goalId out" on create — and a CLI user can
|
|
16
|
+
* type neither. So the goal id THIS command sent is named, with the flag that
|
|
17
|
+
* gets past the refusal: `--goal none` on update (see `resolveTaskGoalFlag`),
|
|
18
|
+
* leaving the goal out on create, where no goal is simply the default
|
|
19
|
+
* (OSK-10219). `goalSource: 'json'` is a create whose id came from
|
|
20
|
+
* `--from-json` rather than `--goal`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function describeTaskGoalNotFound({ goalId, command, bin, goalSource, }: {
|
|
23
|
+
goalId: string;
|
|
24
|
+
command: 'create' | 'update';
|
|
25
|
+
bin?: string;
|
|
26
|
+
goalSource?: 'flag' | 'json';
|
|
27
|
+
}): string;
|
|
10
28
|
export declare const TASK_PRIORITIES: readonly ["low", "medium", "high", "critical"];
|
|
11
29
|
/**
|
|
12
30
|
* The kinds `tasks events append --kind` will accept.
|
package/dist/lib/tasks.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RECOGNIZED_TASK_VERDICTS = exports.DELIVERABLE_LIFECYCLE_VALUES = exports.EXPECT_FLAG_HELP = exports.TASK_WORK_EVENT_KINDS = exports.TASK_PRIORITIES = void 0;
|
|
3
|
+
exports.RECOGNIZED_TASK_VERDICTS = exports.DELIVERABLE_LIFECYCLE_VALUES = exports.EXPECT_FLAG_HELP = exports.TASK_WORK_EVENT_KINDS = exports.TASK_PRIORITIES = exports.TASK_GOAL_NOT_FOUND = void 0;
|
|
4
4
|
exports.resolveTaskGoalFlag = resolveTaskGoalFlag;
|
|
5
|
+
exports.describeTaskGoalNotFound = describeTaskGoalNotFound;
|
|
5
6
|
exports.releasePinRepairGuard = releasePinRepairGuard;
|
|
6
7
|
exports.taskUpdateMutationGuard = taskUpdateMutationGuard;
|
|
7
8
|
exports.executionIsolationFromWorktreeFlag = executionIsolationFromWorktreeFlag;
|
|
@@ -52,6 +53,26 @@ function resolveTaskGoalFlag(value) {
|
|
|
52
53
|
return null;
|
|
53
54
|
return v;
|
|
54
55
|
}
|
|
56
|
+
exports.TASK_GOAL_NOT_FOUND = 'TASK_GOAL_NOT_FOUND';
|
|
57
|
+
/**
|
|
58
|
+
* The refusal for a goal id that names no goal, in CLI terms.
|
|
59
|
+
*
|
|
60
|
+
* The server's sentence carries the API's remedy — "detach the goal with
|
|
61
|
+
* goalId: null" on update, "leave goalId out" on create — and a CLI user can
|
|
62
|
+
* type neither. So the goal id THIS command sent is named, with the flag that
|
|
63
|
+
* gets past the refusal: `--goal none` on update (see `resolveTaskGoalFlag`),
|
|
64
|
+
* leaving the goal out on create, where no goal is simply the default
|
|
65
|
+
* (OSK-10219). `goalSource: 'json'` is a create whose id came from
|
|
66
|
+
* `--from-json` rather than `--goal`.
|
|
67
|
+
*/
|
|
68
|
+
function describeTaskGoalNotFound({ goalId, command, bin = 'skrr', goalSource = 'flag', }) {
|
|
69
|
+
const find = `Pass an existing goal id (\`${bin} goals list\` shows them)`;
|
|
70
|
+
if (command === 'update') {
|
|
71
|
+
return `No goal "${goalId}" exists. ${find}, or detach the task from its goal with \`--goal none\`.`;
|
|
72
|
+
}
|
|
73
|
+
const omit = goalSource === 'json' ? 'remove goalId from the --from-json body' : 'leave out --goal';
|
|
74
|
+
return `No goal "${goalId}" exists, so no task was created. ${find}, or ${omit} to create it without a goal.`;
|
|
75
|
+
}
|
|
55
76
|
exports.TASK_PRIORITIES = ['low', 'medium', 'high', 'critical'];
|
|
56
77
|
const DESCRIPTION_FORMATS = ['html', 'markdown', 'plain'];
|
|
57
78
|
/**
|
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
* a re-export, not a second CLI vocabulary: adding a saved-view capability is
|
|
6
6
|
* one data-provider registration followed by renderer work on each surface.
|
|
7
7
|
*/
|
|
8
|
-
export { SPACE_RENDERABLE_VIEW_TYPES, TASK_RENDERABLE_VIEW_TYPES, VIEW_GROUP_BY_REGISTRY, VIEW_GROUP_BY_VALUES, VIEW_QUICK_FILTER_REGISTRY, VIEW_QUICK_FILTERS, VIEW_SORT_DIRECTIONS, VIEW_SORT_KEY_REGISTRY, VIEW_SORT_KEYS, VIEW_TYPE_REGISTRY, VIEW_TYPES, viewTypesForSurface, } from '@skrr-ai/data-provider';
|
|
8
|
+
export { SPACE_RENDERABLE_VIEW_TYPES, TASK_VIEW_DEFAULT_GROUP_BY, TASK_VIEW_DEFAULT_TYPE, TASK_RENDERABLE_VIEW_TYPES, VIEW_GROUP_BY_REGISTRY, VIEW_GROUP_BY_VALUES, VIEW_QUICK_FILTER_REGISTRY, VIEW_QUICK_FILTERS, VIEW_SORT_DIRECTIONS, VIEW_SORT_KEY_REGISTRY, VIEW_SORT_KEYS, VIEW_TYPE_REGISTRY, VIEW_TYPES, viewTypesForSurface, } from '@skrr-ai/data-provider';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.viewTypesForSurface = exports.VIEW_TYPES = exports.VIEW_TYPE_REGISTRY = exports.VIEW_SORT_KEYS = exports.VIEW_SORT_KEY_REGISTRY = exports.VIEW_SORT_DIRECTIONS = exports.VIEW_QUICK_FILTERS = exports.VIEW_QUICK_FILTER_REGISTRY = exports.VIEW_GROUP_BY_VALUES = exports.VIEW_GROUP_BY_REGISTRY = exports.TASK_RENDERABLE_VIEW_TYPES = exports.SPACE_RENDERABLE_VIEW_TYPES = void 0;
|
|
3
|
+
exports.viewTypesForSurface = exports.VIEW_TYPES = exports.VIEW_TYPE_REGISTRY = exports.VIEW_SORT_KEYS = exports.VIEW_SORT_KEY_REGISTRY = exports.VIEW_SORT_DIRECTIONS = exports.VIEW_QUICK_FILTERS = exports.VIEW_QUICK_FILTER_REGISTRY = exports.VIEW_GROUP_BY_VALUES = exports.VIEW_GROUP_BY_REGISTRY = exports.TASK_RENDERABLE_VIEW_TYPES = exports.TASK_VIEW_DEFAULT_TYPE = exports.TASK_VIEW_DEFAULT_GROUP_BY = exports.SPACE_RENDERABLE_VIEW_TYPES = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* CLI parity re-export for persisted task views.
|
|
6
6
|
*
|
|
@@ -10,6 +10,8 @@ exports.viewTypesForSurface = exports.VIEW_TYPES = exports.VIEW_TYPE_REGISTRY =
|
|
|
10
10
|
*/
|
|
11
11
|
var data_provider_1 = require("@skrr-ai/data-provider");
|
|
12
12
|
Object.defineProperty(exports, "SPACE_RENDERABLE_VIEW_TYPES", { enumerable: true, get: function () { return data_provider_1.SPACE_RENDERABLE_VIEW_TYPES; } });
|
|
13
|
+
Object.defineProperty(exports, "TASK_VIEW_DEFAULT_GROUP_BY", { enumerable: true, get: function () { return data_provider_1.TASK_VIEW_DEFAULT_GROUP_BY; } });
|
|
14
|
+
Object.defineProperty(exports, "TASK_VIEW_DEFAULT_TYPE", { enumerable: true, get: function () { return data_provider_1.TASK_VIEW_DEFAULT_TYPE; } });
|
|
13
15
|
Object.defineProperty(exports, "TASK_RENDERABLE_VIEW_TYPES", { enumerable: true, get: function () { return data_provider_1.TASK_RENDERABLE_VIEW_TYPES; } });
|
|
14
16
|
Object.defineProperty(exports, "VIEW_GROUP_BY_REGISTRY", { enumerable: true, get: function () { return data_provider_1.VIEW_GROUP_BY_REGISTRY; } });
|
|
15
17
|
Object.defineProperty(exports, "VIEW_GROUP_BY_VALUES", { enumerable: true, get: function () { return data_provider_1.VIEW_GROUP_BY_VALUES; } });
|
|
@@ -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 {};
|
|
@@ -97,6 +97,11 @@ exports.firstPartyHarnessFeedPrefixes = firstPartyHarnessFeedPrefixes;
|
|
|
97
97
|
exports.firstPartyHarnessStagingPrefix = firstPartyHarnessStagingPrefix;
|
|
98
98
|
exports.firstPartyHarnessDefaultFeedBase = firstPartyHarnessDefaultFeedBase;
|
|
99
99
|
exports.readFirstPartyHarnessEnv = readFirstPartyHarnessEnv;
|
|
100
|
+
exports.firstPartyHarnessEngineEnvNames = firstPartyHarnessEngineEnvNames;
|
|
101
|
+
exports.readFirstPartyHarnessEngineEnv = readFirstPartyHarnessEngineEnv;
|
|
102
|
+
exports.firstPartyHarnessEngineEnvEntries = firstPartyHarnessEngineEnvEntries;
|
|
103
|
+
exports.firstPartyHarnessEngineProjectDirectories = firstPartyHarnessEngineProjectDirectories;
|
|
104
|
+
exports.firstPartyHarnessEngineHomeDirnames = firstPartyHarnessEngineHomeDirnames;
|
|
100
105
|
/** A slug usable as a directory name, a capability prefix and an event segment. */
|
|
101
106
|
const SLUG = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
102
107
|
function defineIdentity(identity) {
|
|
@@ -320,7 +325,8 @@ function firstPartyHarnessBinaryNames(platform) {
|
|
|
320
325
|
* the managed `AGENTS.md` from `<home>`. Deriving it from the provider would, on
|
|
321
326
|
* a fresh install after a provider rename, create a second directory the engine
|
|
322
327
|
* never reads — managed instructions would stop applying with no error. It moves
|
|
323
|
-
* when the engine's namespace moves, and not before
|
|
328
|
+
* when the engine's namespace moves, and not before; it did in OSK-8674, and
|
|
329
|
+
* `migrateFirstPartyHarnessHome` moves a home under a legacy name onto it.
|
|
324
330
|
*/
|
|
325
331
|
function firstPartyHarnessHomeDirname() {
|
|
326
332
|
return exports.FIRST_PARTY_HARNESS_ENGINE.appName;
|
|
@@ -368,7 +374,8 @@ function envName(name) {
|
|
|
368
374
|
* (OSK-8663) and are not read at all now. The ENGINE's own variables are a
|
|
369
375
|
* different namespace (`FIRST_PARTY_HARNESS_ENGINE.env`): the fork reads them,
|
|
370
376
|
* so a platform reader that must agree with the engine consults the engine's
|
|
371
|
-
*
|
|
377
|
+
* names explicitly (`readFirstPartyHarnessEngineEnv`) — the engine home is the
|
|
378
|
+
* one case (`home` below).
|
|
372
379
|
*/
|
|
373
380
|
exports.FIRST_PARTY_HARNESS_ENV = Object.freeze({
|
|
374
381
|
/** Absolute path to an engine binary, overriding resolution. */
|
|
@@ -384,10 +391,11 @@ exports.FIRST_PARTY_HARNESS_ENV = Object.freeze({
|
|
|
384
391
|
/** Engine version the desktop build bundles. */
|
|
385
392
|
bundleVersion: envName('SKRR_FIRST_PARTY_HARNESS_BUNDLE_VERSION'),
|
|
386
393
|
/**
|
|
387
|
-
* Engine home override. The engine reads only its own variable
|
|
388
|
-
* (`
|
|
389
|
-
* the engine will use reads
|
|
390
|
-
* the resolved path under
|
|
394
|
+
* Engine home override. The engine reads only its own variable, under every
|
|
395
|
+
* name it has had (`readFirstPartyHarnessEngineEnv(env, 'home')`), so a reader
|
|
396
|
+
* that resolves the home the engine will use reads those second, and a
|
|
397
|
+
* launcher hands the engine the resolved path under every one of them
|
|
398
|
+
* (`firstPartyHarnessEngineEnvEntries`).
|
|
391
399
|
*/
|
|
392
400
|
home: envName('SKRR_FIRST_PARTY_HARNESS_HOME'),
|
|
393
401
|
/** Engine version baked into the cloud-coding image. */
|
|
@@ -413,35 +421,136 @@ function readFirstPartyHarnessEnv(env, key) {
|
|
|
413
421
|
return { value: undefined, name: undefined };
|
|
414
422
|
}
|
|
415
423
|
/* ── The ENGINE's own namespace (defined inside the fork) ───────────────── */
|
|
424
|
+
/**
|
|
425
|
+
* The engine's state namespace today. Moved from `sky-code` by OSK-8674: XDG
|
|
426
|
+
* dirs, project directory, config basename, the engine home under the skrr
|
|
427
|
+
* root, and every variable the engine reads all derive from it.
|
|
428
|
+
*/
|
|
429
|
+
const ENGINE_APP_NAME = 'skrr-code';
|
|
430
|
+
/**
|
|
431
|
+
* Earlier engine namespaces, newest first. Still READ on both sides of the
|
|
432
|
+
* daemon↔engine boundary: an engine binary, a daemon, a CLI and a desktop app
|
|
433
|
+
* each ship on their own schedule, and a machine holds state written under
|
|
434
|
+
* every name it has run.
|
|
435
|
+
*/
|
|
436
|
+
const ENGINE_LEGACY_APP_NAMES = ['sky-code'];
|
|
437
|
+
/**
|
|
438
|
+
* Every variable the engine reads, by purpose, as the suffix after the app
|
|
439
|
+
* name's prefix (`skrr-code` → `SKRR_CODE_<suffix>`). The fork names all of its
|
|
440
|
+
* own variables this way, so the names follow the namespace rather than being
|
|
441
|
+
* written out once per spelling.
|
|
442
|
+
*/
|
|
443
|
+
const ENGINE_ENV_SUFFIXES = Object.freeze({
|
|
444
|
+
serverPassword: 'SERVER_PASSWORD',
|
|
445
|
+
serverUsername: 'SERVER_USERNAME',
|
|
446
|
+
home: 'HOME',
|
|
447
|
+
config: 'CONFIG',
|
|
448
|
+
appName: 'APP_NAME',
|
|
449
|
+
scriptName: 'SCRIPT_NAME',
|
|
450
|
+
allowUpstreamEgress: 'ALLOW_UPSTREAM_EGRESS',
|
|
451
|
+
compatOpencode: 'COMPAT_OPENCODE',
|
|
452
|
+
noCompatPrompts: 'NO_COMPAT_PROMPTS',
|
|
453
|
+
});
|
|
454
|
+
function engineEnvName(appName, key) {
|
|
455
|
+
return `${appName.toUpperCase().replace(/-/g, '_')}_${ENGINE_ENV_SUFFIXES[key]}`;
|
|
456
|
+
}
|
|
457
|
+
function engineEnvTable(appName) {
|
|
458
|
+
return Object.freeze(Object.fromEntries(Object.keys(ENGINE_ENV_SUFFIXES).map((key) => [
|
|
459
|
+
key,
|
|
460
|
+
engineEnvName(appName, key),
|
|
461
|
+
])));
|
|
462
|
+
}
|
|
463
|
+
function defineEngineNamespace(appName, legacyAppNames) {
|
|
464
|
+
const every = [appName, ...legacyAppNames];
|
|
465
|
+
for (const name of every) {
|
|
466
|
+
if (!SLUG.test(name)) {
|
|
467
|
+
throw new Error(`first-party harness engine app name ${JSON.stringify(name)} is not a slug; it becomes a ` +
|
|
468
|
+
'directory name and a variable prefix');
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
if (new Set(every).size !== every.length) {
|
|
472
|
+
throw new Error('first-party harness engine appName and legacyAppNames must be distinct');
|
|
473
|
+
}
|
|
474
|
+
return Object.freeze({
|
|
475
|
+
/**
|
|
476
|
+
* The engine's state namespace: XDG dirs, project marker, config basename, and
|
|
477
|
+
* the engine home under the skrr root (`firstPartyHarnessHomeDirname`).
|
|
478
|
+
*/
|
|
479
|
+
appName,
|
|
480
|
+
/**
|
|
481
|
+
* Earlier `appName`s, newest first. `migrateFirstPartyHarnessHome` moves a home
|
|
482
|
+
* under one of them onto the current name and leaves a symlink; readers of
|
|
483
|
+
* engine state look under them after the current name.
|
|
484
|
+
*/
|
|
485
|
+
legacyAppNames: Object.freeze([...legacyAppNames]),
|
|
486
|
+
/** Project-local configuration directory inside a user's repository. */
|
|
487
|
+
projectDirectory: `.${appName}`,
|
|
488
|
+
/**
|
|
489
|
+
* Earlier project directories, newest first. The engine still reads them and
|
|
490
|
+
* the platform never rewrites a user's repository to move one, so a reader
|
|
491
|
+
* looks here after `projectDirectory`, and a writer adopts an existing file
|
|
492
|
+
* here rather than creating a second one beside it.
|
|
493
|
+
*/
|
|
494
|
+
legacyProjectDirectories: Object.freeze(legacyAppNames.map((name) => `.${name}`)),
|
|
495
|
+
/**
|
|
496
|
+
* Environment variables the engine reads, under the CURRENT namespace. The
|
|
497
|
+
* engine also reads each one under every legacy namespace, second — use
|
|
498
|
+
* `readFirstPartyHarnessEngineEnv` to read one the way the engine does and
|
|
499
|
+
* `firstPartyHarnessEngineEnvEntries` to set one every engine build honours.
|
|
500
|
+
*/
|
|
501
|
+
env: engineEnvTable(appName),
|
|
502
|
+
});
|
|
503
|
+
}
|
|
416
504
|
/**
|
|
417
505
|
* Names the ENGINE itself defines and reads. The platform sets or reads them
|
|
418
506
|
* across the daemon↔engine boundary, so they are recorded here as values rather
|
|
419
|
-
* than scattered as literals
|
|
420
|
-
*
|
|
507
|
+
* than scattered as literals. They are the fork's names, and moving one is a
|
|
508
|
+
* two-sided change: the engine reads the new name first and every legacy name
|
|
509
|
+
* second, and while engine and platform releases can arrive in either order the
|
|
510
|
+
* platform SETS every name and READS new-then-legacy (contract §6, OSK-8674).
|
|
421
511
|
*/
|
|
422
|
-
exports.FIRST_PARTY_HARNESS_ENGINE =
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
512
|
+
exports.FIRST_PARTY_HARNESS_ENGINE = defineEngineNamespace(ENGINE_APP_NAME, ENGINE_LEGACY_APP_NAMES);
|
|
513
|
+
/**
|
|
514
|
+
* Every name the engine reads for one purpose, current namespace first — the
|
|
515
|
+
* engine's own lookup order.
|
|
516
|
+
*/
|
|
517
|
+
function firstPartyHarnessEngineEnvNames(key) {
|
|
518
|
+
return [exports.FIRST_PARTY_HARNESS_ENGINE.appName, ...exports.FIRST_PARTY_HARNESS_ENGINE.legacyAppNames].map((appName) => engineEnvName(appName, key));
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Read one engine variable the way the engine reads it: the current name, then
|
|
522
|
+
* every legacy name. A blank value counts as unset.
|
|
523
|
+
*/
|
|
524
|
+
function readFirstPartyHarnessEngineEnv(env, key) {
|
|
525
|
+
for (const name of firstPartyHarnessEngineEnvNames(key)) {
|
|
526
|
+
const raw = env[name];
|
|
527
|
+
if (typeof raw === 'string' && raw.trim() !== '') {
|
|
528
|
+
return { value: raw.trim(), name };
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
return { value: undefined, name: undefined };
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* One engine variable set under EVERY name the engine has read, for a process
|
|
535
|
+
* that spawns the engine. An engine binary is installed on its own schedule, so
|
|
536
|
+
* a launcher cannot know whether the one it starts reads the current name or a
|
|
537
|
+
* legacy one; setting both means either build receives the value.
|
|
538
|
+
*/
|
|
539
|
+
function firstPartyHarnessEngineEnvEntries(key, value) {
|
|
540
|
+
return Object.fromEntries(firstPartyHarnessEngineEnvNames(key).map((name) => [name, value]));
|
|
541
|
+
}
|
|
542
|
+
/** Every engine project directory, current first — the engine's read order. */
|
|
543
|
+
function firstPartyHarnessEngineProjectDirectories() {
|
|
544
|
+
return [
|
|
545
|
+
exports.FIRST_PARTY_HARNESS_ENGINE.projectDirectory,
|
|
546
|
+
...exports.FIRST_PARTY_HARNESS_ENGINE.legacyProjectDirectories,
|
|
547
|
+
];
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Every engine home directory name under a config root, current first: where an
|
|
551
|
+
* engine home may exist on disk. `firstPartyHarnessHomeDirname` is the one the
|
|
552
|
+
* platform writes.
|
|
553
|
+
*/
|
|
554
|
+
function firstPartyHarnessEngineHomeDirnames() {
|
|
555
|
+
return [exports.FIRST_PARTY_HARNESS_ENGINE.appName, ...exports.FIRST_PARTY_HARNESS_ENGINE.legacyAppNames];
|
|
556
|
+
}
|
|
@@ -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;
|
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.LEGACY_CUTOVER_RUNBOOK = void 0;
|
|
6
7
|
exports.findLegacyLocalState = findLegacyLocalState;
|
|
7
8
|
exports.describeLegacyState = describeLegacyState;
|
|
8
9
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
@@ -50,22 +51,69 @@ function findLegacyLocalState(home = node_os_1.default.homedir()) {
|
|
|
50
51
|
return { findings, hasLegacyState: findings.length > 0 };
|
|
51
52
|
}
|
|
52
53
|
/**
|
|
53
|
-
* The
|
|
54
|
-
*
|
|
55
|
-
* Written for someone who has just been stopped and wants to know why and what
|
|
56
|
-
* to do — so it names the exact paths, says explicitly that nothing was touched,
|
|
57
|
-
* and points at the runbook rather than improvising a fix. It does NOT offer a
|
|
58
|
-
* `--force`: the operator's next step is the backup the runbook specifies, and
|
|
59
|
-
* a flag that skips a safety check is the flag everyone learns to paste.
|
|
60
|
-
*/
|
|
61
|
-
/**
|
|
62
|
-
* The pre-rename runtime binary. Named in the refusal above because deregistering
|
|
54
|
+
* The pre-rename runtime binary. Named in the refusal below because deregistering
|
|
63
55
|
* the OLD service is the one step the NEW binary cannot do: `uninstall` resolves
|
|
64
56
|
* the current profile's label (`ai.skrr.daemon.*`), and the legacy sweep is wired
|
|
65
57
|
* only into the install path.
|
|
66
58
|
*/
|
|
67
59
|
const LEGACY_BINARY_NAME = 'oversky';
|
|
68
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Where the full procedure lives, by repository path. The refusal used to say
|
|
62
|
+
* "follow the team cutover runbook" without naming one, which stopped a person
|
|
63
|
+
* at a pointer they could not follow (OSK-6895). The steps the refusal prints
|
|
64
|
+
* are the runbook's own, so the path is for the parts a terminal message cannot
|
|
65
|
+
* carry: Linux and Windows service removal, Keychain entries, the old app.
|
|
66
|
+
*/
|
|
67
|
+
exports.LEGACY_CUTOVER_RUNBOOK = 'docs/runbooks/skrr-cutover-dev-machine.md';
|
|
68
|
+
/** Credential file patterns the runbook strips from its backup (§5.5). */
|
|
69
|
+
const BACKUP_CREDENTIAL_PATTERNS = ['auth.json', 'cli-auth.json', '*token*'];
|
|
70
|
+
function posixQuote(value) {
|
|
71
|
+
return `'${value.split("'").join(`'\\''`)}'`;
|
|
72
|
+
}
|
|
73
|
+
function powershellQuote(value) {
|
|
74
|
+
return `'${value.split("'").join("''")}'`;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The commands for the three steps a person runs by hand, in the shell they are
|
|
78
|
+
* actually in. A POSIX `rm -rf` pasted into PowerShell is not an instruction.
|
|
79
|
+
*/
|
|
80
|
+
function cutoverCommands(paths, platform) {
|
|
81
|
+
if (platform === 'win32') {
|
|
82
|
+
const backupDir = '"$HOME\\skrr-cutover-backup"';
|
|
83
|
+
return {
|
|
84
|
+
backup: [
|
|
85
|
+
`New-Item -ItemType Directory -Force ${backupDir} | Out-Null`,
|
|
86
|
+
...paths.map((p) => `Copy-Item -Recurse ${powershellQuote(p)} ${backupDir}`),
|
|
87
|
+
`Get-ChildItem -Recurse -File ${backupDir} -Include ${BACKUP_CREDENTIAL_PATTERNS.join(',')} | Remove-Item`,
|
|
88
|
+
],
|
|
89
|
+
remove: paths.map((p) => `Remove-Item -Recurse -Force ${powershellQuote(p)}`),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const names = BACKUP_CREDENTIAL_PATTERNS.map((n) => `-name '${n}'`).join(' -o ');
|
|
93
|
+
return {
|
|
94
|
+
backup: [
|
|
95
|
+
'mkdir -p ~/skrr-cutover-backup && chmod 700 ~/skrr-cutover-backup',
|
|
96
|
+
`cp -a ${paths.map(posixQuote).join(' ')} ~/skrr-cutover-backup/`,
|
|
97
|
+
`find ~/skrr-cutover-backup -type f \\( ${names} \\) -delete`,
|
|
98
|
+
],
|
|
99
|
+
remove: [`rm -rf ${paths.map(posixQuote).join(' ')}`],
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* The message shown when preflight refuses.
|
|
104
|
+
*
|
|
105
|
+
* Written for someone who has just been stopped and wants to know why and what
|
|
106
|
+
* to do — so it names the exact paths, says explicitly that nothing was touched,
|
|
107
|
+
* and prints the cutover as commands to run rather than a pointer to follow. It
|
|
108
|
+
* does NOT offer a `--force`: the operator's next step is the backup, and a flag
|
|
109
|
+
* that skips a safety check is the flag everyone learns to paste.
|
|
110
|
+
*
|
|
111
|
+
* `command` is what the operator re-runs to install — `skrrd` when the runtime
|
|
112
|
+
* refused, `skrr daemon` when the CLI refused before fetching one.
|
|
113
|
+
*/
|
|
114
|
+
function describeLegacyState(report, command, platform = process.platform) {
|
|
115
|
+
const paths = report.findings.map((f) => f.path);
|
|
116
|
+
const { backup, remove } = cutoverCommands(paths, platform);
|
|
69
117
|
const lines = [];
|
|
70
118
|
lines.push('Found state from the previous product identity on this machine:');
|
|
71
119
|
lines.push('');
|
|
@@ -76,20 +124,28 @@ function describeLegacyState(report, binaryName) {
|
|
|
76
124
|
lines.push('Installing beside it risks two runtimes holding two different service');
|
|
77
125
|
lines.push('labels, each believing it owns the single-instance lock.');
|
|
78
126
|
lines.push('');
|
|
79
|
-
lines.push('Nothing above has been read, copied or removed
|
|
80
|
-
lines.push('
|
|
127
|
+
lines.push('Nothing above has been read, copied or removed, and no service was registered.');
|
|
128
|
+
lines.push('To finish the cutover:');
|
|
81
129
|
lines.push('');
|
|
130
|
+
lines.push(' 1. Keep a copy, with its credentials removed, in case you need an old setting:');
|
|
131
|
+
for (const line of backup)
|
|
132
|
+
lines.push(` ${line}`);
|
|
82
133
|
// The OLD binary, deliberately: it is the one that knows the old service
|
|
83
134
|
// label. `<current> uninstall` resolves the CURRENT profile's label and would
|
|
84
135
|
// report success while leaving the pre-rename service registered. Guarded by
|
|
85
136
|
// "only if" rather than omitted, because this module inspects directories and
|
|
86
137
|
// has no way to know whether that binary is still on PATH.
|
|
87
|
-
lines.push(
|
|
88
|
-
lines.push(
|
|
89
|
-
lines.push(
|
|
138
|
+
lines.push(' 2. If the old runtime is still installed, deregister it with the old binary —');
|
|
139
|
+
lines.push(' it is the one that knows the old service label:');
|
|
140
|
+
lines.push(` ${LEGACY_BINARY_NAME} uninstall`);
|
|
141
|
+
lines.push(' 3. Remove the directories listed above:');
|
|
142
|
+
for (const line of remove)
|
|
143
|
+
lines.push(` ${line}`);
|
|
144
|
+
lines.push(' 4. Run this again:');
|
|
145
|
+
lines.push(` ${command} install`);
|
|
90
146
|
lines.push('');
|
|
91
|
-
lines.push(`Any pre-rename service still registered is swept by \`${
|
|
92
|
-
lines.push('once those directories are gone, so
|
|
93
|
-
lines.push(
|
|
147
|
+
lines.push(`Any pre-rename service still registered is swept by \`${command} install\``);
|
|
148
|
+
lines.push('once those directories are gone, so step 4 completes the cutover either way.');
|
|
149
|
+
lines.push(`Full runbook, including Keychain entries and the old app: ${exports.LEGACY_CUTOVER_RUNBOOK}`);
|
|
94
150
|
return lines.join('\n');
|
|
95
151
|
}
|