@skrr-ai/cli 0.1.42 → 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/overage.js +4 -3
- package/dist/commands/balance/plan.js +10 -6
- package/dist/commands/balance/show.d.ts +32 -0
- package/dist/commands/balance/show.js +74 -3
- package/dist/commands/balance/usage/events.js +3 -2
- package/dist/commands/balance/usage.js +2 -1
- package/dist/commands/browser/install.js +3 -2
- package/dist/commands/browser/uninstall.js +3 -2
- package/dist/commands/code/handover.d.ts +1 -0
- package/dist/commands/code/handover.js +4 -0
- package/dist/commands/code/install.js +3 -2
- 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/install.d.ts +11 -0
- package/dist/commands/harnesses/install.js +33 -14
- package/dist/commands/harnesses/installers.d.ts +10 -0
- package/dist/commands/harnesses/installers.js +31 -0
- package/dist/commands/harnesses/leases/show.js +14 -0
- package/dist/commands/harnesses/list.js +3 -2
- 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/attachments/set-role.d.ts +24 -0
- package/dist/commands/tasks/attachments/set-role.js +60 -0
- package/dist/commands/tasks/attachments/upload.d.ts +1 -0
- package/dist/commands/tasks/attachments/upload.js +18 -52
- package/dist/commands/tasks/comments/add.d.ts +1 -0
- package/dist/commands/tasks/comments/add.js +67 -2
- package/dist/commands/tasks/complete.d.ts +1 -0
- package/dist/commands/tasks/complete.js +56 -1
- 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/result/submit.d.ts +3 -0
- package/dist/commands/tasks/result/submit.js +76 -8
- package/dist/commands/tasks/show.d.ts +23 -0
- package/dist/commands/tasks/show.js +61 -1
- package/dist/commands/tasks/update.js +16 -2
- package/dist/commands/tasks/updates/add.d.ts +1 -0
- package/dist/commands/tasks/updates/add.js +63 -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/api-fetch.js +7 -2
- package/dist/lib/cli-installers.d.ts +23 -4
- package/dist/lib/cli-installers.js +56 -8
- package/dist/lib/daemon-setup.d.ts +18 -1
- package/dist/lib/daemon-setup.js +33 -1
- package/dist/lib/dedicated-machines.js +4 -2
- package/dist/lib/file-mime.js +1 -1
- package/dist/lib/first-party-harness-agent.d.ts +16 -1
- package/dist/lib/first-party-harness-agent.js +47 -17
- package/dist/lib/first-party-harness-doctor.js +49 -48
- package/dist/lib/first-party-harness-managed.d.ts +9 -4
- package/dist/lib/first-party-harness-managed.js +13 -10
- package/dist/lib/first-party-harness.d.ts +32 -21
- package/dist/lib/first-party-harness.js +49 -31
- package/dist/lib/harness-provider-input.d.ts +18 -12
- package/dist/lib/harness-provider-input.js +18 -12
- package/dist/lib/harness-tiers.d.ts +4 -3
- package/dist/lib/harness-tiers.js +4 -3
- package/dist/lib/harnesses.d.ts +6 -0
- package/dist/lib/html-text.js +25 -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/session-task-endpoints.d.ts +1 -1
- package/dist/lib/session-task-endpoints.js +3 -0
- package/dist/lib/task-asset-upload.d.ts +84 -0
- package/dist/lib/task-asset-upload.js +374 -0
- package/dist/lib/task-closure.d.ts +15 -0
- package/dist/lib/task-closure.js +20 -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 +26 -0
- package/dist/lib/tasks.js +38 -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 +183 -58
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.js +286 -100
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessChannels.d.ts +21 -33
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessChannels.js +24 -50
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessHome.d.ts +19 -7
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessHome.js +26 -10
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessTrust.d.ts +9 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessTrust.js +9 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +1 -13
- 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 +183 -58
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.js +279 -99
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessChannels.d.ts +21 -33
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessChannels.js +24 -49
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessHome.d.ts +19 -7
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessHome.js +27 -11
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessTrust.d.ts +9 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessTrust.js +9 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +1 -4
- 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 +4588 -4509
- package/dist/node_modules/@skrr-ai/data-provider/package.json +1 -1
- package/oclif.manifest.json +33980 -33832
- package/package.json +3 -3
|
@@ -28,14 +28,13 @@
|
|
|
28
28
|
* file spells the product.
|
|
29
29
|
*/
|
|
30
30
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
-
exports.
|
|
31
|
+
exports.DEFAULT_FIRST_PARTY_HARNESS_CHANNEL = exports.FIRST_PARTY_HARNESS_CHANNELS = void 0;
|
|
32
32
|
exports.isFirstPartyHarnessChannel = isFirstPartyHarnessChannel;
|
|
33
33
|
exports.resolveFirstPartyHarnessChannel = resolveFirstPartyHarnessChannel;
|
|
34
34
|
exports.firstPartyHarnessChannelPrefix = firstPartyHarnessChannelPrefix;
|
|
35
35
|
exports.resolveChannelManifestUrl = resolveChannelManifestUrl;
|
|
36
36
|
exports.firstPartyHarnessFeedBase = firstPartyHarnessFeedBase;
|
|
37
37
|
exports.firstPartyHarnessFeedCandidates = firstPartyHarnessFeedCandidates;
|
|
38
|
-
exports.skyCodeFeedBase = skyCodeFeedBase;
|
|
39
38
|
const firstPartyHarness_js_1 = require("./firstPartyHarness.js");
|
|
40
39
|
/** Channels in promotion order. Index order IS the promotion order. */
|
|
41
40
|
exports.FIRST_PARTY_HARNESS_CHANNELS = ['internal', 'canary', 'beta', 'stable'];
|
|
@@ -126,61 +125,36 @@ function firstPartyHarnessFeedBase(env = process.env) {
|
|
|
126
125
|
* Every place a manifest may be published, in the order an installer should
|
|
127
126
|
* try them: the canonical spelling first, then each alias.
|
|
128
127
|
*
|
|
129
|
-
* Why a list: publishing writes every spelling, but an installer can
|
|
130
|
-
* the first release that does, and a machine can point at a feed
|
|
131
|
-
* an older pipeline. An installer that asked only for the canonical
|
|
132
|
-
* then find NOTHING and report "no release" on a feed that has one.
|
|
133
|
-
* aliases on not-found closes that window in both directions without
|
|
134
|
-
* having to deploy in a particular order.
|
|
128
|
+
* Why a list: publishing writes every accepted spelling, but an installer can
|
|
129
|
+
* ship before the first release that does, and a machine can point at a feed
|
|
130
|
+
* published by an older pipeline. An installer that asked only for the canonical
|
|
131
|
+
* path would then find NOTHING and report "no release" on a feed that has one.
|
|
132
|
+
* Trying the aliases on not-found closes that window in both directions without
|
|
133
|
+
* anyone having to deploy in a particular order.
|
|
134
|
+
*
|
|
135
|
+
* WHICH spellings depends on what is being read, and the difference is the
|
|
136
|
+
* point:
|
|
137
|
+
*
|
|
138
|
+
* - a CHANNEL pointer (`pinnedRelease` false) is current state. Only the
|
|
139
|
+
* accepted spellings are tried: a former spelling's pointer stopped moving
|
|
140
|
+
* when publishing stopped writing it, so falling back to one would install
|
|
141
|
+
* whatever that channel named on the day of contract — a silent downgrade.
|
|
142
|
+
* - a PINNED release (`pinnedRelease` true) is an immutable artifact. Former
|
|
143
|
+
* spellings are tried too: a release published before the canonical prefix
|
|
144
|
+
* existed lives only under the old one, and its signed bytes — artifact URLs
|
|
145
|
+
* included — are the same wherever they are found.
|
|
135
146
|
*
|
|
136
147
|
* An operator override keeps its base and still tries each manifest filename,
|
|
137
148
|
* since a dev feed staged by an older script names the file the old way.
|
|
138
149
|
*/
|
|
139
|
-
function firstPartyHarnessFeedCandidates(env = process.env) {
|
|
150
|
+
function firstPartyHarnessFeedCandidates(env = process.env, options = {}) {
|
|
140
151
|
const override = (0, firstPartyHarness_js_1.readFirstPartyHarnessEnv)(env, 'updateFeedBase').value?.replace(/\/+$/, '');
|
|
141
|
-
|
|
152
|
+
const spellings = options.pinnedRelease
|
|
153
|
+
? (0, firstPartyHarness_js_1.firstPartyHarnessArtifactSpellings)()
|
|
154
|
+
: (0, firstPartyHarness_js_1.firstPartyHarnessSpellings)();
|
|
155
|
+
return spellings.map((provider) => ({
|
|
142
156
|
base: override || (0, firstPartyHarness_js_1.firstPartyHarnessDefaultFeedBase)(provider),
|
|
143
157
|
manifestFilename: (0, firstPartyHarness_js_1.firstPartyHarnessManifestFile)(provider),
|
|
144
158
|
provider,
|
|
145
159
|
}));
|
|
146
160
|
}
|
|
147
|
-
/* ── Deprecated names ───────────────────────────────────────────────────────
|
|
148
|
-
*
|
|
149
|
-
* `@skrr-ai/auth-core` is PUBLISHED, and the released CLI resolves it with a
|
|
150
|
-
* caret range. An installed CLI that picks up this version must still find the
|
|
151
|
-
* names it was compiled against, or it crashes at import. These aliases leave in
|
|
152
|
-
* the contract phase (OSK-8663), with a minor-version bump — never a patch.
|
|
153
|
-
*
|
|
154
|
-
* The ones that name a feed name the LEGACY one, the spelling a caller compiled
|
|
155
|
-
* against them was built for — the retired alias, not `wireProvider`, which has
|
|
156
|
-
* moved to canonical.
|
|
157
|
-
*/
|
|
158
|
-
/** The spelling the deprecated names were written for. */
|
|
159
|
-
const LEGACY_SPELLING = firstPartyHarness_js_1.FIRST_PARTY_HARNESS.aliases[0] ?? firstPartyHarness_js_1.FIRST_PARTY_HARNESS.provider;
|
|
160
|
-
/** @deprecated Use `FIRST_PARTY_HARNESS_CHANNELS`. */
|
|
161
|
-
exports.SKY_CODE_CHANNELS = exports.FIRST_PARTY_HARNESS_CHANNELS;
|
|
162
|
-
/** @deprecated Use `DEFAULT_FIRST_PARTY_HARNESS_CHANNEL`. */
|
|
163
|
-
exports.DEFAULT_SKY_CODE_CHANNEL = exports.DEFAULT_FIRST_PARTY_HARNESS_CHANNEL;
|
|
164
|
-
/** @deprecated Read the channel with `resolveFirstPartyHarnessChannel`; the variable has a neutral name now. */
|
|
165
|
-
exports.SKY_CODE_CHANNEL_ENV = firstPartyHarness_js_1.FIRST_PARTY_HARNESS_ENV.channel.legacy[0];
|
|
166
|
-
/** @deprecated Use `firstPartyHarnessManifestFile()`. Names the legacy file. */
|
|
167
|
-
exports.SKY_CODE_MANIFEST_FILE = (0, firstPartyHarness_js_1.firstPartyHarnessManifestFile)(LEGACY_SPELLING);
|
|
168
|
-
/** @deprecated Use `isFirstPartyHarnessChannel`. */
|
|
169
|
-
exports.isSkyCodeChannel = isFirstPartyHarnessChannel;
|
|
170
|
-
/** @deprecated Use `resolveFirstPartyHarnessChannel`. */
|
|
171
|
-
exports.resolveSkyCodeChannel = resolveFirstPartyHarnessChannel;
|
|
172
|
-
/** @deprecated Use `firstPartyHarnessChannelPrefix`. */
|
|
173
|
-
exports.skyCodeChannelPrefix = firstPartyHarnessChannelPrefix;
|
|
174
|
-
/** @deprecated Use `firstPartyHarnessDefaultFeedBase()`. Names the legacy feed. */
|
|
175
|
-
exports.DEFAULT_SKY_CODE_FEED_BASE = (0, firstPartyHarness_js_1.firstPartyHarnessDefaultFeedBase)(LEGACY_SPELLING);
|
|
176
|
-
/** @deprecated Read the feed with `firstPartyHarnessFeedBase`; the variable has a neutral name now. */
|
|
177
|
-
exports.SKY_CODE_FEED_BASE_ENV = firstPartyHarness_js_1.FIRST_PARTY_HARNESS_ENV.updateFeedBase.legacy[0];
|
|
178
|
-
/**
|
|
179
|
-
* @deprecated Use `firstPartyHarnessFeedCandidates`. Keeps the LEGACY feed as its
|
|
180
|
-
* default, because that is the only feed a caller compiled against this name knows
|
|
181
|
-
* how to read.
|
|
182
|
-
*/
|
|
183
|
-
function skyCodeFeedBase(env = process.env) {
|
|
184
|
-
const override = (0, firstPartyHarness_js_1.readFirstPartyHarnessEnv)(env, 'updateFeedBase').value;
|
|
185
|
-
return (override || (0, firstPartyHarness_js_1.firstPartyHarnessDefaultFeedBase)(LEGACY_SPELLING)).replace(/\/+$/, '');
|
|
186
|
-
}
|
|
@@ -20,9 +20,15 @@
|
|
|
20
20
|
* leave the legacy name as a relative symlink. (No legacy app name exists
|
|
21
21
|
* yet; this step is what an engine-namespace rename will use.)
|
|
22
22
|
* 2. The BINARY follows the provider. Inside `<home>/bin`, if the canonical
|
|
23
|
-
* binary does not exist and an
|
|
24
|
-
* each companion (rollback copy, provenance sidecar),
|
|
25
|
-
* symlink at every old name.
|
|
23
|
+
* binary does not exist and a binary under an older spelling is a real
|
|
24
|
+
* file, rename it and each companion (rollback copy, provenance sidecar),
|
|
25
|
+
* leaving a relative symlink at every old name.
|
|
26
|
+
*
|
|
27
|
+
* "Older spelling" means every ARTIFACT spelling that is not canonical — the
|
|
28
|
+
* aliases AND the former spellings (`firstPartyHarnessArtifactSpellings`). An
|
|
29
|
+
* installed binary is an artifact: a machine that never ran a post-rename client
|
|
30
|
+
* still has its engine under the old name after that name stops being accepted
|
|
31
|
+
* anywhere, and it must still be moved rather than reinstalled beside.
|
|
26
32
|
*
|
|
27
33
|
* The two follow different names on purpose: the home is shared with the
|
|
28
34
|
* engine, which reads its config and managed `AGENTS.md` from it, so it can only
|
|
@@ -73,7 +79,9 @@ export interface FirstPartyHarnessHomeFs {
|
|
|
73
79
|
* Move a legacy engine home and binary onto the canonical names. See the file
|
|
74
80
|
* header for the exact contract. Returns what it did; never throws.
|
|
75
81
|
*
|
|
76
|
-
* Inside `<home>/bin` it resolves the three layouts a rename can leave
|
|
82
|
+
* Inside `<home>/bin` it resolves the three layouts a rename can leave. An
|
|
83
|
+
* "alias" below is any non-canonical artifact spelling — an accepted alias or a
|
|
84
|
+
* former spelling alike, since the file on disk does not know which it is now:
|
|
77
85
|
*
|
|
78
86
|
* - canonical ABSENT, an alias is a real file — the ordinary legacy install.
|
|
79
87
|
* The alias moves to canonical and a link is left at its name.
|
|
@@ -96,13 +104,17 @@ export declare function migrateFirstPartyHarnessHome(options?: {
|
|
|
96
104
|
fs?: FirstPartyHarnessHomeFs;
|
|
97
105
|
}): FirstPartyHarnessHomeMigration;
|
|
98
106
|
/**
|
|
99
|
-
* Leave a relative symlink at every
|
|
107
|
+
* Leave a relative symlink at every older name — binary and provenance sidecar —
|
|
100
108
|
* that does not exist yet, pointing at the canonical file.
|
|
101
109
|
*
|
|
102
110
|
* Call after installing the canonical binary. A platform CLI or daemon installed
|
|
103
111
|
* before a rename resolves the legacy name; the link keeps it on the current
|
|
104
|
-
* engine.
|
|
105
|
-
*
|
|
112
|
+
* engine. "Older" includes FORMER spellings, not only aliases: an installed CLI
|
|
113
|
+
* cannot be telemetry-gated the way a connected daemon can, and it does not stop
|
|
114
|
+
* existing when its spelling stops being accepted, so the link outlives the
|
|
115
|
+
* alias window (`firstPartyHarnessBinaryNames`). It never replaces anything that
|
|
116
|
+
* exists, whether a real file (an older engine someone may still run) or a link
|
|
117
|
+
* someone else placed. Never throws.
|
|
106
118
|
*/
|
|
107
119
|
export declare function linkFirstPartyHarnessAliases(options?: {
|
|
108
120
|
env?: NodeJS.ProcessEnv;
|
|
@@ -21,9 +21,15 @@
|
|
|
21
21
|
* leave the legacy name as a relative symlink. (No legacy app name exists
|
|
22
22
|
* yet; this step is what an engine-namespace rename will use.)
|
|
23
23
|
* 2. The BINARY follows the provider. Inside `<home>/bin`, if the canonical
|
|
24
|
-
* binary does not exist and an
|
|
25
|
-
* each companion (rollback copy, provenance sidecar),
|
|
26
|
-
* symlink at every old name.
|
|
24
|
+
* binary does not exist and a binary under an older spelling is a real
|
|
25
|
+
* file, rename it and each companion (rollback copy, provenance sidecar),
|
|
26
|
+
* leaving a relative symlink at every old name.
|
|
27
|
+
*
|
|
28
|
+
* "Older spelling" means every ARTIFACT spelling that is not canonical — the
|
|
29
|
+
* aliases AND the former spellings (`firstPartyHarnessArtifactSpellings`). An
|
|
30
|
+
* installed binary is an artifact: a machine that never ran a post-rename client
|
|
31
|
+
* still has its engine under the old name after that name stops being accepted
|
|
32
|
+
* anywhere, and it must still be moved rather than reinstalled beside.
|
|
27
33
|
*
|
|
28
34
|
* The two follow different names on purpose: the home is shared with the
|
|
29
35
|
* engine, which reads its config and managed `AGENTS.md` from it, so it can only
|
|
@@ -54,6 +60,10 @@ const node_fs_1 = require("node:fs");
|
|
|
54
60
|
const node_path_1 = __importDefault(require("node:path"));
|
|
55
61
|
const configRoot_js_1 = require("./configRoot.js");
|
|
56
62
|
const firstPartyHarness_js_1 = require("./firstPartyHarness.js");
|
|
63
|
+
/** Every artifact spelling except the canonical one, newest first. */
|
|
64
|
+
function olderSpellings() {
|
|
65
|
+
return (0, firstPartyHarness_js_1.firstPartyHarnessArtifactSpellings)().filter((spelling) => spelling !== firstPartyHarness_js_1.FIRST_PARTY_HARNESS.provider);
|
|
66
|
+
}
|
|
57
67
|
/** Suffix of the rollback copy the installer keeps beside the binary. */
|
|
58
68
|
exports.FIRST_PARTY_HARNESS_PREVIOUS_SUFFIX = '.previous';
|
|
59
69
|
/**
|
|
@@ -119,7 +129,9 @@ const NEWER_THRESHOLD_MS = 1000;
|
|
|
119
129
|
* Move a legacy engine home and binary onto the canonical names. See the file
|
|
120
130
|
* header for the exact contract. Returns what it did; never throws.
|
|
121
131
|
*
|
|
122
|
-
* Inside `<home>/bin` it resolves the three layouts a rename can leave
|
|
132
|
+
* Inside `<home>/bin` it resolves the three layouts a rename can leave. An
|
|
133
|
+
* "alias" below is any non-canonical artifact spelling — an accepted alias or a
|
|
134
|
+
* former spelling alike, since the file on disk does not know which it is now:
|
|
123
135
|
*
|
|
124
136
|
* - canonical ABSENT, an alias is a real file — the ordinary legacy install.
|
|
125
137
|
* The alias moves to canonical and a link is left at its name.
|
|
@@ -182,7 +194,7 @@ function migrateFirstPartyHarnessHome(options = {}) {
|
|
|
182
194
|
const canonicalName = (0, firstPartyHarness_js_1.firstPartyHarnessBinaryName)(canonical, platform);
|
|
183
195
|
const canonicalBinary = node_path_1.default.join(binDir, canonicalName);
|
|
184
196
|
const canonicalStat = fs.lstat(canonicalBinary);
|
|
185
|
-
const aliasNames =
|
|
197
|
+
const aliasNames = olderSpellings().map((spelling) => (0, firstPartyHarness_js_1.firstPartyHarnessBinaryName)(spelling, platform));
|
|
186
198
|
/** Move `<from><suffix>` onto `<to><suffix>` and leave a link; `replaceable` says what may sit at the target. */
|
|
187
199
|
const relocate = (fromName, suffix, replaceable) => {
|
|
188
200
|
const from = node_path_1.default.join(binDir, `${fromName}${suffix}`);
|
|
@@ -271,13 +283,17 @@ function migrateFirstPartyHarnessHome(options = {}) {
|
|
|
271
283
|
return { moved, errors };
|
|
272
284
|
}
|
|
273
285
|
/**
|
|
274
|
-
* Leave a relative symlink at every
|
|
286
|
+
* Leave a relative symlink at every older name — binary and provenance sidecar —
|
|
275
287
|
* that does not exist yet, pointing at the canonical file.
|
|
276
288
|
*
|
|
277
289
|
* Call after installing the canonical binary. A platform CLI or daemon installed
|
|
278
290
|
* before a rename resolves the legacy name; the link keeps it on the current
|
|
279
|
-
* engine.
|
|
280
|
-
*
|
|
291
|
+
* engine. "Older" includes FORMER spellings, not only aliases: an installed CLI
|
|
292
|
+
* cannot be telemetry-gated the way a connected daemon can, and it does not stop
|
|
293
|
+
* existing when its spelling stops being accepted, so the link outlives the
|
|
294
|
+
* alias window (`firstPartyHarnessBinaryNames`). It never replaces anything that
|
|
295
|
+
* exists, whether a real file (an older engine someone may still run) or a link
|
|
296
|
+
* someone else placed. Never throws.
|
|
281
297
|
*/
|
|
282
298
|
function linkFirstPartyHarnessAliases(options = {}) {
|
|
283
299
|
const env = options.env ?? process.env;
|
|
@@ -293,8 +309,8 @@ function linkFirstPartyHarnessAliases(options = {}) {
|
|
|
293
309
|
if (!isRealFile(fs.lstat(node_path_1.default.join(binDir, canonicalName)))) {
|
|
294
310
|
return { moved, errors };
|
|
295
311
|
}
|
|
296
|
-
for (const
|
|
297
|
-
const aliasName = (0, firstPartyHarness_js_1.firstPartyHarnessBinaryName)(
|
|
312
|
+
for (const spelling of olderSpellings()) {
|
|
313
|
+
const aliasName = (0, firstPartyHarness_js_1.firstPartyHarnessBinaryName)(spelling, platform);
|
|
298
314
|
// Sidecar FIRST: a verifier that finds the binary link must find its record.
|
|
299
315
|
for (const suffix of [exports.FIRST_PARTY_HARNESS_PROVENANCE_SUFFIX, '']) {
|
|
300
316
|
const target = `${canonicalName}${suffix}`;
|
|
@@ -49,11 +49,15 @@ export type HarnessTrustTier = 1 | 2 | 3;
|
|
|
49
49
|
* in `daemon/src/harness-trust.ts` beside the gates that read it — the argument
|
|
50
50
|
* belongs where the enforcement is, not in a shared vocabulary module.
|
|
51
51
|
*
|
|
52
|
-
* It is entered under
|
|
53
|
-
* canonical one.
|
|
54
|
-
* and an alias that fell through to the Tier 3 default
|
|
55
|
-
* harness of the trust the owner granted it — a failure
|
|
56
|
-
* permission prompt storm, not like a rename.
|
|
52
|
+
* It is entered under every ACCEPTED spelling (`firstPartyHarnessSpellings`), not
|
|
53
|
+
* only the canonical one. During a rename a backend name reaches this lookup from
|
|
54
|
+
* a daemon of any version, and an alias that fell through to the Tier 3 default
|
|
55
|
+
* would silently strip the harness of the trust the owner granted it — a failure
|
|
56
|
+
* that looks like a permission prompt storm, not like a rename.
|
|
57
|
+
*
|
|
58
|
+
* A FORMER spelling is deliberately absent. Nothing dispatches under one after
|
|
59
|
+
* contract, and a name that is not accepted must never inherit Tier 1 by being
|
|
60
|
+
* remembered: it falls to the default like any unknown backend.
|
|
57
61
|
*/
|
|
58
62
|
export declare const HARNESS_TIERS: Readonly<Record<string, HarnessTrustTier>>;
|
|
59
63
|
/**
|
|
@@ -54,11 +54,15 @@ const firstPartyHarness_js_1 = require("./firstPartyHarness.js");
|
|
|
54
54
|
* in `daemon/src/harness-trust.ts` beside the gates that read it — the argument
|
|
55
55
|
* belongs where the enforcement is, not in a shared vocabulary module.
|
|
56
56
|
*
|
|
57
|
-
* It is entered under
|
|
58
|
-
* canonical one.
|
|
59
|
-
* and an alias that fell through to the Tier 3 default
|
|
60
|
-
* harness of the trust the owner granted it — a failure
|
|
61
|
-
* permission prompt storm, not like a rename.
|
|
57
|
+
* It is entered under every ACCEPTED spelling (`firstPartyHarnessSpellings`), not
|
|
58
|
+
* only the canonical one. During a rename a backend name reaches this lookup from
|
|
59
|
+
* a daemon of any version, and an alias that fell through to the Tier 3 default
|
|
60
|
+
* would silently strip the harness of the trust the owner granted it — a failure
|
|
61
|
+
* that looks like a permission prompt storm, not like a rename.
|
|
62
|
+
*
|
|
63
|
+
* A FORMER spelling is deliberately absent. Nothing dispatches under one after
|
|
64
|
+
* contract, and a name that is not accepted must never inherit Tier 1 by being
|
|
65
|
+
* remembered: it falls to the default like any unknown backend.
|
|
62
66
|
*/
|
|
63
67
|
exports.HARNESS_TIERS = Object.freeze({
|
|
64
68
|
// --- Tier 1: vendor first-party / audited ---
|
|
@@ -37,7 +37,7 @@ export { CONFIG_DIR_NAME, LEGACY_CONFIG_DIR_NAMES, NATIVE_ID_PREFIX, LEGACY_NATI
|
|
|
37
37
|
export { findLegacyLocalState, describeLegacyState, type LegacyStateFinding, type LegacyStateReport, } from './legacyStatePreflight.js';
|
|
38
38
|
export * from './firstPartyHarness.js';
|
|
39
39
|
export { FIRST_PARTY_HARNESS_PREVIOUS_SUFFIX, FIRST_PARTY_HARNESS_PROVENANCE_SUFFIX, firstPartyHarnessBinDir, firstPartyHarnessHomeDir, firstPartyHarnessInstalledBinaryPath, linkFirstPartyHarnessAliases, migrateFirstPartyHarnessHome, type FirstPartyHarnessHomeFs, type FirstPartyHarnessHomeMigration, } from './firstPartyHarnessHome.js';
|
|
40
|
-
export { DEFAULT_FIRST_PARTY_HARNESS_CHANNEL, FIRST_PARTY_HARNESS_CHANNELS, firstPartyHarnessChannelPrefix, firstPartyHarnessFeedBase, firstPartyHarnessFeedCandidates, isFirstPartyHarnessChannel, resolveChannelManifestUrl, resolveFirstPartyHarnessChannel, type FirstPartyHarnessChannel, type FirstPartyHarnessFeedCandidate,
|
|
40
|
+
export { DEFAULT_FIRST_PARTY_HARNESS_CHANNEL, FIRST_PARTY_HARNESS_CHANNELS, firstPartyHarnessChannelPrefix, firstPartyHarnessFeedBase, firstPartyHarnessFeedCandidates, isFirstPartyHarnessChannel, resolveChannelManifestUrl, resolveFirstPartyHarnessChannel, type FirstPartyHarnessChannel, type FirstPartyHarnessFeedCandidate, } from './firstPartyHarnessChannels.js';
|
|
41
41
|
export { OVERSKY_RELEASE_PUBLIC_KEYS, type ReleaseKey } from './releaseKeys.js';
|
|
42
42
|
export { MAX_SIGS, buildArtifactMessage, buildManifestMessage, getDeltaFor, verifyArtifact, verifyManifest, type DaemonVersionManifest, type DeltaDescriptor, type ManifestSignature, type PlatformArtifact, type VerifyResult, } from './releaseManifest.js';
|
|
43
43
|
export { resolveConfigRoot, configRootPath, isConfigRootOverridden } from './configRoot.js';
|
|
@@ -25,7 +25,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
25
25
|
exports.challenge = exports.generateVerifier = exports.invalidateHeadersHelperCache = exports.runHeadersHelper = exports.SENTINEL_TRIGGERING_FAILURES = exports.__resetAuthHelperFailureReasonForTest = exports.getLastAuthHelperFailureReason = exports.getDefaultHelperTtlMs = exports.invokeAuthHelper = exports.AuthHelperUnavailableError = exports.AuthHelperUntrustedError = exports.CI_TOKEN_PREFIX = exports.classifyTokenKind = exports.invalidateAuthHelperCache = exports.__resetCredentialResolverForTest = exports.CREDENTIAL_PRECEDENCE = exports.CredentialResolver = exports.__setFdReaderForTest = exports.readAuthFromFd = exports.createRefreshScheduler = exports.UNKNOWN_401_BUDGET = exports.__resetUnknown401StreaksForTest = exports.__refreshDiagnostics = exports.installLockExitHandlers = exports.clearReauthState = exports.needsReauthState = exports.persistReauthState = exports.withAuthLock = exports.revokeDaemonRefreshSession = exports.refreshDaemonToken = exports.classifyRefreshResponse = exports.EXIT_NEEDS_REAUTH = exports.formatReauthMessage = exports.handleMidStreamAuthExpiry = exports.isAuthExpiredSseEvent = exports.decodeJwtPayload = exports.decodeJwtExpiry = exports.TransientAuthFailure = exports.PermanentAuthFailure = exports.emitAuthTelemetry = exports.getAuthBinaryName = exports.getAuthKillSwitches = exports.getAuthConfigDir = exports.getAuthLogger = exports.configureAuthCore = exports.OAUTH_CLI_SCOPE = exports.isDaemonScope = exports.VALID_DAEMON_SCOPE_SET = exports.ALL_DAEMON_SCOPES = exports.SCOPES = void 0;
|
|
26
26
|
exports.tokenHash = exports.publicJwkFromX = exports.normalizeHtu = exports.jwkThumbprint = exports.generateDeviceKeyPair = exports.buildDeviceProof = exports.zeroizeKekCaches = exports.WindowsKek = exports.registerZeroizeHook = exports.MacosKek = exports.LinuxKek = exports.KekUnavailableError = exports.UnavailableKek = exports.InMemoryKek = exports.getKekStrategy = exports.__setKekStrategyForTest = exports.credEnvelopeWrap = exports.credEnvelopeUnwrap = exports.credEnvelopeSerialize = exports.credSealBuffer = exports.credOpenBuffer = exports.CRED_KEY_LEN = exports.isCredEnvelopeString = exports.generateDek = exports.CRED_ENVELOPE_MAGIC = exports.credEnvelopeEncrypt = exports.credEnvelopeDeserialize = exports.credEnvelopeDecrypt = exports.buildCredentialAad = exports.isValidRecoveryCode = exports.normalizeRecoveryCode = exports.parseRecoveryCode = exports.formatRecoveryCode = exports.MAX_TTL_DAYS = exports.MIN_TTL_DAYS = exports.parseTtlDays = exports.LoginExchangeError = exports.LoginInitError = exports.loginWithLocalhost = exports.LocalCallbackMalformedError = exports.LocalCallbackDeniedError = exports.LocalCallbackStateMismatchError = exports.LocalCallbackTimeoutError = exports.LocalCallbackBindError = exports.LocalCallbackError = exports.DEFAULT_LOGIN_TIMEOUT_MS = exports.startLocalCallback = exports.verifyChallenge = exports.safeEqual = exports.generateState = void 0;
|
|
27
27
|
exports.getHarnessTier = exports.HARNESS_TIERS = exports.pairUint8ArrayToBase64Url = exports.pairUint8ArrayToBase64 = exports.parsePairUrl = exports.parsePairPlaintext = exports.parsePairBundle = exports.openPairBundleBase64 = exports.generatePairKeyPair = exports.buildPairUrl = exports.buildPairAad = exports.pairBase64UrlToUint8Array = exports.pairBase64ToUint8Array = exports.assemblePairBundleBase64 = exports.PairBundleError = exports.PAIR_SECRET_LEN = exports.PAIR_PUBKEY_LEN = exports.PAIR_NONCE_LEN = exports.PAIR_BUNDLE_MAX_BASE64_LEN = exports.PAIR_AAD_MAX_LEN = exports.PAIR_AAD_PREFIX = exports.__resetCachedDaemonIdForTest = exports.legacyDaemonUuids = exports.ensureMachineDaemonId = exports.__getDeviceIdentityStateForTest = exports.__setDeviceIdentityStateForTest = exports.__enrollmentBackoffPathForTest = exports.__enrollmentMarkerPathForTest = exports.__privateKeyPathForTest = exports.__publicKeyPathForTest = exports.describeDeviceIdentityState = exports.getDevicePublicKey = exports.isDeviceIdentityActive = exports.clearEnrollmentMarker = exports.enrollWithServer = exports.signServerRequest = exports.resetDeviceIdentity = exports.initDeviceIdentity = exports.__resetShutdownGuardForTest = exports.__getCredEnvelopeStateForTest = exports.__setCredEnvelopeStateForTest = exports.__wrappedDekFilePathForTest = exports.maybeDecryptOnRead = exports.maybeEncryptForWrite = exports.describeCredEnvelopeState = exports.isCredEnvelopeActive = exports.shutdownCredEnvelope = exports.resetCredEnvelope = exports.initCredEnvelope = exports.verifyDeviceProof = void 0;
|
|
28
|
-
exports.isConfigRootOverridden = exports.configRootPath = exports.resolveConfigRoot = exports.verifyManifest = exports.verifyArtifact = exports.getDeltaFor = exports.buildManifestMessage = exports.buildArtifactMessage = exports.MAX_SIGS = exports.OVERSKY_RELEASE_PUBLIC_KEYS = exports.
|
|
28
|
+
exports.isConfigRootOverridden = exports.configRootPath = exports.resolveConfigRoot = exports.verifyManifest = exports.verifyArtifact = exports.getDeltaFor = exports.buildManifestMessage = exports.buildArtifactMessage = exports.MAX_SIGS = exports.OVERSKY_RELEASE_PUBLIC_KEYS = exports.resolveFirstPartyHarnessChannel = exports.resolveChannelManifestUrl = exports.isFirstPartyHarnessChannel = exports.firstPartyHarnessFeedCandidates = exports.firstPartyHarnessFeedBase = exports.firstPartyHarnessChannelPrefix = exports.FIRST_PARTY_HARNESS_CHANNELS = exports.DEFAULT_FIRST_PARTY_HARNESS_CHANNEL = exports.migrateFirstPartyHarnessHome = exports.linkFirstPartyHarnessAliases = exports.firstPartyHarnessInstalledBinaryPath = exports.firstPartyHarnessHomeDir = exports.firstPartyHarnessBinDir = exports.FIRST_PARTY_HARNESS_PROVENANCE_SUFFIX = exports.FIRST_PARTY_HARNESS_PREVIOUS_SUFFIX = exports.describeLegacyState = exports.findLegacyLocalState = exports.DEFAULT_BINARY_NAME = exports.LEGACY_NATIVE_ID_PREFIXES = exports.NATIVE_ID_PREFIX = exports.LEGACY_CONFIG_DIR_NAMES = exports.CONFIG_DIR_NAME = exports.SENSITIVE_ENV_PREFIX_EXCEPTIONS = exports.SENSITIVE_ENV_NAME_TOKENS = exports.SENSITIVE_ENV_SUFFIXES = exports.SENSITIVE_ENV_PREFIXES = exports.SENSITIVE_ENV_VARS = exports.sanitizeSpawnEnv = exports.tierPermitsConfiguredAutoMode = exports.credentialPolicyForTier = void 0;
|
|
29
29
|
// Daemon scope vocabulary — single source of truth for non-Mongoose tiers
|
|
30
30
|
// (daemon, desktop, cli). Schema-bound canonical lives in
|
|
31
31
|
// `@skrr-ai/data-schemas/common/daemonScopes`; the two are kept byte-equal
|
|
@@ -341,18 +341,6 @@ Object.defineProperty(exports, "firstPartyHarnessFeedCandidates", { enumerable:
|
|
|
341
341
|
Object.defineProperty(exports, "isFirstPartyHarnessChannel", { enumerable: true, get: function () { return firstPartyHarnessChannels_js_1.isFirstPartyHarnessChannel; } });
|
|
342
342
|
Object.defineProperty(exports, "resolveChannelManifestUrl", { enumerable: true, get: function () { return firstPartyHarnessChannels_js_1.resolveChannelManifestUrl; } });
|
|
343
343
|
Object.defineProperty(exports, "resolveFirstPartyHarnessChannel", { enumerable: true, get: function () { return firstPartyHarnessChannels_js_1.resolveFirstPartyHarnessChannel; } });
|
|
344
|
-
// Deprecated names kept for installed CLIs that resolve this published package
|
|
345
|
-
// with a caret range. Removed in the contract phase with a minor bump.
|
|
346
|
-
Object.defineProperty(exports, "DEFAULT_SKY_CODE_CHANNEL", { enumerable: true, get: function () { return firstPartyHarnessChannels_js_1.DEFAULT_SKY_CODE_CHANNEL; } });
|
|
347
|
-
Object.defineProperty(exports, "DEFAULT_SKY_CODE_FEED_BASE", { enumerable: true, get: function () { return firstPartyHarnessChannels_js_1.DEFAULT_SKY_CODE_FEED_BASE; } });
|
|
348
|
-
Object.defineProperty(exports, "SKY_CODE_CHANNELS", { enumerable: true, get: function () { return firstPartyHarnessChannels_js_1.SKY_CODE_CHANNELS; } });
|
|
349
|
-
Object.defineProperty(exports, "SKY_CODE_CHANNEL_ENV", { enumerable: true, get: function () { return firstPartyHarnessChannels_js_1.SKY_CODE_CHANNEL_ENV; } });
|
|
350
|
-
Object.defineProperty(exports, "SKY_CODE_MANIFEST_FILE", { enumerable: true, get: function () { return firstPartyHarnessChannels_js_1.SKY_CODE_MANIFEST_FILE; } });
|
|
351
|
-
Object.defineProperty(exports, "isSkyCodeChannel", { enumerable: true, get: function () { return firstPartyHarnessChannels_js_1.isSkyCodeChannel; } });
|
|
352
|
-
Object.defineProperty(exports, "resolveSkyCodeChannel", { enumerable: true, get: function () { return firstPartyHarnessChannels_js_1.resolveSkyCodeChannel; } });
|
|
353
|
-
Object.defineProperty(exports, "skyCodeChannelPrefix", { enumerable: true, get: function () { return firstPartyHarnessChannels_js_1.skyCodeChannelPrefix; } });
|
|
354
|
-
Object.defineProperty(exports, "skyCodeFeedBase", { enumerable: true, get: function () { return firstPartyHarnessChannels_js_1.skyCodeFeedBase; } });
|
|
355
|
-
Object.defineProperty(exports, "SKY_CODE_FEED_BASE_ENV", { enumerable: true, get: function () { return firstPartyHarnessChannels_js_1.SKY_CODE_FEED_BASE_ENV; } });
|
|
356
344
|
// Daemon release trust: the pinned ed25519 keys and the canonical signature
|
|
357
345
|
// messages. Shared because BOTH the daemon (self-update) and the CLI
|
|
358
346
|
// (`skrr daemon install`, which runs when there is no daemon to ask) verify the
|
|
@@ -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
|
}
|