@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.
- package/README.md +153 -165
- package/bin/run.js +32 -0
- package/bin/update-npm-runner.cjs +33 -0
- package/bin/update-session.cjs +194 -0
- package/bin/update-worker.cjs +208 -0
- package/dist/base-command.js +0 -15
- package/dist/commands/agents/operating-plan.d.ts +11 -0
- package/dist/commands/agents/operating-plan.js +54 -0
- package/dist/commands/agents/roles/example.d.ts +11 -0
- package/dist/commands/agents/roles/example.js +30 -0
- package/dist/commands/{commitments/mode.d.ts → agents/roles/export.d.ts} +5 -5
- package/dist/commands/agents/roles/export.js +81 -0
- package/dist/commands/agents/roles/install.d.ts +12 -0
- package/dist/commands/agents/roles/install.js +48 -0
- package/dist/commands/agents/roles/list.d.ts +11 -0
- package/dist/commands/agents/roles/list.js +36 -0
- package/dist/commands/agents/roles/preview.d.ts +14 -0
- package/dist/commands/agents/roles/preview.js +49 -0
- package/dist/commands/agents/roles/withdraw.d.ts +13 -0
- package/dist/commands/agents/roles/withdraw.js +43 -0
- package/dist/commands/code/doctor.d.ts +1 -0
- package/dist/commands/code/doctor.js +6 -0
- package/dist/commands/code/index.js +4 -0
- package/dist/commands/code/install.d.ts +5 -62
- package/dist/commands/code/install.js +86 -279
- package/dist/commands/code/rollback.d.ts +8 -0
- package/dist/commands/code/rollback.js +20 -0
- package/dist/commands/code/update.d.ts +8 -37
- package/dist/commands/code/update.js +134 -213
- package/dist/commands/commitments/{autonomy-requests → cadence-requests}/decide.d.ts +5 -7
- package/dist/commands/commitments/{autonomy-requests → cadence-requests}/decide.js +13 -15
- package/dist/commands/commitments/cost.d.ts +1 -1
- package/dist/commands/commitments/cost.js +1 -1
- package/dist/commands/commitments/create.d.ts +0 -7
- package/dist/commands/commitments/create.js +9 -98
- package/dist/commands/commitments/delivery.js +3 -21
- package/dist/commands/commitments/doctor.js +28 -27
- package/dist/commands/commitments/effective-policy.js +5 -36
- package/dist/commands/commitments/evaluations.d.ts +15 -0
- package/dist/commands/commitments/evaluations.js +54 -0
- package/dist/commands/commitments/pack/activate.d.ts +11 -0
- package/dist/commands/commitments/pack/activate.js +22 -0
- package/dist/commands/commitments/pack/bind.js +1 -1
- package/dist/commands/commitments/remediate.js +2 -5
- package/dist/commands/commitments/show.js +1 -1
- package/dist/commands/commitments/update.js +9 -9
- package/dist/commands/commitments/wake-capabilities.d.ts +1 -3
- package/dist/commands/commitments/wake-capabilities.js +5 -21
- package/dist/commands/daemon/install.js +4 -0
- package/dist/commands/generate-recovery-code.d.ts +13 -1
- package/dist/commands/generate-recovery-code.js +146 -13
- package/dist/commands/instructions/guide.d.ts +20 -0
- package/dist/commands/instructions/guide.js +84 -0
- package/dist/commands/instructions/install.js +57 -33
- package/dist/commands/instructions/setup.d.ts +14 -0
- package/dist/commands/instructions/setup.js +72 -0
- package/dist/commands/integrations/execute.js +1 -1
- package/dist/commands/login.d.ts +5 -6
- package/dist/commands/login.js +27 -11
- package/dist/commands/logout.js +7 -7
- package/dist/commands/security/overview.d.ts +11 -0
- package/dist/commands/security/overview.js +158 -0
- package/dist/commands/spaces/claim.d.ts +12 -0
- package/dist/commands/spaces/claim.js +42 -0
- package/dist/commands/spaces/ownership.d.ts +12 -0
- package/dist/commands/spaces/ownership.js +46 -0
- package/dist/commands/tasks/cancel-cascade.js +1 -1
- package/dist/commands/tasks/create-tree.d.ts +5 -1
- package/dist/commands/tasks/create-tree.js +35 -7
- package/dist/commands/tasks/interrupt.js +2 -2
- package/dist/commands/tasks/pause-schedule.js +1 -1
- package/dist/commands/token/list.d.ts +3 -5
- package/dist/commands/token/list.js +99 -57
- package/dist/commands/update.d.ts +14 -0
- package/dist/commands/update.js +61 -0
- package/dist/generated/managed-instruction-guides.json +9 -0
- package/dist/hooks/init.d.ts +5 -0
- package/dist/hooks/init.js +27 -0
- package/dist/lib/commitment-product.d.ts +0 -6
- package/dist/lib/commitment-product.js +1 -30
- package/dist/lib/commitments.d.ts +9 -53
- package/dist/lib/commitments.js +23 -146
- package/dist/lib/daemon-installer.d.ts +2 -0
- package/dist/lib/daemon-installer.js +100 -24
- package/dist/lib/first-party-harness-doctor.js +31 -1
- package/dist/lib/first-party-harness-remote-install.d.ts +71 -0
- package/dist/lib/first-party-harness-remote-install.js +310 -0
- package/dist/lib/first-party-harness-remote-update.d.ts +46 -0
- package/dist/lib/first-party-harness-remote-update.js +242 -0
- package/dist/lib/first-party-harness-startup-update.d.ts +26 -0
- package/dist/lib/first-party-harness-startup-update.js +166 -0
- package/dist/lib/first-party-harness-update.d.ts +46 -0
- package/dist/lib/first-party-harness-update.js +289 -0
- package/dist/lib/first-party-harness.js +7 -4
- package/dist/lib/managed-instruction-local.d.ts +12 -0
- package/dist/lib/managed-instruction-local.js +58 -0
- package/dist/lib/managed-instruction-setup.d.ts +35 -0
- package/dist/lib/managed-instruction-setup.js +306 -0
- package/dist/lib/memory-sync.d.ts +1 -0
- package/dist/lib/memory-sync.js +279 -68
- package/dist/lib/northstars.js +1 -1
- package/dist/lib/platform-update-local.d.ts +2 -0
- package/dist/lib/platform-update-local.js +113 -0
- package/dist/lib/platform-update.d.ts +39 -0
- package/dist/lib/platform-update.js +84 -0
- package/dist/lib/profile-machine-identity-guard.d.ts +2 -0
- package/dist/lib/profile-machine-identity-guard.js +13 -0
- package/dist/lib/prompt.d.ts +1 -0
- package/dist/lib/prompt.js +4 -3
- package/dist/lib/roles.d.ts +98 -0
- package/dist/lib/roles.js +45 -0
- package/dist/lib/task-batch.d.ts +9 -0
- package/dist/lib/task-batch.js +94 -17
- package/dist/lib/task-instruction-offer.d.ts +1 -4
- package/dist/lib/task-instruction-offer.js +3 -129
- package/dist/lib/update-check.d.ts +61 -53
- package/dist/lib/update-check.js +453 -314
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/commitmentExecutionContract.d.ts +45 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/commitmentExecutionContract.js +550 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessChannels.d.ts +3 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessChannels.js +3 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessReleaseKeys.d.ts +82 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessReleaseKeys.js +105 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessUpdater.d.ts +110 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessUpdater.js +945 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessPermissionControls.d.ts +32 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessPermissionControls.js +62 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +4 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.js +35 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releasePolicy.d.ts +63 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releasePolicy.js +169 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releaseVersions.d.ts +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releaseVersions.js +44 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/sessionPermissionAuthority.d.ts +7 -44
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/sessionPermissionAuthority.js +8 -47
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/commitmentExecutionContract.d.ts +45 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/commitmentExecutionContract.js +545 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessChannels.d.ts +3 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessChannels.js +3 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessReleaseKeys.d.ts +82 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessReleaseKeys.js +102 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessUpdater.d.ts +110 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessUpdater.js +923 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessPermissionControls.d.ts +32 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessPermissionControls.js +59 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.js +35 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releasePolicy.d.ts +63 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releasePolicy.js +163 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releaseVersions.d.ts +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releaseVersions.js +41 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/sessionPermissionAuthority.d.ts +7 -44
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/sessionPermissionAuthority.js +8 -47
- package/dist/node_modules/@skrr-ai/auth-core/package.json +41 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +7362 -7232
- package/dist/node_modules/@skrr-ai/data-provider/package.json +2 -2
- package/docs/v1/README.md +28 -0
- package/docs/v1/api.md +55 -0
- package/docs/v1/changelog.md +16 -0
- package/docs/v1/check-examples.mjs +178 -0
- package/docs/v1/examples/api-readonly.mjs +144 -0
- package/docs/v1/operations.md +87 -0
- package/docs/v1/quickstart.md +71 -0
- package/oclif.manifest.json +46381 -45478
- package/package.json +16 -11
- package/dist/commands/commitments/autonomy.d.ts +0 -30
- package/dist/commands/commitments/autonomy.js +0 -67
- package/dist/commands/commitments/mode.js +0 -58
- package/dist/commands/commitments/pack/promote.d.ts +0 -19
- package/dist/commands/commitments/pack/promote.js +0 -46
- package/dist/commands/commitments/pack/shadow.d.ts +0 -20
- package/dist/commands/commitments/pack/shadow.js +0 -42
package/dist/lib/commitments.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.COMMITMENT_CLI_EVALUATORS = exports.COMMITMENT_CREATE_KEYS = exports.COMMITMENT_REMEDIATION_ACTIONS = exports.COMMITMENT_FEEDBACK_KINDS = exports.commitmentApi = exports.commitmentPackApi = exports.MAX_COMMITMENT_INTERVAL_MS = exports.MIN_COMMITMENT_INTERVAL_MS = exports.COMMITMENT_EXECUTION_ISOLATION_MODES = exports.
|
|
4
|
-
exports.storedAutonomyModeForAuthoring = storedAutonomyModeForAuthoring;
|
|
5
|
-
exports.authoringAutonomyModeForStored = authoringAutonomyModeForStored;
|
|
6
|
-
exports.commitmentAutonomyLabel = commitmentAutonomyLabel;
|
|
3
|
+
exports.COMMITMENT_CLI_EVALUATORS = exports.COMMITMENT_CREATE_KEYS = exports.COMMITMENT_REMEDIATION_ACTIONS = exports.COMMITMENT_FEEDBACK_KINDS = exports.commitmentApi = exports.commitmentPackApi = exports.MAX_COMMITMENT_INTERVAL_MS = exports.MIN_COMMITMENT_INTERVAL_MS = exports.COMMITMENT_EXECUTION_ISOLATION_MODES = exports.COMMITMENT_AUTHORABLE_CADENCE_MODES = exports.COMMITMENT_KIND_VALUES = exports.COMMITMENT_STATUSES = exports.COMMITMENT_CADENCE_MAX_TIMES = exports.COMMITMENT_CADENCE_TIME_PATTERN = exports.COMMITMENT_CADENCE_MODES = exports.COMMITMENT_TEMPLATE_IDS = exports.COMMITMENT_WATCHED_SOURCES = void 0;
|
|
7
4
|
exports.permissionLines = permissionLines;
|
|
8
5
|
exports.retiredFieldsLine = retiredFieldsLine;
|
|
9
6
|
exports.readCommitmentAgentDirective = readCommitmentAgentDirective;
|
|
@@ -14,14 +11,11 @@ exports.describeCommitmentConcurrency = describeCommitmentConcurrency;
|
|
|
14
11
|
exports.parseIntervalToMs = parseIntervalToMs;
|
|
15
12
|
exports.buildWatchedSources = buildWatchedSources;
|
|
16
13
|
exports.describeEvidenceHealth = describeEvidenceHealth;
|
|
17
|
-
exports.describeStalledHealth = describeStalledHealth;
|
|
18
14
|
exports.describeIntervalMs = describeIntervalMs;
|
|
19
15
|
exports.buildSuccessCriteria = buildSuccessCriteria;
|
|
20
16
|
exports.cadenceLabel = cadenceLabel;
|
|
21
17
|
exports.renderCommitmentList = renderCommitmentList;
|
|
22
|
-
exports.effectiveAutonomyMode = effectiveAutonomyMode;
|
|
23
18
|
exports.extractStandstillFromCheck = extractStandstillFromCheck;
|
|
24
|
-
exports.describeAutonomyLine = describeAutonomyLine;
|
|
25
19
|
exports.describeExecutorBlocked = describeExecutorBlocked;
|
|
26
20
|
exports.renderCommitmentSummary = renderCommitmentSummary;
|
|
27
21
|
exports.describeWakeDecision = describeWakeDecision;
|
|
@@ -63,7 +57,6 @@ Object.defineProperty(exports, "COMMITMENT_TEMPLATE_IDS", { enumerable: true, ge
|
|
|
63
57
|
Object.defineProperty(exports, "COMMITMENT_CADENCE_MODES", { enumerable: true, get: function () { return data_provider_1.COMMITMENT_CADENCE_MODES; } });
|
|
64
58
|
Object.defineProperty(exports, "COMMITMENT_CADENCE_TIME_PATTERN", { enumerable: true, get: function () { return data_provider_1.COMMITMENT_CADENCE_TIME_PATTERN; } });
|
|
65
59
|
Object.defineProperty(exports, "COMMITMENT_CADENCE_MAX_TIMES", { enumerable: true, get: function () { return data_provider_1.COMMITMENT_CADENCE_MAX_TIMES; } });
|
|
66
|
-
Object.defineProperty(exports, "COMMITMENT_AUTONOMY_MODES", { enumerable: true, get: function () { return data_provider_1.COMMITMENT_AUTONOMY_MODES; } });
|
|
67
60
|
Object.defineProperty(exports, "COMMITMENT_EXECUTION_ISOLATION_MODES", { enumerable: true, get: function () { return data_provider_1.COMMITMENT_EXECUTION_ISOLATION_MODES; } });
|
|
68
61
|
Object.defineProperty(exports, "COMMITMENT_STATUSES", { enumerable: true, get: function () { return data_provider_1.COMMITMENT_STATUSES; } });
|
|
69
62
|
Object.defineProperty(exports, "COMMITMENT_KIND_VALUES", { enumerable: true, get: function () { return data_provider_1.COMMITMENT_KIND_VALUES; } });
|
|
@@ -74,34 +67,6 @@ const triggers_1 = require("./triggers");
|
|
|
74
67
|
/** Derived from the installed compatibility vocabulary so the CLI remains
|
|
75
68
|
* safe even while data-provider and CLI packages roll out separately. */
|
|
76
69
|
exports.COMMITMENT_AUTHORABLE_CADENCE_MODES = data_provider_1.COMMITMENT_CADENCE_MODES.filter((mode) => mode !== 'sampled');
|
|
77
|
-
exports.COMMITMENT_AUTHORABLE_AUTONOMY_MODES = ['monitor', 'prepare', 'execute'];
|
|
78
|
-
function storedAutonomyModeForAuthoring(mode) {
|
|
79
|
-
if (mode === 'monitor')
|
|
80
|
-
return 'suggestions_only';
|
|
81
|
-
if (mode === 'prepare')
|
|
82
|
-
return 'ask_first';
|
|
83
|
-
if (mode === 'execute')
|
|
84
|
-
return 'auto_run';
|
|
85
|
-
throw new Error(`Unsupported autonomy mode: ${mode}. Use monitor, prepare, or execute.`);
|
|
86
|
-
}
|
|
87
|
-
function authoringAutonomyModeForStored(mode) {
|
|
88
|
-
if (mode === 'ask_first')
|
|
89
|
-
return 'prepare';
|
|
90
|
-
if (mode === 'auto_run' || mode === 'auto_run_limited')
|
|
91
|
-
return 'execute';
|
|
92
|
-
return 'monitor';
|
|
93
|
-
}
|
|
94
|
-
function commitmentAutonomyLabel(mode) {
|
|
95
|
-
if (mode === 'suggestions_only')
|
|
96
|
-
return 'Monitor';
|
|
97
|
-
if (mode === 'ask_first')
|
|
98
|
-
return 'Prepare';
|
|
99
|
-
if (mode === 'auto_run' || mode === 'auto_run_limited')
|
|
100
|
-
return 'Execute';
|
|
101
|
-
if (mode === 'off')
|
|
102
|
-
return 'Legacy off (pause the Commitment)';
|
|
103
|
-
return mode || '-';
|
|
104
|
-
}
|
|
105
70
|
/**
|
|
106
71
|
* Interval bounds for `cadence.intervalMs`.
|
|
107
72
|
*
|
|
@@ -151,8 +116,7 @@ exports.commitmentPackApi = {
|
|
|
151
116
|
preflight: (id, nextRunCount) => data_provider_1.request.post(`${packBase(id)}/preflight`, {
|
|
152
117
|
...(typeof nextRunCount === 'number' ? { nextRunCount } : {}),
|
|
153
118
|
}),
|
|
154
|
-
|
|
155
|
-
promote: (id) => data_provider_1.request.post(`${packBase(id)}/promote`, {}),
|
|
119
|
+
activate: (id) => data_provider_1.request.post(`${packBase(id)}/activate`, {}),
|
|
156
120
|
};
|
|
157
121
|
exports.commitmentApi = {
|
|
158
122
|
/**
|
|
@@ -217,8 +181,6 @@ exports.commitmentApi = {
|
|
|
217
181
|
pause: (id) => data_provider_1.request.post(`${base(id)}/pause`, {}),
|
|
218
182
|
resume: (id) => data_provider_1.request.post(`${base(id)}/resume`, {}),
|
|
219
183
|
complete: (id) => data_provider_1.request.post(`${base(id)}/complete`, {}),
|
|
220
|
-
autonomy: (id, body) => data_provider_1.request.post(`${base(id)}/autonomy`, body),
|
|
221
|
-
mode: (id, body) => data_provider_1.request.post(`${base(id)}/mode`, body),
|
|
222
184
|
delivery: (id, body) => data_provider_1.request.post(`${base(id)}/delivery`, body),
|
|
223
185
|
receipts: (id, query = 1) => data_provider_1.request.get((0, triggers_1.withQuery)(`${base(id)}/receipts`, typeof query === 'number' ? { limit: query } : query)),
|
|
224
186
|
receiptQuarterlyMetrics: (id, year, quarter) => data_provider_1.request.get((0, triggers_1.withQuery)(`${base(id)}/receipt-metrics/quarterly`, { year, quarter })),
|
|
@@ -325,6 +287,9 @@ exports.commitmentApi = {
|
|
|
325
287
|
* investigation of the same drift most needs answered before it starts.
|
|
326
288
|
*/
|
|
327
289
|
hypotheses: (id, query = {}) => data_provider_1.request.get((0, triggers_1.withQuery)(`${base(id)}/hypotheses`, query)),
|
|
290
|
+
evaluations: (id, query = {}) => data_provider_1.request.get((0, triggers_1.withQuery)(`${base(id)}/evaluations`, query)),
|
|
291
|
+
createEvaluation: (id, body) => data_provider_1.request.post(`${base(id)}/evaluations`, body),
|
|
292
|
+
retryEvaluationLearning: (id, scheduleId) => data_provider_1.request.post(`${base(id)}/evaluations/${encodeURIComponent(scheduleId)}/retry-learning`, {}),
|
|
328
293
|
observations: (id, query = {}) => data_provider_1.request.get((0, triggers_1.withQuery)(`${base(id)}/observations`, query)),
|
|
329
294
|
/* ------------------------------------------------------------------------ *
|
|
330
295
|
* Steering
|
|
@@ -334,7 +299,7 @@ exports.commitmentApi = {
|
|
|
334
299
|
/** Bounded, named corrections — never a free-form contract edit. */
|
|
335
300
|
remediate: (id, body) => data_provider_1.request.post(`${base(id)}/remediation`, body),
|
|
336
301
|
/** Approve/reject an Agent-proposed cadence change the server parked. */
|
|
337
|
-
|
|
302
|
+
decideCadenceRequest: (id, requestId, approved) => data_provider_1.request.post(`${base(id)}/cadence-requests/${encodeURIComponent(requestId)}/decision`, {
|
|
338
303
|
approved,
|
|
339
304
|
}),
|
|
340
305
|
linkGoal: (id, goalId) => data_provider_1.request.put(`${base(id)}/goals/${encodeURIComponent(goalId)}`, {}),
|
|
@@ -351,7 +316,6 @@ exports.COMMITMENT_REMEDIATION_ACTIONS = [
|
|
|
351
316
|
'pause_commitment',
|
|
352
317
|
'mute_user_nudges',
|
|
353
318
|
'reduce_nudge_frequency',
|
|
354
|
-
'tighten_policy',
|
|
355
319
|
'mark_noop',
|
|
356
320
|
];
|
|
357
321
|
/** The only keys `createBodySchema` (a `z.strictObject`) accepts. */
|
|
@@ -427,8 +391,8 @@ function parseCommitmentConcurrencyLimit(input) {
|
|
|
427
391
|
if (['unlimited', 'unbounded', 'none', 'null'].includes(raw))
|
|
428
392
|
return null;
|
|
429
393
|
const value = Number(raw);
|
|
430
|
-
if (!Number.isSafeInteger(value) || value <
|
|
431
|
-
throw new Error('--max-concurrent-runs must be "unlimited" or an integer from
|
|
394
|
+
if (!Number.isSafeInteger(value) || value < 0 || value > 100) {
|
|
395
|
+
throw new Error('--max-concurrent-runs must be "unlimited" or an integer from 0 to 100.');
|
|
432
396
|
}
|
|
433
397
|
return value;
|
|
434
398
|
}
|
|
@@ -453,7 +417,7 @@ function commitmentConcurrencyEnvelopePatch({ rawValue, reason, autonomous = pro
|
|
|
453
417
|
};
|
|
454
418
|
}
|
|
455
419
|
function describeCommitmentConcurrency(commitment) {
|
|
456
|
-
const envelope = commitment.policy?.
|
|
420
|
+
const envelope = commitment.policy?.executionBudget;
|
|
457
421
|
const limit = envelope?.maxConcurrentRuns;
|
|
458
422
|
const decision = envelope?.maxConcurrentRunsDecision;
|
|
459
423
|
if (limit == null) {
|
|
@@ -638,57 +602,6 @@ function describeEvidenceHealth(health, criteriaCount) {
|
|
|
638
602
|
}
|
|
639
603
|
return `${state}${detail}`;
|
|
640
604
|
}
|
|
641
|
-
/**
|
|
642
|
-
* Why a commitment is `stalled`, in the reconciler's own words.
|
|
643
|
-
*
|
|
644
|
-
* These clauses are the CLI voicing of the `details` table in
|
|
645
|
-
* `CommitmentLivenessReconciler.alertCopy` — an operator who gets the alert
|
|
646
|
-
* ("<name> is stalled — its expected checks are no longer arriving") and then
|
|
647
|
-
* runs `commitments show` must read the same sentence, or the two surfaces look
|
|
648
|
-
* like two different problems.
|
|
649
|
-
*
|
|
650
|
-
* `contract_version_mismatch` has no entry there because it is not a diagnosis;
|
|
651
|
-
* the reconciler synthesises it when the running contract is fenced behind the
|
|
652
|
-
* authored one. It still reaches `state.liveness.diagnosisKind`, so it needs a
|
|
653
|
-
* clause here or the one case with an obvious fix prints bare.
|
|
654
|
-
*/
|
|
655
|
-
const STALLED_DIAGNOSES = {
|
|
656
|
-
scheduler_stalled: 'its expected checks are no longer arriving',
|
|
657
|
-
work_failing: 'every recent run reached the agent and failed while doing the work',
|
|
658
|
-
runtime_failing: 'recent runs never started — the runtime refused them',
|
|
659
|
-
result_rejected: 'every recent run reached the agent, but its result was rejected',
|
|
660
|
-
observation_unreadable: 'the latest check could not read every configured source',
|
|
661
|
-
execution_budget_exhausted: 'recent planned work was skipped — the execution budget is exhausted',
|
|
662
|
-
no_advancement: 'no server-recorded advancement exists inside the declared window',
|
|
663
|
-
owner_action_blocked: 'a completed work run is blocked pending owner action',
|
|
664
|
-
contract_version_mismatch: 'the running contract is older than the authored one; its triggers have not resynced',
|
|
665
|
-
};
|
|
666
|
-
/**
|
|
667
|
-
* `stalled` is a verdict, not a reason. Printed bare it reads like `unknown`
|
|
668
|
-
* with a harsher word, and the operator's next move is to go and read run
|
|
669
|
-
* history to find what the reconciler had already decided. Returns undefined
|
|
670
|
-
* for every other health value, including `unknown` — "nobody has judged" has
|
|
671
|
-
* no diagnosis to name.
|
|
672
|
-
*/
|
|
673
|
-
function describeStalledHealth(commitment) {
|
|
674
|
-
if (commitment.state?.health !== 'stalled')
|
|
675
|
-
return undefined;
|
|
676
|
-
const liveness = (commitment.state?.liveness || {});
|
|
677
|
-
const kind = typeof liveness.diagnosisKind === 'string' ? liveness.diagnosisKind : undefined;
|
|
678
|
-
const clause = (kind && STALLED_DIAGNOSES[kind]) ||
|
|
679
|
-
'this loop has stopped producing; the reconciler did not record which check failed';
|
|
680
|
-
// What refused and what to change, when the reconciler recorded them
|
|
681
|
-
// (OSK-12137). A machine failure has a specific fix; printing only the
|
|
682
|
-
// verdict would send the owner to read run history for it.
|
|
683
|
-
const code = typeof liveness.diagnosisCode === 'string' && liveness.diagnosisCode
|
|
684
|
-
? ` (${liveness.diagnosisCode})`
|
|
685
|
-
: '';
|
|
686
|
-
const since = typeof liveness.unhealthySinceAt === 'string' ? ` (since ${liveness.unhealthySinceAt})` : '';
|
|
687
|
-
const fix = typeof liveness.diagnosisFix === 'string' && liveness.diagnosisFix
|
|
688
|
-
? ` — ${liveness.diagnosisFix}`
|
|
689
|
-
: '';
|
|
690
|
-
return `${clause}${code}${since}${fix}`;
|
|
691
|
-
}
|
|
692
605
|
/** Render an interval back as a compact human string. */
|
|
693
606
|
function describeIntervalMs(ms) {
|
|
694
607
|
if (!ms || !Number.isFinite(ms))
|
|
@@ -777,16 +690,18 @@ function renderCommitmentList(commitments, log) {
|
|
|
777
690
|
id: o.id ?? '-',
|
|
778
691
|
title: o.title ?? '-',
|
|
779
692
|
status: o.status ?? '-',
|
|
780
|
-
|
|
693
|
+
outcome: o.assessment?.label ?? 'Unknown',
|
|
694
|
+
evidence: o.assessment?.evidence ?? 'unavailable',
|
|
695
|
+
operation: o.assessment?.operation ?? 'blocked',
|
|
781
696
|
cadence: cadenceLabel(o),
|
|
782
|
-
autonomy: (0, commitment_product_1.productModeLabel)(o.policy?.autonomyMode),
|
|
783
697
|
agent: o.agentId ?? '-',
|
|
784
698
|
})), [
|
|
785
699
|
{ key: 'title', header: 'TITLE', maxWidth: 34 },
|
|
786
700
|
{ key: 'status', header: 'STATUS', maxWidth: 10 },
|
|
787
|
-
{ key: '
|
|
701
|
+
{ key: 'outcome', header: 'OUTCOME', maxWidth: 16 },
|
|
702
|
+
{ key: 'evidence', header: 'EVIDENCE', maxWidth: 14 },
|
|
703
|
+
{ key: 'operation', header: 'OPERATION', maxWidth: 12 },
|
|
788
704
|
{ key: 'cadence', header: 'CADENCE', maxWidth: 10 },
|
|
789
|
-
{ key: 'autonomy', header: 'MODE', maxWidth: 18 },
|
|
790
705
|
{ key: 'agent', header: 'AGENT', verbatim: true },
|
|
791
706
|
// Commitment ids are routinely pasted into `check-now`, so this column
|
|
792
707
|
// is never clipped. Widening the guess (28 → 44) fixed today's
|
|
@@ -794,32 +709,6 @@ function renderCommitmentList(commitments, log) {
|
|
|
794
709
|
{ key: 'id', header: 'ID', verbatim: true },
|
|
795
710
|
], log);
|
|
796
711
|
}
|
|
797
|
-
/**
|
|
798
|
-
* The autonomy mode a check ACTUALLY ran at, read from its policy trace
|
|
799
|
-
* (OSK-4881).
|
|
800
|
-
*
|
|
801
|
-
* A check records the Mode it actually used in `decision.policyTrace`. For the
|
|
802
|
-
* v2 product contract, only an explicit Workspace-admin constraint may lower
|
|
803
|
-
* the declared Mode; legacy checks may still carry older effective-mode traces.
|
|
804
|
-
* Either `autonomyMode` or `effectiveAutonomyMode` answers what governed that
|
|
805
|
-
* particular run. Returns undefined when the trace carries neither.
|
|
806
|
-
*
|
|
807
|
-
* Exported for tests.
|
|
808
|
-
*/
|
|
809
|
-
function effectiveAutonomyMode(check) {
|
|
810
|
-
const trace = check?.decision?.policyTrace;
|
|
811
|
-
if (!Array.isArray(trace))
|
|
812
|
-
return undefined;
|
|
813
|
-
for (const entry of trace) {
|
|
814
|
-
if (!entry || typeof entry !== 'object')
|
|
815
|
-
continue;
|
|
816
|
-
const e = entry;
|
|
817
|
-
const mode = e.autonomyMode ?? e.effectiveAutonomyMode;
|
|
818
|
-
if (typeof mode === 'string' && mode.length)
|
|
819
|
-
return mode;
|
|
820
|
-
}
|
|
821
|
-
return undefined;
|
|
822
|
-
}
|
|
823
712
|
/**
|
|
824
713
|
* A `commitment_standstill` policyTrace entry, extracted from the latest
|
|
825
714
|
* check's decision. The arbiter appends it whenever a quiet posture is the
|
|
@@ -864,14 +753,6 @@ function extractStandstillFromCheck(check) {
|
|
|
864
753
|
*
|
|
865
754
|
* Exported for tests.
|
|
866
755
|
*/
|
|
867
|
-
function describeAutonomyLine(commitment, latestCheck) {
|
|
868
|
-
const stated = commitment.policy?.autonomyMode ?? '-';
|
|
869
|
-
const effective = effectiveAutonomyMode(latestCheck);
|
|
870
|
-
if (effective && effective !== stated) {
|
|
871
|
-
return `${(0, commitment_product_1.productModeLabel)(stated)} (effective: ${(0, commitment_product_1.productModeLabel)(effective)} — constrained by configured policy)`;
|
|
872
|
-
}
|
|
873
|
-
return (0, commitment_product_1.productModeLabel)(stated);
|
|
874
|
-
}
|
|
875
756
|
/**
|
|
876
757
|
* One-line rendering of `commitment.executorBlocked` — the B4/A7 signal that
|
|
877
758
|
* the executor's targets are all unusable: `{reason:'quota'|'offline'|'waiting_for_machine', until?,
|
|
@@ -927,21 +808,17 @@ latestCheck) {
|
|
|
927
808
|
if (commitment.target?.deadlineAt)
|
|
928
809
|
log(`Deadline: ${commitment.target.deadlineAt}`);
|
|
929
810
|
log(`Cadence: ${cadenceLabel(commitment)}`);
|
|
930
|
-
log(`Mode: ${describeAutonomyLine(commitment, latestCheck)}`);
|
|
931
811
|
log(`Delivery: ${(0, commitment_product_1.deliveryLabel)(commitment.delivery?.mode)}${commitment.delivery?.repo ? ` · ${commitment.delivery.repo}` : ''}${commitment.delivery?.baseBranch ? ` → ${commitment.delivery.baseBranch}` : ''}`);
|
|
932
812
|
log(`Concurrency: ${describeCommitmentConcurrency(commitment)}`);
|
|
933
813
|
const criteria = commitment.target?.successCriteria || [];
|
|
934
814
|
const evidenceHealth = latestCheck?.inputs?.evidenceHealth;
|
|
935
815
|
const evidenceLine = describeEvidenceHealth(evidenceHealth, criteria.length);
|
|
936
|
-
const
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
const stalledExplanation = describeStalledHealth(commitment);
|
|
943
|
-
const healthExplanation = unevidenceableExplanation || (stalledExplanation ? ` — ${stalledExplanation}` : '');
|
|
944
|
-
log(`Health: ${health}${healthExplanation}`);
|
|
816
|
+
const assessment = commitment.assessment
|
|
817
|
+
? (0, data_provider_1.readCommitmentAssessment)(commitment.assessment)
|
|
818
|
+
: undefined;
|
|
819
|
+
log(`Assessment: ${assessment?.label ?? 'Unknown'}`);
|
|
820
|
+
log(`Evidence: ${assessment?.evidence ?? 'unavailable'}`);
|
|
821
|
+
log(`Operation: ${assessment?.operation ?? 'blocked'}${assessment?.operationReason ? ` — ${assessment.operationReason}` : ''}`);
|
|
945
822
|
if (commitment.state?.lastCheckedAt)
|
|
946
823
|
log(`Checked: ${commitment.state.lastCheckedAt}`);
|
|
947
824
|
if (typeof commitment.state?.consecutiveUnresolvedChecks === 'number') {
|
|
@@ -1016,8 +893,8 @@ const INVOCATION_SKIP_REASONS = {
|
|
|
1016
893
|
state_watch_intact: 'watch intact',
|
|
1017
894
|
// NAMES THE ENVELOPE, not "autonomy", because they are different fields.
|
|
1018
895
|
//
|
|
1019
|
-
// The server sets this code from `
|
|
1020
|
-
// (`WakeIntentResolver.js:35`, `
|
|
896
|
+
// The server sets this code from `executionBudget.enabled !== true`
|
|
897
|
+
// (`WakeIntentResolver.js:35`, `CommitmentCadenceService.js:12`). It was
|
|
1021
898
|
// rendered as "autonomy off", which a reader maps onto `policy.autonomyMode`
|
|
1022
899
|
// — the field the CLI prints as `Autonomy:` and the one `commitments autonomy`
|
|
1023
900
|
// sets. So a commitment sitting at `suggestions_only` reported "autonomy off",
|
|
@@ -20,6 +20,8 @@ export interface DaemonInstallOptions {
|
|
|
20
20
|
feedBase?: string;
|
|
21
21
|
/** Injected for tests; defaults to global fetch. */
|
|
22
22
|
fetchImpl?: typeof fetch;
|
|
23
|
+
/** Cancel an in-progress install, including consumption of a response body. */
|
|
24
|
+
signal?: AbortSignal;
|
|
23
25
|
/**
|
|
24
26
|
* Trust anchors. Defaults to the pinned production set; tests substitute a
|
|
25
27
|
* generated keypair, exactly as the first-party harness installer does. Passing an EMPTY
|
|
@@ -105,19 +105,106 @@ function daemonPlatformKey(platform = process.platform, arch = process.arch) {
|
|
|
105
105
|
function fail(code, error) {
|
|
106
106
|
return { ok: false, code, error };
|
|
107
107
|
}
|
|
108
|
-
|
|
108
|
+
class DownloadSizeLimitError extends Error {
|
|
109
|
+
constructor(maxBytes) {
|
|
110
|
+
super(`download exceeds the size ceiling (${maxBytes} bytes)`);
|
|
111
|
+
this.name = 'DownloadSizeLimitError';
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Own the request until EOF, rather than releasing its deadline at headers.
|
|
116
|
+
* Count delivered bytes before retaining them; Content-Length is only an early
|
|
117
|
+
* refusal, since it may be absent, incorrect, or describe compressed bytes.
|
|
118
|
+
*/
|
|
119
|
+
async function getBytesWithTimeout(url, timeoutMs, maxBytes, fetchImpl, signal) {
|
|
120
|
+
signal?.throwIfAborted();
|
|
109
121
|
const controller = new AbortController();
|
|
110
|
-
|
|
122
|
+
let response;
|
|
123
|
+
let reader;
|
|
124
|
+
const cancelBody = (reason) => {
|
|
125
|
+
// Cancellation is best effort: a broken producer must not extend the
|
|
126
|
+
// deadline by returning a cancel promise that never settles.
|
|
127
|
+
try {
|
|
128
|
+
const cancelled = reader ? reader.cancel(reason) : response?.body?.cancel(reason);
|
|
129
|
+
void cancelled?.catch(() => undefined);
|
|
130
|
+
}
|
|
131
|
+
catch { /* response may already be closed */ }
|
|
132
|
+
};
|
|
133
|
+
let rejectAbort;
|
|
134
|
+
const aborted = new Promise((_, reject) => { rejectAbort = reject; });
|
|
135
|
+
const onAbort = () => {
|
|
136
|
+
rejectAbort(controller.signal.reason);
|
|
137
|
+
cancelBody(controller.signal.reason);
|
|
138
|
+
};
|
|
139
|
+
controller.signal.addEventListener('abort', onAbort, { once: true });
|
|
140
|
+
const onCallerAbort = () => controller.abort(signal?.reason);
|
|
141
|
+
signal?.addEventListener('abort', onCallerAbort, { once: true });
|
|
142
|
+
const timer = setTimeout(() => controller.abort(new Error(`download timed out after ${timeoutMs} ms`)), timeoutMs);
|
|
111
143
|
try {
|
|
112
|
-
|
|
144
|
+
const requested = fetchImpl(url, {
|
|
113
145
|
signal: controller.signal,
|
|
114
146
|
headers: { 'User-Agent': 'skrr-cli (daemon install)' },
|
|
147
|
+
}).then((res) => {
|
|
148
|
+
response = res;
|
|
149
|
+
// Injected transports can ignore AbortSignal. Dispose a response that
|
|
150
|
+
// arrives after our deadline rather than leaving its connection open.
|
|
151
|
+
if (controller.signal.aborted)
|
|
152
|
+
cancelBody(controller.signal.reason);
|
|
153
|
+
return res;
|
|
115
154
|
});
|
|
155
|
+
const downloaded = (async () => {
|
|
156
|
+
response = await requested;
|
|
157
|
+
controller.signal.throwIfAborted();
|
|
158
|
+
if (!response.ok)
|
|
159
|
+
throw new Error(`returned HTTP ${response.status}`);
|
|
160
|
+
const contentLength = response.headers.get('content-length');
|
|
161
|
+
if (contentLength && /^\d+$/.test(contentLength.trim()) && Number(contentLength) > maxBytes) {
|
|
162
|
+
throw new DownloadSizeLimitError(maxBytes);
|
|
163
|
+
}
|
|
164
|
+
if (!response.body)
|
|
165
|
+
return Buffer.alloc(0);
|
|
166
|
+
reader = response.body.getReader();
|
|
167
|
+
// Grow one buffer rather than retaining a separate allocation per chunk.
|
|
168
|
+
// A producer emitting tiny chunks must not defeat the byte ceiling with
|
|
169
|
+
// unbounded chunk metadata.
|
|
170
|
+
let bytes = Buffer.alloc(0);
|
|
171
|
+
let receivedBytes = 0;
|
|
172
|
+
for (;;) {
|
|
173
|
+
const { done, value } = await reader.read();
|
|
174
|
+
controller.signal.throwIfAborted();
|
|
175
|
+
if (done)
|
|
176
|
+
break;
|
|
177
|
+
if (value.byteLength > maxBytes - receivedBytes)
|
|
178
|
+
throw new DownloadSizeLimitError(maxBytes);
|
|
179
|
+
const neededBytes = receivedBytes + value.byteLength;
|
|
180
|
+
if (neededBytes > bytes.byteLength) {
|
|
181
|
+
const nextBytes = Buffer.allocUnsafe(Math.min(maxBytes, Math.max(64 * 1_024, bytes.byteLength * 2, neededBytes)));
|
|
182
|
+
bytes.copy(nextBytes, 0, 0, receivedBytes);
|
|
183
|
+
bytes = nextBytes;
|
|
184
|
+
}
|
|
185
|
+
bytes.set(value, receivedBytes);
|
|
186
|
+
receivedBytes += value.byteLength;
|
|
187
|
+
}
|
|
188
|
+
return bytes.subarray(0, receivedBytes);
|
|
189
|
+
})();
|
|
190
|
+
// Race the entire transfer once: racing each read retains an abort-promise
|
|
191
|
+
// reaction per chunk until the download ends.
|
|
192
|
+
return await Promise.race([downloaded, aborted]);
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
controller.abort(err);
|
|
196
|
+
throw err;
|
|
116
197
|
}
|
|
117
198
|
finally {
|
|
118
199
|
clearTimeout(timer);
|
|
200
|
+
signal?.removeEventListener('abort', onCallerAbort);
|
|
201
|
+
controller.signal.removeEventListener('abort', onAbort);
|
|
202
|
+
reader?.releaseLock();
|
|
119
203
|
}
|
|
120
204
|
}
|
|
205
|
+
function errorMessage(error) {
|
|
206
|
+
return error instanceof Error ? error.message : String(error);
|
|
207
|
+
}
|
|
121
208
|
/** Fetch `<feedBase>/latest/daemon-version.json` and verify its signature. */
|
|
122
209
|
async function fetchVerifiedDaemonManifest(opts = {}) {
|
|
123
210
|
const env = opts.env ?? process.env;
|
|
@@ -125,19 +212,16 @@ async function fetchVerifiedDaemonManifest(opts = {}) {
|
|
|
125
212
|
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
126
213
|
const keys = opts.keys ?? auth_core_1.OVERSKY_RELEASE_PUBLIC_KEYS;
|
|
127
214
|
const url = `${feedBase}/latest/daemon-version.json`;
|
|
128
|
-
let
|
|
215
|
+
let text;
|
|
129
216
|
try {
|
|
130
|
-
|
|
217
|
+
const bytes = await getBytesWithTimeout(url, MANIFEST_TIMEOUT_MS, MAX_MANIFEST_BYTES, fetchImpl, opts.signal);
|
|
218
|
+
text = bytes.toString('utf8');
|
|
131
219
|
}
|
|
132
220
|
catch (err) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
return fail('manifest_unreachable', `${url}
|
|
137
|
-
}
|
|
138
|
-
const text = await res.text();
|
|
139
|
-
if (text.length > MAX_MANIFEST_BYTES) {
|
|
140
|
-
return fail('manifest_malformed', 'release manifest is implausibly large');
|
|
221
|
+
if (err instanceof DownloadSizeLimitError) {
|
|
222
|
+
return fail('manifest_malformed', 'release manifest is implausibly large');
|
|
223
|
+
}
|
|
224
|
+
return fail('manifest_unreachable', `${url}: ${errorMessage(err)}`);
|
|
141
225
|
}
|
|
142
226
|
let manifest;
|
|
143
227
|
try {
|
|
@@ -172,7 +256,7 @@ async function installDaemon(opts = {}) {
|
|
|
172
256
|
if (!platformKey) {
|
|
173
257
|
return fail('unsupported_platform', `no daemon build for ${process.platform}-${process.arch}`);
|
|
174
258
|
}
|
|
175
|
-
const fetched = await fetchVerifiedDaemonManifest({ env, feedBase, fetchImpl, keys });
|
|
259
|
+
const fetched = await fetchVerifiedDaemonManifest({ env, feedBase, fetchImpl, keys, signal: opts.signal });
|
|
176
260
|
if (!('manifest' in fetched))
|
|
177
261
|
return fetched;
|
|
178
262
|
const { manifest } = fetched;
|
|
@@ -193,18 +277,10 @@ async function installDaemon(opts = {}) {
|
|
|
193
277
|
}
|
|
194
278
|
let bytes;
|
|
195
279
|
try {
|
|
196
|
-
|
|
197
|
-
if (!res.ok) {
|
|
198
|
-
return fail('download_failed', `${artifact.url} returned HTTP ${res.status}`);
|
|
199
|
-
}
|
|
200
|
-
const buf = Buffer.from(await res.arrayBuffer());
|
|
201
|
-
if (buf.byteLength > MAX_ARTIFACT_BYTES) {
|
|
202
|
-
return fail('download_failed', 'downloaded artifact exceeds the size ceiling');
|
|
203
|
-
}
|
|
204
|
-
bytes = buf;
|
|
280
|
+
bytes = await getBytesWithTimeout(artifact.url, ARTIFACT_TIMEOUT_MS, MAX_ARTIFACT_BYTES, fetchImpl, opts.signal);
|
|
205
281
|
}
|
|
206
282
|
catch (err) {
|
|
207
|
-
return fail('download_failed', `${artifact.url}: ${err
|
|
283
|
+
return fail('download_failed', `${artifact.url}: ${errorMessage(err)}`);
|
|
208
284
|
}
|
|
209
285
|
const actual = (0, node_crypto_1.createHash)('sha256').update(bytes).digest('hex');
|
|
210
286
|
if (actual !== artifact.sha256.toLowerCase()) {
|
|
@@ -41,6 +41,7 @@ const node_path_1 = __importDefault(require("node:path"));
|
|
|
41
41
|
const first_party_harness_1 = require("./first-party-harness");
|
|
42
42
|
const auth_core_1 = require("@skrr-ai/auth-core");
|
|
43
43
|
const harness_tiers_1 = require("./harness-tiers");
|
|
44
|
+
const first_party_harness_update_1 = require("./first-party-harness-update");
|
|
44
45
|
const first_party_harness_managed_1 = require("./first-party-harness-managed");
|
|
45
46
|
const first_party_harness_project_trust_1 = require("./first-party-harness-project-trust");
|
|
46
47
|
/**
|
|
@@ -103,7 +104,7 @@ function releaseChannelCheck(env) {
|
|
|
103
104
|
name: 'release-channel',
|
|
104
105
|
status: 'ok',
|
|
105
106
|
detail: `${channel} — ${canonical}`,
|
|
106
|
-
remedy: '
|
|
107
|
+
remedy: 'Run `skrr code update --check` to verify the published release, or fetch that URL to inspect it.' +
|
|
107
108
|
(alsoTried.length ? ` If it has none, an installer also tries ${alsoTried.join(', ')}.` : ''),
|
|
108
109
|
};
|
|
109
110
|
}
|
|
@@ -245,6 +246,34 @@ function engineCheck(env) {
|
|
|
245
246
|
remedy: `Install the engine (\`${auth_core_1.FIRST_PARTY_HARNESS.command} install\`), or set ${pathVar} to an existing build.`,
|
|
246
247
|
};
|
|
247
248
|
}
|
|
249
|
+
function engineUpdateCheck(env) {
|
|
250
|
+
const update = (0, first_party_harness_update_1.getLocalCodeUpdateStatus)(env);
|
|
251
|
+
const last = update.lastAttempt;
|
|
252
|
+
const completed = typeof last?.completedAt === 'number' ? new Date(last.completedAt) : null;
|
|
253
|
+
const completedAt = completed && Number.isFinite(completed.getTime()) ? completed.toISOString() : null;
|
|
254
|
+
const details = [
|
|
255
|
+
`installed ${update.installedVersion ?? (update.activePath ? 'version not recorded' : 'none')}`,
|
|
256
|
+
`owner ${update.owner}`,
|
|
257
|
+
update.installedVerified ? 'signed release verified' : null,
|
|
258
|
+
update.offeredVersion ? `latest ${update.offeredVersion}` : 'channel not checked recently',
|
|
259
|
+
last
|
|
260
|
+
? `last ${last.operation}: ${last.status}${completedAt ? ` at ${completedAt}` : ''}`
|
|
261
|
+
: 'no recorded update attempt',
|
|
262
|
+
]
|
|
263
|
+
.filter(Boolean)
|
|
264
|
+
.join('; ');
|
|
265
|
+
return {
|
|
266
|
+
name: 'engine-update',
|
|
267
|
+
status: last?.status === 'failed' || update.state === 'check-failed' ? 'warn' : 'ok',
|
|
268
|
+
detail: details,
|
|
269
|
+
remedy: last?.status === 'failed'
|
|
270
|
+
? `${last.error ?? last.code ?? 'Update failed.'} ${update.owner === 'managed' ? 'Retry with `skrr code update`.' : (update.message ?? update.command)}`
|
|
271
|
+
: (update.message ??
|
|
272
|
+
(update.state === 'update-available'
|
|
273
|
+
? 'Run `skrr code update` to install the signed release.'
|
|
274
|
+
: 'Run `skrr code update --check` to check the signed channel; `skrr code rollback` restores the previous verified release.')),
|
|
275
|
+
};
|
|
276
|
+
}
|
|
248
277
|
function stateDirCheck(cwd, env) {
|
|
249
278
|
const project = projectStateDir(cwd);
|
|
250
279
|
const user = (0, first_party_harness_1.engineHome)(env);
|
|
@@ -863,6 +892,7 @@ function agentAttributionCheck() {
|
|
|
863
892
|
function runDoctor(cwd = process.cwd(), env = process.env) {
|
|
864
893
|
const checks = [
|
|
865
894
|
engineCheck(env),
|
|
895
|
+
engineUpdateCheck(env),
|
|
866
896
|
releaseChannelCheck(env),
|
|
867
897
|
stateDirCheck(cwd, env),
|
|
868
898
|
compatCheck(cwd, env),
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { BaseCommand } from '../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* `skrr code install` — install the engine from the terminal.
|
|
4
|
+
*
|
|
5
|
+
* ── Why this command exists ────────────────────────────────────────────────
|
|
6
|
+
*
|
|
7
|
+
* `skrr code`'s not-installed message offered exactly two routes and neither
|
|
8
|
+
* worked without a browser: "In the web app: the runtime menu … → Install", or
|
|
9
|
+
* point the engine-path override at a build you already have — which is the thing
|
|
10
|
+
* you are trying to obtain, and the route that gives up provenance. So the
|
|
11
|
+
* ordinary case for a coding harness (a dev box over SSH, a CI runner, a cloud
|
|
12
|
+
* VM) had no way in (dogfood OSK-276).
|
|
13
|
+
*
|
|
14
|
+
* Nothing underneath was missing. The daemon has performed the verified install
|
|
15
|
+
* since 2026-08-08, and `POST /api/daemons/:id/cli-installers/:provider/install`
|
|
16
|
+
* has fronted it since June. The install was API-exposed and CLI-unreachable —
|
|
17
|
+
* the shape the root `CLAUDE.md` names under CLI ↔ API parity: "an endpoint the
|
|
18
|
+
* API exposes must be reachable from `skrr`."
|
|
19
|
+
*
|
|
20
|
+
* So this adds a SURFACE and no mechanism. Same route the web app posts, same
|
|
21
|
+
* daemon job, same signature verification. A second install path would be a
|
|
22
|
+
* second thing to keep in step with the first, and the first is the one that
|
|
23
|
+
* verifies the signed manifest.
|
|
24
|
+
*/
|
|
25
|
+
export default class CodeInstall extends BaseCommand {
|
|
26
|
+
static description: string;
|
|
27
|
+
static examples: string[];
|
|
28
|
+
static flags: {
|
|
29
|
+
daemon: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
30
|
+
wait: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
31
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
32
|
+
};
|
|
33
|
+
run(): Promise<void>;
|
|
34
|
+
/** Which daemon the install targets, by the rule every daemon-picking command shares. */
|
|
35
|
+
private resolveTarget;
|
|
36
|
+
/**
|
|
37
|
+
* The daemon id to install through, or the refusal.
|
|
38
|
+
*
|
|
39
|
+
* Refuses rather than guessing when several are active. Picking one would mean
|
|
40
|
+
* installing a hundred megabytes onto a machine the user was not thinking
|
|
41
|
+
* about. The candidates are CONNECTED daemons by the id the installer routes
|
|
42
|
+
* take (`listConnectedDaemons`), so the error names values that work — the
|
|
43
|
+
* Daemon resource list `skrr list-daemons` prints is a different id space
|
|
44
|
+
* (OSK-9993).
|
|
45
|
+
*
|
|
46
|
+
* A Dedicated Runtime's own machine is refused here, before any request. The
|
|
47
|
+
* daemon and the API refuse it too; saying so locally is what keeps the answer
|
|
48
|
+
* the same whether or not this machine's daemon is reachable, and whether or
|
|
49
|
+
* not it has published its id. Another of the owner's machines, named with
|
|
50
|
+
* `--daemon`, is not this machine and goes to the API like anywhere else.
|
|
51
|
+
*/
|
|
52
|
+
private installTarget;
|
|
53
|
+
/**
|
|
54
|
+
* What the daemon says about this provider, when it started no job.
|
|
55
|
+
*
|
|
56
|
+
* Read from the SAME list route the web app uses, so the CLI reports the
|
|
57
|
+
* daemon's own words rather than inventing an explanation for silence. Best
|
|
58
|
+
* effort: a failure here means falling back to the honest "does not say why",
|
|
59
|
+
* never to a guess.
|
|
60
|
+
*/
|
|
61
|
+
private installerNote;
|
|
62
|
+
/**
|
|
63
|
+
* Poll the job until it settles, printing each new log line.
|
|
64
|
+
*
|
|
65
|
+
* The daemon already writes a progress log — "Fetching the signed release
|
|
66
|
+
* manifest", "Verified and installed …" — and it is the only account
|
|
67
|
+
* of a hundred-megabyte download the user is waiting on. Printing only the
|
|
68
|
+
* lines not yet seen keeps a poll loop from repeating the whole log.
|
|
69
|
+
*/
|
|
70
|
+
private followJob;
|
|
71
|
+
}
|