@skrr-ai/cli 0.1.108 → 0.1.110
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/README.md +10 -0
- package/dist/base-command.d.ts +74 -0
- package/dist/base-command.js +182 -24
- package/dist/commands/agents/triggers/create.js +1 -1
- package/dist/commands/agents/triggers/update.js +1 -1
- package/dist/commands/agents/update.d.ts +25 -0
- package/dist/commands/agents/update.js +98 -3
- package/dist/commands/commitments/accounting.js +7 -2
- package/dist/commands/commitments/cost.d.ts +11 -0
- package/dist/commands/commitments/cost.js +26 -3
- package/dist/commands/commitments/create.js +2 -1
- package/dist/commands/commitments/operating-review.d.ts +15 -0
- package/dist/commands/commitments/operating-review.js +103 -50
- package/dist/commands/commitments/update.js +12 -5
- package/dist/commands/daemon/install.js +17 -1
- package/dist/commands/daemon/login.js +14 -0
- package/dist/commands/doctor.js +9 -0
- package/dist/commands/goals/list.js +6 -1
- package/dist/commands/grants/rotate.js +4 -0
- package/dist/commands/harnesses/prune.d.ts +26 -0
- package/dist/commands/harnesses/prune.js +172 -0
- package/dist/commands/login.js +53 -14
- package/dist/commands/machines/list.js +28 -6
- package/dist/commands/projects/show.js +1 -1
- package/dist/commands/revoke-daemon.js +2 -1
- package/dist/commands/spaces/workflows/archive.d.ts +1 -0
- package/dist/commands/spaces/workflows/archive.js +1 -0
- package/dist/commands/spaces/workflows/artifact.d.ts +1 -0
- package/dist/commands/spaces/workflows/artifact.js +1 -0
- package/dist/commands/spaces/workflows/cancel-node.d.ts +1 -0
- package/dist/commands/spaces/workflows/cancel-node.js +1 -0
- package/dist/commands/spaces/workflows/cancel.d.ts +1 -0
- package/dist/commands/spaces/workflows/cancel.js +6 -2
- package/dist/commands/spaces/workflows/create.d.ts +1 -0
- package/dist/commands/spaces/workflows/create.js +7 -1
- package/dist/commands/spaces/workflows/events.d.ts +1 -0
- package/dist/commands/spaces/workflows/events.js +1 -0
- package/dist/commands/spaces/workflows/fixtures/create.d.ts +1 -0
- package/dist/commands/spaces/workflows/fixtures/create.js +1 -0
- package/dist/commands/spaces/workflows/fixtures/list.d.ts +1 -0
- package/dist/commands/spaces/workflows/fixtures/list.js +1 -0
- package/dist/commands/spaces/workflows/lifecycle-diagnostics.d.ts +1 -0
- package/dist/commands/spaces/workflows/lifecycle-diagnostics.js +1 -0
- package/dist/commands/spaces/workflows/list.d.ts +1 -0
- package/dist/commands/spaces/workflows/list.js +1 -0
- package/dist/commands/spaces/workflows/node-types.d.ts +2 -0
- package/dist/commands/spaces/workflows/node-types.js +24 -6
- package/dist/commands/spaces/workflows/pause.d.ts +1 -0
- package/dist/commands/spaces/workflows/pause.js +1 -0
- package/dist/commands/spaces/workflows/plan/show.d.ts +1 -0
- package/dist/commands/spaces/workflows/plan/show.js +1 -0
- package/dist/commands/spaces/workflows/plan/update.d.ts +1 -0
- package/dist/commands/spaces/workflows/plan/update.js +1 -0
- package/dist/commands/spaces/workflows/proposals/apply.d.ts +1 -0
- package/dist/commands/spaces/workflows/proposals/apply.js +1 -0
- package/dist/commands/spaces/workflows/proposals/confirm.d.ts +1 -0
- package/dist/commands/spaces/workflows/proposals/confirm.js +1 -0
- package/dist/commands/spaces/workflows/proposals/create.d.ts +1 -0
- package/dist/commands/spaces/workflows/proposals/create.js +1 -0
- package/dist/commands/spaces/workflows/proposals/dismiss.d.ts +1 -0
- package/dist/commands/spaces/workflows/proposals/dismiss.js +1 -0
- package/dist/commands/spaces/workflows/proposals/list.d.ts +1 -0
- package/dist/commands/spaces/workflows/proposals/list.js +1 -0
- package/dist/commands/spaces/workflows/publish.d.ts +1 -0
- package/dist/commands/spaces/workflows/publish.js +9 -0
- package/dist/commands/spaces/workflows/reconcile.d.ts +1 -0
- package/dist/commands/spaces/workflows/reconcile.js +1 -0
- package/dist/commands/spaces/workflows/resume.d.ts +1 -0
- package/dist/commands/spaces/workflows/resume.js +1 -0
- package/dist/commands/spaces/workflows/retry.d.ts +1 -0
- package/dist/commands/spaces/workflows/retry.js +1 -0
- package/dist/commands/spaces/workflows/run.d.ts +1 -0
- package/dist/commands/spaces/workflows/run.js +14 -7
- package/dist/commands/spaces/workflows/runs.d.ts +1 -0
- package/dist/commands/spaces/workflows/runs.js +1 -0
- package/dist/commands/spaces/workflows/show.d.ts +25 -0
- package/dist/commands/spaces/workflows/show.js +42 -4
- package/dist/commands/spaces/workflows/signal.d.ts +12 -0
- package/dist/commands/spaces/workflows/signal.js +40 -2
- package/dist/commands/spaces/workflows/start.d.ts +1 -0
- package/dist/commands/spaces/workflows/start.js +4 -1
- package/dist/commands/spaces/workflows/task-execution/create.d.ts +1 -0
- package/dist/commands/spaces/workflows/task-execution/create.js +1 -0
- package/dist/commands/spaces/workflows/test.d.ts +1 -0
- package/dist/commands/spaces/workflows/test.js +1 -0
- package/dist/commands/spaces/workflows/triggers/create.d.ts +1 -0
- package/dist/commands/spaces/workflows/triggers/create.js +1 -0
- package/dist/commands/spaces/workflows/triggers/fire.d.ts +1 -0
- package/dist/commands/spaces/workflows/triggers/fire.js +1 -0
- package/dist/commands/spaces/workflows/triggers/list.d.ts +1 -0
- package/dist/commands/spaces/workflows/triggers/list.js +1 -0
- package/dist/commands/spaces/workflows/triggers/update.d.ts +1 -0
- package/dist/commands/spaces/workflows/triggers/update.js +1 -0
- package/dist/commands/spaces/workflows/update.d.ts +1 -0
- package/dist/commands/spaces/workflows/update.js +4 -0
- package/dist/commands/spaces/workflows/validate.d.ts +1 -0
- package/dist/commands/spaces/workflows/validate.js +27 -2
- package/dist/commands/tasks/activity.js +17 -3
- package/dist/commands/tasks/bulk-update.d.ts +1 -0
- package/dist/commands/tasks/bulk-update.js +7 -0
- package/dist/commands/tasks/complete.js +2 -1
- package/dist/commands/tasks/create-tree.d.ts +69 -0
- package/dist/commands/tasks/create-tree.js +413 -47
- package/dist/commands/tasks/list.d.ts +2 -0
- package/dist/commands/tasks/list.js +25 -3
- package/dist/commands/tasks/rearm-recurrence.d.ts +22 -0
- package/dist/commands/tasks/rearm-recurrence.js +87 -0
- package/dist/commands/tasks/show.d.ts +9 -0
- package/dist/commands/tasks/show.js +79 -33
- package/dist/commands/tasks/timeline.js +4 -0
- package/dist/commands/tasks/unschedule.js +5 -1
- package/dist/commands/tasks/update.d.ts +1 -0
- package/dist/commands/tasks/update.js +17 -2
- package/dist/commands/triggers/audit.js +12 -3
- package/dist/commands/triggers/create.js +9 -3
- package/dist/commands/triggers/fire-detail.d.ts +7 -0
- package/dist/commands/triggers/fire-detail.js +30 -12
- package/dist/commands/triggers/fire.js +13 -3
- package/dist/commands/triggers/parse-intent.d.ts +7 -0
- package/dist/commands/triggers/parse-intent.js +31 -9
- package/dist/commands/triggers/update.js +1 -1
- package/dist/commands/workspaces/grants.js +20 -3
- package/dist/commands/workspaces/members.d.ts +20 -0
- package/dist/commands/workspaces/members.js +64 -0
- package/dist/commands/workspaces/stewardship.js +14 -2
- package/dist/help.js +12 -0
- package/dist/hooks/command-not-found.js +27 -1
- package/dist/lib/command-miss.d.ts +52 -2
- package/dist/lib/command-miss.js +187 -18
- package/dist/lib/commitment-loop-status.d.ts +8 -0
- package/dist/lib/commitment-loop-status.js +45 -0
- package/dist/lib/commitment-product.js +5 -2
- package/dist/lib/commitments.d.ts +18 -3
- package/dist/lib/commitments.js +85 -45
- package/dist/lib/daemon-command-hint.d.ts +15 -0
- package/dist/lib/daemon-command-hint.js +21 -0
- package/dist/lib/daemon-machine-identity-copy.d.ts +14 -0
- package/dist/lib/daemon-machine-identity-copy.js +27 -0
- package/dist/lib/daemon-machine-identity.d.ts +27 -0
- package/dist/lib/daemon-machine-identity.js +61 -0
- package/dist/lib/daemon-setup.js +10 -1
- package/dist/lib/daemonBrokerRefusal.js +3 -2
- package/dist/lib/daemonHandoff.d.ts +19 -1
- package/dist/lib/daemonHandoff.js +61 -1
- package/dist/lib/deployed-build.d.ts +43 -0
- package/dist/lib/deployed-build.js +66 -0
- package/dist/lib/grants.d.ts +27 -1
- package/dist/lib/grants.js +39 -21
- package/dist/lib/harnesses.d.ts +71 -0
- package/dist/lib/harnesses.js +70 -0
- package/dist/lib/json-mode.d.ts +11 -0
- package/dist/lib/json-mode.js +19 -0
- package/dist/lib/json-output.d.ts +25 -0
- package/dist/lib/json-output.js +30 -0
- package/dist/lib/list-output.d.ts +10 -1
- package/dist/lib/list-output.js +22 -1
- package/dist/lib/local-daemon-readiness.d.ts +90 -0
- package/dist/lib/local-daemon-readiness.js +143 -0
- package/dist/lib/machines.d.ts +117 -0
- package/dist/lib/machines.js +139 -0
- package/dist/lib/managed-instruction-local.d.ts +2 -0
- package/dist/lib/managed-instruction-local.js +2 -0
- package/dist/lib/profile-machine-identity-guard.d.ts +18 -0
- package/dist/lib/profile-machine-identity-guard.js +39 -0
- package/dist/lib/request-field-flags.d.ts +20 -0
- package/dist/lib/request-field-flags.js +34 -0
- package/dist/lib/stewardship-output.d.ts +1 -1
- package/dist/lib/stewardship-output.js +26 -30
- package/dist/lib/task-batch.d.ts +61 -4
- package/dist/lib/task-batch.js +316 -80
- package/dist/lib/task-economics.d.ts +15 -0
- package/dist/lib/task-economics.js +39 -2
- package/dist/lib/task-recurrence-outcome.d.ts +6 -6
- package/dist/lib/task-recurrence-outcome.js +27 -3
- package/dist/lib/tasks.d.ts +39 -0
- package/dist/lib/tasks.js +132 -0
- package/dist/lib/triggers.d.ts +42 -1
- package/dist/lib/triggers.js +98 -2
- package/dist/lib/workflow-issues.d.ts +14 -0
- package/dist/lib/workflow-issues.js +32 -0
- package/dist/lib/workflow-run-view.d.ts +59 -0
- package/dist/lib/workflow-run-view.js +110 -0
- package/dist/lib/workspaces.d.ts +48 -4
- package/dist/lib/workspaces.js +55 -0
- package/dist/lib/write-target.d.ts +29 -0
- package/dist/lib/write-target.js +72 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +5 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.d.ts +60 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.js +130 -6
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/workspaceIsolationProbeWire.d.ts +51 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/workspaceIsolationProbeWire.js +50 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.d.ts +60 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.js +128 -6
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/workspaceIsolationProbeWire.d.ts +51 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/workspaceIsolationProbeWire.js +46 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +11 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +7523 -7140
- package/oclif.manifest.json +473 -59
- package/package.json +28 -1
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The workspace-isolation probe wire contract (OSK-15099).
|
|
4
|
+
*
|
|
5
|
+
* A Commitment Run is always isolated: the daemon cuts it a private git
|
|
6
|
+
* worktree from the directory the Run is rooted in, and refuses the Run with
|
|
7
|
+
* `EXECUTION_ISOLATION_UNAVAILABLE` before any tool when it cannot. Preflight
|
|
8
|
+
* had no way to read that machine's filesystem, so it reported `ready`,
|
|
9
|
+
* activation succeeded, and the first Run failed. The daemon now answers the
|
|
10
|
+
* same question BEFORE a Run, through the same predicate its executor refuses
|
|
11
|
+
* on, and this module is the one place both ends spell it.
|
|
12
|
+
*
|
|
13
|
+
* - The daemon announces {@link WORKSPACE_ISOLATION_PROBE_CAPABILITY}. A daemon
|
|
14
|
+
* that does not is never asked, and the server reports the prerequisite as
|
|
15
|
+
* UNVERIFIED — never as satisfied (unknown is never ok).
|
|
16
|
+
* - The server sends {@link WORKSPACE_ISOLATION_PROBE_METHOD} as a control RPC
|
|
17
|
+
* with `{ workingDirectory? }`: exactly the directory it would put on the
|
|
18
|
+
* Run's request (`agent.workingDirectory || daemon cwd`).
|
|
19
|
+
* - The daemon answers {@link WorkspaceIsolationProbeAnswer}.
|
|
20
|
+
*
|
|
21
|
+
* Pure: no I/O, safe for the browser, the CLI and the API.
|
|
22
|
+
*/
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.REFUSING_WORKTREE_BASE_VERDICTS = exports.WORKTREE_BASE_VERDICTS = exports.WORKSPACE_ISOLATION_PROBE_METHOD = exports.WORKSPACE_ISOLATION_PROBE_CAPABILITY = void 0;
|
|
25
|
+
exports.isWorktreeBaseVerdict = isWorktreeBaseVerdict;
|
|
26
|
+
exports.WORKSPACE_ISOLATION_PROBE_CAPABILITY = 'workspace_isolation_probe_v1';
|
|
27
|
+
exports.WORKSPACE_ISOLATION_PROBE_METHOD = 'daemon:workspace:isolation-probe';
|
|
28
|
+
/**
|
|
29
|
+
* What an explicit isolation request can be given from a base directory.
|
|
30
|
+
*
|
|
31
|
+
* - `worktree` — a git repository with a commit: a worktree is cut;
|
|
32
|
+
* - `sandbox` — the daemon's own bare scratch workspace: an empty
|
|
33
|
+
* private sandbox is used instead;
|
|
34
|
+
* - `not_a_repository` — refused: not inside a git repository;
|
|
35
|
+
* - `no_initial_commit` — refused: a repository with an unborn HEAD.
|
|
36
|
+
*/
|
|
37
|
+
exports.WORKTREE_BASE_VERDICTS = Object.freeze([
|
|
38
|
+
'worktree',
|
|
39
|
+
'sandbox',
|
|
40
|
+
'not_a_repository',
|
|
41
|
+
'no_initial_commit',
|
|
42
|
+
]);
|
|
43
|
+
/** The verdicts on which the daemon refuses an isolated Run before any tool. */
|
|
44
|
+
exports.REFUSING_WORKTREE_BASE_VERDICTS = new Set([
|
|
45
|
+
'not_a_repository',
|
|
46
|
+
'no_initial_commit',
|
|
47
|
+
]);
|
|
48
|
+
function isWorktreeBaseVerdict(value) {
|
|
49
|
+
return typeof value === 'string' && exports.WORKTREE_BASE_VERDICTS.includes(value);
|
|
50
|
+
}
|
|
@@ -30,7 +30,7 @@ export { buildProof as buildDeviceProof, generateDeviceKeyPair, jwkThumbprint, n
|
|
|
30
30
|
export { DPOP_HEADER, DPOP_MAX_AGE_SECONDS, DPOP_PROOF_INVALID, DPOP_PROOF_REQUIRED, DPOP_PROOF_TYP, DPOP_PROOF_VERIFY_UNAVAILABLE, accessTokenHash, createDpopKey, isAth, isJwkThumbprint, normalizeDpopHtu, verifyDpopProof, type DpopKey, type DpopProofClaims, type DpopProofRequest, type DpopVerifyFailureReason, type DpopVerifyOptions, type DpopVerifyResult, } from './dpop.js';
|
|
31
31
|
export { initCredEnvelope, resetCredEnvelope, shutdownCredEnvelope, isCredEnvelopeActive, hasCredEnvelopePathConflict, describeCredEnvelopeState, splitKeyConvergencePolicy, maybeEncryptForWrite, maybeDecryptOnRead, DEFAULT_UNREADABLE_CREDENTIAL_HINT, type DecryptOnReadOptions, __wrappedDekFilePathForTest, __setStateForTest as __setCredEnvelopeStateForTest, __getStateForTest as __getCredEnvelopeStateForTest, __resetShutdownGuardForTest, type ReadTransformResult, } from './credentialEnvelopeBridge.js';
|
|
32
32
|
export { initDeviceIdentity, resetDeviceIdentity, signServerRequest, enrollWithServer, clearEnrollmentMarker, isDeviceIdentityActive, getDevicePublicKey, describeDeviceIdentityState, describeDeviceKeySplit, __publicKeyPathForTest, __privateKeyPathForTest, __enrollmentMarkerPathForTest, __enrollmentBackoffPathForTest, __setStateForTest as __setDeviceIdentityStateForTest, __getStateForTest as __getDeviceIdentityStateForTest, type EnrollmentResult, } from './deviceIdentityBridge.js';
|
|
33
|
-
export { getMachineUuid, getHardwareMachineUuid, setMachineUuidProfile, getMachineUuidProfile, qualifyMachineUuid, MACHINE_IDENTITY_FILENAME, hostedRuntimeIdOverride, HOSTED_RUNTIME_MACHINE_SOURCES, __resetMachineUuidCacheForTest, } from './machineUuid.js';
|
|
33
|
+
export { getMachineUuid, getMachineUuidForProfile, describeMachineIdentity, type MachineIdentityDescription, type MachineIdentityReason, getHardwareMachineUuid, setMachineUuidProfile, getMachineUuidProfile, qualifyMachineUuid, MACHINE_IDENTITY_FILENAME, hostedRuntimeIdOverride, HOSTED_RUNTIME_MACHINE_SOURCES, __resetMachineUuidCacheForTest, } from './machineUuid.js';
|
|
34
34
|
export { ensureMachineDaemonId, legacyDaemonUuids, __resetCachedDaemonIdForTest, } from './machineId.js';
|
|
35
35
|
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';
|
|
36
36
|
export { HARNESS_TIERS, getHarnessTier, credentialPolicyForTier, tierPermitsConfiguredAutoMode, type HarnessTrustTier, type CredentialDeliveryPolicy, type CredentialMode, } from './harnessTrust.js';
|
|
@@ -125,7 +125,7 @@ __publicKeyPathForTest, __privateKeyPathForTest, __enrollmentMarkerPathForTest,
|
|
|
125
125
|
// Hardware machine identity sent as `machineUuid` (IOPlatformUUID /
|
|
126
126
|
// machine-id / MachineGuid). ONE implementation for daemon and CLI —
|
|
127
127
|
// OSK-12063. Also exposed dependency-free as `@skrr-ai/auth-core/machine-uuid`.
|
|
128
|
-
export { getMachineUuid, getHardwareMachineUuid, setMachineUuidProfile, getMachineUuidProfile, qualifyMachineUuid, MACHINE_IDENTITY_FILENAME, hostedRuntimeIdOverride, HOSTED_RUNTIME_MACHINE_SOURCES, __resetMachineUuidCacheForTest, } from './machineUuid.js';
|
|
128
|
+
export { getMachineUuid, getMachineUuidForProfile, describeMachineIdentity, getHardwareMachineUuid, setMachineUuidProfile, getMachineUuidProfile, qualifyMachineUuid, MACHINE_IDENTITY_FILENAME, hostedRuntimeIdOverride, HOSTED_RUNTIME_MACHINE_SOURCES, __resetMachineUuidCacheForTest, } from './machineUuid.js';
|
|
129
129
|
// Stable per-machine UUIDv7 identity persisted at <configDir>/daemon.id.
|
|
130
130
|
// NOT a `machineUuid` — see machineUuid.ts.
|
|
131
131
|
export { ensureMachineDaemonId, legacyDaemonUuids, __resetCachedDaemonIdForTest, } from './machineId.js';
|
|
@@ -56,5 +56,65 @@ export declare function getMachineUuidProfile(): string | null;
|
|
|
56
56
|
* profile that already held credentials; see the block above.
|
|
57
57
|
*/
|
|
58
58
|
export declare function getMachineUuid(): string;
|
|
59
|
+
/**
|
|
60
|
+
* The `machineUuid` a process running as `profile` sends, WITHOUT changing which
|
|
61
|
+
* profile this process runs as.
|
|
62
|
+
*
|
|
63
|
+
* The CLI needs the answer for the profile it is about to hand a credential to,
|
|
64
|
+
* and asks the daemon binary what IT will send (`accept-handoff --print-id`).
|
|
65
|
+
* Two programs that compute one identity can only be known to agree by
|
|
66
|
+
* comparing them, and a daemon that predates per-profile identities does not
|
|
67
|
+
* agree: it sends the hardware value whatever the profile's
|
|
68
|
+
* `machine-identity.json` says, so a credential minted for what it reports
|
|
69
|
+
* registers the profile on the default machine's row (the OSK-13845 failure, now
|
|
70
|
+
* reached through version skew rather than through the rule). The comparison
|
|
71
|
+
* needs this: the expected value for the TARGET profile, which is not
|
|
72
|
+
* necessarily the one this process is running as.
|
|
73
|
+
*
|
|
74
|
+
* Decides and persists the profile's identity if nothing has yet — the same
|
|
75
|
+
* side effect `getMachineUuid()` has, for the same reason.
|
|
76
|
+
*/
|
|
77
|
+
export declare function getMachineUuidForProfile(profile: string | null | undefined): string;
|
|
78
|
+
export type MachineIdentityReason =
|
|
79
|
+
/** The default profile, which always uses this computer's own identity. */
|
|
80
|
+
'default_profile'
|
|
81
|
+
/** A hosted runtime, whose identity the control plane issued. */
|
|
82
|
+
| 'hosted_runtime'
|
|
83
|
+
/** A profile that held no credentials when its identity was first decided. */
|
|
84
|
+
| 'new_profile'
|
|
85
|
+
/** A profile that already held credentials, so it keeps the shared identity. */
|
|
86
|
+
| 'pre_existing_profile'
|
|
87
|
+
/** Recovered from the copy kept outside the profile after product state was removed. */
|
|
88
|
+
| 'restored_profile'
|
|
89
|
+
/** The profile's record could not be read (the identity is still the one in use). */
|
|
90
|
+
| 'unrecorded';
|
|
91
|
+
export interface MachineIdentityDescription {
|
|
92
|
+
/** The profile this process runs as; null for the default profile. */
|
|
93
|
+
profile: string | null;
|
|
94
|
+
/** The value sent to the server as `machineUuid`. */
|
|
95
|
+
machineUuid: string;
|
|
96
|
+
/** This computer's own identity. */
|
|
97
|
+
hardware: string;
|
|
98
|
+
/**
|
|
99
|
+
* A non-default profile that registers on the SAME machine row as the default
|
|
100
|
+
* profile: they share one Daemon row, one device-key pin and one machine page.
|
|
101
|
+
*/
|
|
102
|
+
sharesDefaultMachine: boolean;
|
|
103
|
+
reason: MachineIdentityReason;
|
|
104
|
+
/** The files that made a profile "already hold credentials", when recorded. */
|
|
105
|
+
evidence: string[];
|
|
106
|
+
decidedAt: string | null;
|
|
107
|
+
/** One sentence for a person. Written once, here, so no surface words it differently. */
|
|
108
|
+
sentence: string;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Which machine this process registers as, and WHY — the question a person has
|
|
112
|
+
* when two profiles turn up on one machine page and the logs say nothing.
|
|
113
|
+
*
|
|
114
|
+
* A read, not a decision: it reports the identity `getMachineUuid()` settled on
|
|
115
|
+
* (settling it if nothing has, exactly as any caller would) and the record that
|
|
116
|
+
* explains it. It never changes what a profile registers as.
|
|
117
|
+
*/
|
|
118
|
+
export declare function describeMachineIdentity(): MachineIdentityDescription;
|
|
59
119
|
/** @internal test seam — forget the cached value so the next call re-probes. */
|
|
60
120
|
export declare function __resetMachineUuidCacheForTest(): void;
|
|
@@ -218,7 +218,7 @@ function readPersistedChoice(file, hardware, profile, requireProfile = false) {
|
|
|
218
218
|
return null;
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
|
-
function persistChoice(dir, file, hardware, machineUuid, reason, profile) {
|
|
221
|
+
function persistChoice(dir, file, hardware, machineUuid, reason, profile, evidence) {
|
|
222
222
|
try {
|
|
223
223
|
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
224
224
|
const tmp = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
@@ -228,6 +228,12 @@ function persistChoice(dir, file, hardware, machineUuid, reason, profile) {
|
|
|
228
228
|
machineUuid,
|
|
229
229
|
profile,
|
|
230
230
|
reason,
|
|
231
|
+
// WHICH file made a profile "already hold credentials". The reason alone
|
|
232
|
+
// says a profile shares the default's machine row; this says what put it
|
|
233
|
+
// there, which is the difference between "an older Skrr set it up" and
|
|
234
|
+
// "its first credential was written before anything chose its identity".
|
|
235
|
+
// Additive: a reader that predates it ignores the field.
|
|
236
|
+
...(evidence && evidence.length > 0 ? { evidence: [...evidence] } : {}),
|
|
231
237
|
decidedAt: new Date().toISOString(),
|
|
232
238
|
};
|
|
233
239
|
fs.writeFileSync(tmp, `${JSON.stringify(body)}\n`, { mode: 0o600 });
|
|
@@ -267,7 +273,7 @@ function resolveProfileMachineUuid(profile, hardware) {
|
|
|
267
273
|
persistChoice(dir, file, hardware, chosen, 'restored_profile', profile);
|
|
268
274
|
}
|
|
269
275
|
if (!chosen) {
|
|
270
|
-
const
|
|
276
|
+
const evidence = PRE_EXISTING_PROFILE_EVIDENCE.filter((name) => {
|
|
271
277
|
try {
|
|
272
278
|
return fs.existsSync(path.join(dir, name));
|
|
273
279
|
}
|
|
@@ -275,8 +281,9 @@ function resolveProfileMachineUuid(profile, hardware) {
|
|
|
275
281
|
return false;
|
|
276
282
|
}
|
|
277
283
|
});
|
|
284
|
+
const preExisting = evidence.length > 0;
|
|
278
285
|
chosen = preExisting ? hardware : qualifyMachineUuid(hardware, profile);
|
|
279
|
-
persistChoice(dir, file, hardware, chosen, preExisting ? 'pre_existing_profile' : 'new_profile', profile);
|
|
286
|
+
persistChoice(dir, file, hardware, chosen, preExisting ? 'pre_existing_profile' : 'new_profile', profile, evidence);
|
|
280
287
|
}
|
|
281
288
|
preserveRecoveryChoice(profile, hardware, chosen);
|
|
282
289
|
profileChoiceCache.set(cacheKey, chosen);
|
|
@@ -296,14 +303,129 @@ function resolveProfileMachineUuid(profile, hardware) {
|
|
|
296
303
|
* profile that already held credentials; see the block above.
|
|
297
304
|
*/
|
|
298
305
|
export function getMachineUuid() {
|
|
306
|
+
return getMachineUuidForProfile(activeMachineProfile);
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* The `machineUuid` a process running as `profile` sends, WITHOUT changing which
|
|
310
|
+
* profile this process runs as.
|
|
311
|
+
*
|
|
312
|
+
* The CLI needs the answer for the profile it is about to hand a credential to,
|
|
313
|
+
* and asks the daemon binary what IT will send (`accept-handoff --print-id`).
|
|
314
|
+
* Two programs that compute one identity can only be known to agree by
|
|
315
|
+
* comparing them, and a daemon that predates per-profile identities does not
|
|
316
|
+
* agree: it sends the hardware value whatever the profile's
|
|
317
|
+
* `machine-identity.json` says, so a credential minted for what it reports
|
|
318
|
+
* registers the profile on the default machine's row (the OSK-13845 failure, now
|
|
319
|
+
* reached through version skew rather than through the rule). The comparison
|
|
320
|
+
* needs this: the expected value for the TARGET profile, which is not
|
|
321
|
+
* necessarily the one this process is running as.
|
|
322
|
+
*
|
|
323
|
+
* Decides and persists the profile's identity if nothing has yet — the same
|
|
324
|
+
* side effect `getMachineUuid()` has, for the same reason.
|
|
325
|
+
*/
|
|
326
|
+
export function getMachineUuidForProfile(profile) {
|
|
299
327
|
const hardware = getHardwareMachineUuid();
|
|
300
328
|
// A hosted runtime's identity is ISSUED and fenced by the control plane.
|
|
301
329
|
if (hostedRuntimeIdOverride('OVERSKY_MACHINE_UUID'))
|
|
302
330
|
return hardware;
|
|
303
|
-
const
|
|
304
|
-
if (!
|
|
331
|
+
const name = typeof profile === 'string' ? profile.trim() : '';
|
|
332
|
+
if (!name || name === DEFAULT_PROFILE_NAME)
|
|
305
333
|
return hardware;
|
|
306
|
-
return resolveProfileMachineUuid(
|
|
334
|
+
return resolveProfileMachineUuid(name, hardware);
|
|
335
|
+
}
|
|
336
|
+
function readRecordedChoice(profile) {
|
|
337
|
+
try {
|
|
338
|
+
const file = path.join(resolveConfigRoot(), 'profiles', profile, MACHINE_IDENTITY_FILENAME);
|
|
339
|
+
const parsed = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
340
|
+
const reason = parsed.reason === 'new_profile' ||
|
|
341
|
+
parsed.reason === 'pre_existing_profile' ||
|
|
342
|
+
parsed.reason === 'restored_profile'
|
|
343
|
+
? parsed.reason
|
|
344
|
+
: null;
|
|
345
|
+
return {
|
|
346
|
+
reason,
|
|
347
|
+
evidence: Array.isArray(parsed.evidence)
|
|
348
|
+
? parsed.evidence.filter((e) => typeof e === 'string')
|
|
349
|
+
: [],
|
|
350
|
+
decidedAt: typeof parsed.decidedAt === 'string' ? parsed.decidedAt : null,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
return { reason: null, evidence: [], decidedAt: null };
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Which machine this process registers as, and WHY — the question a person has
|
|
359
|
+
* when two profiles turn up on one machine page and the logs say nothing.
|
|
360
|
+
*
|
|
361
|
+
* A read, not a decision: it reports the identity `getMachineUuid()` settled on
|
|
362
|
+
* (settling it if nothing has, exactly as any caller would) and the record that
|
|
363
|
+
* explains it. It never changes what a profile registers as.
|
|
364
|
+
*/
|
|
365
|
+
export function describeMachineIdentity() {
|
|
366
|
+
const hardware = getHardwareMachineUuid();
|
|
367
|
+
const machineUuid = getMachineUuid();
|
|
368
|
+
const active = activeMachineProfile;
|
|
369
|
+
const profile = active && active !== DEFAULT_PROFILE_NAME ? active : null;
|
|
370
|
+
const base = { profile, machineUuid, hardware };
|
|
371
|
+
if (hostedRuntimeIdOverride('OVERSKY_MACHINE_UUID')) {
|
|
372
|
+
return {
|
|
373
|
+
...base,
|
|
374
|
+
sharesDefaultMachine: false,
|
|
375
|
+
reason: 'hosted_runtime',
|
|
376
|
+
evidence: [],
|
|
377
|
+
decidedAt: null,
|
|
378
|
+
sentence: 'This runtime is hosted; its machine identity was issued by the control plane.',
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
if (!profile) {
|
|
382
|
+
return {
|
|
383
|
+
...base,
|
|
384
|
+
sharesDefaultMachine: false,
|
|
385
|
+
reason: 'default_profile',
|
|
386
|
+
evidence: [],
|
|
387
|
+
decidedAt: null,
|
|
388
|
+
sentence: "The default profile uses this computer's own machine identity.",
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
const recorded = readRecordedChoice(profile);
|
|
392
|
+
const sharesDefaultMachine = machineUuid === hardware;
|
|
393
|
+
const reason = recorded.reason ?? 'unrecorded';
|
|
394
|
+
const decided = recorded.decidedAt ? ` (decided ${recorded.decidedAt})` : '';
|
|
395
|
+
const held = recorded.evidence.length > 0 ? ` (${recorded.evidence.join(', ')})` : '';
|
|
396
|
+
let sentence;
|
|
397
|
+
if (reason === 'new_profile') {
|
|
398
|
+
sentence =
|
|
399
|
+
`Profile '${profile}' has its own machine identity: it held no credentials when that ` +
|
|
400
|
+
`identity was first chosen${decided}.`;
|
|
401
|
+
}
|
|
402
|
+
else if (reason === 'pre_existing_profile') {
|
|
403
|
+
sentence =
|
|
404
|
+
`Profile '${profile}' shares this computer's default machine identity: it already held ` +
|
|
405
|
+
`credentials${held} when its identity was first chosen${decided}, and the server ties ` +
|
|
406
|
+
'those credentials to that identity, so changing it would sign the profile out.';
|
|
407
|
+
}
|
|
408
|
+
else if (reason === 'restored_profile') {
|
|
409
|
+
sentence = sharesDefaultMachine
|
|
410
|
+
? `Profile '${profile}' shares this computer's default machine identity, restored from the ` +
|
|
411
|
+
`copy kept outside the profile after its state was removed${decided}.`
|
|
412
|
+
: `Profile '${profile}' has its own machine identity, restored from the copy kept outside ` +
|
|
413
|
+
`the profile after its state was removed${decided}.`;
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
sentence = sharesDefaultMachine
|
|
417
|
+
? `Profile '${profile}' uses this computer's default machine identity; the record of why ` +
|
|
418
|
+
'could not be read.'
|
|
419
|
+
: `Profile '${profile}' has its own machine identity; the record of why could not be read.`;
|
|
420
|
+
}
|
|
421
|
+
return {
|
|
422
|
+
...base,
|
|
423
|
+
sharesDefaultMachine,
|
|
424
|
+
reason,
|
|
425
|
+
evidence: recorded.evidence,
|
|
426
|
+
decidedAt: recorded.decidedAt,
|
|
427
|
+
sentence,
|
|
428
|
+
};
|
|
307
429
|
}
|
|
308
430
|
/** @internal test seam — forget the cached value so the next call re-probes. */
|
|
309
431
|
export function __resetMachineUuidCacheForTest() {
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The workspace-isolation probe wire contract (OSK-15099).
|
|
3
|
+
*
|
|
4
|
+
* A Commitment Run is always isolated: the daemon cuts it a private git
|
|
5
|
+
* worktree from the directory the Run is rooted in, and refuses the Run with
|
|
6
|
+
* `EXECUTION_ISOLATION_UNAVAILABLE` before any tool when it cannot. Preflight
|
|
7
|
+
* had no way to read that machine's filesystem, so it reported `ready`,
|
|
8
|
+
* activation succeeded, and the first Run failed. The daemon now answers the
|
|
9
|
+
* same question BEFORE a Run, through the same predicate its executor refuses
|
|
10
|
+
* on, and this module is the one place both ends spell it.
|
|
11
|
+
*
|
|
12
|
+
* - The daemon announces {@link WORKSPACE_ISOLATION_PROBE_CAPABILITY}. A daemon
|
|
13
|
+
* that does not is never asked, and the server reports the prerequisite as
|
|
14
|
+
* UNVERIFIED — never as satisfied (unknown is never ok).
|
|
15
|
+
* - The server sends {@link WORKSPACE_ISOLATION_PROBE_METHOD} as a control RPC
|
|
16
|
+
* with `{ workingDirectory? }`: exactly the directory it would put on the
|
|
17
|
+
* Run's request (`agent.workingDirectory || daemon cwd`).
|
|
18
|
+
* - The daemon answers {@link WorkspaceIsolationProbeAnswer}.
|
|
19
|
+
*
|
|
20
|
+
* Pure: no I/O, safe for the browser, the CLI and the API.
|
|
21
|
+
*/
|
|
22
|
+
export declare const WORKSPACE_ISOLATION_PROBE_CAPABILITY: "workspace_isolation_probe_v1";
|
|
23
|
+
export declare const WORKSPACE_ISOLATION_PROBE_METHOD: "daemon:workspace:isolation-probe";
|
|
24
|
+
/**
|
|
25
|
+
* What an explicit isolation request can be given from a base directory.
|
|
26
|
+
*
|
|
27
|
+
* - `worktree` — a git repository with a commit: a worktree is cut;
|
|
28
|
+
* - `sandbox` — the daemon's own bare scratch workspace: an empty
|
|
29
|
+
* private sandbox is used instead;
|
|
30
|
+
* - `not_a_repository` — refused: not inside a git repository;
|
|
31
|
+
* - `no_initial_commit` — refused: a repository with an unborn HEAD.
|
|
32
|
+
*/
|
|
33
|
+
export declare const WORKTREE_BASE_VERDICTS: readonly ["worktree", "sandbox", "not_a_repository", "no_initial_commit"];
|
|
34
|
+
export type WorktreeBaseVerdict = (typeof WORKTREE_BASE_VERDICTS)[number];
|
|
35
|
+
/** The verdicts on which the daemon refuses an isolated Run before any tool. */
|
|
36
|
+
export declare const REFUSING_WORKTREE_BASE_VERDICTS: ReadonlySet<WorktreeBaseVerdict>;
|
|
37
|
+
export declare function isWorktreeBaseVerdict(value: unknown): value is WorktreeBaseVerdict;
|
|
38
|
+
export interface WorkspaceIsolationProbeRequest {
|
|
39
|
+
/** Omitted: the daemon resolves its own default, as it would for the Run. */
|
|
40
|
+
workingDirectory?: string;
|
|
41
|
+
}
|
|
42
|
+
export interface WorkspaceIsolationProbeAnswer {
|
|
43
|
+
/** The directory a Run asked with this `workingDirectory` would be rooted in. */
|
|
44
|
+
baseCwd: string;
|
|
45
|
+
/** Whether a person chose it (agent/task directory or configured default). */
|
|
46
|
+
chosenExplicitly: boolean;
|
|
47
|
+
verdict: WorktreeBaseVerdict;
|
|
48
|
+
/** The refusal sentence the Run would fail with; null when it would be admitted. */
|
|
49
|
+
remedy: string | null;
|
|
50
|
+
checkedAt: string;
|
|
51
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The workspace-isolation probe wire contract (OSK-15099).
|
|
3
|
+
*
|
|
4
|
+
* A Commitment Run is always isolated: the daemon cuts it a private git
|
|
5
|
+
* worktree from the directory the Run is rooted in, and refuses the Run with
|
|
6
|
+
* `EXECUTION_ISOLATION_UNAVAILABLE` before any tool when it cannot. Preflight
|
|
7
|
+
* had no way to read that machine's filesystem, so it reported `ready`,
|
|
8
|
+
* activation succeeded, and the first Run failed. The daemon now answers the
|
|
9
|
+
* same question BEFORE a Run, through the same predicate its executor refuses
|
|
10
|
+
* on, and this module is the one place both ends spell it.
|
|
11
|
+
*
|
|
12
|
+
* - The daemon announces {@link WORKSPACE_ISOLATION_PROBE_CAPABILITY}. A daemon
|
|
13
|
+
* that does not is never asked, and the server reports the prerequisite as
|
|
14
|
+
* UNVERIFIED — never as satisfied (unknown is never ok).
|
|
15
|
+
* - The server sends {@link WORKSPACE_ISOLATION_PROBE_METHOD} as a control RPC
|
|
16
|
+
* with `{ workingDirectory? }`: exactly the directory it would put on the
|
|
17
|
+
* Run's request (`agent.workingDirectory || daemon cwd`).
|
|
18
|
+
* - The daemon answers {@link WorkspaceIsolationProbeAnswer}.
|
|
19
|
+
*
|
|
20
|
+
* Pure: no I/O, safe for the browser, the CLI and the API.
|
|
21
|
+
*/
|
|
22
|
+
export const WORKSPACE_ISOLATION_PROBE_CAPABILITY = 'workspace_isolation_probe_v1';
|
|
23
|
+
export const WORKSPACE_ISOLATION_PROBE_METHOD = 'daemon:workspace:isolation-probe';
|
|
24
|
+
/**
|
|
25
|
+
* What an explicit isolation request can be given from a base directory.
|
|
26
|
+
*
|
|
27
|
+
* - `worktree` — a git repository with a commit: a worktree is cut;
|
|
28
|
+
* - `sandbox` — the daemon's own bare scratch workspace: an empty
|
|
29
|
+
* private sandbox is used instead;
|
|
30
|
+
* - `not_a_repository` — refused: not inside a git repository;
|
|
31
|
+
* - `no_initial_commit` — refused: a repository with an unborn HEAD.
|
|
32
|
+
*/
|
|
33
|
+
export const WORKTREE_BASE_VERDICTS = Object.freeze([
|
|
34
|
+
'worktree',
|
|
35
|
+
'sandbox',
|
|
36
|
+
'not_a_repository',
|
|
37
|
+
'no_initial_commit',
|
|
38
|
+
]);
|
|
39
|
+
/** The verdicts on which the daemon refuses an isolated Run before any tool. */
|
|
40
|
+
export const REFUSING_WORKTREE_BASE_VERDICTS = new Set([
|
|
41
|
+
'not_a_repository',
|
|
42
|
+
'no_initial_commit',
|
|
43
|
+
]);
|
|
44
|
+
export function isWorktreeBaseVerdict(value) {
|
|
45
|
+
return typeof value === 'string' && WORKTREE_BASE_VERDICTS.includes(value);
|
|
46
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skrr-ai/auth-core",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.27",
|
|
4
4
|
"main": "dist/cjs/index.js",
|
|
5
5
|
"types": "dist/esm/index.d.ts",
|
|
6
6
|
"exports": {
|
|
@@ -144,6 +144,16 @@
|
|
|
144
144
|
"default": "./dist/cjs/dedicatedRuntimeWakeWire.js"
|
|
145
145
|
}
|
|
146
146
|
},
|
|
147
|
+
"./workspace-isolation-probe-wire": {
|
|
148
|
+
"import": {
|
|
149
|
+
"types": "./dist/esm/workspaceIsolationProbeWire.d.ts",
|
|
150
|
+
"default": "./dist/esm/workspaceIsolationProbeWire.js"
|
|
151
|
+
},
|
|
152
|
+
"require": {
|
|
153
|
+
"types": "./dist/cjs/workspaceIsolationProbeWire.d.ts",
|
|
154
|
+
"default": "./dist/cjs/workspaceIsolationProbeWire.js"
|
|
155
|
+
}
|
|
156
|
+
},
|
|
147
157
|
"./commitment-execution-contract": {
|
|
148
158
|
"import": {
|
|
149
159
|
"types": "./dist/esm/commitmentExecutionContract.d.ts",
|