@skrr-ai/cli 0.1.44 → 0.1.46
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 +13 -1
- package/dist/base-command.js +37 -3
- package/dist/commands/agents/actions/create.js +11 -4
- package/dist/commands/agents/chat.js +3 -4
- package/dist/commands/browser/cloud-agents.d.ts +20 -0
- package/dist/commands/browser/cloud-agents.js +43 -0
- package/dist/commands/code/handover.d.ts +11 -0
- package/dist/commands/code/handover.js +105 -1
- package/dist/commands/commitments/handover.d.ts +29 -0
- package/dist/commands/commitments/handover.js +99 -0
- package/dist/commands/followups/list.js +1 -1
- package/dist/commands/followups/watch.js +40 -5
- package/dist/commands/initiatives/list.d.ts +1 -0
- package/dist/commands/initiatives/list.js +11 -2
- package/dist/commands/labels/list.d.ts +28 -0
- package/dist/commands/labels/list.js +50 -32
- package/dist/commands/tasks/fork.d.ts +32 -0
- package/dist/commands/tasks/fork.js +171 -0
- package/dist/commands/tasks/handover.d.ts +23 -0
- package/dist/commands/tasks/handover.js +205 -0
- package/dist/commands/tasks/promote.d.ts +23 -0
- package/dist/commands/tasks/promote.js +82 -0
- package/dist/commands/tasks/runs.d.ts +16 -0
- package/dist/commands/tasks/runs.js +46 -1
- package/dist/commands/tasks/show.d.ts +23 -0
- package/dist/commands/tasks/show.js +59 -0
- package/dist/lib/agentic-stream.js +41 -2
- package/dist/lib/api-fetch.d.ts +7 -1
- package/dist/lib/api-fetch.js +9 -2
- package/dist/lib/auth-core-init.js +11 -4
- package/dist/lib/code-handover.d.ts +60 -0
- package/dist/lib/code-handover.js +120 -0
- package/dist/lib/commitments.d.ts +22 -0
- package/dist/lib/commitments.js +42 -0
- package/dist/lib/dedicated-wait.js +22 -1
- package/dist/lib/followups.d.ts +18 -0
- package/dist/lib/followups.js +44 -0
- package/dist/lib/initiatives.d.ts +15 -3
- package/dist/lib/label-ref.d.ts +2 -0
- package/dist/lib/node-adapter.js +6 -0
- package/dist/lib/task-extras.d.ts +44 -0
- package/dist/lib/task-extras.js +73 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialEnvelopeBridge.d.ts +29 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialEnvelopeBridge.js +169 -23
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.js +91 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.d.ts +8 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.js +7 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessHome.js +45 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessSkillLayout.d.ts +65 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessSkillLayout.js +99 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +3 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +26 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/loginLocalhost.js +177 -26
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/profileStateDir.d.ts +119 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/profileStateDir.js +346 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialEnvelopeBridge.d.ts +29 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialEnvelopeBridge.js +169 -24
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.js +93 -7
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.d.ts +8 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.js +7 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessHome.js +45 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessSkillLayout.d.ts +65 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessSkillLayout.js +94 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +3 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +10 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/loginLocalhost.js +177 -26
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/profileStateDir.d.ts +119 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/profileStateDir.js +333 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +11 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +2746 -2711
- package/dist/node_modules/@skrr-ai/inference-broker/package.json +1 -1
- package/oclif.manifest.json +34300 -33843
- package/package.json +2 -2
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OSK-10409 — which harnesses resolve the `.claude/skills/<name>/SKILL.md`
|
|
4
|
+
* layout, shared by the server and the daemon.
|
|
5
|
+
*
|
|
6
|
+
* ── Why this lives in auth-core ────────────────────────────────────────────
|
|
7
|
+
*
|
|
8
|
+
* The same reason `harnessTrust.ts` does: it is a DECLARED per-harness fact
|
|
9
|
+
* that several processes have to agree on, and the cost of them disagreeing is
|
|
10
|
+
* silent. It is not auth, and it does not pretend to be — auth-core is where
|
|
11
|
+
* this repo already keeps the small tables that a harness's identity answers.
|
|
12
|
+
*
|
|
13
|
+
* ── What the fact IS ───────────────────────────────────────────────────────
|
|
14
|
+
*
|
|
15
|
+
* The daemon materializes a session's skills at
|
|
16
|
+
* `<root>/.claude/skills/<name>/SKILL.md` and hands `<root>` to the harness —
|
|
17
|
+
* `--add-dir` for the Claude CLI, ACP `additionalDirectories` for Devin. A
|
|
18
|
+
* harness on this list READS that layout: it enumerates the tree, surfaces the
|
|
19
|
+
* manifest line, and resolves the body from disk. A harness that is not on it
|
|
20
|
+
* ignores the tree entirely, so nothing laid there ever reaches its model.
|
|
21
|
+
*
|
|
22
|
+
* It is a capability with EVIDENCE, never a brand check. The gate this replaced
|
|
23
|
+
* read `provider !== 'claude'` on the stated premise that every other harness
|
|
24
|
+
* ignores the layout, and the premise was false for Devin (OSK-10264): the
|
|
25
|
+
* daemon lays the same tree, passes it on `additionalDirectories`, and Devin
|
|
26
|
+
* loads it — measured live on 3000.10.31. Add a harness here only with the same
|
|
27
|
+
* kind of evidence, that its sessions actually surface a skill laid out this
|
|
28
|
+
* way. A harness that ignores the layout gains nothing and pays for the wire.
|
|
29
|
+
*
|
|
30
|
+
* ── Three readers, in three directions ─────────────────────────────────────
|
|
31
|
+
*
|
|
32
|
+
* 1. The server's PUSH gate (`buildDaemonServerSkills`): a harness on this
|
|
33
|
+
* list is one a pushed skill should be sent to.
|
|
34
|
+
* 2. The server's INVOKED-BODY gate (`buildInvokedSkillsPrompt`, OSK-10361):
|
|
35
|
+
* a harness on this list must NOT also have the body pasted into its
|
|
36
|
+
* prompt — it already has it from the tree, and on ACP the paste lands in
|
|
37
|
+
* the transcript at full skill size on every invoked turn.
|
|
38
|
+
* 3. The daemon's SHADOWING protection (`skill-shadowing.ts`, OSK-10044): a
|
|
39
|
+
* harness on this list resolves `/<name>` from its own `.claude/skills`
|
|
40
|
+
* roots, so a picked skill can be shadowed there by a same-named one — and
|
|
41
|
+
* the daemon is the only place that collision can be seen. That gate spelled
|
|
42
|
+
* `claude` and so never reached Devin, which the server-side paste was
|
|
43
|
+
* accidentally masking until (2) stopped pasting.
|
|
44
|
+
*
|
|
45
|
+
* Reader 3 is why the table moved out of the API: the daemon cannot require an
|
|
46
|
+
* api-side module, and a second copy of a table whose whole value is that every
|
|
47
|
+
* reader agrees is worse than no table at all.
|
|
48
|
+
*/
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.HARNESSES_LOADING_CLAUDE_SKILLS_LAYOUT = void 0;
|
|
51
|
+
exports.harnessLoadsClaudeSkillsLayout = harnessLoadsClaudeSkillsLayout;
|
|
52
|
+
exports.claudeSkillsLayoutEvidence = claudeSkillsLayoutEvidence;
|
|
53
|
+
const firstPartyHarness_js_1 = require("./firstPartyHarness.js");
|
|
54
|
+
/**
|
|
55
|
+
* Harness provider → the evidence that its sessions load the layout.
|
|
56
|
+
*
|
|
57
|
+
* The reason string is part of the entry, not decoration: an entry added
|
|
58
|
+
* without one is an entry nobody can audit later.
|
|
59
|
+
*/
|
|
60
|
+
exports.HARNESSES_LOADING_CLAUDE_SKILLS_LAYOUT = new Map([
|
|
61
|
+
['claude', 'Claude Code reads .claude/skills natively from --add-dir'],
|
|
62
|
+
[
|
|
63
|
+
'devin',
|
|
64
|
+
'Devin imports the Claude convention from additionalDirectories ' +
|
|
65
|
+
'(read_config_from.claude, on by default) — verified live on 3000.10.31',
|
|
66
|
+
],
|
|
67
|
+
]);
|
|
68
|
+
/**
|
|
69
|
+
* Canonicalise the way every reader of this table must.
|
|
70
|
+
*
|
|
71
|
+
* The provider is lower-cased and trimmed, then passed through
|
|
72
|
+
* `canonicalHarnessProvider` so an accepted alias of the first-party harness
|
|
73
|
+
* resolves to the same decision as its canonical slug rather than falling
|
|
74
|
+
* through to "not a native resolver". Callers with a RICHER normalizer (the API
|
|
75
|
+
* has `normalizeSessionProvider`, which also folds `claude-code`) apply theirs
|
|
76
|
+
* first; this is the floor, not a replacement.
|
|
77
|
+
*/
|
|
78
|
+
function canonicalize(provider) {
|
|
79
|
+
return String((0, firstPartyHarness_js_1.canonicalHarnessProvider)(provider.trim().toLowerCase()));
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Whether this harness resolves a skill from the `.claude/skills` tree the
|
|
83
|
+
* daemon materializes, so the body reaches it without being pasted anywhere.
|
|
84
|
+
*
|
|
85
|
+
* An absent provider is NOT a native resolver. "We do not know what this is"
|
|
86
|
+
* must never mean "it reads the layout" — that direction withholds the body
|
|
87
|
+
* from a harness that needed it, which is a turn that looks like the skill ran.
|
|
88
|
+
*/
|
|
89
|
+
function harnessLoadsClaudeSkillsLayout(provider) {
|
|
90
|
+
if (!provider || typeof provider !== 'string')
|
|
91
|
+
return false;
|
|
92
|
+
return exports.HARNESSES_LOADING_CLAUDE_SKILLS_LAYOUT.has(canonicalize(provider));
|
|
93
|
+
}
|
|
94
|
+
/** The stated evidence for a harness on the list, or `null` when it is not. */
|
|
95
|
+
function claudeSkillsLayoutEvidence(provider) {
|
|
96
|
+
if (!provider || typeof provider !== 'string')
|
|
97
|
+
return null;
|
|
98
|
+
return exports.HARNESSES_LOADING_CLAUDE_SKILLS_LAYOUT.get(canonicalize(provider)) ?? null;
|
|
99
|
+
}
|
|
@@ -27,11 +27,12 @@ export { formatRecoveryCode, parseRecoveryCode, normalizeRecoveryCode, isValidRe
|
|
|
27
27
|
export { buildCredentialAad, decrypt as credEnvelopeDecrypt, deserialize as credEnvelopeDeserialize, encrypt as credEnvelopeEncrypt, ENVELOPE_MAGIC as CRED_ENVELOPE_MAGIC, generateDek, isEnvelopeString as isCredEnvelopeString, KEY_LEN as CRED_KEY_LEN, openBuffer as credOpenBuffer, sealBuffer as credSealBuffer, serialize as credEnvelopeSerialize, unwrap as credEnvelopeUnwrap, wrap as credEnvelopeWrap, type SealedBlob as CredSealedBlob, } from './credentialEnvelope.js';
|
|
28
28
|
export { __setKekStrategyForTest, getKekStrategy, InMemoryKek, UnavailableKek, KekUnavailableError, LinuxKek, MacosKek, registerZeroizeHook, WindowsKek, zeroizeKekCaches, type KekStrategy, } from './kek/index.js';
|
|
29
29
|
export { buildProof as buildDeviceProof, generateDeviceKeyPair, jwkThumbprint, normalizeHtu, publicJwkFromX, tokenHash, verifyProof as verifyDeviceProof, type DeviceKeyPair, type DeviceProofClaims, type DeviceProofHeader, type Ed25519PrivateJwk, type Ed25519PublicJwk, type VerifyFailureReason as DeviceProofVerifyFailureReason, type VerifyFailure as DeviceProofVerifyFailure, type VerifyOptions as DeviceProofVerifyOptions, type VerifySuccess as DeviceProofVerifySuccess, } from './deviceKey.js';
|
|
30
|
-
export { initCredEnvelope, resetCredEnvelope, shutdownCredEnvelope, isCredEnvelopeActive, describeCredEnvelopeState, maybeEncryptForWrite, maybeDecryptOnRead, __wrappedDekFilePathForTest, __setStateForTest as __setCredEnvelopeStateForTest, __getStateForTest as __getCredEnvelopeStateForTest, __resetShutdownGuardForTest, type ReadTransformResult, } from './credentialEnvelopeBridge.js';
|
|
30
|
+
export { initCredEnvelope, resetCredEnvelope, shutdownCredEnvelope, isCredEnvelopeActive, hasCredEnvelopePathConflict, describeCredEnvelopeState, maybeEncryptForWrite, maybeDecryptOnRead, __wrappedDekFilePathForTest, __setStateForTest as __setCredEnvelopeStateForTest, __getStateForTest as __getCredEnvelopeStateForTest, __resetShutdownGuardForTest, type ReadTransformResult, } from './credentialEnvelopeBridge.js';
|
|
31
31
|
export { initDeviceIdentity, resetDeviceIdentity, signServerRequest, enrollWithServer, clearEnrollmentMarker, isDeviceIdentityActive, getDevicePublicKey, describeDeviceIdentityState, __publicKeyPathForTest, __privateKeyPathForTest, __enrollmentMarkerPathForTest, __enrollmentBackoffPathForTest, __setStateForTest as __setDeviceIdentityStateForTest, __getStateForTest as __getDeviceIdentityStateForTest, type EnrollmentResult, } from './deviceIdentityBridge.js';
|
|
32
32
|
export { ensureMachineDaemonId, legacyDaemonUuids, __resetCachedDaemonIdForTest, } from './machineId.js';
|
|
33
33
|
export { PAIR_AAD_PREFIX, PAIR_AAD_MAX_LEN, PAIR_BUNDLE_MAX_BASE64_LEN, PAIR_NONCE_LEN, PAIR_PUBKEY_LEN, PAIR_SECRET_LEN, PairBundleError, assemblePairBundleBase64, base64ToUint8Array as pairBase64ToUint8Array, base64UrlToUint8Array as pairBase64UrlToUint8Array, buildPairAad, buildPairUrl, generatePairKeyPair, openPairBundleBase64, parsePairBundle, parsePairPlaintext, parsePairUrl, uint8ArrayToBase64 as pairUint8ArrayToBase64, uint8ArrayToBase64Url as pairUint8ArrayToBase64Url, type AssembleBundleOptions as PairAssembleBundleOptions, type OpenBundleOptions as PairOpenBundleOptions, type PairBundle, type PairBundleErrorCode, type PairKeyPair, type PairPlaintextV1, type PairUrlFields, } from './daemonPair.js';
|
|
34
34
|
export { HARNESS_TIERS, getHarnessTier, credentialPolicyForTier, tierPermitsConfiguredAutoMode, type HarnessTrustTier, type CredentialDeliveryPolicy, type CredentialMode, } from './harnessTrust.js';
|
|
35
|
+
export { HARNESSES_LOADING_CLAUDE_SKILLS_LAYOUT, claudeSkillsLayoutEvidence, harnessLoadsClaudeSkillsLayout, } from './harnessSkillLayout.js';
|
|
35
36
|
export { sanitizeSpawnEnv, SENSITIVE_ENV_VARS, SENSITIVE_ENV_PREFIXES, SENSITIVE_ENV_SUFFIXES, SENSITIVE_ENV_NAME_TOKENS, SENSITIVE_ENV_PREFIX_EXCEPTIONS, } from './spawnEnv.js';
|
|
36
37
|
export { CONFIG_DIR_NAME, LEGACY_CONFIG_DIR_NAMES, NATIVE_ID_PREFIX, LEGACY_NATIVE_ID_PREFIXES, DEFAULT_BINARY_NAME, } from './localIdentity.js';
|
|
37
38
|
export { findLegacyLocalState, describeLegacyState, type LegacyStateFinding, type LegacyStateReport, } from './legacyStatePreflight.js';
|
|
@@ -41,3 +42,4 @@ export { DEFAULT_FIRST_PARTY_HARNESS_CHANNEL, FIRST_PARTY_HARNESS_CHANNELS, firs
|
|
|
41
42
|
export { OVERSKY_RELEASE_PUBLIC_KEYS, type ReleaseKey } from './releaseKeys.js';
|
|
42
43
|
export { MAX_SIGS, buildArtifactMessage, buildManifestMessage, getDeltaFor, verifyArtifact, verifyManifest, type DaemonVersionManifest, type DeltaDescriptor, type ManifestSignature, type PlatformArtifact, type VerifyResult, } from './releaseManifest.js';
|
|
43
44
|
export { resolveConfigRoot, configRootPath, isConfigRootOverridden } from './configRoot.js';
|
|
45
|
+
export { PROFILES_SEGMENT, SUPERSEDED_MARKER_SUFFIX, SUPERSEDED_COPY_SUFFIX, profileStateDir, legacyProfileStateDir, resolveProfileStateDir, resolveProfileStateFile, profileStateFileLocations, profileStateFilePathsToClear, consolidateProfileState, type ResolvedProfileStateDir, type ConsolidationSpec, type ConsolidationStatus, type ConsolidationOutcome, } from './profileStateDir.js';
|
|
@@ -24,8 +24,9 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
24
24
|
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
|
-
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;
|
|
27
|
+
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.hasCredEnvelopePathConflict = exports.isCredEnvelopeActive = exports.shutdownCredEnvelope = exports.resetCredEnvelope = exports.initCredEnvelope = exports.verifyDeviceProof = void 0;
|
|
28
|
+
exports.resolveProfileStateDir = exports.legacyProfileStateDir = exports.profileStateDir = exports.SUPERSEDED_COPY_SUFFIX = exports.SUPERSEDED_MARKER_SUFFIX = exports.PROFILES_SEGMENT = 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.harnessLoadsClaudeSkillsLayout = exports.claudeSkillsLayoutEvidence = exports.HARNESSES_LOADING_CLAUDE_SKILLS_LAYOUT = exports.tierPermitsConfiguredAutoMode = exports.credentialPolicyForTier = exports.getHarnessTier = void 0;
|
|
29
|
+
exports.consolidateProfileState = exports.profileStateFilePathsToClear = exports.profileStateFileLocations = exports.resolveProfileStateFile = void 0;
|
|
29
30
|
// Daemon scope vocabulary — single source of truth for non-Mongoose tiers
|
|
30
31
|
// (daemon, desktop, cli). Schema-bound canonical lives in
|
|
31
32
|
// `@skrr-ai/data-schemas/common/daemonScopes`; the two are kept byte-equal
|
|
@@ -228,6 +229,7 @@ Object.defineProperty(exports, "initCredEnvelope", { enumerable: true, get: func
|
|
|
228
229
|
Object.defineProperty(exports, "resetCredEnvelope", { enumerable: true, get: function () { return credentialEnvelopeBridge_js_1.resetCredEnvelope; } });
|
|
229
230
|
Object.defineProperty(exports, "shutdownCredEnvelope", { enumerable: true, get: function () { return credentialEnvelopeBridge_js_1.shutdownCredEnvelope; } });
|
|
230
231
|
Object.defineProperty(exports, "isCredEnvelopeActive", { enumerable: true, get: function () { return credentialEnvelopeBridge_js_1.isCredEnvelopeActive; } });
|
|
232
|
+
Object.defineProperty(exports, "hasCredEnvelopePathConflict", { enumerable: true, get: function () { return credentialEnvelopeBridge_js_1.hasCredEnvelopePathConflict; } });
|
|
231
233
|
Object.defineProperty(exports, "describeCredEnvelopeState", { enumerable: true, get: function () { return credentialEnvelopeBridge_js_1.describeCredEnvelopeState; } });
|
|
232
234
|
Object.defineProperty(exports, "maybeEncryptForWrite", { enumerable: true, get: function () { return credentialEnvelopeBridge_js_1.maybeEncryptForWrite; } });
|
|
233
235
|
Object.defineProperty(exports, "maybeDecryptOnRead", { enumerable: true, get: function () { return credentialEnvelopeBridge_js_1.maybeDecryptOnRead; } });
|
|
@@ -293,6 +295,14 @@ Object.defineProperty(exports, "HARNESS_TIERS", { enumerable: true, get: functio
|
|
|
293
295
|
Object.defineProperty(exports, "getHarnessTier", { enumerable: true, get: function () { return harnessTrust_js_1.getHarnessTier; } });
|
|
294
296
|
Object.defineProperty(exports, "credentialPolicyForTier", { enumerable: true, get: function () { return harnessTrust_js_1.credentialPolicyForTier; } });
|
|
295
297
|
Object.defineProperty(exports, "tierPermitsConfiguredAutoMode", { enumerable: true, get: function () { return harnessTrust_js_1.tierPermitsConfiguredAutoMode; } });
|
|
298
|
+
// OSK-10409 — which harnesses resolve the `.claude/skills` layout the daemon
|
|
299
|
+
// materializes. One declared table with per-harness evidence, read by the
|
|
300
|
+
// server's two skill gates and by the daemon's shadowing protection. See
|
|
301
|
+
// harnessSkillLayout.ts for why a second copy would be worse than none.
|
|
302
|
+
var harnessSkillLayout_js_1 = require("./harnessSkillLayout.js");
|
|
303
|
+
Object.defineProperty(exports, "HARNESSES_LOADING_CLAUDE_SKILLS_LAYOUT", { enumerable: true, get: function () { return harnessSkillLayout_js_1.HARNESSES_LOADING_CLAUDE_SKILLS_LAYOUT; } });
|
|
304
|
+
Object.defineProperty(exports, "claudeSkillsLayoutEvidence", { enumerable: true, get: function () { return harnessSkillLayout_js_1.claudeSkillsLayoutEvidence; } });
|
|
305
|
+
Object.defineProperty(exports, "harnessLoadsClaudeSkillsLayout", { enumerable: true, get: function () { return harnessSkillLayout_js_1.harnessLoadsClaudeSkillsLayout; } });
|
|
296
306
|
// OSK-3892 — spawn-env sanitization, shared by the daemon (which has stripped
|
|
297
307
|
// its own credentials before every harness spawn all along) and the CLI (which
|
|
298
308
|
// spawns the SAME engine and did not). `daemon/src/env-sanitize.ts` re-exports
|
|
@@ -361,3 +371,17 @@ var configRoot_js_1 = require("./configRoot.js");
|
|
|
361
371
|
Object.defineProperty(exports, "resolveConfigRoot", { enumerable: true, get: function () { return configRoot_js_1.resolveConfigRoot; } });
|
|
362
372
|
Object.defineProperty(exports, "configRootPath", { enumerable: true, get: function () { return configRoot_js_1.configRootPath; } });
|
|
363
373
|
Object.defineProperty(exports, "isConfigRootOverridden", { enumerable: true, get: function () { return configRoot_js_1.isConfigRootOverridden; } });
|
|
374
|
+
// The one definition of where a PROFILE's auth state lives under that root, and
|
|
375
|
+
// the migration for a machine that ended up with two. Same lesson, one level
|
|
376
|
+
// down: two modules spelled the rule themselves and the two consumers disagreed.
|
|
377
|
+
var profileStateDir_js_1 = require("./profileStateDir.js");
|
|
378
|
+
Object.defineProperty(exports, "PROFILES_SEGMENT", { enumerable: true, get: function () { return profileStateDir_js_1.PROFILES_SEGMENT; } });
|
|
379
|
+
Object.defineProperty(exports, "SUPERSEDED_MARKER_SUFFIX", { enumerable: true, get: function () { return profileStateDir_js_1.SUPERSEDED_MARKER_SUFFIX; } });
|
|
380
|
+
Object.defineProperty(exports, "SUPERSEDED_COPY_SUFFIX", { enumerable: true, get: function () { return profileStateDir_js_1.SUPERSEDED_COPY_SUFFIX; } });
|
|
381
|
+
Object.defineProperty(exports, "profileStateDir", { enumerable: true, get: function () { return profileStateDir_js_1.profileStateDir; } });
|
|
382
|
+
Object.defineProperty(exports, "legacyProfileStateDir", { enumerable: true, get: function () { return profileStateDir_js_1.legacyProfileStateDir; } });
|
|
383
|
+
Object.defineProperty(exports, "resolveProfileStateDir", { enumerable: true, get: function () { return profileStateDir_js_1.resolveProfileStateDir; } });
|
|
384
|
+
Object.defineProperty(exports, "resolveProfileStateFile", { enumerable: true, get: function () { return profileStateDir_js_1.resolveProfileStateFile; } });
|
|
385
|
+
Object.defineProperty(exports, "profileStateFileLocations", { enumerable: true, get: function () { return profileStateDir_js_1.profileStateFileLocations; } });
|
|
386
|
+
Object.defineProperty(exports, "profileStateFilePathsToClear", { enumerable: true, get: function () { return profileStateDir_js_1.profileStateFilePathsToClear; } });
|
|
387
|
+
Object.defineProperty(exports, "consolidateProfileState", { enumerable: true, get: function () { return profileStateDir_js_1.consolidateProfileState; } });
|
|
@@ -318,10 +318,30 @@ async function startLocalCallback(opts) {
|
|
|
318
318
|
},
|
|
319
319
|
};
|
|
320
320
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
321
|
+
/**
|
|
322
|
+
* The machine end of the handshake. Deliberately a display rather than
|
|
323
|
+
* a terminal window: the user just came from a browser, and a monitor
|
|
324
|
+
* outline is the one glyph that reads as "the computer in front of
|
|
325
|
+
* you" without needing a caption.
|
|
326
|
+
*/
|
|
327
|
+
const DISPLAY_GLYPH = `<svg class="glyph" viewBox="0 0 24 24" aria-hidden="true">
|
|
328
|
+
<rect x="2.25" y="3.5" width="19.5" height="13.5" rx="2.5"/>
|
|
329
|
+
<path d="M12 17v3.25"/>
|
|
330
|
+
<path d="M8.5 20.5h7"/>
|
|
331
|
+
</svg>`;
|
|
332
|
+
/** Badge interiors, one per verdict. Stroked, never filled. */
|
|
333
|
+
const VERDICT_MARK = {
|
|
334
|
+
success: '<path d="M5.5 12.5 10 17l8.5-9"/>',
|
|
335
|
+
declined: '<path d="M7 7l10 10M17 7 7 17"/>',
|
|
336
|
+
error: '<path d="M12 7v6.25"/><path d="M12 16.75h.01"/>',
|
|
337
|
+
};
|
|
338
|
+
/**
|
|
339
|
+
* Renders the shared page. `verdict` selects the badge palette via a
|
|
340
|
+
* class — no interpolated colour, so the template stays a constant
|
|
341
|
+
* string per state and there is nothing for a caller to smuggle CSS
|
|
342
|
+
* through.
|
|
343
|
+
*/
|
|
344
|
+
function htmlShell(title, verdict, headline, body) {
|
|
325
345
|
// Single inline template — keeps the binary self-contained (no
|
|
326
346
|
// bundled assets) and survives offline/firewalled environments.
|
|
327
347
|
return `<!doctype html>
|
|
@@ -330,39 +350,170 @@ function htmlShell(title, accent, headline, body) {
|
|
|
330
350
|
<meta charset="utf-8">
|
|
331
351
|
<title>${title}</title>
|
|
332
352
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
353
|
+
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='8' fill='%230d0d0d'/%3E%3Ctext x='16' y='21' font-family='system-ui,sans-serif' font-size='11' font-weight='700' fill='%23fff' text-anchor='middle'%3ESkrr%3C/text%3E%3C/svg%3E">
|
|
333
354
|
<style>
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
355
|
+
:root {
|
|
356
|
+
color-scheme: light dark;
|
|
357
|
+
--bg: #ffffff;
|
|
358
|
+
--ink: #0d0d0d;
|
|
359
|
+
--muted: #6b7280;
|
|
360
|
+
--stroke: #111111;
|
|
361
|
+
--tile-bg: #0d0d0d;
|
|
362
|
+
--tile-ink: #ffffff;
|
|
363
|
+
--ok-bg: #e7f6ec;
|
|
364
|
+
--ok-ink: #16a34a;
|
|
365
|
+
--neutral-bg: #f1f3f5;
|
|
366
|
+
--neutral-ink: #6b7280;
|
|
367
|
+
--bad-bg: #fdeceb;
|
|
368
|
+
--bad-ink: #dc2626;
|
|
369
|
+
}
|
|
370
|
+
@media (prefers-color-scheme: dark) {
|
|
371
|
+
:root {
|
|
372
|
+
--bg: #0b0d12;
|
|
373
|
+
--ink: #f4f6fb;
|
|
374
|
+
--muted: #9aa4b5;
|
|
375
|
+
--stroke: #e7eaf1;
|
|
376
|
+
--tile-bg: #f4f6fb;
|
|
377
|
+
--tile-ink: #0b0d12;
|
|
378
|
+
--ok-bg: rgba(52, 211, 153, 0.14);
|
|
379
|
+
--ok-ink: #34d399;
|
|
380
|
+
--neutral-bg: rgba(148, 163, 184, 0.16);
|
|
381
|
+
--neutral-ink: #94a3b8;
|
|
382
|
+
--bad-bg: rgba(248, 113, 113, 0.16);
|
|
383
|
+
--bad-ink: #f87171;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
* { box-sizing: border-box; }
|
|
388
|
+
html, body { height: 100%; }
|
|
389
|
+
body {
|
|
390
|
+
margin: 0;
|
|
391
|
+
background: var(--bg);
|
|
392
|
+
color: var(--ink);
|
|
393
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto,
|
|
394
|
+
system-ui, "Helvetica Neue", Arial, sans-serif;
|
|
395
|
+
-webkit-font-smoothing: antialiased;
|
|
396
|
+
text-rendering: optimizeLegibility;
|
|
397
|
+
display: grid;
|
|
398
|
+
place-items: center;
|
|
399
|
+
padding: 32px 24px;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.card { width: 100%; max-width: 32rem; text-align: center; }
|
|
403
|
+
|
|
404
|
+
/* The handshake row. */
|
|
405
|
+
.stage {
|
|
406
|
+
display: flex;
|
|
407
|
+
align-items: center;
|
|
408
|
+
justify-content: center;
|
|
409
|
+
gap: 18px;
|
|
410
|
+
margin-bottom: 56px;
|
|
411
|
+
}
|
|
412
|
+
.glyph, .badge, .tile { flex: 0 0 auto; }
|
|
413
|
+
|
|
414
|
+
.glyph {
|
|
415
|
+
width: 46px; height: 46px;
|
|
416
|
+
fill: none;
|
|
417
|
+
stroke: var(--stroke);
|
|
418
|
+
stroke-width: 1.85;
|
|
419
|
+
stroke-linecap: round;
|
|
420
|
+
stroke-linejoin: round;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
.badge {
|
|
424
|
+
width: 48px; height: 48px;
|
|
425
|
+
border-radius: 50%;
|
|
426
|
+
display: grid;
|
|
427
|
+
place-items: center;
|
|
428
|
+
background: var(--neutral-bg);
|
|
429
|
+
}
|
|
430
|
+
.badge svg {
|
|
431
|
+
width: 23px; height: 23px;
|
|
432
|
+
fill: none;
|
|
433
|
+
stroke: var(--neutral-ink);
|
|
434
|
+
stroke-width: 2.6;
|
|
435
|
+
stroke-linecap: round;
|
|
436
|
+
stroke-linejoin: round;
|
|
437
|
+
}
|
|
438
|
+
.badge.is-success { background: var(--ok-bg); }
|
|
439
|
+
.badge.is-success svg { stroke: var(--ok-ink); }
|
|
440
|
+
.badge.is-error { background: var(--bad-bg); }
|
|
441
|
+
.badge.is-error svg { stroke: var(--bad-ink); }
|
|
442
|
+
|
|
443
|
+
.tile {
|
|
444
|
+
width: 46px; height: 46px;
|
|
445
|
+
border-radius: 12px;
|
|
446
|
+
background: var(--tile-bg);
|
|
447
|
+
color: var(--tile-ink);
|
|
448
|
+
display: grid;
|
|
449
|
+
place-items: center;
|
|
450
|
+
font-size: 13.5px;
|
|
451
|
+
font-weight: 700;
|
|
452
|
+
letter-spacing: -0.03em;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
h1 {
|
|
456
|
+
margin: 0 0 12px;
|
|
457
|
+
font-size: clamp(27px, 6.2vw, 36px);
|
|
458
|
+
font-weight: 700;
|
|
459
|
+
letter-spacing: -0.021em;
|
|
460
|
+
line-height: 1.15;
|
|
461
|
+
}
|
|
462
|
+
p {
|
|
463
|
+
margin: 0;
|
|
464
|
+
color: var(--muted);
|
|
465
|
+
font-size: clamp(15px, 3.2vw, 19px);
|
|
466
|
+
font-weight: 400;
|
|
467
|
+
line-height: 1.5;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/* Entrance: one short rise, staggered. Nothing loops, nothing
|
|
471
|
+
moves after ~0.4s — this page is read once and closed. */
|
|
472
|
+
@keyframes rise {
|
|
473
|
+
from { opacity: 0; transform: translateY(9px); }
|
|
474
|
+
to { opacity: 1; transform: none; }
|
|
475
|
+
}
|
|
476
|
+
@keyframes draw { to { stroke-dashoffset: 0; } }
|
|
477
|
+
.stage, h1, p { animation: rise 420ms cubic-bezier(0.22, 0.8, 0.3, 1) both; }
|
|
478
|
+
h1 { animation-delay: 60ms; }
|
|
479
|
+
p { animation-delay: 110ms; }
|
|
480
|
+
.badge.is-success svg path {
|
|
481
|
+
stroke-dasharray: 26;
|
|
482
|
+
stroke-dashoffset: 26;
|
|
483
|
+
animation: draw 340ms cubic-bezier(0.65, 0, 0.35, 1) 220ms both;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
@media (prefers-reduced-motion: reduce) {
|
|
487
|
+
.stage, h1, p, .badge.is-success svg path {
|
|
488
|
+
animation: none;
|
|
489
|
+
opacity: 1;
|
|
490
|
+
transform: none;
|
|
491
|
+
stroke-dashoffset: 0;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
344
494
|
</style>
|
|
345
495
|
</head>
|
|
346
496
|
<body>
|
|
347
|
-
<
|
|
348
|
-
|
|
497
|
+
<main class="card">
|
|
498
|
+
<div class="stage">
|
|
499
|
+
${DISPLAY_GLYPH}
|
|
500
|
+
<div class="badge is-${verdict}">
|
|
501
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">${VERDICT_MARK[verdict]}</svg>
|
|
502
|
+
</div>
|
|
503
|
+
<div class="tile" aria-hidden="true">Skrr</div>
|
|
504
|
+
</div>
|
|
505
|
+
<h1>${headline}</h1>
|
|
349
506
|
<p>${body}</p>
|
|
350
|
-
</
|
|
507
|
+
</main>
|
|
351
508
|
</body>
|
|
352
509
|
</html>`;
|
|
353
510
|
}
|
|
354
511
|
function successHtml() {
|
|
355
|
-
|
|
356
|
-
<h1>Authorized</h1>`;
|
|
357
|
-
return htmlShell('skrr — Authorized', '#10b981', headline, 'You can close this tab and return to your terminal.');
|
|
512
|
+
return htmlShell('Connected to Skrr', 'success', 'Connected to Skrr', 'You may now close this window and return to your terminal.');
|
|
358
513
|
}
|
|
359
514
|
function declinedHtml() {
|
|
360
|
-
|
|
361
|
-
<h1>Authorization declined</h1>`;
|
|
362
|
-
return htmlShell('skrr — Authorization declined', '#64748b', headline, 'You can close this tab. Run the CLI command again to retry.');
|
|
515
|
+
return htmlShell('Skrr — Authorization declined', 'declined', 'Authorization declined', 'You can close this window. Run the command again to retry.');
|
|
363
516
|
}
|
|
364
517
|
function genericFailureHtml() {
|
|
365
|
-
|
|
366
|
-
<h1>Authorization error</h1>`;
|
|
367
|
-
return htmlShell('skrr — Authorization error', '#ef4444', headline, 'Something went wrong. You can close this tab and retry from the terminal.');
|
|
518
|
+
return htmlShell('Skrr — Authorization error', 'error', 'Authorization error', 'Something went wrong. Close this window and try again.');
|
|
368
519
|
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/** Directory segment that separates per-profile state from machine-scoped state. */
|
|
2
|
+
export declare const PROFILES_SEGMENT = "profiles";
|
|
3
|
+
/**
|
|
4
|
+
* Sidecar written beside a legacy file once it has been consolidated. Its
|
|
5
|
+
* PRESENCE is what flips resolution to the canonical copy; its contents are for
|
|
6
|
+
* a human reading the directory afterwards.
|
|
7
|
+
*/
|
|
8
|
+
export declare const SUPERSEDED_MARKER_SUFFIX = ".superseded.json";
|
|
9
|
+
/**
|
|
10
|
+
* Suffix for a canonical file moved aside to make room. Only used when the
|
|
11
|
+
* canonical copy existed and was NOT usable — a usable one is never replaced.
|
|
12
|
+
*/
|
|
13
|
+
export declare const SUPERSEDED_COPY_SUFFIX = ".superseded";
|
|
14
|
+
/** The canonical directory for a profile's auth state. */
|
|
15
|
+
export declare function profileStateDir(profile: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Where a consumer whose `configDir` is already profile-scoped used to write.
|
|
18
|
+
*
|
|
19
|
+
* `null` when it resolves to the canonical directory — i.e. the consumer passes
|
|
20
|
+
* the machine root and never had a second location. Callers branch on `null`
|
|
21
|
+
* rather than comparing strings so the "one root" case costs one check.
|
|
22
|
+
*/
|
|
23
|
+
export declare function legacyProfileStateDir(profile: string): string | null;
|
|
24
|
+
export interface ResolvedProfileStateDir {
|
|
25
|
+
/** The directory this process must read and write. */
|
|
26
|
+
dir: string;
|
|
27
|
+
canonicalDir: string;
|
|
28
|
+
legacyDir: string | null;
|
|
29
|
+
/** True when `dir` is the legacy directory — i.e. consolidation is still owed. */
|
|
30
|
+
usingLegacy: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Resolve the directory holding `primaryFilename` for `profile`.
|
|
34
|
+
*
|
|
35
|
+
* `primaryFilename` is the file whose presence decides where a group of related
|
|
36
|
+
* files lives. Device identity has four files that must be read from ONE
|
|
37
|
+
* directory — a public JWK from one copy and a private key from the other is a
|
|
38
|
+
* keypair mismatch — so the group anchors on the private key rather than each
|
|
39
|
+
* file answering for itself.
|
|
40
|
+
*/
|
|
41
|
+
export declare function resolveProfileStateDir(profile: string, primaryFilename: string): ResolvedProfileStateDir;
|
|
42
|
+
/** `resolveProfileStateDir` for a single self-anchoring file. */
|
|
43
|
+
export declare function resolveProfileStateFile(profile: string, filename: string): ResolvedProfileStateDir & {
|
|
44
|
+
path: string;
|
|
45
|
+
canonicalPath: string;
|
|
46
|
+
legacyPath: string | null;
|
|
47
|
+
};
|
|
48
|
+
/** Every location `filename` may occupy for `profile`, canonical first. */
|
|
49
|
+
export declare function profileStateFileLocations(profile: string, filename: string): string[];
|
|
50
|
+
export type ConsolidationStatus =
|
|
51
|
+
/** One root — this consumer never had a second location. */
|
|
52
|
+
'not_applicable'
|
|
53
|
+
/** Nothing at the legacy location to migrate. */
|
|
54
|
+
| 'nothing_to_migrate'
|
|
55
|
+
/** Already done, or both copies already agree. */
|
|
56
|
+
| 'already_consolidated'
|
|
57
|
+
/** Canonical was absent; the legacy copy was adopted as canonical. */
|
|
58
|
+
| 'adopted'
|
|
59
|
+
/** Canonical was present but unusable; replaced, and kept under `.superseded`. */
|
|
60
|
+
| 'superseded'
|
|
61
|
+
/** Both copies are usable and DIFFERENT. Refused — a human decides. */
|
|
62
|
+
| 'conflict';
|
|
63
|
+
export interface ConsolidationOutcome {
|
|
64
|
+
status: ConsolidationStatus;
|
|
65
|
+
profile: string;
|
|
66
|
+
canonicalDir: string;
|
|
67
|
+
legacyDir: string | null;
|
|
68
|
+
/** Canonical paths written by this call. Empty on a refusal or a dry run. */
|
|
69
|
+
written: string[];
|
|
70
|
+
/** Canonical paths moved aside before being replaced. */
|
|
71
|
+
supersededAside: string[];
|
|
72
|
+
/** Identities compared, when both sides were read. `null` means unreadable. */
|
|
73
|
+
identities?: {
|
|
74
|
+
canonical: string | null;
|
|
75
|
+
legacy: string | null;
|
|
76
|
+
};
|
|
77
|
+
dryRun: boolean;
|
|
78
|
+
}
|
|
79
|
+
export interface ConsolidationSpec {
|
|
80
|
+
/** Files to move together, in copy order. Missing ones are skipped. */
|
|
81
|
+
files: readonly string[];
|
|
82
|
+
/** The file whose presence decides whether the group exists at a location. */
|
|
83
|
+
primary: string;
|
|
84
|
+
/**
|
|
85
|
+
* Stable identity of the state held in `dir`, or `null` when it cannot be
|
|
86
|
+
* read. Two directories are the same state iff their identities are equal and
|
|
87
|
+
* non-null.
|
|
88
|
+
*
|
|
89
|
+
* This exists because raw bytes cannot answer the question. A wrapped DEK
|
|
90
|
+
* carries a random nonce, so wrapping ONE key twice produces two different
|
|
91
|
+
* files — comparing bytes would report a conflict between two copies of the
|
|
92
|
+
* same key and refuse a migration that was safe. The envelope hashes the
|
|
93
|
+
* UNWRAPPED key; device identity reads the plaintext public JWK.
|
|
94
|
+
*
|
|
95
|
+
* Default: SHA-256 of the primary file's bytes, which is only correct for
|
|
96
|
+
* content that is not re-serialized.
|
|
97
|
+
*/
|
|
98
|
+
identify?: (dir: string) => Promise<string | null> | string | null;
|
|
99
|
+
/** Report what would happen and write nothing. */
|
|
100
|
+
dryRun?: boolean;
|
|
101
|
+
onEvent?: (name: string, success: boolean, meta: Record<string, unknown>) => void;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Consolidate a profile's state onto the canonical path. Idempotent, additive,
|
|
105
|
+
* and refuses rather than guesses.
|
|
106
|
+
*
|
|
107
|
+
* The one case it will not decide is two usable, different keys for one profile:
|
|
108
|
+
* each side has sealed content under its own, that content lives in the OS
|
|
109
|
+
* keychain, and nothing here can re-seal it. Picking a winner there would
|
|
110
|
+
* destroy the loser's credentials silently, which is the exact failure this
|
|
111
|
+
* whole module exists to avoid.
|
|
112
|
+
*/
|
|
113
|
+
export declare function consolidateProfileState(profile: string, spec: ConsolidationSpec): Promise<ConsolidationOutcome>;
|
|
114
|
+
/**
|
|
115
|
+
* Every path a profile's copy of `filename` can occupy, plus its marker —
|
|
116
|
+
* what a genuine logout must remove. Deliberately separate from the migration:
|
|
117
|
+
* this module never deletes, and logout is the one caller that must.
|
|
118
|
+
*/
|
|
119
|
+
export declare function profileStateFilePathsToClear(profile: string, filename: string): string[];
|