@skrr-ai/cli 0.1.93 → 0.1.95

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.
Files changed (174) hide show
  1. package/README.md +153 -165
  2. package/bin/run.js +32 -0
  3. package/bin/update-npm-runner.cjs +33 -0
  4. package/bin/update-session.cjs +194 -0
  5. package/bin/update-worker.cjs +208 -0
  6. package/dist/base-command.js +0 -15
  7. package/dist/commands/agents/operating-plan.d.ts +11 -0
  8. package/dist/commands/agents/operating-plan.js +54 -0
  9. package/dist/commands/agents/roles/example.d.ts +11 -0
  10. package/dist/commands/agents/roles/example.js +30 -0
  11. package/dist/commands/{commitments/mode.d.ts → agents/roles/export.d.ts} +5 -5
  12. package/dist/commands/agents/roles/export.js +81 -0
  13. package/dist/commands/agents/roles/install.d.ts +12 -0
  14. package/dist/commands/agents/roles/install.js +48 -0
  15. package/dist/commands/agents/roles/list.d.ts +11 -0
  16. package/dist/commands/agents/roles/list.js +36 -0
  17. package/dist/commands/agents/roles/preview.d.ts +14 -0
  18. package/dist/commands/agents/roles/preview.js +49 -0
  19. package/dist/commands/agents/roles/withdraw.d.ts +13 -0
  20. package/dist/commands/agents/roles/withdraw.js +43 -0
  21. package/dist/commands/code/doctor.d.ts +1 -0
  22. package/dist/commands/code/doctor.js +6 -0
  23. package/dist/commands/code/index.js +4 -0
  24. package/dist/commands/code/install.d.ts +5 -62
  25. package/dist/commands/code/install.js +86 -279
  26. package/dist/commands/code/rollback.d.ts +8 -0
  27. package/dist/commands/code/rollback.js +20 -0
  28. package/dist/commands/code/update.d.ts +8 -37
  29. package/dist/commands/code/update.js +134 -213
  30. package/dist/commands/commitments/{autonomy-requests → cadence-requests}/decide.d.ts +5 -7
  31. package/dist/commands/commitments/{autonomy-requests → cadence-requests}/decide.js +13 -15
  32. package/dist/commands/commitments/cost.d.ts +1 -1
  33. package/dist/commands/commitments/cost.js +1 -1
  34. package/dist/commands/commitments/create.d.ts +0 -7
  35. package/dist/commands/commitments/create.js +9 -98
  36. package/dist/commands/commitments/delivery.js +3 -21
  37. package/dist/commands/commitments/doctor.js +28 -27
  38. package/dist/commands/commitments/effective-policy.js +5 -36
  39. package/dist/commands/commitments/evaluations.d.ts +15 -0
  40. package/dist/commands/commitments/evaluations.js +54 -0
  41. package/dist/commands/commitments/pack/activate.d.ts +11 -0
  42. package/dist/commands/commitments/pack/activate.js +22 -0
  43. package/dist/commands/commitments/pack/bind.js +1 -1
  44. package/dist/commands/commitments/remediate.js +2 -5
  45. package/dist/commands/commitments/show.js +1 -1
  46. package/dist/commands/commitments/update.js +9 -9
  47. package/dist/commands/commitments/wake-capabilities.d.ts +1 -3
  48. package/dist/commands/commitments/wake-capabilities.js +5 -21
  49. package/dist/commands/daemon/install.js +4 -0
  50. package/dist/commands/generate-recovery-code.d.ts +13 -1
  51. package/dist/commands/generate-recovery-code.js +146 -13
  52. package/dist/commands/instructions/guide.d.ts +20 -0
  53. package/dist/commands/instructions/guide.js +84 -0
  54. package/dist/commands/instructions/install.js +57 -33
  55. package/dist/commands/instructions/setup.d.ts +14 -0
  56. package/dist/commands/instructions/setup.js +72 -0
  57. package/dist/commands/integrations/execute.js +1 -1
  58. package/dist/commands/login.d.ts +5 -6
  59. package/dist/commands/login.js +27 -11
  60. package/dist/commands/logout.js +7 -7
  61. package/dist/commands/security/overview.d.ts +11 -0
  62. package/dist/commands/security/overview.js +158 -0
  63. package/dist/commands/spaces/claim.d.ts +12 -0
  64. package/dist/commands/spaces/claim.js +42 -0
  65. package/dist/commands/spaces/ownership.d.ts +12 -0
  66. package/dist/commands/spaces/ownership.js +46 -0
  67. package/dist/commands/tasks/cancel-cascade.js +1 -1
  68. package/dist/commands/tasks/create-tree.d.ts +5 -1
  69. package/dist/commands/tasks/create-tree.js +35 -7
  70. package/dist/commands/tasks/interrupt.js +2 -2
  71. package/dist/commands/tasks/pause-schedule.js +1 -1
  72. package/dist/commands/token/list.d.ts +3 -5
  73. package/dist/commands/token/list.js +99 -57
  74. package/dist/commands/update.d.ts +14 -0
  75. package/dist/commands/update.js +61 -0
  76. package/dist/generated/managed-instruction-guides.json +9 -0
  77. package/dist/hooks/init.d.ts +5 -0
  78. package/dist/hooks/init.js +27 -0
  79. package/dist/lib/commitment-product.d.ts +0 -6
  80. package/dist/lib/commitment-product.js +1 -30
  81. package/dist/lib/commitments.d.ts +9 -53
  82. package/dist/lib/commitments.js +23 -146
  83. package/dist/lib/daemon-installer.d.ts +2 -0
  84. package/dist/lib/daemon-installer.js +100 -24
  85. package/dist/lib/first-party-harness-doctor.js +31 -1
  86. package/dist/lib/first-party-harness-remote-install.d.ts +71 -0
  87. package/dist/lib/first-party-harness-remote-install.js +310 -0
  88. package/dist/lib/first-party-harness-remote-update.d.ts +46 -0
  89. package/dist/lib/first-party-harness-remote-update.js +242 -0
  90. package/dist/lib/first-party-harness-startup-update.d.ts +26 -0
  91. package/dist/lib/first-party-harness-startup-update.js +166 -0
  92. package/dist/lib/first-party-harness-update.d.ts +46 -0
  93. package/dist/lib/first-party-harness-update.js +289 -0
  94. package/dist/lib/first-party-harness.js +7 -4
  95. package/dist/lib/managed-instruction-local.d.ts +12 -0
  96. package/dist/lib/managed-instruction-local.js +58 -0
  97. package/dist/lib/managed-instruction-setup.d.ts +35 -0
  98. package/dist/lib/managed-instruction-setup.js +306 -0
  99. package/dist/lib/memory-sync.d.ts +1 -0
  100. package/dist/lib/memory-sync.js +279 -68
  101. package/dist/lib/northstars.js +1 -1
  102. package/dist/lib/platform-update-local.d.ts +2 -0
  103. package/dist/lib/platform-update-local.js +113 -0
  104. package/dist/lib/platform-update.d.ts +39 -0
  105. package/dist/lib/platform-update.js +84 -0
  106. package/dist/lib/profile-machine-identity-guard.d.ts +2 -0
  107. package/dist/lib/profile-machine-identity-guard.js +13 -0
  108. package/dist/lib/prompt.d.ts +1 -0
  109. package/dist/lib/prompt.js +4 -3
  110. package/dist/lib/roles.d.ts +98 -0
  111. package/dist/lib/roles.js +45 -0
  112. package/dist/lib/task-batch.d.ts +9 -0
  113. package/dist/lib/task-batch.js +94 -17
  114. package/dist/lib/task-instruction-offer.d.ts +1 -4
  115. package/dist/lib/task-instruction-offer.js +3 -129
  116. package/dist/lib/update-check.d.ts +61 -53
  117. package/dist/lib/update-check.js +453 -314
  118. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/commitmentExecutionContract.d.ts +45 -0
  119. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/commitmentExecutionContract.js +550 -0
  120. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessChannels.d.ts +3 -4
  121. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessChannels.js +3 -4
  122. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessReleaseKeys.d.ts +82 -0
  123. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessReleaseKeys.js +105 -0
  124. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessUpdater.d.ts +110 -0
  125. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessUpdater.js +945 -0
  126. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessPermissionControls.d.ts +32 -0
  127. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessPermissionControls.js +62 -0
  128. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +2 -0
  129. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +4 -1
  130. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.js +35 -5
  131. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releasePolicy.d.ts +63 -0
  132. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releasePolicy.js +169 -0
  133. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releaseVersions.d.ts +2 -0
  134. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releaseVersions.js +44 -0
  135. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/sessionPermissionAuthority.d.ts +7 -44
  136. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/sessionPermissionAuthority.js +8 -47
  137. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/commitmentExecutionContract.d.ts +45 -0
  138. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/commitmentExecutionContract.js +545 -0
  139. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessChannels.d.ts +3 -4
  140. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessChannels.js +3 -4
  141. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessReleaseKeys.d.ts +82 -0
  142. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessReleaseKeys.js +102 -0
  143. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessUpdater.d.ts +110 -0
  144. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessUpdater.js +923 -0
  145. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessPermissionControls.d.ts +32 -0
  146. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessPermissionControls.js +59 -0
  147. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +2 -0
  148. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +2 -0
  149. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.js +35 -5
  150. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releasePolicy.d.ts +63 -0
  151. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releasePolicy.js +163 -0
  152. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releaseVersions.d.ts +2 -0
  153. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releaseVersions.js +41 -0
  154. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/sessionPermissionAuthority.d.ts +7 -44
  155. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/sessionPermissionAuthority.js +8 -47
  156. package/dist/node_modules/@skrr-ai/auth-core/package.json +41 -1
  157. package/dist/node_modules/@skrr-ai/data-provider/index.js +7362 -7232
  158. package/dist/node_modules/@skrr-ai/data-provider/package.json +2 -2
  159. package/docs/v1/README.md +28 -0
  160. package/docs/v1/api.md +55 -0
  161. package/docs/v1/changelog.md +16 -0
  162. package/docs/v1/check-examples.mjs +178 -0
  163. package/docs/v1/examples/api-readonly.mjs +144 -0
  164. package/docs/v1/operations.md +87 -0
  165. package/docs/v1/quickstart.md +71 -0
  166. package/oclif.manifest.json +46381 -45478
  167. package/package.json +16 -11
  168. package/dist/commands/commitments/autonomy.d.ts +0 -30
  169. package/dist/commands/commitments/autonomy.js +0 -67
  170. package/dist/commands/commitments/mode.js +0 -58
  171. package/dist/commands/commitments/pack/promote.d.ts +0 -19
  172. package/dist/commands/commitments/pack/promote.js +0 -46
  173. package/dist/commands/commitments/pack/shadow.d.ts +0 -20
  174. package/dist/commands/commitments/pack/shadow.js +0 -42
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.configureCodeStartupChecks = configureCodeStartupChecks;
7
+ exports.shouldCheckCodeAtStartup = shouldCheckCodeAtStartup;
8
+ exports.ttyCodeUpdateAsker = ttyCodeUpdateAsker;
9
+ exports.maybeOfferCodeUpdate = maybeOfferCodeUpdate;
10
+ const node_fs_1 = require("node:fs");
11
+ const node_path_1 = __importDefault(require("node:path"));
12
+ const node_readline_1 = __importDefault(require("node:readline"));
13
+ const auth_core_1 = require("@skrr-ai/auth-core");
14
+ const first_party_harness_update_1 = require("./first-party-harness-update");
15
+ function preferencesPath(env) {
16
+ return node_path_1.default.join((0, auth_core_1.resolveConfigRoot)(env), 'code-update-preferences.json');
17
+ }
18
+ function readPreferences(env) {
19
+ try {
20
+ const value = JSON.parse((0, node_fs_1.readFileSync)(preferencesPath(env), 'utf8'));
21
+ if (!value || typeof value !== 'object' || Array.isArray(value))
22
+ return {};
23
+ const input = value;
24
+ const skipped = input.skippedVersions;
25
+ return {
26
+ ...(typeof input.promptOnStartup === 'boolean'
27
+ ? { promptOnStartup: input.promptOnStartup }
28
+ : {}),
29
+ ...(skipped && typeof skipped === 'object' && !Array.isArray(skipped)
30
+ ? {
31
+ skippedVersions: Object.fromEntries(Object.entries(skipped).filter((entry) => typeof entry[1] === 'string')),
32
+ }
33
+ : {}),
34
+ };
35
+ }
36
+ catch {
37
+ return {};
38
+ }
39
+ }
40
+ function saveChoice(env, result, choice) {
41
+ if (choice !== 'version' && choice !== 'disable')
42
+ return;
43
+ try {
44
+ const previous = readPreferences(env);
45
+ const next = choice === 'disable'
46
+ ? { ...previous, promptOnStartup: false }
47
+ : {
48
+ ...previous,
49
+ skippedVersions: {
50
+ ...previous.skippedVersions,
51
+ [result.channel]: result.offeredVersion,
52
+ },
53
+ };
54
+ const file = preferencesPath(env);
55
+ (0, node_fs_1.mkdirSync)(node_path_1.default.dirname(file), { recursive: true, mode: 0o700 });
56
+ const staging = `${file}.${process.pid}.tmp`;
57
+ (0, node_fs_1.writeFileSync)(staging, JSON.stringify(next), { mode: 0o600 });
58
+ (0, node_fs_1.renameSync)(staging, file);
59
+ }
60
+ catch {
61
+ /* Update preferences must never make a session unavailable. */
62
+ }
63
+ }
64
+ function configureCodeStartupChecks(enabled, env = process.env) {
65
+ const file = preferencesPath(env);
66
+ (0, node_fs_1.mkdirSync)(node_path_1.default.dirname(file), { recursive: true, mode: 0o700 });
67
+ const staging = `${file}.${process.pid}.tmp`;
68
+ (0, node_fs_1.writeFileSync)(staging, JSON.stringify({ ...readPreferences(env), promptOnStartup: enabled }), {
69
+ mode: 0o600,
70
+ });
71
+ (0, node_fs_1.renameSync)(staging, file);
72
+ return { enabled, preferencesPath: file };
73
+ }
74
+ const disabled = (value) => /^(0|false|off|no|disabled)$/i.test(value ?? '');
75
+ const enabled = (value) => /^(1|true|on|yes)$/i.test(value ?? '');
76
+ function shouldCheckCodeAtStartup(input) {
77
+ const env = input.env ?? process.env;
78
+ if (!(input.stdinTTY ?? process.stdin.isTTY) ||
79
+ !(input.stdoutTTY ?? process.stdout.isTTY) ||
80
+ !(input.stderrTTY ?? process.stderr.isTTY))
81
+ return false;
82
+ if (enabled(env.CI) ||
83
+ disabled(env.SKRR_CODE_UPDATE_CHECK) ||
84
+ disabled(env.SKRR_CODE_UPDATE_PROMPT) ||
85
+ enabled(env.OVERSKY_SKIP_UPDATE_CHECK) ||
86
+ enabled(env.OVERSKY_NO_UPDATE_NUDGE))
87
+ return false;
88
+ if ((0, first_party_harness_update_1.localCodeUpdateOwner)(env) !== 'managed' || readPreferences(env).promptOnStartup === false)
89
+ return false;
90
+ if (input.argv.some((arg) => /^(--help|-h|--version|-v|--json|--print|-p|--no-tui|--output|--format)(=|$)/.test(arg)))
91
+ return false;
92
+ if (/^(run|acp|serve|web|auth|upgrade|update|doctor|install|rollback|export|import|session|models)$/.test(input.argv[0] ?? ''))
93
+ return false;
94
+ return true;
95
+ }
96
+ function ttyCodeUpdateAsker() {
97
+ return (result) => new Promise((resolve) => {
98
+ const rl = node_readline_1.default.createInterface({ input: process.stdin, output: process.stderr });
99
+ let settled = false;
100
+ const finish = (choice) => {
101
+ if (settled)
102
+ return;
103
+ settled = true;
104
+ rl.close();
105
+ resolve(choice);
106
+ };
107
+ rl.on('close', () => finish('once'));
108
+ rl.question(`\n${auth_core_1.FIRST_PARTY_HARNESS.displayName} update: ${result.installedVersion ?? 'installed version not recorded'} → ${result.offeredVersion} (${result.channel})\n` +
109
+ ' [1] Update and start [2] Skip this time [3] Skip this version [4] Disable startup checks\nChoose [2]: ', (reply) => finish(reply.trim() === '1'
110
+ ? 'update'
111
+ : reply.trim() === '3'
112
+ ? 'version'
113
+ : reply.trim() === '4'
114
+ ? 'disable'
115
+ : 'once'));
116
+ });
117
+ }
118
+ /** The only caller is a new interactive TUI launch, before any broker or lease. */
119
+ async function maybeOfferCodeUpdate(input) {
120
+ if (!shouldCheckCodeAtStartup(input))
121
+ return;
122
+ const env = input.env ?? process.env;
123
+ const controller = new AbortController();
124
+ let timer;
125
+ try {
126
+ // Bound the whole discovery, including feed fallbacks; failed checks remain
127
+ // inspectable through update --check but do not hold the session open.
128
+ const timeout = new Promise((resolve) => {
129
+ timer = setTimeout(() => {
130
+ controller.abort();
131
+ resolve(null);
132
+ }, 1500);
133
+ });
134
+ const result = await Promise.race([
135
+ (input.check ?? first_party_harness_update_1.checkLocalCodeUpdate)({
136
+ env,
137
+ signal: controller.signal,
138
+ manifestTimeoutMs: 1500,
139
+ }),
140
+ timeout,
141
+ ]);
142
+ if (timer) {
143
+ clearTimeout(timer);
144
+ timer = undefined;
145
+ }
146
+ if (!result || result.state !== 'update-available' || !result.offeredVersion)
147
+ return;
148
+ if (readPreferences(env).skippedVersions?.[result.channel] === result.offeredVersion)
149
+ return;
150
+ const choice = await (input.ask ?? ttyCodeUpdateAsker())(result);
151
+ saveChoice(env, result, choice);
152
+ if (choice !== 'update')
153
+ return;
154
+ const updated = await (input.update ?? first_party_harness_update_1.updateLocalCode)({ env, onProgress: input.say });
155
+ input.say((0, first_party_harness_update_1.formatLocalCodeUpdate)(updated));
156
+ if (updated.state === 'failed')
157
+ input.say('Starting the installed engine. Inspect the update result with `skrr code doctor` or retry `skrr code update`.');
158
+ }
159
+ catch (error) {
160
+ input.say(`${auth_core_1.FIRST_PARTY_HARNESS.displayName} update could not complete: ${error instanceof Error ? error.message : String(error)}. Starting the installed engine.`);
161
+ }
162
+ finally {
163
+ if (timer)
164
+ clearTimeout(timer);
165
+ }
166
+ }
@@ -0,0 +1,46 @@
1
+ import { readFirstPartyHarnessUpdateState } from '@skrr-ai/auth-core/first-party-harness-updater';
2
+ export type CodeUpdateOwner = 'managed' | 'external' | 'desktop' | 'image';
3
+ export interface LocalCodeUpdateStatus {
4
+ component: 'code';
5
+ state: 'not-installed' | 'unchecked' | 'up-to-date' | 'update-available' | 'owner-managed' | 'check-failed' | 'installed' | 'failed' | 'rolled-back';
6
+ runningVersion: null;
7
+ installedVersion: string | null;
8
+ offeredVersion: string | null;
9
+ channel: string;
10
+ owner: CodeUpdateOwner;
11
+ activePath: string | null;
12
+ managedPath: string;
13
+ installedVerified: boolean;
14
+ command: string;
15
+ lastAttempt: ReturnType<typeof readFirstPartyHarnessUpdateState>;
16
+ message?: string;
17
+ code?: string;
18
+ }
19
+ export interface LocalCodeUpdateOptions {
20
+ env?: NodeJS.ProcessEnv;
21
+ force?: boolean;
22
+ version?: string;
23
+ allowDowngrade?: boolean;
24
+ onProgress?: (line: string) => void;
25
+ signal?: AbortSignal;
26
+ manifestTimeoutMs?: number;
27
+ /** Only an explicit install may adopt an engine currently found on PATH. */
28
+ install?: boolean;
29
+ }
30
+ export declare function localCodeUpdateOwner(env?: NodeJS.ProcessEnv): CodeUpdateOwner;
31
+ /** Read metadata without networking or executing the engine. External versions are unknown. */
32
+ export declare function getLocalCodeUpdateStatus(env?: NodeJS.ProcessEnv): LocalCodeUpdateStatus;
33
+ export declare function checkLocalCodeUpdate(options?: LocalCodeUpdateOptions): Promise<LocalCodeUpdateStatus>;
34
+ export declare function updateLocalCode(options?: LocalCodeUpdateOptions): Promise<LocalCodeUpdateStatus>;
35
+ export declare function rollbackLocalCode(env?: NodeJS.ProcessEnv): LocalCodeUpdateStatus;
36
+ /** Explicit --no-wait launches the same local command, with a durable private log. */
37
+ export declare function startLocalCodeUpdate(options?: LocalCodeUpdateOptions & {
38
+ operation?: 'install' | 'update';
39
+ }): Promise<{
40
+ component: 'code';
41
+ state: 'queued';
42
+ pid: number;
43
+ logPath: string;
44
+ command: string;
45
+ }>;
46
+ export declare function formatLocalCodeUpdate(result: LocalCodeUpdateStatus): string;
@@ -0,0 +1,289 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.localCodeUpdateOwner = localCodeUpdateOwner;
7
+ exports.getLocalCodeUpdateStatus = getLocalCodeUpdateStatus;
8
+ exports.checkLocalCodeUpdate = checkLocalCodeUpdate;
9
+ exports.updateLocalCode = updateLocalCode;
10
+ exports.rollbackLocalCode = rollbackLocalCode;
11
+ exports.startLocalCodeUpdate = startLocalCodeUpdate;
12
+ exports.formatLocalCodeUpdate = formatLocalCodeUpdate;
13
+ /** Local Code updates share the daemon's signed installer and never need an account. */
14
+ const node_child_process_1 = require("node:child_process");
15
+ const node_fs_1 = require("node:fs");
16
+ const node_path_1 = __importDefault(require("node:path"));
17
+ const auth_core_1 = require("@skrr-ai/auth-core");
18
+ const first_party_harness_updater_1 = require("@skrr-ai/auth-core/first-party-harness-updater");
19
+ const first_party_harness_1 = require("./first-party-harness");
20
+ function localCodeUpdateOwner(env = process.env) {
21
+ if ((0, first_party_harness_1.isDedicatedRuntimeWorkload)(env) ||
22
+ ['dedicated-runtime', 'hosted-machine', 'cloud-coding'].includes(env.OVERSKY_DAEMON_SOURCE ?? '') ||
23
+ (0, node_fs_1.existsSync)('/etc/skrr-dedicated-runtime.env'))
24
+ return 'image';
25
+ const resolution = (0, first_party_harness_1.resolveEngine)(env);
26
+ // CLI package ownership and engine ownership are independent: Desktop seeds
27
+ // the managed engine and intentionally allows it to advance separately.
28
+ let activePath = resolution.path;
29
+ try {
30
+ if (activePath)
31
+ activePath = (0, node_fs_1.realpathSync)(activePath);
32
+ }
33
+ catch {
34
+ /* Resolution reports a disappearing binary separately. */
35
+ }
36
+ if (env.SKRR_FIRST_PARTY_HARNESS_OWNER === 'desktop' ||
37
+ (activePath && /\.app[/\\]/i.test(activePath)))
38
+ return 'desktop';
39
+ return ['managed', 'legacy-managed', 'unresolved'].includes(resolution.source) &&
40
+ !resolution.envName
41
+ ? 'managed'
42
+ : 'external';
43
+ }
44
+ function ownerMessage(owner) {
45
+ if (owner === 'image')
46
+ return 'This engine belongs to the runtime image. Update the runtime image to change its engine.';
47
+ if (owner === 'desktop')
48
+ return 'This engine belongs to the desktop app. Update the app to change its engine.';
49
+ if (owner === 'external')
50
+ return 'The active engine comes from an explicit path or an external installation. Update it with its installer, or unset the path override and run `skrr code install` to use managed releases.';
51
+ return undefined;
52
+ }
53
+ /** Read metadata without networking or executing the engine. External versions are unknown. */
54
+ function getLocalCodeUpdateStatus(env = process.env) {
55
+ const resolution = (0, first_party_harness_1.resolveEngine)(env);
56
+ const owner = localCodeUpdateOwner(env);
57
+ const installed = (0, first_party_harness_updater_1.getVerifiedInstalledFirstPartyHarness)({ env });
58
+ const managedActive = owner === 'managed' && ['managed', 'legacy-managed'].includes(resolution.source);
59
+ const message = ownerMessage(owner);
60
+ const status = {
61
+ component: 'code',
62
+ state: owner !== 'managed' ? 'owner-managed' : resolution.path ? 'unchecked' : 'not-installed',
63
+ runningVersion: null,
64
+ installedVersion: managedActive ? installed.version : null,
65
+ offeredVersion: null,
66
+ channel: (0, auth_core_1.resolveFirstPartyHarnessChannel)(env).channel,
67
+ owner,
68
+ activePath: resolution.path,
69
+ managedPath: (0, first_party_harness_1.managedEnginePath)(env),
70
+ installedVerified: managedActive && installed.verified,
71
+ command: owner === 'managed'
72
+ ? resolution.path
73
+ ? 'skrr code update'
74
+ : 'skrr code install'
75
+ : owner === 'desktop'
76
+ ? 'Update the skrr app'
77
+ : owner === 'image'
78
+ ? 'Update the runtime image'
79
+ : 'Update the external engine installation',
80
+ lastAttempt: (0, first_party_harness_updater_1.readFirstPartyHarnessUpdateState)(env),
81
+ ...(message ? { message } : {}),
82
+ };
83
+ if (owner === 'managed') {
84
+ const cached = readCheckCache(env, checkCacheKey(status, env));
85
+ if (cached)
86
+ return {
87
+ ...status,
88
+ state: cached.state,
89
+ offeredVersion: cached.offeredVersion,
90
+ ...(cached.state === 'check-failed' ? { message: cached.message, code: cached.code } : {}),
91
+ };
92
+ }
93
+ return status;
94
+ }
95
+ const CHECK_TTL_MS = 4 * 60 * 60 * 1000;
96
+ const FAILED_CHECK_TTL_MS = 60_000;
97
+ function checkCachePath(env) {
98
+ return node_path_1.default.join((0, auth_core_1.resolveConfigRoot)(env), 'code-update-check.json');
99
+ }
100
+ function checkCacheKey(current, env, version) {
101
+ return JSON.stringify([
102
+ current.channel,
103
+ current.installedVersion,
104
+ current.activePath,
105
+ (0, auth_core_1.readFirstPartyHarnessEnv)(env, 'updateFeedBase').value,
106
+ version,
107
+ ]);
108
+ }
109
+ function readCheckCache(env, key) {
110
+ try {
111
+ const cache = JSON.parse((0, node_fs_1.readFileSync)(checkCachePath(env), 'utf8'));
112
+ const ttl = cache.result?.state === 'check-failed' ? FAILED_CHECK_TTL_MS : CHECK_TTL_MS;
113
+ if (cache.key === key &&
114
+ Date.now() - cache.checkedAt >= 0 &&
115
+ Date.now() - cache.checkedAt < ttl)
116
+ return cache.result;
117
+ }
118
+ catch {
119
+ /* Missing, invalid and expired caches are a cache miss. */
120
+ }
121
+ return null;
122
+ }
123
+ function writeCache(env, cache) {
124
+ try {
125
+ const file = checkCachePath(env);
126
+ (0, node_fs_1.mkdirSync)(node_path_1.default.dirname(file), { recursive: true, mode: 0o700 });
127
+ const staging = `${file}.${process.pid}.tmp`;
128
+ (0, node_fs_1.writeFileSync)(staging, JSON.stringify(cache), { mode: 0o600 });
129
+ (0, node_fs_1.renameSync)(staging, file);
130
+ }
131
+ catch {
132
+ /* A read-only home must not prevent launching an installed engine. */
133
+ }
134
+ }
135
+ async function checkLocalCodeUpdate(options = {}) {
136
+ const env = options.env ?? process.env;
137
+ const current = getLocalCodeUpdateStatus(env);
138
+ if (current.owner !== 'managed')
139
+ return current;
140
+ const key = checkCacheKey(current, env, options.version);
141
+ if (!options.force) {
142
+ const cached = readCheckCache(env, key);
143
+ if (cached)
144
+ return { ...cached, lastAttempt: current.lastAttempt };
145
+ }
146
+ try {
147
+ const checked = await (0, first_party_harness_updater_1.checkFirstPartyHarnessUpdate)({
148
+ env,
149
+ version: options.version,
150
+ signal: options.signal,
151
+ manifestTimeoutMs: options.manifestTimeoutMs ?? 5000,
152
+ });
153
+ const result = checked.ok
154
+ ? {
155
+ ...current,
156
+ installedVersion: checked.installedVersion,
157
+ installedVerified: checked.installedVerified,
158
+ offeredVersion: checked.latestVersion,
159
+ state: !current.activePath
160
+ ? 'not-installed'
161
+ : checked.updateAvailable
162
+ ? 'update-available'
163
+ : 'up-to-date',
164
+ lastAttempt: checked.lastUpdate,
165
+ }
166
+ : { ...current, state: 'check-failed', code: checked.code, message: checked.error };
167
+ writeCache(env, { checkedAt: Date.now(), key, result });
168
+ return result;
169
+ }
170
+ catch (error) {
171
+ const result = {
172
+ ...current,
173
+ state: 'check-failed',
174
+ code: 'CHECK_FAILED',
175
+ message: error instanceof Error ? error.message : String(error),
176
+ };
177
+ writeCache(env, { checkedAt: Date.now(), key, result });
178
+ return result;
179
+ }
180
+ }
181
+ async function updateLocalCode(options = {}) {
182
+ const env = options.env ?? process.env;
183
+ const current = getLocalCodeUpdateStatus(env);
184
+ if (!current.activePath && current.owner === 'managed' && !options.install) {
185
+ return {
186
+ ...current,
187
+ state: 'failed',
188
+ code: 'NOT_INSTALLED',
189
+ message: `${auth_core_1.FIRST_PARTY_HARNESS.displayName} is not installed on this computer. Run \`skrr code install\`.`,
190
+ };
191
+ }
192
+ const adoptingPath = options.install &&
193
+ current.owner === 'external' &&
194
+ ['path', 'fallback'].includes((0, first_party_harness_1.resolveEngine)(env).source);
195
+ if (current.owner !== 'managed' && !adoptingPath)
196
+ return { ...current, state: 'failed', code: 'ENGINE_UPDATE_OWNER' };
197
+ const result = await (0, first_party_harness_updater_1.installFirstPartyHarness)({
198
+ env,
199
+ version: options.version,
200
+ allowDowngrade: options.allowDowngrade,
201
+ onProgress: options.onProgress,
202
+ signal: options.signal,
203
+ manifestTimeoutMs: options.manifestTimeoutMs,
204
+ });
205
+ if (!result.ok)
206
+ return {
207
+ ...getLocalCodeUpdateStatus(env),
208
+ state: 'failed',
209
+ code: result.code,
210
+ message: result.error,
211
+ };
212
+ // Only a successful verified install invalidates an offered-version cache.
213
+ writeCache(env, { checkedAt: 0, key: '', result: current });
214
+ return {
215
+ ...getLocalCodeUpdateStatus(env),
216
+ state: result.changed === false ? 'up-to-date' : 'installed',
217
+ offeredVersion: result.version ?? null,
218
+ ...(adoptingPath
219
+ ? { message: `The managed signed release now takes precedence over ${current.activePath}.` }
220
+ : {}),
221
+ };
222
+ }
223
+ function rollbackLocalCode(env = process.env) {
224
+ const current = getLocalCodeUpdateStatus(env);
225
+ if (current.owner !== 'managed')
226
+ return { ...current, state: 'failed', code: 'ENGINE_UPDATE_OWNER' };
227
+ const result = (0, first_party_harness_updater_1.rollbackFirstPartyHarness)(env);
228
+ if (!result.ok)
229
+ return {
230
+ ...getLocalCodeUpdateStatus(env),
231
+ state: 'failed',
232
+ code: result.code,
233
+ message: result.error,
234
+ };
235
+ writeCache(env, { checkedAt: 0, key: '', result: current });
236
+ return { ...getLocalCodeUpdateStatus(env), state: 'rolled-back', offeredVersion: null };
237
+ }
238
+ /** Explicit --no-wait launches the same local command, with a durable private log. */
239
+ async function startLocalCodeUpdate(options = {}) {
240
+ const env = options.env ?? process.env;
241
+ const current = getLocalCodeUpdateStatus(env);
242
+ const adoptingPath = options.operation === 'install' &&
243
+ current.owner === 'external' &&
244
+ ['path', 'fallback'].includes((0, first_party_harness_1.resolveEngine)(env).source);
245
+ if (current.owner !== 'managed' && !adoptingPath)
246
+ throw new Error(current.message);
247
+ const dir = node_path_1.default.join((0, auth_core_1.resolveConfigRoot)(env), 'update-logs');
248
+ (0, node_fs_1.mkdirSync)(dir, { recursive: true, mode: 0o700 });
249
+ const logPath = node_path_1.default.join(dir, `code-${Date.now()}-${process.pid}.log`);
250
+ const fd = (0, node_fs_1.openSync)(logPath, 'wx', 0o600);
251
+ try {
252
+ const args = [
253
+ node_path_1.default.resolve(__dirname, '../../bin/run.js'),
254
+ 'code',
255
+ options.operation ?? 'update',
256
+ '--json',
257
+ ];
258
+ if (options.version)
259
+ args.push('--target-version', options.version);
260
+ if (options.allowDowngrade)
261
+ args.push('--allow-downgrade');
262
+ const child = (0, node_child_process_1.spawn)(process.execPath, args, { detached: true, stdio: ['ignore', fd, fd], env });
263
+ await new Promise((resolve, reject) => {
264
+ child.once('spawn', resolve);
265
+ child.once('error', reject);
266
+ });
267
+ child.unref();
268
+ return {
269
+ component: 'code',
270
+ state: 'queued',
271
+ pid: child.pid,
272
+ logPath,
273
+ command: 'skrr code doctor',
274
+ };
275
+ }
276
+ finally {
277
+ (0, node_fs_1.closeSync)(fd);
278
+ }
279
+ }
280
+ function formatLocalCodeUpdate(result) {
281
+ const installed = result.installedVersion ?? (result.activePath ? 'version not recorded' : 'not installed');
282
+ if (result.state === 'failed' || result.state === 'check-failed' || result.owner !== 'managed')
283
+ return result.message ?? `${result.code}: ${result.command}`;
284
+ if (result.state === 'rolled-back')
285
+ return `${auth_core_1.FIRST_PARTY_HARNESS.displayName} rolled back to ${installed}. New sessions use this release; existing sessions continue.`;
286
+ if (result.state === 'installed')
287
+ return `${auth_core_1.FIRST_PARTY_HARNESS.displayName} ${installed} is installed. New sessions use this release; existing sessions continue.${result.message ? ` ${result.message}` : ''}`;
288
+ return `${auth_core_1.FIRST_PARTY_HARNESS.displayName}: ${installed}; channel ${result.channel}${result.offeredVersion ? `; latest ${result.offeredVersion}` : ''}. ${result.state === 'update-available' ? 'Run `skrr code update` to install it.' : result.state === 'not-installed' ? 'Run `skrr code install` to install it.' : result.state === 'unchecked' ? 'Run `skrr code update --check` to check the channel.' : 'Up to date.'}`;
289
+ }
@@ -344,10 +344,10 @@ function notInstalledMessage(env = process.env) {
344
344
  return [
345
345
  `The ${displayName} engine (\`${(0, auth_core_1.firstPartyHarnessBinaryName)()}\`) is not installed on this machine.`,
346
346
  '',
347
- 'Install it through the daemon, which verifies the signed release:',
348
- ` • \`${command} install\` — from here, no browser needed`,
347
+ 'Install a verified signed release on this computer:',
348
+ ` • \`${command} install\` — no account or daemon needed`,
349
349
  ` • Or in the web app: the runtime menu beside the chat input → ${displayName} → Install`,
350
- ' • Either way a daemon must be running here: `skrr daemon status`',
350
+ ' (the web app installs through a connected daemon)',
351
351
  '',
352
352
  `Or point the CLI at an existing build: export ${auth_core_1.FIRST_PARTY_HARNESS_ENV.path.name}=/absolute/path/to/${(0, auth_core_1.firstPartyHarnessBinaryName)()}`,
353
353
  ' (an unsigned build runs, and since 2026-08-11 at the same trust tier as a',
@@ -660,6 +660,9 @@ async function execEngine(args, env = process.env, options = {}) {
660
660
  const { path: bin } = resolveEngine(env);
661
661
  if (!bin)
662
662
  throw new Error(exports.ENGINE_NOT_INSTALLED);
663
+ // Updates switch a symlink to an immutable release. Resolve it before the
664
+ // asynchronous broker preparation so this launch keeps the release it chose.
665
+ const pinnedBin = (0, node_fs_1.realpathSync)(bin);
663
666
  // Assumed until the spawn tells us otherwise, so a teardown that runs after a
664
667
  // spawn ERROR does not claim the run was interrupted.
665
668
  const outcome = { interrupted: false };
@@ -672,7 +675,7 @@ async function execEngine(args, env = process.env, options = {}) {
672
675
  const spawnArgs = options.finalizeArgs ? options.finalizeArgs([...args]) : args;
673
676
  // Read AFTER `prepare`, because that is when the hook knows what it acquired.
674
677
  const mode = options.credentialMode?.() ?? 'byok';
675
- return await spawnEngine(bin, spawnArgs, env, extraEnv, mode, outcome, options.policyEnv);
678
+ return await spawnEngine(pinnedBin, spawnArgs, env, extraEnv, mode, outcome, options.policyEnv);
676
679
  }
677
680
  finally {
678
681
  // In a `finally` rather than on `exit`, so a spawn error and a Ctrl-C both
@@ -0,0 +1,12 @@
1
+ export interface LocalInstructionIdentity {
2
+ daemonId: string;
3
+ serverUrl: string;
4
+ profile: string;
5
+ connected: boolean;
6
+ userId?: string;
7
+ }
8
+ /** Cloud ownership never proves locality. Verify the exact profile over loopback. */
9
+ export declare function resolveLocalInstructionDaemon(options?: {
10
+ waitMs?: number;
11
+ log?: (message: string) => void;
12
+ }): Promise<string | null>;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveLocalInstructionDaemon = resolveLocalInstructionDaemon;
4
+ const loopback_http_1 = require("@skrr-ai/auth-core/loopback-http");
5
+ const data_provider_1 = require("@skrr-ai/data-provider");
6
+ const config_1 = require("./config");
7
+ const daemonBroker_1 = require("./daemonBroker");
8
+ const keychain_1 = require("./keychain");
9
+ /** Cloud ownership never proves locality. Verify the exact profile over loopback. */
10
+ async function resolveLocalInstructionDaemon(options = {}) {
11
+ const profile = (0, keychain_1.getActiveProfile)();
12
+ const serverUrl = (0, config_1.loadConfig)().baseURL;
13
+ const deadline = Date.now() + (options.waitMs ?? 0);
14
+ let waiting = false;
15
+ for (;;) {
16
+ const daemonId = await inspectLocalInstructionDaemon(profile, serverUrl);
17
+ if (daemonId)
18
+ return daemonId;
19
+ if (Date.now() >= deadline)
20
+ return null;
21
+ if (!waiting) {
22
+ options.log?.('Waiting for the signed-in local daemon before instruction setup...');
23
+ waiting = true;
24
+ }
25
+ await new Promise((resolve) => setTimeout(resolve, Math.min(300, deadline - Date.now())));
26
+ }
27
+ }
28
+ async function inspectLocalInstructionDaemon(profile, serverUrl) {
29
+ for (const candidate of (0, daemonBroker_1.resolveExactProfileBootstrapPaths)(profile)) {
30
+ const bootstrap = (0, daemonBroker_1.readBootstrap)(candidate);
31
+ if (!bootstrap?.secret)
32
+ continue;
33
+ if (bootstrap.serverUrl &&
34
+ (0, daemonBroker_1.normalizeBaseUrl)(bootstrap.serverUrl) !== (0, daemonBroker_1.normalizeBaseUrl)(serverUrl))
35
+ continue;
36
+ try {
37
+ const response = await (0, loopback_http_1.loopbackFetch)(`http://${bootstrap.host}:${bootstrap.port}/managed-instructions/identity`, { headers: { 'X-Island-Secret': bootstrap.secret }, signal: AbortSignal.timeout(3_000) });
38
+ if (!response.ok)
39
+ continue;
40
+ const identity = (await response.json());
41
+ if (!identity.daemonId ||
42
+ identity.connected !== true ||
43
+ !identity.userId ||
44
+ (0, daemonBroker_1.normalizeBaseUrl)(identity.serverUrl) !== (0, daemonBroker_1.normalizeBaseUrl)(serverUrl) ||
45
+ identity.profile !== profile ||
46
+ (bootstrap.daemonId && identity.daemonId !== bootstrap.daemonId))
47
+ continue;
48
+ const user = await data_provider_1.dataService.getUser();
49
+ if (user.id === identity.userId)
50
+ return identity.daemonId;
51
+ }
52
+ catch {
53
+ // Old services, reconnecting auth and stale descriptors are recoverable.
54
+ // Never infer a replacement from other profiles or the account's machines.
55
+ }
56
+ }
57
+ return null;
58
+ }
@@ -0,0 +1,35 @@
1
+ import type { ManagedInstructionProvider, ManagedInstructionTarget, ManagedInstructionPrepareResponse } from '@skrr-ai/data-provider';
2
+ type PreparedOffer = ManagedInstructionPrepareResponse;
3
+ export interface InstructionSetupOptions {
4
+ log: (message: string) => void;
5
+ trigger: 'manual' | 'login' | 'task';
6
+ daemonId?: string;
7
+ providers?: ManagedInstructionProvider[];
8
+ trackingMode?: 'latest' | 'pinned';
9
+ yes?: boolean;
10
+ json?: boolean;
11
+ review?: boolean;
12
+ /** Only a successful credential handoff proves a local service is becoming ready. */
13
+ waitForLocalReady?: boolean;
14
+ }
15
+ export interface InstructionSetupResult {
16
+ status: 'skipped' | 'unavailable' | 'reviewed' | 'unchanged' | 'decided';
17
+ daemonId?: string;
18
+ message?: string;
19
+ prepared?: PreparedOffer;
20
+ targets: ManagedInstructionTarget[];
21
+ installed: ManagedInstructionTarget[];
22
+ decisions: Array<{
23
+ provider: ManagedInstructionProvider;
24
+ action: 'install' | 'snooze' | 'decline' | 'keep';
25
+ }>;
26
+ }
27
+ export declare function shouldSkipInstructionPrompt(): boolean;
28
+ export declare function instructionProviderLabel(provider: ManagedInstructionProvider): string;
29
+ /** Read-only preflight precedes every consent and every write to the API. */
30
+ export declare function runManagedInstructionSetup(options: InstructionSetupOptions): Promise<InstructionSetupResult>;
31
+ /** Optional onboarding must not change the successful login/task exit status. */
32
+ export declare function maybeOfferManagedInstructionSetup(options: Omit<InstructionSetupOptions, 'trigger'> & {
33
+ trigger: 'login' | 'task';
34
+ }): Promise<void>;
35
+ export {};