@skrr-ai/cli 0.1.8 → 0.1.9
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 +27 -0
- package/dist/base-command.js +83 -11
- package/dist/commands/agent/message/send.js +1 -1
- package/dist/commands/agents/chat.d.ts +1 -1
- package/dist/commands/agents/chat.js +1 -1
- package/dist/commands/browser/install.d.ts +1 -1
- package/dist/commands/browser/install.js +10 -2
- package/dist/commands/browser/mcp-config.js +3 -1
- package/dist/commands/browser/skill/show.js +1 -1
- package/dist/commands/browser/status.js +4 -1
- package/dist/commands/browser/uninstall.d.ts +1 -1
- package/dist/commands/browser/uninstall.js +10 -2
- package/dist/commands/browser.d.ts +1 -1
- package/dist/commands/browser.js +3 -3
- package/dist/commands/code/index.js +6 -3
- package/dist/commands/code/install.d.ts +61 -0
- package/dist/commands/code/install.js +247 -0
- package/dist/commands/code/oversky-agent.d.ts +2 -1
- package/dist/commands/code/oversky-agent.js +12 -8
- package/dist/commands/commands.js +1 -1
- package/dist/commands/context.js +1 -1
- package/dist/commands/create-token.js +1 -1
- package/dist/commands/daemon/byok.d.ts +1 -0
- package/dist/commands/daemon/byok.js +14 -1
- package/dist/commands/daemon/index.js +18 -7
- package/dist/commands/daemon/install.d.ts +1 -0
- package/dist/commands/daemon/install.js +22 -3
- package/dist/commands/daemon/logs.d.ts +1 -0
- package/dist/commands/daemon/logs.js +4 -0
- package/dist/commands/daemon/start.d.ts +1 -0
- package/dist/commands/daemon/start.js +15 -2
- package/dist/commands/daemon/status.d.ts +1 -0
- package/dist/commands/daemon/status.js +14 -1
- package/dist/commands/daemon/stop.d.ts +1 -0
- package/dist/commands/daemon/stop.js +14 -1
- package/dist/commands/daemon/uninstall.d.ts +1 -0
- package/dist/commands/daemon/uninstall.js +15 -2
- package/dist/commands/daemon/usage.d.ts +1 -0
- package/dist/commands/daemon/usage.js +5 -1
- package/dist/commands/doctor.js +2 -2
- package/dist/commands/github/allow-tools.d.ts +1 -0
- package/dist/commands/github/app/install.d.ts +1 -0
- package/dist/commands/github/app/status.d.ts +1 -0
- package/dist/commands/github/connect.d.ts +1 -0
- package/dist/commands/github/connections.d.ts +1 -0
- package/dist/commands/github/disconnect.d.ts +1 -0
- package/dist/commands/github/finalize.d.ts +1 -0
- package/dist/commands/github/reconnect.d.ts +1 -0
- package/dist/commands/github/run.d.ts +1 -0
- package/dist/commands/github/tools.d.ts +1 -0
- package/dist/commands/goals/create.js +2 -2
- package/dist/commands/goals/show.js +5 -0
- package/dist/commands/harnesses/list.js +14 -3
- package/dist/commands/harnesses/show.js +14 -0
- package/dist/commands/instructions/activate.js +1 -1
- package/dist/commands/instructions/archive-version.js +1 -1
- package/dist/commands/instructions/delete.js +1 -1
- package/dist/commands/instructions/diff.js +1 -1
- package/dist/commands/instructions/install.js +7 -1
- package/dist/commands/instructions/restore.js +1 -1
- package/dist/commands/instructions/show.js +17 -1
- package/dist/commands/instructions/update.js +1 -1
- package/dist/commands/integrations/connections/connect.d.ts +1 -0
- package/dist/commands/integrations/connections/disconnect.d.ts +1 -0
- package/dist/commands/integrations/connections/finalize.d.ts +1 -0
- package/dist/commands/integrations/connections/list.d.ts +1 -0
- package/dist/commands/integrations/connections/reconnect.d.ts +1 -0
- package/dist/commands/integrations/execute.d.ts +1 -0
- package/dist/commands/integrations/search.d.ts +1 -0
- package/dist/commands/integrations/toolkits.d.ts +1 -0
- package/dist/commands/integrations/tools/allow.d.ts +1 -0
- package/dist/commands/integrations/tools/list.d.ts +1 -0
- package/dist/commands/list-daemons.d.ts +2 -7
- package/dist/commands/list-daemons.js +13 -13
- package/dist/commands/login.js +73 -31
- package/dist/commands/logout.js +52 -1
- package/dist/commands/machines/hosted/start.js +1 -1
- package/dist/commands/pair.js +2 -2
- package/dist/commands/projects/create.js +6 -1
- package/dist/commands/projects/tasks.js +6 -1
- package/dist/commands/revoke-daemon.js +6 -2
- package/dist/commands/set-capabilities.js +6 -2
- package/dist/commands/skills/install.js +1 -1
- package/dist/commands/skills/library.js +2 -2
- package/dist/commands/spaces/create.js +6 -2
- package/dist/commands/tasks/complete.d.ts +1 -1
- package/dist/commands/tasks/complete.js +21 -8
- package/dist/commands/tasks/create.js +4 -1
- package/dist/commands/tasks/current.js +1 -1
- package/dist/commands/tasks/delete.d.ts +1 -0
- package/dist/commands/tasks/delete.js +9 -0
- package/dist/commands/tasks/export.js +5 -1
- package/dist/commands/tasks/follow-up.js +2 -1
- package/dist/commands/tasks/list.js +5 -1
- package/dist/commands/tasks/pr.js +1 -1
- package/dist/commands/tasks/show.js +10 -1
- package/dist/commands/tasks/triage.js +2 -1
- package/dist/commands/tasks/update.js +4 -1
- package/dist/commands/tasks/upsert.js +4 -1
- package/dist/commands/usage.js +1 -1
- package/dist/lib/agentic-stream.js +21 -1
- package/dist/lib/api-fetch.d.ts +1 -1
- package/dist/lib/api-fetch.js +1 -1
- package/dist/lib/auth-core-init.js +23 -3
- package/dist/lib/auth-storage.d.ts +0 -12
- package/dist/lib/auth-storage.js +37 -2
- package/dist/lib/config.d.ts +3 -3
- package/dist/lib/config.js +327 -26
- package/dist/lib/created-line.d.ts +22 -0
- package/dist/lib/created-line.js +25 -0
- package/dist/lib/daemon-binding.d.ts +29 -0
- package/dist/lib/daemon-binding.js +63 -0
- package/dist/lib/daemon-ref.d.ts +31 -0
- package/dist/lib/daemon-ref.js +47 -0
- package/dist/lib/daemonBroker.js +1 -1
- package/dist/lib/delegated-cli.js +3 -3
- package/dist/lib/exec-oversky.d.ts +18 -1
- package/dist/lib/exec-oversky.js +21 -4
- package/dist/lib/html-text.d.ts +15 -0
- package/dist/lib/html-text.js +40 -0
- package/dist/lib/keychain.d.ts +43 -0
- package/dist/lib/keychain.js +145 -4
- package/dist/lib/login.js +3 -3
- package/dist/lib/node-adapter.js +1 -1
- package/dist/lib/oauthLogin.js +17 -6
- package/dist/lib/sky-code-agent.d.ts +1 -1
- package/dist/lib/sky-code-agent.js +8 -8
- package/dist/lib/sky-code-broker.js +18 -2
- package/dist/lib/sky-code-doctor.js +120 -4
- package/dist/lib/sky-code-managed.d.ts +12 -0
- package/dist/lib/sky-code-managed.js +21 -7
- package/dist/lib/sky-code.d.ts +16 -1
- package/dist/lib/sky-code.js +102 -4
- package/dist/lib/task-execution.js +4 -11
- package/dist/lib/tasks.d.ts +1 -0
- package/dist/lib/tasks.js +9 -6
- package/dist/lib/update-check.js +1 -1
- package/dist/lib/usage-discovery.js +1 -1
- package/dist/lib/web-url.js +12 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialResolver.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialResolver.js +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +1 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +13 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/linux.js +16 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/legacyStatePreflight.d.ts +0 -9
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/legacyStatePreflight.js +18 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/loginLocalhost.js +3 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/messages.js +3 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/runtime.d.ts +7 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/skyCodeChannels.d.ts +96 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/skyCodeChannels.js +115 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialResolver.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialResolver.js +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +1 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +1 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/linux.js +16 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/legacyStatePreflight.d.ts +0 -9
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/legacyStatePreflight.js +18 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/loginLocalhost.js +3 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/messages.js +3 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/runtime.d.ts +7 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/skyCodeChannels.d.ts +96 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/skyCodeChannels.js +107 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +4206 -4191
- package/dist/node_modules/@skrr-ai/inference-broker/dist/cjs/managed-inference-broker.js +2 -2
- package/dist/node_modules/@skrr-ai/inference-broker/dist/esm/managed-inference-broker.js +2 -2
- package/oclif.manifest.json +9924 -3352
- package/package.json +22 -19
package/dist/lib/tasks.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TASK_WORK_EVENT_KINDS = void 0;
|
|
3
|
+
exports.TASK_WORK_EVENT_KINDS = exports.TASK_PRIORITIES = void 0;
|
|
4
4
|
exports.releasePinRepairGuard = releasePinRepairGuard;
|
|
5
5
|
exports.taskUpdateMutationGuard = taskUpdateMutationGuard;
|
|
6
6
|
exports.executionIsolationFromWorktreeFlag = executionIsolationFromWorktreeFlag;
|
|
@@ -30,7 +30,7 @@ exports.normalizeBulkUpdateInput = normalizeBulkUpdateInput;
|
|
|
30
30
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
31
31
|
const prompt_1 = require("./prompt");
|
|
32
32
|
const projects_1 = require("./projects");
|
|
33
|
-
|
|
33
|
+
exports.TASK_PRIORITIES = ['low', 'medium', 'high', 'critical'];
|
|
34
34
|
const DESCRIPTION_FORMATS = ['html', 'markdown', 'plain'];
|
|
35
35
|
/**
|
|
36
36
|
* The kinds `tasks events append --kind` will accept.
|
|
@@ -201,8 +201,8 @@ function validateTaskCreatePayload(payload) {
|
|
|
201
201
|
errors.push(`descriptionFormat must be one of: ${DESCRIPTION_FORMATS.join(', ')}`);
|
|
202
202
|
}
|
|
203
203
|
if (payload.priority !== undefined &&
|
|
204
|
-
!TASK_PRIORITIES.includes(payload.priority)) {
|
|
205
|
-
errors.push(`priority must be one of: ${TASK_PRIORITIES.join(', ')}`);
|
|
204
|
+
!exports.TASK_PRIORITIES.includes(payload.priority)) {
|
|
205
|
+
errors.push(`priority must be one of: ${exports.TASK_PRIORITIES.join(', ')}`);
|
|
206
206
|
}
|
|
207
207
|
if (payload.externalKey !== undefined && !isBoundedString(payload.externalKey, 1, 300)) {
|
|
208
208
|
errors.push('externalKey must be a non-empty string at most 300 characters');
|
|
@@ -566,9 +566,12 @@ function taskRef(task) {
|
|
|
566
566
|
return '';
|
|
567
567
|
}
|
|
568
568
|
function formatTaskLabel(task) {
|
|
569
|
-
|
|
569
|
+
// Ref first, id as the fallback — matching every other entity's confirmation
|
|
570
|
+
// (see `lib/created-line.ts`). Printing both put a uuid in front of the ref a
|
|
571
|
+
// person would actually type, and the `View it at` line already carries the id.
|
|
570
572
|
const ref = taskRef(task);
|
|
571
|
-
|
|
573
|
+
const label = ref || taskId(task) || '?';
|
|
574
|
+
return `${label} — ${String(task.title ?? '(no title)')}`;
|
|
572
575
|
}
|
|
573
576
|
function hasTaskAssignee(task) {
|
|
574
577
|
return (stringArray(task?.assigneeAgentIds).length > 0 || stringArray(task?.assigneeUserIds).length > 0);
|
package/dist/lib/update-check.js
CHANGED
|
@@ -138,7 +138,7 @@ function buildNudgeLine(currentVersion, latest, npmPackage) {
|
|
|
138
138
|
if (!latest || !isOlderVersion(currentVersion, latest))
|
|
139
139
|
return null;
|
|
140
140
|
const pkg = npmPackage || '@skrr-ai/cli';
|
|
141
|
-
return (`[
|
|
141
|
+
return (`[skrr] Update available: ${currentVersion} → ${latest}. ` +
|
|
142
142
|
`Run \`npm update -g ${pkg}\` (or update the skrr app). ` +
|
|
143
143
|
`Silence with OVERSKY_NO_UPDATE_NUDGE=1.\n`);
|
|
144
144
|
}
|
|
@@ -95,7 +95,7 @@ function buildUsageReference(manifest, domainInput, options = {}) {
|
|
|
95
95
|
}
|
|
96
96
|
function renderUsageOverview(overview) {
|
|
97
97
|
const lines = [
|
|
98
|
-
`
|
|
98
|
+
`skrr command domains (${overview.domains.length}; manifest-derived).`,
|
|
99
99
|
'Read one domain at a time: skrr usage <domain>.',
|
|
100
100
|
...overview.domains.map(({ domain }) => domain),
|
|
101
101
|
];
|
package/dist/lib/web-url.js
CHANGED
|
@@ -40,6 +40,7 @@ exports.withNorthstarUrl = withNorthstarUrl;
|
|
|
40
40
|
exports.withAgentUrl = withAgentUrl;
|
|
41
41
|
exports.withDataUrls = withDataUrls;
|
|
42
42
|
exports.workflowUrlFrom = workflowUrlFrom;
|
|
43
|
+
const publicEndpoints_generated_1 = require("./publicEndpoints.generated");
|
|
43
44
|
/**
|
|
44
45
|
* Site-relative canonical path for an entity, or `null` when the required id is
|
|
45
46
|
* missing. When a task/goal knows its hosting space we emit the canonical
|
|
@@ -141,8 +142,18 @@ function webUrl(baseURL, ref) {
|
|
|
141
142
|
* custom) passes through unchanged — only the known skrr api hosts are mapped.
|
|
142
143
|
*/
|
|
143
144
|
const WEB_ORIGIN_FROM_API = {
|
|
145
|
+
// DERIVED from the one domain contract, not hand-listed. The hand-listed
|
|
146
|
+
// version knew only the pre-rename hosts, so `api.skrr.ai` — the CURRENT prod
|
|
147
|
+
// API origin — mapped to nothing and fell through unchanged, and every link
|
|
148
|
+
// the CLI printed from that baseURL would point at the API host instead of
|
|
149
|
+
// the SPA. Deriving it means the next environment cannot be silently omitted.
|
|
150
|
+
...Object.fromEntries(Object.values(publicEndpoints_generated_1.OVERSKY_ENVIRONMENT_ENDPOINTS).map((e) => [
|
|
151
|
+
e.realtimeUrl.toLowerCase(),
|
|
152
|
+
e.appUrl,
|
|
153
|
+
])),
|
|
154
|
+
// Prod's retained previous origin. `oversky.ai` still resolves and is
|
|
155
|
+
// deliberately kept (LEGACY_PROD_BASE_URL), so its api. host must map too.
|
|
144
156
|
'https://api.oversky.ai': 'https://oversky.ai',
|
|
145
|
-
'https://api.oversky.dev': 'https://oversky.dev',
|
|
146
157
|
};
|
|
147
158
|
function toWebOrigin(baseURL) {
|
|
148
159
|
const trimmed = trimTrailingSlash(baseURL);
|
|
@@ -215,7 +215,7 @@ export declare class AuthHelperUnavailableError extends Error {
|
|
|
215
215
|
/**
|
|
216
216
|
* L6.1 — typed error thrown when the workspace-trust gate blocks a
|
|
217
217
|
* project- or local-scope helper. Surfaces the actionable next step
|
|
218
|
-
* (`
|
|
218
|
+
* (`skrrd trust accept`) to the user; the daemon catches and presents
|
|
219
219
|
* this without falling through to OAuth.
|
|
220
220
|
*/
|
|
221
221
|
export declare class AuthHelperUntrustedError extends Error {
|
|
@@ -137,7 +137,7 @@ exports.AuthHelperUnavailableError = AuthHelperUnavailableError;
|
|
|
137
137
|
/**
|
|
138
138
|
* L6.1 — typed error thrown when the workspace-trust gate blocks a
|
|
139
139
|
* project- or local-scope helper. Surfaces the actionable next step
|
|
140
|
-
* (`
|
|
140
|
+
* (`skrrd trust accept`) to the user; the daemon catches and presents
|
|
141
141
|
* this without falling through to OAuth.
|
|
142
142
|
*/
|
|
143
143
|
class AuthHelperUntrustedError extends Error {
|
|
@@ -146,7 +146,7 @@ class AuthHelperUntrustedError extends Error {
|
|
|
146
146
|
helperPath;
|
|
147
147
|
constructor(helperPath, origin, reason) {
|
|
148
148
|
super(`OVERSKY_AUTH_HELPER (${origin}-scope) is not trusted for this workspace ` +
|
|
149
|
-
`(reason: ${reason}). Run \`
|
|
149
|
+
`(reason: ${reason}). Run \`skrrd trust accept\` to allow it.`);
|
|
150
150
|
this.name = 'AuthHelperUntrustedError';
|
|
151
151
|
this.origin = origin;
|
|
152
152
|
this.reason = reason;
|
|
@@ -35,3 +35,4 @@ export { HARNESS_TIERS, getHarnessTier, credentialPolicyForTier, tierPermitsConf
|
|
|
35
35
|
export { sanitizeSpawnEnv, SENSITIVE_ENV_VARS, SENSITIVE_ENV_PREFIXES, SENSITIVE_ENV_SUFFIXES, SENSITIVE_ENV_PREFIX_EXCEPTIONS, } from './spawnEnv.js';
|
|
36
36
|
export { CONFIG_DIR_NAME, LEGACY_CONFIG_DIR_NAMES, NATIVE_ID_PREFIX, LEGACY_NATIVE_ID_PREFIXES, DEFAULT_BINARY_NAME, } from './localIdentity.js';
|
|
37
37
|
export { findLegacyLocalState, describeLegacyState, type LegacyStateFinding, type LegacyStateReport, } from './legacyStatePreflight.js';
|
|
38
|
+
export { DEFAULT_SKY_CODE_CHANNEL, DEFAULT_SKY_CODE_FEED_BASE, SKY_CODE_CHANNELS, SKY_CODE_CHANNEL_ENV, SKY_CODE_MANIFEST_FILE, isSkyCodeChannel, resolveChannelManifestUrl, resolveSkyCodeChannel, skyCodeChannelPrefix, skyCodeFeedBase, SKY_CODE_FEED_BASE_ENV, type SkyCodeChannel, } from './skyCodeChannels.js';
|
|
@@ -11,7 +11,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
11
11
|
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;
|
|
12
12
|
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;
|
|
13
13
|
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;
|
|
14
|
-
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_SUFFIXES = exports.SENSITIVE_ENV_PREFIXES = exports.SENSITIVE_ENV_VARS = exports.sanitizeSpawnEnv = exports.tierPermitsConfiguredAutoMode = exports.credentialPolicyForTier = void 0;
|
|
14
|
+
exports.SKY_CODE_FEED_BASE_ENV = exports.skyCodeFeedBase = exports.skyCodeChannelPrefix = exports.resolveSkyCodeChannel = exports.resolveChannelManifestUrl = exports.isSkyCodeChannel = exports.SKY_CODE_MANIFEST_FILE = exports.SKY_CODE_CHANNEL_ENV = exports.SKY_CODE_CHANNELS = exports.DEFAULT_SKY_CODE_FEED_BASE = exports.DEFAULT_SKY_CODE_CHANNEL = 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_SUFFIXES = exports.SENSITIVE_ENV_PREFIXES = exports.SENSITIVE_ENV_VARS = exports.sanitizeSpawnEnv = exports.tierPermitsConfiguredAutoMode = exports.credentialPolicyForTier = void 0;
|
|
15
15
|
// Daemon scope vocabulary — single source of truth for non-Mongoose tiers
|
|
16
16
|
// (daemon, desktop, cli). Schema-bound canonical lives in
|
|
17
17
|
// `@skrr-ai/data-schemas/common/daemonScopes`; the two are kept byte-equal
|
|
@@ -303,3 +303,15 @@ Object.defineProperty(exports, "DEFAULT_BINARY_NAME", { enumerable: true, get: f
|
|
|
303
303
|
var legacyStatePreflight_js_1 = require("./legacyStatePreflight.js");
|
|
304
304
|
Object.defineProperty(exports, "findLegacyLocalState", { enumerable: true, get: function () { return legacyStatePreflight_js_1.findLegacyLocalState; } });
|
|
305
305
|
Object.defineProperty(exports, "describeLegacyState", { enumerable: true, get: function () { return legacyStatePreflight_js_1.describeLegacyState; } });
|
|
306
|
+
var skyCodeChannels_js_1 = require("./skyCodeChannels.js");
|
|
307
|
+
Object.defineProperty(exports, "DEFAULT_SKY_CODE_CHANNEL", { enumerable: true, get: function () { return skyCodeChannels_js_1.DEFAULT_SKY_CODE_CHANNEL; } });
|
|
308
|
+
Object.defineProperty(exports, "DEFAULT_SKY_CODE_FEED_BASE", { enumerable: true, get: function () { return skyCodeChannels_js_1.DEFAULT_SKY_CODE_FEED_BASE; } });
|
|
309
|
+
Object.defineProperty(exports, "SKY_CODE_CHANNELS", { enumerable: true, get: function () { return skyCodeChannels_js_1.SKY_CODE_CHANNELS; } });
|
|
310
|
+
Object.defineProperty(exports, "SKY_CODE_CHANNEL_ENV", { enumerable: true, get: function () { return skyCodeChannels_js_1.SKY_CODE_CHANNEL_ENV; } });
|
|
311
|
+
Object.defineProperty(exports, "SKY_CODE_MANIFEST_FILE", { enumerable: true, get: function () { return skyCodeChannels_js_1.SKY_CODE_MANIFEST_FILE; } });
|
|
312
|
+
Object.defineProperty(exports, "isSkyCodeChannel", { enumerable: true, get: function () { return skyCodeChannels_js_1.isSkyCodeChannel; } });
|
|
313
|
+
Object.defineProperty(exports, "resolveChannelManifestUrl", { enumerable: true, get: function () { return skyCodeChannels_js_1.resolveChannelManifestUrl; } });
|
|
314
|
+
Object.defineProperty(exports, "resolveSkyCodeChannel", { enumerable: true, get: function () { return skyCodeChannels_js_1.resolveSkyCodeChannel; } });
|
|
315
|
+
Object.defineProperty(exports, "skyCodeChannelPrefix", { enumerable: true, get: function () { return skyCodeChannels_js_1.skyCodeChannelPrefix; } });
|
|
316
|
+
Object.defineProperty(exports, "skyCodeFeedBase", { enumerable: true, get: function () { return skyCodeChannels_js_1.skyCodeFeedBase; } });
|
|
317
|
+
Object.defineProperty(exports, "SKY_CODE_FEED_BASE_ENV", { enumerable: true, get: function () { return skyCodeChannels_js_1.SKY_CODE_FEED_BASE_ENV; } });
|
|
@@ -84,8 +84,21 @@ const DBUS_TRANSPORT_ERRORS = [
|
|
|
84
84
|
'No such interface',
|
|
85
85
|
'Cannot autolaunch',
|
|
86
86
|
];
|
|
87
|
-
/**
|
|
88
|
-
*
|
|
87
|
+
/**
|
|
88
|
+
* HKDF-SHA256 parameters for Tier-3. Stable across versions: ANY change
|
|
89
|
+
* silently invalidates every wrapped DEK on disk.
|
|
90
|
+
*
|
|
91
|
+
* That includes the brand. These strings are cryptographic derivation inputs
|
|
92
|
+
* that happen to read like a name, so a rename sweep produces exactly the same
|
|
93
|
+
* outcome as bumping the `v1` suffix — every credential on every machine
|
|
94
|
+
* becomes undecryptable, with no error at write time and a failure that
|
|
95
|
+
* surfaces only when someone next tries to unwrap. The KEK's SERVICE name moved
|
|
96
|
+
* to `ai.skrr.daemon.kek`; these did not, and must not.
|
|
97
|
+
*
|
|
98
|
+
* Rotating them deliberately is a re-issue, not a rename: it needs the old
|
|
99
|
+
* envelope discarded and credentials re-obtained, which is a decision with a
|
|
100
|
+
* user-visible cost rather than a string edit.
|
|
101
|
+
*/
|
|
89
102
|
const HKDF_SALT = Buffer.from('oversky-cred-kek-salt-v1');
|
|
90
103
|
const HKDF_INFO = Buffer.from('oversky-cred-kek-v1');
|
|
91
104
|
/** Filesystem paths for Tier-3 IKM components. */
|
|
@@ -299,7 +312,7 @@ async function writeKekToSecretService(kek, service, account) {
|
|
|
299
312
|
}
|
|
300
313
|
const b64 = kek.toString('base64');
|
|
301
314
|
try {
|
|
302
|
-
await exec('secret-tool', ['store', '--label=
|
|
315
|
+
await exec('secret-tool', ['store', '--label=skrr daemon master KEK', 'service', service, 'account', account], { input: b64 });
|
|
303
316
|
}
|
|
304
317
|
catch (err) {
|
|
305
318
|
throw new types_js_1.KekUnavailableError(KIND_LIBSECRET, 'secret-tool store failed', { cause: err });
|
|
@@ -55,13 +55,4 @@ 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
|
-
/**
|
|
59
|
-
* The message shown when preflight refuses.
|
|
60
|
-
*
|
|
61
|
-
* Written for someone who has just been stopped and wants to know why and what
|
|
62
|
-
* to do — so it names the exact paths, says explicitly that nothing was touched,
|
|
63
|
-
* and points at the runbook rather than improvising a fix. It does NOT offer a
|
|
64
|
-
* `--force`: the operator's next step is the backup the runbook specifies, and
|
|
65
|
-
* a flag that skips a safety check is the flag everyone learns to paste.
|
|
66
|
-
*/
|
|
67
58
|
export declare function describeLegacyState(report: LegacyStateReport, binaryName: string): string;
|
|
@@ -58,6 +58,13 @@ function findLegacyLocalState(home = node_os_1.default.homedir()) {
|
|
|
58
58
|
* `--force`: the operator's next step is the backup the runbook specifies, and
|
|
59
59
|
* a flag that skips a safety check is the flag everyone learns to paste.
|
|
60
60
|
*/
|
|
61
|
+
/**
|
|
62
|
+
* The pre-rename runtime binary. Named in the refusal above because deregistering
|
|
63
|
+
* the OLD service is the one step the NEW binary cannot do: `uninstall` resolves
|
|
64
|
+
* the current profile's label (`ai.skrr.daemon.*`), and the legacy sweep is wired
|
|
65
|
+
* only into the install path.
|
|
66
|
+
*/
|
|
67
|
+
const LEGACY_BINARY_NAME = 'oversky';
|
|
61
68
|
function describeLegacyState(report, binaryName) {
|
|
62
69
|
const lines = [];
|
|
63
70
|
lines.push('Found state from the previous product identity on this machine:');
|
|
@@ -72,7 +79,17 @@ function describeLegacyState(report, binaryName) {
|
|
|
72
79
|
lines.push('Nothing above has been read, copied or removed. Follow the team cutover');
|
|
73
80
|
lines.push('runbook — it takes a backup first — and then run this again:');
|
|
74
81
|
lines.push('');
|
|
75
|
-
|
|
82
|
+
// The OLD binary, deliberately: it is the one that knows the old service
|
|
83
|
+
// label. `<current> uninstall` resolves the CURRENT profile's label and would
|
|
84
|
+
// report success while leaving the pre-rename service registered. Guarded by
|
|
85
|
+
// "only if" rather than omitted, because this module inspects directories and
|
|
86
|
+
// has no way to know whether that binary is still on PATH.
|
|
87
|
+
lines.push(` ${LEGACY_BINARY_NAME} uninstall # only if the old runtime is still installed —`);
|
|
88
|
+
lines.push(` # it is the one that knows the old service label`);
|
|
76
89
|
lines.push(' # then remove the directories listed above, per the runbook');
|
|
90
|
+
lines.push('');
|
|
91
|
+
lines.push(`Any pre-rename service still registered is swept by \`${binaryName} install\``);
|
|
92
|
+
lines.push('once those directories are gone, so re-running the install completes the');
|
|
93
|
+
lines.push('cutover either way.');
|
|
77
94
|
return lines.join('\n');
|
|
78
95
|
}
|
|
@@ -354,15 +354,15 @@ function htmlShell(title, accent, headline, body) {
|
|
|
354
354
|
function successHtml() {
|
|
355
355
|
const headline = `<div class="badge"><svg viewBox="0 0 24 24"><path d="M5 13l4 4L19 7"/></svg></div>
|
|
356
356
|
<h1>Authorized</h1>`;
|
|
357
|
-
return htmlShell('
|
|
357
|
+
return htmlShell('skrr — Authorized', '#10b981', headline, 'You can close this tab and return to your terminal.');
|
|
358
358
|
}
|
|
359
359
|
function declinedHtml() {
|
|
360
360
|
const headline = `<div class="badge" style="background:#64748b"><svg viewBox="0 0 24 24"><path d="M6 6l12 12M18 6L6 18"/></svg></div>
|
|
361
361
|
<h1>Authorization declined</h1>`;
|
|
362
|
-
return htmlShell('
|
|
362
|
+
return htmlShell('skrr — Authorization declined', '#64748b', headline, 'You can close this tab. Run the CLI command again to retry.');
|
|
363
363
|
}
|
|
364
364
|
function genericFailureHtml() {
|
|
365
365
|
const headline = `<div class="badge" style="background:#ef4444"><svg viewBox="0 0 24 24"><path d="M12 8v4M12 16h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg></div>
|
|
366
366
|
<h1>Authorization error</h1>`;
|
|
367
|
-
return htmlShell('
|
|
367
|
+
return htmlShell('skrr — Authorization error', '#ef4444', headline, 'Something went wrong. You can close this tab and retry from the terminal.');
|
|
368
368
|
}
|
|
@@ -18,8 +18,8 @@ const REASON_HUMAN = {
|
|
|
18
18
|
SESSION_REVOKED: 'Your session was ended (you signed out elsewhere or your password changed).',
|
|
19
19
|
TOKEN_EXPIRED: 'Your access token has expired.',
|
|
20
20
|
TOKEN_INVALID: 'Your saved credentials are no longer valid.',
|
|
21
|
-
UNKNOWN_401: '
|
|
22
|
-
UNKNOWN: '
|
|
21
|
+
UNKNOWN_401: 'skrr needs you to sign in again.',
|
|
22
|
+
UNKNOWN: 'skrr needs you to sign in again.',
|
|
23
23
|
};
|
|
24
24
|
function formatReauthMessage(reason) {
|
|
25
25
|
const norm = REASON_HUMAN[reason] || REASON_HUMAN.UNKNOWN;
|
|
@@ -28,7 +28,7 @@ function formatReauthMessage(reason) {
|
|
|
28
28
|
const cmd = isHeadless ? `${bin} login --device` : `${bin} login`;
|
|
29
29
|
return [
|
|
30
30
|
'',
|
|
31
|
-
'
|
|
31
|
+
'skrr cannot connect — re-authentication required.',
|
|
32
32
|
` Reason: ${norm}`,
|
|
33
33
|
'',
|
|
34
34
|
` To continue, run: ${cmd}`,
|
|
@@ -49,9 +49,13 @@ export interface AuthCoreConfig {
|
|
|
49
49
|
* per-profile and silently killed the `legacyDaemonUuids()` fold safety net
|
|
50
50
|
* (it scanned `<profileDir>/profiles/*`, which never exists). See OSK-1478.
|
|
51
51
|
*
|
|
52
|
-
* Default: falls back to `configDir()` when unset.
|
|
53
|
-
*
|
|
54
|
-
*
|
|
52
|
+
* Default: falls back to `configDir()` when unset. BOTH callers now wire it
|
|
53
|
+
* explicitly — the daemon to its root `CONFIG_DIR` in `auth/configure.ts`,
|
|
54
|
+
* and the CLI in `auth-core-init.ts`. The CLI's used to need no wiring
|
|
55
|
+
* because its `configDir` was unconditionally the machine root; that stopped
|
|
56
|
+
* being true when `configDir` became profile-aware, and an unwired default
|
|
57
|
+
* would have drifted `cliId` per profile — which the server rejects, because
|
|
58
|
+
* it binds that value into the JWT `did` claim.
|
|
55
59
|
*/
|
|
56
60
|
machineConfigDir?: () => string;
|
|
57
61
|
/** Logger used by all stateful helpers. */
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* skrr Code update channels — the vocabulary, in the ONE place both readers resolve.
|
|
3
|
+
*
|
|
4
|
+
* It lived in `daemon/src/sky-code/channels.ts`, whose only importer was the
|
|
5
|
+
* daemon's own installer. That was fine while the daemon was the only thing that
|
|
6
|
+
* needed it, and it stopped being fine the moment a user could be told to go
|
|
7
|
+
* looking: `skrr code`'s not-installed message promised that `skrr code doctor`
|
|
8
|
+
* would name "which channel this machine follows and whether that channel has a
|
|
9
|
+
* published release", and the CLI had no access to any of it — so the sentence
|
|
10
|
+
* described a diagnosis nobody had written (dogfood OSK-274).
|
|
11
|
+
*
|
|
12
|
+
* A MIRROR in the CLI was the obvious alternative and is the wrong answer here,
|
|
13
|
+
* with precedent: OSK-3894 shipped exactly that for the harness trust tiers and
|
|
14
|
+
* OSK-3897 removed it, because a mirror proves two copies agree rather than
|
|
15
|
+
* proving there is one copy. `harnessTrust.ts` moved into this package for that
|
|
16
|
+
* reason, the daemon re-exports it, and a static check keeps the daemon from
|
|
17
|
+
* quietly redeclaring. This follows that road rather than reopening the one it
|
|
18
|
+
* replaced.
|
|
19
|
+
*
|
|
20
|
+
* Only the VOCABULARY moves — channel names, the env var, the default, and the
|
|
21
|
+
* URL shape. The installer, the signature verification and the promotion
|
|
22
|
+
* machinery stay in the daemon, which is the only process that performs them.
|
|
23
|
+
*/
|
|
24
|
+
/** Channels in promotion order. Index order IS the promotion order. */
|
|
25
|
+
export declare const SKY_CODE_CHANNELS: readonly ["internal", "canary", "beta", "stable"];
|
|
26
|
+
export type SkyCodeChannel = (typeof SKY_CODE_CHANNELS)[number];
|
|
27
|
+
/**
|
|
28
|
+
* The channel a build without an explicit setting follows.
|
|
29
|
+
*
|
|
30
|
+
* `stable`, and never inferred from anything else. A default that drifted with
|
|
31
|
+
* the build (say, dev builds silently on `canary`) would mean a user's update
|
|
32
|
+
* path depended on how their binary happened to be produced.
|
|
33
|
+
*/
|
|
34
|
+
export declare const DEFAULT_SKY_CODE_CHANNEL: SkyCodeChannel;
|
|
35
|
+
/** Env var selecting the channel. Explicit opt-in; never set implicitly. */
|
|
36
|
+
export declare const SKY_CODE_CHANNEL_ENV = "OVERSKY_SKY_CODE_CHANNEL";
|
|
37
|
+
/** Manifest filename, under a channel prefix or an immutable release prefix. */
|
|
38
|
+
export declare const SKY_CODE_MANIFEST_FILE = "sky-code-version.json";
|
|
39
|
+
export declare function isSkyCodeChannel(value: unknown): value is SkyCodeChannel;
|
|
40
|
+
/**
|
|
41
|
+
* The channel this process should follow.
|
|
42
|
+
*
|
|
43
|
+
* An unrecognised value falls back to the default rather than throwing. A
|
|
44
|
+
* typo'd channel must not brick updates altogether — that turns a harmless
|
|
45
|
+
* mistake into an un-updatable machine, which is the failure the updater exists
|
|
46
|
+
* to prevent. The caller is handed `invalid` so it can say so out loud.
|
|
47
|
+
*/
|
|
48
|
+
export declare function resolveSkyCodeChannel(env?: NodeJS.ProcessEnv): {
|
|
49
|
+
channel: SkyCodeChannel;
|
|
50
|
+
invalid?: string;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Where a channel's signed manifest lives.
|
|
54
|
+
*
|
|
55
|
+
* `stable` is NOT special-cased to `latest/`. Two paths that must always agree
|
|
56
|
+
* is a pair that eventually will not, and the one that disagrees silently is
|
|
57
|
+
* the one serving production. `latest/` remains for the daemon feed and for
|
|
58
|
+
* anything already pointing at it; skrr Code channel clients read
|
|
59
|
+
* `channels/<name>/` uniformly.
|
|
60
|
+
*/
|
|
61
|
+
export declare function skyCodeChannelPrefix(channel: SkyCodeChannel): string;
|
|
62
|
+
/**
|
|
63
|
+
* Manifest URL for a channel, or for a pinned version.
|
|
64
|
+
*
|
|
65
|
+
* A pinned version wins over the channel and reads its immutable per-release
|
|
66
|
+
* copy: pinning means "this exact build", and a channel pointer that moved
|
|
67
|
+
* underneath would make the pin a suggestion.
|
|
68
|
+
*
|
|
69
|
+
* Builds only MANIFEST urls, never artifact ones. `buildManifestMessage` signs
|
|
70
|
+
* version, minimum, forceUpdate and the per-platform sha256s; `buildArtifactMessage`
|
|
71
|
+
* signs the artifact URL. Neither signs a channel — so artifact URLs stay
|
|
72
|
+
* channel-independent and promotion is a COPY OF AN ALREADY-SIGNED OBJECT that
|
|
73
|
+
* never needs the release key. Put the channel in the artifact URL instead and
|
|
74
|
+
* every promotion becomes a re-signing ceremony, which decides whether the
|
|
75
|
+
* ed25519 key has to be reachable from routine automation. A helper here that
|
|
76
|
+
* adjusted artifact urls would silently reintroduce exactly that coupling.
|
|
77
|
+
*/
|
|
78
|
+
export declare function resolveChannelManifestUrl(input: {
|
|
79
|
+
base: string;
|
|
80
|
+
manifestFilename: string;
|
|
81
|
+
channel: SkyCodeChannel;
|
|
82
|
+
pinnedVersion?: string | null;
|
|
83
|
+
}): string;
|
|
84
|
+
/** Default public feed. Mirrors the daemon's `updates.oversky.ai/daemon` prefix. */
|
|
85
|
+
export declare const DEFAULT_SKY_CODE_FEED_BASE = "https://updates.oversky.ai/sky-code";
|
|
86
|
+
/**
|
|
87
|
+
* Feed override, read at call time rather than module load so a test or an
|
|
88
|
+
* operator can repoint it without re-importing.
|
|
89
|
+
*
|
|
90
|
+
* Explicit-only: a production user must never be silently enrolled onto a
|
|
91
|
+
* different feed. Selecting a feed changes WHICH signed manifest is read, never
|
|
92
|
+
* WHETHER the signature is checked — every artifact is verified against the
|
|
93
|
+
* pinned keys regardless of where it came from.
|
|
94
|
+
*/
|
|
95
|
+
export declare const SKY_CODE_FEED_BASE_ENV = "OVERSKY_SKY_CODE_UPDATE_FEED_BASE";
|
|
96
|
+
export declare function skyCodeFeedBase(env?: NodeJS.ProcessEnv): string;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* skrr Code update channels — the vocabulary, in the ONE place both readers resolve.
|
|
4
|
+
*
|
|
5
|
+
* It lived in `daemon/src/sky-code/channels.ts`, whose only importer was the
|
|
6
|
+
* daemon's own installer. That was fine while the daemon was the only thing that
|
|
7
|
+
* needed it, and it stopped being fine the moment a user could be told to go
|
|
8
|
+
* looking: `skrr code`'s not-installed message promised that `skrr code doctor`
|
|
9
|
+
* would name "which channel this machine follows and whether that channel has a
|
|
10
|
+
* published release", and the CLI had no access to any of it — so the sentence
|
|
11
|
+
* described a diagnosis nobody had written (dogfood OSK-274).
|
|
12
|
+
*
|
|
13
|
+
* A MIRROR in the CLI was the obvious alternative and is the wrong answer here,
|
|
14
|
+
* with precedent: OSK-3894 shipped exactly that for the harness trust tiers and
|
|
15
|
+
* OSK-3897 removed it, because a mirror proves two copies agree rather than
|
|
16
|
+
* proving there is one copy. `harnessTrust.ts` moved into this package for that
|
|
17
|
+
* reason, the daemon re-exports it, and a static check keeps the daemon from
|
|
18
|
+
* quietly redeclaring. This follows that road rather than reopening the one it
|
|
19
|
+
* replaced.
|
|
20
|
+
*
|
|
21
|
+
* Only the VOCABULARY moves — channel names, the env var, the default, and the
|
|
22
|
+
* URL shape. The installer, the signature verification and the promotion
|
|
23
|
+
* machinery stay in the daemon, which is the only process that performs them.
|
|
24
|
+
*/
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.SKY_CODE_FEED_BASE_ENV = exports.DEFAULT_SKY_CODE_FEED_BASE = exports.SKY_CODE_MANIFEST_FILE = exports.SKY_CODE_CHANNEL_ENV = exports.DEFAULT_SKY_CODE_CHANNEL = exports.SKY_CODE_CHANNELS = void 0;
|
|
27
|
+
exports.isSkyCodeChannel = isSkyCodeChannel;
|
|
28
|
+
exports.resolveSkyCodeChannel = resolveSkyCodeChannel;
|
|
29
|
+
exports.skyCodeChannelPrefix = skyCodeChannelPrefix;
|
|
30
|
+
exports.resolveChannelManifestUrl = resolveChannelManifestUrl;
|
|
31
|
+
exports.skyCodeFeedBase = skyCodeFeedBase;
|
|
32
|
+
/** Channels in promotion order. Index order IS the promotion order. */
|
|
33
|
+
exports.SKY_CODE_CHANNELS = ['internal', 'canary', 'beta', 'stable'];
|
|
34
|
+
/**
|
|
35
|
+
* The channel a build without an explicit setting follows.
|
|
36
|
+
*
|
|
37
|
+
* `stable`, and never inferred from anything else. A default that drifted with
|
|
38
|
+
* the build (say, dev builds silently on `canary`) would mean a user's update
|
|
39
|
+
* path depended on how their binary happened to be produced.
|
|
40
|
+
*/
|
|
41
|
+
exports.DEFAULT_SKY_CODE_CHANNEL = 'stable';
|
|
42
|
+
/** Env var selecting the channel. Explicit opt-in; never set implicitly. */
|
|
43
|
+
exports.SKY_CODE_CHANNEL_ENV = 'OVERSKY_SKY_CODE_CHANNEL';
|
|
44
|
+
/** Manifest filename, under a channel prefix or an immutable release prefix. */
|
|
45
|
+
exports.SKY_CODE_MANIFEST_FILE = 'sky-code-version.json';
|
|
46
|
+
function isSkyCodeChannel(value) {
|
|
47
|
+
return typeof value === 'string' && exports.SKY_CODE_CHANNELS.includes(value);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The channel this process should follow.
|
|
51
|
+
*
|
|
52
|
+
* An unrecognised value falls back to the default rather than throwing. A
|
|
53
|
+
* typo'd channel must not brick updates altogether — that turns a harmless
|
|
54
|
+
* mistake into an un-updatable machine, which is the failure the updater exists
|
|
55
|
+
* to prevent. The caller is handed `invalid` so it can say so out loud.
|
|
56
|
+
*/
|
|
57
|
+
function resolveSkyCodeChannel(env = process.env) {
|
|
58
|
+
const raw = env[exports.SKY_CODE_CHANNEL_ENV]?.trim();
|
|
59
|
+
if (!raw)
|
|
60
|
+
return { channel: exports.DEFAULT_SKY_CODE_CHANNEL };
|
|
61
|
+
if (isSkyCodeChannel(raw))
|
|
62
|
+
return { channel: raw };
|
|
63
|
+
return { channel: exports.DEFAULT_SKY_CODE_CHANNEL, invalid: raw };
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Where a channel's signed manifest lives.
|
|
67
|
+
*
|
|
68
|
+
* `stable` is NOT special-cased to `latest/`. Two paths that must always agree
|
|
69
|
+
* is a pair that eventually will not, and the one that disagrees silently is
|
|
70
|
+
* the one serving production. `latest/` remains for the daemon feed and for
|
|
71
|
+
* anything already pointing at it; skrr Code channel clients read
|
|
72
|
+
* `channels/<name>/` uniformly.
|
|
73
|
+
*/
|
|
74
|
+
function skyCodeChannelPrefix(channel) {
|
|
75
|
+
return `channels/${channel}/`;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Manifest URL for a channel, or for a pinned version.
|
|
79
|
+
*
|
|
80
|
+
* A pinned version wins over the channel and reads its immutable per-release
|
|
81
|
+
* copy: pinning means "this exact build", and a channel pointer that moved
|
|
82
|
+
* underneath would make the pin a suggestion.
|
|
83
|
+
*
|
|
84
|
+
* Builds only MANIFEST urls, never artifact ones. `buildManifestMessage` signs
|
|
85
|
+
* version, minimum, forceUpdate and the per-platform sha256s; `buildArtifactMessage`
|
|
86
|
+
* signs the artifact URL. Neither signs a channel — so artifact URLs stay
|
|
87
|
+
* channel-independent and promotion is a COPY OF AN ALREADY-SIGNED OBJECT that
|
|
88
|
+
* never needs the release key. Put the channel in the artifact URL instead and
|
|
89
|
+
* every promotion becomes a re-signing ceremony, which decides whether the
|
|
90
|
+
* ed25519 key has to be reachable from routine automation. A helper here that
|
|
91
|
+
* adjusted artifact urls would silently reintroduce exactly that coupling.
|
|
92
|
+
*/
|
|
93
|
+
function resolveChannelManifestUrl(input) {
|
|
94
|
+
const base = input.base.replace(/\/+$/, '');
|
|
95
|
+
if (input.pinnedVersion) {
|
|
96
|
+
return `${base}/releases/${input.pinnedVersion}/${input.manifestFilename}`;
|
|
97
|
+
}
|
|
98
|
+
return `${base}/${skyCodeChannelPrefix(input.channel)}${input.manifestFilename}`;
|
|
99
|
+
}
|
|
100
|
+
/** Default public feed. Mirrors the daemon's `updates.oversky.ai/daemon` prefix. */
|
|
101
|
+
exports.DEFAULT_SKY_CODE_FEED_BASE = 'https://updates.oversky.ai/sky-code';
|
|
102
|
+
/**
|
|
103
|
+
* Feed override, read at call time rather than module load so a test or an
|
|
104
|
+
* operator can repoint it without re-importing.
|
|
105
|
+
*
|
|
106
|
+
* Explicit-only: a production user must never be silently enrolled onto a
|
|
107
|
+
* different feed. Selecting a feed changes WHICH signed manifest is read, never
|
|
108
|
+
* WHETHER the signature is checked — every artifact is verified against the
|
|
109
|
+
* pinned keys regardless of where it came from.
|
|
110
|
+
*/
|
|
111
|
+
exports.SKY_CODE_FEED_BASE_ENV = 'OVERSKY_SKY_CODE_UPDATE_FEED_BASE';
|
|
112
|
+
function skyCodeFeedBase(env = process.env) {
|
|
113
|
+
const override = (env[exports.SKY_CODE_FEED_BASE_ENV] || '').trim();
|
|
114
|
+
return (override || exports.DEFAULT_SKY_CODE_FEED_BASE).replace(/\/+$/, '');
|
|
115
|
+
}
|
|
@@ -215,7 +215,7 @@ export declare class AuthHelperUnavailableError extends Error {
|
|
|
215
215
|
/**
|
|
216
216
|
* L6.1 — typed error thrown when the workspace-trust gate blocks a
|
|
217
217
|
* project- or local-scope helper. Surfaces the actionable next step
|
|
218
|
-
* (`
|
|
218
|
+
* (`skrrd trust accept`) to the user; the daemon catches and presents
|
|
219
219
|
* this without falling through to OAuth.
|
|
220
220
|
*/
|
|
221
221
|
export declare class AuthHelperUntrustedError extends Error {
|
|
@@ -130,7 +130,7 @@ export class AuthHelperUnavailableError extends Error {
|
|
|
130
130
|
/**
|
|
131
131
|
* L6.1 — typed error thrown when the workspace-trust gate blocks a
|
|
132
132
|
* project- or local-scope helper. Surfaces the actionable next step
|
|
133
|
-
* (`
|
|
133
|
+
* (`skrrd trust accept`) to the user; the daemon catches and presents
|
|
134
134
|
* this without falling through to OAuth.
|
|
135
135
|
*/
|
|
136
136
|
export class AuthHelperUntrustedError extends Error {
|
|
@@ -139,7 +139,7 @@ export class AuthHelperUntrustedError extends Error {
|
|
|
139
139
|
helperPath;
|
|
140
140
|
constructor(helperPath, origin, reason) {
|
|
141
141
|
super(`OVERSKY_AUTH_HELPER (${origin}-scope) is not trusted for this workspace ` +
|
|
142
|
-
`(reason: ${reason}). Run \`
|
|
142
|
+
`(reason: ${reason}). Run \`skrrd trust accept\` to allow it.`);
|
|
143
143
|
this.name = 'AuthHelperUntrustedError';
|
|
144
144
|
this.origin = origin;
|
|
145
145
|
this.reason = reason;
|
|
@@ -35,3 +35,4 @@ export { HARNESS_TIERS, getHarnessTier, credentialPolicyForTier, tierPermitsConf
|
|
|
35
35
|
export { sanitizeSpawnEnv, SENSITIVE_ENV_VARS, SENSITIVE_ENV_PREFIXES, SENSITIVE_ENV_SUFFIXES, SENSITIVE_ENV_PREFIX_EXCEPTIONS, } from './spawnEnv.js';
|
|
36
36
|
export { CONFIG_DIR_NAME, LEGACY_CONFIG_DIR_NAMES, NATIVE_ID_PREFIX, LEGACY_NATIVE_ID_PREFIXES, DEFAULT_BINARY_NAME, } from './localIdentity.js';
|
|
37
37
|
export { findLegacyLocalState, describeLegacyState, type LegacyStateFinding, type LegacyStateReport, } from './legacyStatePreflight.js';
|
|
38
|
+
export { DEFAULT_SKY_CODE_CHANNEL, DEFAULT_SKY_CODE_FEED_BASE, SKY_CODE_CHANNELS, SKY_CODE_CHANNEL_ENV, SKY_CODE_MANIFEST_FILE, isSkyCodeChannel, resolveChannelManifestUrl, resolveSkyCodeChannel, skyCodeChannelPrefix, skyCodeFeedBase, SKY_CODE_FEED_BASE_ENV, type SkyCodeChannel, } from './skyCodeChannels.js';
|
|
@@ -142,3 +142,4 @@ export { CONFIG_DIR_NAME, LEGACY_CONFIG_DIR_NAMES, NATIVE_ID_PREFIX, LEGACY_NATI
|
|
|
142
142
|
/* Pre-rename state detection. Callers REFUSE on a positive result; nothing here
|
|
143
143
|
reads, copies or removes what it finds (§7.2, §8.4). */
|
|
144
144
|
export { findLegacyLocalState, describeLegacyState, } from './legacyStatePreflight.js';
|
|
145
|
+
export { DEFAULT_SKY_CODE_CHANNEL, DEFAULT_SKY_CODE_FEED_BASE, SKY_CODE_CHANNELS, SKY_CODE_CHANNEL_ENV, SKY_CODE_MANIFEST_FILE, isSkyCodeChannel, resolveChannelManifestUrl, resolveSkyCodeChannel, skyCodeChannelPrefix, skyCodeFeedBase, SKY_CODE_FEED_BASE_ENV, } from './skyCodeChannels.js';
|
|
@@ -74,8 +74,21 @@ const DBUS_TRANSPORT_ERRORS = [
|
|
|
74
74
|
'No such interface',
|
|
75
75
|
'Cannot autolaunch',
|
|
76
76
|
];
|
|
77
|
-
/**
|
|
78
|
-
*
|
|
77
|
+
/**
|
|
78
|
+
* HKDF-SHA256 parameters for Tier-3. Stable across versions: ANY change
|
|
79
|
+
* silently invalidates every wrapped DEK on disk.
|
|
80
|
+
*
|
|
81
|
+
* That includes the brand. These strings are cryptographic derivation inputs
|
|
82
|
+
* that happen to read like a name, so a rename sweep produces exactly the same
|
|
83
|
+
* outcome as bumping the `v1` suffix — every credential on every machine
|
|
84
|
+
* becomes undecryptable, with no error at write time and a failure that
|
|
85
|
+
* surfaces only when someone next tries to unwrap. The KEK's SERVICE name moved
|
|
86
|
+
* to `ai.skrr.daemon.kek`; these did not, and must not.
|
|
87
|
+
*
|
|
88
|
+
* Rotating them deliberately is a re-issue, not a rename: it needs the old
|
|
89
|
+
* envelope discarded and credentials re-obtained, which is a decision with a
|
|
90
|
+
* user-visible cost rather than a string edit.
|
|
91
|
+
*/
|
|
79
92
|
const HKDF_SALT = Buffer.from('oversky-cred-kek-salt-v1');
|
|
80
93
|
const HKDF_INFO = Buffer.from('oversky-cred-kek-v1');
|
|
81
94
|
/** Filesystem paths for Tier-3 IKM components. */
|
|
@@ -289,7 +302,7 @@ async function writeKekToSecretService(kek, service, account) {
|
|
|
289
302
|
}
|
|
290
303
|
const b64 = kek.toString('base64');
|
|
291
304
|
try {
|
|
292
|
-
await exec('secret-tool', ['store', '--label=
|
|
305
|
+
await exec('secret-tool', ['store', '--label=skrr daemon master KEK', 'service', service, 'account', account], { input: b64 });
|
|
293
306
|
}
|
|
294
307
|
catch (err) {
|
|
295
308
|
throw new KekUnavailableError(KIND_LIBSECRET, 'secret-tool store failed', { cause: err });
|
|
@@ -55,13 +55,4 @@ 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
|
-
/**
|
|
59
|
-
* The message shown when preflight refuses.
|
|
60
|
-
*
|
|
61
|
-
* Written for someone who has just been stopped and wants to know why and what
|
|
62
|
-
* to do — so it names the exact paths, says explicitly that nothing was touched,
|
|
63
|
-
* and points at the runbook rather than improvising a fix. It does NOT offer a
|
|
64
|
-
* `--force`: the operator's next step is the backup the runbook specifies, and
|
|
65
|
-
* a flag that skips a safety check is the flag everyone learns to paste.
|
|
66
|
-
*/
|
|
67
58
|
export declare function describeLegacyState(report: LegacyStateReport, binaryName: string): string;
|