@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
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UPDATE_COMPONENTS = void 0;
|
|
4
|
+
exports.normalizeComponentUpdateStatus = normalizeComponentUpdateStatus;
|
|
5
|
+
exports.runPlatformUpdate = runPlatformUpdate;
|
|
6
|
+
exports.describeComponentUpdate = describeComponentUpdate;
|
|
7
|
+
/** One local update surface; each installation owner still applies its own bytes. */
|
|
8
|
+
exports.UPDATE_COMPONENTS = ['cli', 'code', 'daemon'];
|
|
9
|
+
const optionalString = (value) => typeof value === 'string' && value.length > 0 ? value : null;
|
|
10
|
+
function normalizeComponentUpdateStatus(component, value) {
|
|
11
|
+
const raw = value && typeof value === 'object' && !Array.isArray(value)
|
|
12
|
+
? value
|
|
13
|
+
: {};
|
|
14
|
+
const command = optionalString(raw.command);
|
|
15
|
+
const commands = Array.isArray(raw.commands)
|
|
16
|
+
? raw.commands.filter((item) => typeof item === 'string')
|
|
17
|
+
: command
|
|
18
|
+
? [command]
|
|
19
|
+
: [];
|
|
20
|
+
return {
|
|
21
|
+
component,
|
|
22
|
+
state: optionalString(raw.state) ?? 'unknown',
|
|
23
|
+
runningVersion: optionalString(raw.runningVersion),
|
|
24
|
+
installedVersion: optionalString(raw.installedVersion) ?? optionalString(raw.currentVersion),
|
|
25
|
+
offeredVersion: optionalString(raw.offeredVersion) ?? optionalString(raw.latestVersion),
|
|
26
|
+
owner: optionalString(raw.owner) ?? optionalString(raw.installMethod) ?? 'unknown',
|
|
27
|
+
commands,
|
|
28
|
+
autoUpdateEnabled: typeof raw.autoUpdateEnabled === 'boolean'
|
|
29
|
+
? raw.autoUpdateEnabled
|
|
30
|
+
: typeof raw.autoUpdateAllowed === 'boolean'
|
|
31
|
+
? raw.autoUpdateAllowed
|
|
32
|
+
: null,
|
|
33
|
+
lastAttempt: raw.lastAttempt ?? raw.transaction ?? null,
|
|
34
|
+
detail: optionalString(raw.detail) ?? optionalString(raw.message),
|
|
35
|
+
status: raw,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function failedStatus(component, error) {
|
|
39
|
+
return normalizeComponentUpdateStatus(component, {
|
|
40
|
+
state: 'failed',
|
|
41
|
+
message: error instanceof Error ? error.message : String(error),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
async function runPlatformUpdate(options, dependencies) {
|
|
45
|
+
const components = options.component && options.component !== 'all' ? [options.component] : [...exports.UPDATE_COMPONENTS];
|
|
46
|
+
const run = async (component) => {
|
|
47
|
+
try {
|
|
48
|
+
return normalizeComponentUpdateStatus(component, await dependencies[component](options.mode, options));
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
return failedStatus(component, error);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
// Reads are independent. Writes remain sequential so their results and service
|
|
55
|
+
// restarts are observable, and a failed component never hides the others.
|
|
56
|
+
const statuses = [];
|
|
57
|
+
if (options.mode === 'apply') {
|
|
58
|
+
for (const component of components)
|
|
59
|
+
statuses.push(await run(component));
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
statuses.push(...(await Promise.all(components.map(run))));
|
|
63
|
+
}
|
|
64
|
+
const failureStates = new Set(['failed', 'check-failed', 'update-failed', 'rollback-failed']);
|
|
65
|
+
return {
|
|
66
|
+
schemaVersion: 1,
|
|
67
|
+
mode: options.mode,
|
|
68
|
+
components: statuses,
|
|
69
|
+
ok: statuses.every((item) => !failureStates.has(item.state)),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function describeComponentUpdate(status) {
|
|
73
|
+
const versions = [
|
|
74
|
+
`running ${status.runningVersion ?? '—'}`,
|
|
75
|
+
`installed ${status.installedVersion ?? 'unknown'}`,
|
|
76
|
+
`offered ${status.offeredVersion ?? 'unknown'}`,
|
|
77
|
+
].join(' · ');
|
|
78
|
+
return [
|
|
79
|
+
`${status.component}: ${status.state} (${status.owner})`,
|
|
80
|
+
` ${versions}`,
|
|
81
|
+
...(status.detail ? [` ${status.detail}`] : []),
|
|
82
|
+
...status.commands.map((command) => ` ${command}`),
|
|
83
|
+
].join('\n');
|
|
84
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.legacyProfileSharesDefaultMachine = legacyProfileSharesDefaultMachine;
|
|
4
|
+
const machine_uuid_1 = require("@skrr-ai/auth-core/machine-uuid");
|
|
5
|
+
const keychain_1 = require("./keychain");
|
|
6
|
+
/** An old profile may still share the default machine row and its device pin. */
|
|
7
|
+
function legacyProfileSharesDefaultMachine() {
|
|
8
|
+
const profile = (0, keychain_1.getActiveProfile)();
|
|
9
|
+
return (!!profile &&
|
|
10
|
+
profile !== 'default' &&
|
|
11
|
+
!(0, machine_uuid_1.hostedRuntimeIdOverride)('OVERSKY_MACHINE_UUID') &&
|
|
12
|
+
(0, machine_uuid_1.getMachineUuid)() === (0, machine_uuid_1.getHardwareMachineUuid)());
|
|
13
|
+
}
|
package/dist/lib/prompt.d.ts
CHANGED
package/dist/lib/prompt.js
CHANGED
|
@@ -52,10 +52,11 @@ const readline = __importStar(require("node:readline"));
|
|
|
52
52
|
*/
|
|
53
53
|
function prompt(question, opts = {}) {
|
|
54
54
|
const hidden = opts.hidden ?? false;
|
|
55
|
+
const output = opts.output ?? process.stdout;
|
|
55
56
|
return new Promise((resolve) => {
|
|
56
57
|
const rl = readline.createInterface({
|
|
57
58
|
input: process.stdin,
|
|
58
|
-
output
|
|
59
|
+
output,
|
|
59
60
|
});
|
|
60
61
|
if (hidden) {
|
|
61
62
|
const rlAny = rl;
|
|
@@ -65,12 +66,12 @@ function prompt(question, opts = {}) {
|
|
|
65
66
|
rlAny.output.write(char);
|
|
66
67
|
}
|
|
67
68
|
};
|
|
68
|
-
|
|
69
|
+
output.write(question);
|
|
69
70
|
}
|
|
70
71
|
rl.question(hidden ? '' : question, (answer) => {
|
|
71
72
|
rl.close();
|
|
72
73
|
if (hidden)
|
|
73
|
-
|
|
74
|
+
output.write('\n');
|
|
74
75
|
resolve(answer.trim());
|
|
75
76
|
});
|
|
76
77
|
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { InstalledRole, RolePlanPreview, RoleInstallation, AgentOperatingPlan } from '@skrr-ai/data-provider';
|
|
2
|
+
export declare const roleBase: (agentId: string) => string;
|
|
3
|
+
export declare const roleApi: {
|
|
4
|
+
list: (id: string) => Promise<{
|
|
5
|
+
roles: InstalledRole[];
|
|
6
|
+
canInstall: boolean;
|
|
7
|
+
skillInventory?: {
|
|
8
|
+
status: string;
|
|
9
|
+
skills: Array<{
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
versions: string[];
|
|
13
|
+
}>;
|
|
14
|
+
};
|
|
15
|
+
}>;
|
|
16
|
+
preview: (id: string, spec: unknown, contextBindings?: unknown) => Promise<RolePlanPreview>;
|
|
17
|
+
install: (id: string, preview: RolePlanPreview) => Promise<RoleInstallation>;
|
|
18
|
+
export: (id: string, key: string) => Promise<{
|
|
19
|
+
kind: "oversky.role-operating-spec";
|
|
20
|
+
schemaVersion: 1;
|
|
21
|
+
key: string;
|
|
22
|
+
revision: number;
|
|
23
|
+
title: string;
|
|
24
|
+
purpose: string;
|
|
25
|
+
scope: {
|
|
26
|
+
allow: string[];
|
|
27
|
+
deny: string[];
|
|
28
|
+
};
|
|
29
|
+
requiredCapabilities: string[];
|
|
30
|
+
skills: {
|
|
31
|
+
id: string;
|
|
32
|
+
version: string;
|
|
33
|
+
kind?: "skill" | "reader" | "evaluator" | undefined;
|
|
34
|
+
}[];
|
|
35
|
+
contextSlots: {
|
|
36
|
+
key: string;
|
|
37
|
+
label: string;
|
|
38
|
+
targetType: "space" | "task" | "project" | "goal";
|
|
39
|
+
}[];
|
|
40
|
+
communication: {
|
|
41
|
+
meaningfulChangesOnly: true;
|
|
42
|
+
interruptionLevel: "all" | "urgent" | "important";
|
|
43
|
+
};
|
|
44
|
+
responsibilities: {
|
|
45
|
+
key: string;
|
|
46
|
+
title: string;
|
|
47
|
+
kind: "achieve" | "maintain";
|
|
48
|
+
outcome: string;
|
|
49
|
+
successCriteria: {
|
|
50
|
+
id: string;
|
|
51
|
+
label: string;
|
|
52
|
+
evaluator?: "manual" | "metric" | "source_state" | "task_state" | "goal_state" | "llm_review" | undefined;
|
|
53
|
+
config?: Record<string, unknown> | undefined;
|
|
54
|
+
}[];
|
|
55
|
+
sources: {
|
|
56
|
+
source: "space" | "tasks" | "email" | "goal" | "files" | "local" | "daemon" | "browser" | "conversations" | "memory" | "slack" | "github" | "messages" | "metrics" | "monitor" | "agent_initiatives" | "docs" | "documents" | "calendar" | "product_metrics" | "business_metrics" | "state_monitor" | "agent_run";
|
|
57
|
+
enabled: boolean;
|
|
58
|
+
config?: Record<string, unknown> | undefined;
|
|
59
|
+
}[];
|
|
60
|
+
evidenceKeys: string[];
|
|
61
|
+
wake: {
|
|
62
|
+
mode: "manual" | "daily" | "interval" | "event_plus_interval";
|
|
63
|
+
timezone: string;
|
|
64
|
+
intervalMs?: number | undefined;
|
|
65
|
+
times?: string[] | undefined;
|
|
66
|
+
};
|
|
67
|
+
priority: "low" | "medium" | "high" | "critical";
|
|
68
|
+
budget: {
|
|
69
|
+
maxRunsPerDay: number;
|
|
70
|
+
maxCostUsdPerDay: number;
|
|
71
|
+
maxObservationRunsPerDay?: number | undefined;
|
|
72
|
+
maxConcurrentRuns?: number | undefined;
|
|
73
|
+
};
|
|
74
|
+
extensions: {
|
|
75
|
+
id: string;
|
|
76
|
+
version: string;
|
|
77
|
+
kind?: "skill" | "reader" | "evaluator" | undefined;
|
|
78
|
+
}[];
|
|
79
|
+
contexts: {
|
|
80
|
+
key: string;
|
|
81
|
+
roles: ("home" | "delivery" | "watch" | "advance")[];
|
|
82
|
+
}[];
|
|
83
|
+
directive?: string | undefined;
|
|
84
|
+
deadlineAt?: string | undefined;
|
|
85
|
+
freshness?: {
|
|
86
|
+
staleAfterMs?: number | undefined;
|
|
87
|
+
blockedAfterMs?: number | undefined;
|
|
88
|
+
noProgressAfterMs?: number | undefined;
|
|
89
|
+
} | undefined;
|
|
90
|
+
evaluationPolicy?: Record<string, unknown> | undefined;
|
|
91
|
+
learningPolicy?: Record<string, unknown> | undefined;
|
|
92
|
+
}[];
|
|
93
|
+
}>;
|
|
94
|
+
withdraw: (id: string, key: string, expectedCompassVersion: number) => Promise<RoleInstallation>;
|
|
95
|
+
plan: (id: string) => Promise<AgentOperatingPlan>;
|
|
96
|
+
};
|
|
97
|
+
export declare function readRoleJson(file: string): unknown;
|
|
98
|
+
export declare function assertRolePreview(value: unknown): asserts value is RolePlanPreview;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.roleApi = exports.roleBase = void 0;
|
|
4
|
+
exports.readRoleJson = readRoleJson;
|
|
5
|
+
exports.assertRolePreview = assertRolePreview;
|
|
6
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const roleBase = (agentId) => `/api/agents/${encodeURIComponent(agentId)}`;
|
|
9
|
+
exports.roleBase = roleBase;
|
|
10
|
+
exports.roleApi = {
|
|
11
|
+
list: (id) => data_provider_1.request.get(`${(0, exports.roleBase)(id)}/roles`),
|
|
12
|
+
preview: (id, spec, contextBindings = {}) => data_provider_1.request.post(`${(0, exports.roleBase)(id)}/roles/preview`, {
|
|
13
|
+
spec,
|
|
14
|
+
contextBindings,
|
|
15
|
+
}),
|
|
16
|
+
install: (id, preview) => data_provider_1.request.post(`${(0, exports.roleBase)(id)}/roles/install`, {
|
|
17
|
+
spec: preview.spec,
|
|
18
|
+
fingerprint: preview.fingerprint,
|
|
19
|
+
reviewFingerprint: preview.reviewFingerprint,
|
|
20
|
+
expectedCompassVersion: preview.expectedCompassVersion,
|
|
21
|
+
expectedVersions: preview.expectedVersions,
|
|
22
|
+
contextBindings: preview.contextBindings || {},
|
|
23
|
+
}),
|
|
24
|
+
export: (id, key) => data_provider_1.request.get(`${(0, exports.roleBase)(id)}/roles/${encodeURIComponent(key)}/export`),
|
|
25
|
+
withdraw: (id, key, expectedCompassVersion) => data_provider_1.request.post(`${(0, exports.roleBase)(id)}/roles/${encodeURIComponent(key)}/withdraw`, {
|
|
26
|
+
expectedCompassVersion,
|
|
27
|
+
}),
|
|
28
|
+
plan: (id) => data_provider_1.request.get(`${(0, exports.roleBase)(id)}/operating-plan`),
|
|
29
|
+
};
|
|
30
|
+
function readRoleJson(file) {
|
|
31
|
+
return JSON.parse((0, node_fs_1.readFileSync)(file, 'utf8'));
|
|
32
|
+
}
|
|
33
|
+
function assertRolePreview(value) {
|
|
34
|
+
const v = value;
|
|
35
|
+
if (!v ||
|
|
36
|
+
typeof v.fingerprint !== 'string' ||
|
|
37
|
+
typeof v.reviewFingerprint !== 'string' ||
|
|
38
|
+
!v.agentId ||
|
|
39
|
+
!Number.isInteger(v.expectedCompassVersion) ||
|
|
40
|
+
!v.spec ||
|
|
41
|
+
!v.expectedVersions ||
|
|
42
|
+
!Array.isArray(v.changes)) {
|
|
43
|
+
throw new Error('A server-generated preview is required. Run agents roles preview with --output first.');
|
|
44
|
+
}
|
|
45
|
+
}
|
package/dist/lib/task-batch.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export type ApiFailure = {
|
|
|
4
4
|
status?: number;
|
|
5
5
|
code?: string;
|
|
6
6
|
retryable: boolean;
|
|
7
|
+
requestId?: string;
|
|
7
8
|
};
|
|
8
9
|
/** Normalize a thrown API error (or a per-item batch error) into one shape. */
|
|
9
10
|
export declare function describeApiFailure(err: unknown): ApiFailure;
|
|
@@ -39,8 +40,16 @@ export type BatchCreateFailure = {
|
|
|
39
40
|
key: string;
|
|
40
41
|
/** Not attempted because its parent was not created (or an earlier chunk failed). */
|
|
41
42
|
skipped: boolean;
|
|
43
|
+
/** Unknown is submitted, not equivalent to not_attempted. */
|
|
44
|
+
outcome?: 'unknown' | 'not_attempted' | 'failed';
|
|
45
|
+
externalKey?: string;
|
|
42
46
|
error: ApiFailure;
|
|
43
47
|
};
|
|
48
|
+
/** A lost response is not a lost write. Only READ here; never retry a write. */
|
|
49
|
+
export declare function reconcileSubmittedNodes(nodes: BatchCreateNode[], mapping: Record<string, string>, error: ApiFailure, deadlineAt?: number): Promise<{
|
|
50
|
+
rows: BatchCreatedRow[];
|
|
51
|
+
failures: BatchCreateFailure[];
|
|
52
|
+
}>;
|
|
44
53
|
export type BatchCreateOutcome = {
|
|
45
54
|
supported: false;
|
|
46
55
|
} | {
|
package/dist/lib/task-batch.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.describeApiFailure = describeApiFailure;
|
|
|
4
4
|
exports.isBatchRouteMissing = isBatchRouteMissing;
|
|
5
5
|
exports.chunkItems = chunkItems;
|
|
6
6
|
exports.batchIdempotencyKey = batchIdempotencyKey;
|
|
7
|
+
exports.reconcileSubmittedNodes = reconcileSubmittedNodes;
|
|
7
8
|
exports.createNodesViaBatch = createNodesViaBatch;
|
|
8
9
|
exports.patchTasksViaBatch = patchTasksViaBatch;
|
|
9
10
|
/**
|
|
@@ -17,9 +18,10 @@ exports.patchTasksViaBatch = patchTasksViaBatch;
|
|
|
17
18
|
*/
|
|
18
19
|
const node_crypto_1 = require("node:crypto");
|
|
19
20
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
21
|
+
const tasks_1 = require("./tasks");
|
|
20
22
|
/** Normalize a thrown API error (or a per-item batch error) into one shape. */
|
|
21
23
|
function describeApiFailure(err) {
|
|
22
|
-
const e = err;
|
|
24
|
+
const e = (err ?? {});
|
|
23
25
|
let code = e.code;
|
|
24
26
|
let message = e.message ?? String(err);
|
|
25
27
|
if (e.body) {
|
|
@@ -37,7 +39,8 @@ function describeApiFailure(err) {
|
|
|
37
39
|
message,
|
|
38
40
|
...(status ? { status } : {}),
|
|
39
41
|
...(code ? { code } : {}),
|
|
40
|
-
|
|
42
|
+
...(e.requestId ? { requestId: e.requestId } : {}),
|
|
43
|
+
retryable: !status || status === 408 || status === 425 || status === 429 || (status ?? 0) >= 500,
|
|
41
44
|
};
|
|
42
45
|
}
|
|
43
46
|
/**
|
|
@@ -66,6 +69,52 @@ function batchIdempotencyKey(kind, items) {
|
|
|
66
69
|
const digest = (0, node_crypto_1.createHash)('sha256').update((0, data_provider_1.stableJson)(items)).digest('hex').slice(0, 40);
|
|
67
70
|
return `cli-${kind}-batch:${digest}`;
|
|
68
71
|
}
|
|
72
|
+
/** A lost response is not a lost write. Only READ here; never retry a write. */
|
|
73
|
+
async function reconcileSubmittedNodes(nodes, mapping, error, deadlineAt = Date.now() + 5000) {
|
|
74
|
+
const rows = [];
|
|
75
|
+
const failures = [];
|
|
76
|
+
// Limit simultaneous reads: a 100-item batch must not become 100 connections.
|
|
77
|
+
for (const group of chunkItems(nodes, 4)) {
|
|
78
|
+
await Promise.all(group.map(async (node) => {
|
|
79
|
+
const externalKey = typeof node.payload.externalKey === 'string' ? node.payload.externalKey : undefined;
|
|
80
|
+
if (externalKey && Date.now() < deadlineAt) {
|
|
81
|
+
let timer;
|
|
82
|
+
try {
|
|
83
|
+
const read = (0, tasks_1.findTaskByExternalKey)({
|
|
84
|
+
externalKey, spaceId: node.payload.spaceId, goalId: node.payload.goalId,
|
|
85
|
+
});
|
|
86
|
+
const existing = await Promise.race([read, new Promise((resolve) => {
|
|
87
|
+
timer = setTimeout(() => resolve(null), Math.max(1, deadlineAt - Date.now()));
|
|
88
|
+
})]);
|
|
89
|
+
if (existing?.task?.externalKey === externalKey && (0, tasks_1.taskId)(existing.task)) {
|
|
90
|
+
const id = (0, tasks_1.taskId)(existing.task);
|
|
91
|
+
mapping[node.key] = id;
|
|
92
|
+
rows.push({ key: node.key, id, status: 'exists', externalKey,
|
|
93
|
+
...(typeof existing.task.identifier === 'string' ? { identifier: existing.task.identifier } : {}),
|
|
94
|
+
});
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch { /* A failed read does not prove the write failed. */ }
|
|
99
|
+
finally {
|
|
100
|
+
clearTimeout(timer);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
failures.push({ key: node.key, skipped: false, outcome: 'unknown',
|
|
104
|
+
...(externalKey ? { externalKey } : {}),
|
|
105
|
+
error: { ...error, code: 'BATCH_OUTCOME_UNKNOWN', retryable: Boolean(externalKey),
|
|
106
|
+
message: `The result for "${node.key}" is unknown. ` +
|
|
107
|
+
(externalKey ? `No committed task was confirmed by external key "${externalKey}"; the original write may still finish. Re-run the same keyed tree to reconcile and resume.` :
|
|
108
|
+
'This node has no stable external key. Inspect the Space before another write; do not re-run --fresh blindly.'),
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
}));
|
|
112
|
+
}
|
|
113
|
+
const position = new Map(nodes.map((n, i) => [n.key, i]));
|
|
114
|
+
rows.sort((a, b) => position.get(a.key) - position.get(b.key));
|
|
115
|
+
failures.sort((a, b) => position.get(a.key) - position.get(b.key));
|
|
116
|
+
return { rows, failures };
|
|
117
|
+
}
|
|
69
118
|
/**
|
|
70
119
|
* Create `nodes` (parents before children) in chunks. `mapping` holds key -> id
|
|
71
120
|
* for nodes that already exist and is extended in place. Stops after the first
|
|
@@ -117,25 +166,45 @@ async function createNodesViaBatch(nodes, mapping) {
|
|
|
117
166
|
catch (err) {
|
|
118
167
|
if (chunkIndex === 0 && isBatchRouteMissing(err))
|
|
119
168
|
return { supported: false };
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
169
|
+
const error = describeApiFailure(err);
|
|
170
|
+
const uncertain = !error.status || error.status === 408 || error.status >= 500 || error.code === 'IDEMPOTENCY_IN_PROGRESS';
|
|
171
|
+
if (uncertain) {
|
|
172
|
+
const recovered = await reconcileSubmittedNodes(sent, mapping, error);
|
|
173
|
+
rows.push(...recovered.rows);
|
|
174
|
+
failures.push(...recovered.failures);
|
|
175
|
+
// Even a fully reconciled chunk stops here: no extra write follows a
|
|
176
|
+
// lost response during this run. Later chunks are explicitly unstarted.
|
|
177
|
+
const remaining = nodes.slice((chunkIndex + 1) * (data_provider_1.TASK_BATCH_MAX_ITEMS ?? 100));
|
|
178
|
+
for (const node of remaining)
|
|
179
|
+
failures.push({ key: node.key, skipped: true,
|
|
180
|
+
outcome: 'not_attempted', externalKey: node.payload.externalKey,
|
|
181
|
+
error: { message: 'Not started after a batch transport failure; resume the same keyed tree.', code: 'BATCH_NOT_ATTEMPTED', retryable: true }, });
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
for (const node of sent)
|
|
185
|
+
failures.push({ key: node.key, skipped: false, outcome: 'failed', error });
|
|
186
|
+
for (const node of nodes.slice((chunkIndex + 1) * (data_provider_1.TASK_BATCH_MAX_ITEMS ?? 100))) {
|
|
187
|
+
failures.push({ key: node.key, skipped: true, outcome: 'not_attempted',
|
|
188
|
+
error: { message: 'Not started after a batch refusal.', code: 'BATCH_NOT_ATTEMPTED', retryable: true } });
|
|
189
|
+
}
|
|
131
190
|
}
|
|
132
191
|
break;
|
|
133
192
|
}
|
|
134
193
|
let failed = false;
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
194
|
+
const reconciliationDeadlineAt = Date.now() + 5000;
|
|
195
|
+
for (const [i, node] of sent.entries()) {
|
|
196
|
+
const result = response.results?.find((r) => r.index === i);
|
|
197
|
+
if (!result || result.status === 'pending' || (result.ok && !result.id) || (result.error?.status ?? 0) >= 500) {
|
|
198
|
+
const recovered = await reconcileSubmittedNodes([{ ...node, payload: {
|
|
199
|
+
...node.payload, ...(result?.externalKey ? { externalKey: result.externalKey } : {}),
|
|
200
|
+
} }], mapping, {
|
|
201
|
+
message: 'Batch did not confirm this submitted write', code: 'BATCH_OUTCOME_UNKNOWN', retryable: true,
|
|
202
|
+
}, reconciliationDeadlineAt);
|
|
203
|
+
rows.push(...recovered.rows);
|
|
204
|
+
failures.push(...recovered.failures);
|
|
205
|
+
failed = true;
|
|
138
206
|
continue;
|
|
207
|
+
}
|
|
139
208
|
if (result.ok && result.id) {
|
|
140
209
|
mapping[node.key] = result.id;
|
|
141
210
|
rows.push({
|
|
@@ -151,6 +220,8 @@ async function createNodesViaBatch(nodes, mapping) {
|
|
|
151
220
|
failures.push({
|
|
152
221
|
key: node.key,
|
|
153
222
|
skipped: result.status === 'skipped',
|
|
223
|
+
outcome: result.status === 'skipped' ? 'not_attempted' : 'failed',
|
|
224
|
+
...(result.externalKey ? { externalKey: result.externalKey } : {}),
|
|
154
225
|
error: result.error
|
|
155
226
|
? {
|
|
156
227
|
message: result.error.message,
|
|
@@ -162,8 +233,14 @@ async function createNodesViaBatch(nodes, mapping) {
|
|
|
162
233
|
});
|
|
163
234
|
}
|
|
164
235
|
}
|
|
165
|
-
if (failed)
|
|
236
|
+
if (failed) {
|
|
237
|
+
for (const node of nodes.slice((chunkIndex + 1) * (data_provider_1.TASK_BATCH_MAX_ITEMS ?? 100))) {
|
|
238
|
+
failures.push({ key: node.key, skipped: true, outcome: 'not_attempted',
|
|
239
|
+
externalKey: node.payload.externalKey,
|
|
240
|
+
error: { message: 'Not started after an incomplete batch; resume the same keyed tree.', code: 'BATCH_NOT_ATTEMPTED', retryable: true }, });
|
|
241
|
+
}
|
|
166
242
|
break;
|
|
243
|
+
}
|
|
167
244
|
}
|
|
168
245
|
return { supported: true, rows, failures };
|
|
169
246
|
}
|
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Best-effort contextual activation after a human successfully uses a task
|
|
3
|
-
* command. It must never change the task command's exit status.
|
|
4
|
-
*/
|
|
1
|
+
/** Task creation and login share the same machine-bound, provider-scoped offer. */
|
|
5
2
|
export declare function maybeOfferTaskManagementInstructions(log: (message: string) => void): Promise<void>;
|
|
@@ -1,134 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.maybeOfferTaskManagementInstructions = maybeOfferTaskManagementInstructions;
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
const config_1 = require("./config");
|
|
7
|
-
const daemon_target_1 = require("./daemon-target");
|
|
8
|
-
const prompt_1 = require("./prompt");
|
|
9
|
-
const TEMPLATE_KEY = 'oversky-task-management';
|
|
10
|
-
function capabilitiesOf(daemon) {
|
|
11
|
-
if (Array.isArray(daemon.capabilities))
|
|
12
|
-
return daemon.capabilities.map(String);
|
|
13
|
-
if (typeof daemon.capabilities !== 'string')
|
|
14
|
-
return [];
|
|
15
|
-
try {
|
|
16
|
-
const parsed = JSON.parse(daemon.capabilities);
|
|
17
|
-
if (Array.isArray(parsed))
|
|
18
|
-
return parsed.map(String);
|
|
19
|
-
}
|
|
20
|
-
catch {
|
|
21
|
-
// Older daemon rows used comma-separated capabilities.
|
|
22
|
-
}
|
|
23
|
-
return daemon.capabilities
|
|
24
|
-
.split(',')
|
|
25
|
-
.map((capability) => capability.trim())
|
|
26
|
-
.filter(Boolean);
|
|
27
|
-
}
|
|
28
|
-
function detectedProviders(daemon) {
|
|
29
|
-
const capabilities = capabilitiesOf(daemon);
|
|
30
|
-
const providers = [];
|
|
31
|
-
if (capabilities.includes('claude_session'))
|
|
32
|
-
providers.push('claude');
|
|
33
|
-
if (capabilities.includes('codex_session'))
|
|
34
|
-
providers.push('codex');
|
|
35
|
-
// A daemon advertises the first-party harness under whichever spelling its
|
|
36
|
-
// version speaks; any of them means the harness is there, and the offer names
|
|
37
|
-
// it canonically, which is what the server stores.
|
|
38
|
-
if (capabilities.some(auth_core_1.isFirstPartyHarnessCapability))
|
|
39
|
-
providers.push(auth_core_1.FIRST_PARTY_HARNESS_PROVIDER);
|
|
40
|
-
return providers;
|
|
41
|
-
}
|
|
42
|
-
function providerLabel(provider) {
|
|
43
|
-
if (provider === 'claude')
|
|
44
|
-
return 'Claude Code';
|
|
45
|
-
if (provider === 'codex')
|
|
46
|
-
return 'Codex';
|
|
47
|
-
return auth_core_1.FIRST_PARTY_HARNESS.displayName;
|
|
48
|
-
}
|
|
49
|
-
function providerPath(provider) {
|
|
50
|
-
if (provider === 'claude')
|
|
51
|
-
return '~/.claude/CLAUDE.md';
|
|
52
|
-
if (provider === 'codex')
|
|
53
|
-
return '~/.codex/AGENTS.md';
|
|
54
|
-
// The engine home follows the ENGINE's namespace, not the provider slug — the
|
|
55
|
-
// engine reads its managed `AGENTS.md` from there (contract §5).
|
|
56
|
-
return `~/.skrr/${(0, auth_core_1.firstPartyHarnessHomeDirname)()}/AGENTS.md`;
|
|
57
|
-
}
|
|
58
|
-
function shouldSkipOffer() {
|
|
59
|
-
return Boolean(!process.stdin.isTTY ||
|
|
60
|
-
!process.stdout.isTTY ||
|
|
61
|
-
process.env.CI ||
|
|
62
|
-
process.env.OVERSKY_HEADLESS ||
|
|
63
|
-
process.env.OVERSKY_SESSION_TASK_ID ||
|
|
64
|
-
process.env.OVERSKY_SESSION_AGENT_ID ||
|
|
65
|
-
process.env.OVERSKY_DISABLE_INSTRUCTION_OFFER === '1');
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Best-effort contextual activation after a human successfully uses a task
|
|
69
|
-
* command. It must never change the task command's exit status.
|
|
70
|
-
*/
|
|
4
|
+
const managed_instruction_setup_1 = require("./managed-instruction-setup");
|
|
5
|
+
/** Task creation and login share the same machine-bound, provider-scoped offer. */
|
|
71
6
|
async function maybeOfferTaskManagementInstructions(log) {
|
|
72
|
-
|
|
73
|
-
return;
|
|
74
|
-
try {
|
|
75
|
-
// The offer speaks of "this machine", so on a Dedicated Runtime guest only the
|
|
76
|
-
// guest's own daemon may be the candidate — never the first eligible row of the
|
|
77
|
-
// account, which is the owner's laptop (OSK-8759). A guest whose daemon has
|
|
78
|
-
// published no id gets no candidate. Off a guest nothing is read here and the
|
|
79
|
-
// search below is unchanged.
|
|
80
|
-
const local = (0, daemon_target_1.localMachine)({ baseURL: (0, config_1.loadConfig)().baseURL });
|
|
81
|
-
if (local.dedicatedRuntime && !local.daemonId)
|
|
82
|
-
return;
|
|
83
|
-
const [daemons, offerResponse] = await Promise.all([
|
|
84
|
-
data_provider_1.dataService.getDaemons(),
|
|
85
|
-
data_provider_1.dataService.getManagedInstructionOffer(TEMPLATE_KEY),
|
|
86
|
-
]);
|
|
87
|
-
const candidate = daemons.active.find((daemon) => {
|
|
88
|
-
if (local.dedicatedRuntime && daemon.daemonId !== local.daemonId)
|
|
89
|
-
return false;
|
|
90
|
-
if (!detectedProviders(daemon).length)
|
|
91
|
-
return false;
|
|
92
|
-
return offerResponse.offers.find((offer) => offer.daemonId === daemon.daemonId)?.eligible;
|
|
93
|
-
});
|
|
94
|
-
if (!candidate)
|
|
95
|
-
return;
|
|
96
|
-
const providers = detectedProviders(candidate);
|
|
97
|
-
const labels = providers.map(providerLabel).join(' and ');
|
|
98
|
-
log('');
|
|
99
|
-
log(`Let ${labels} manage skrr tasks automatically?`);
|
|
100
|
-
log('skrr will add a removable managed block to the user-level agent files on this machine.');
|
|
101
|
-
log('Type v to review the exact instruction, y to install and keep it updated, or press Enter for not now.');
|
|
102
|
-
const answer = (await (0, prompt_1.prompt)('Install task-management instructions? [y/N/v] ')).toLowerCase();
|
|
103
|
-
let accepted = answer === 'y' || answer === 'yes';
|
|
104
|
-
if (answer === 'v' || answer === 'view') {
|
|
105
|
-
log('');
|
|
106
|
-
log('--- exact managed instruction ---');
|
|
107
|
-
log(offerResponse.preset.body);
|
|
108
|
-
log('--- end instruction ---');
|
|
109
|
-
log('');
|
|
110
|
-
log('Targets:');
|
|
111
|
-
for (const provider of providers) {
|
|
112
|
-
log(`- ${providerLabel(provider)}: ${providerPath(provider)}`);
|
|
113
|
-
}
|
|
114
|
-
accepted = await (0, prompt_1.confirm)('Install this instruction and keep it updated?', true);
|
|
115
|
-
}
|
|
116
|
-
if (!accepted) {
|
|
117
|
-
await data_provider_1.dataService.respondManagedInstructionOffer(TEMPLATE_KEY, {
|
|
118
|
-
daemonId: candidate.daemonId,
|
|
119
|
-
action: 'snooze',
|
|
120
|
-
});
|
|
121
|
-
log('Not now. skrr will not ask again for 14 days.');
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
await data_provider_1.dataService.acceptManagedInstructionOffer(TEMPLATE_KEY, {
|
|
125
|
-
daemonId: candidate.daemonId,
|
|
126
|
-
providers,
|
|
127
|
-
});
|
|
128
|
-
log(`Installation queued for ${labels}; check Settings for confirmed file status.`);
|
|
129
|
-
}
|
|
130
|
-
catch {
|
|
131
|
-
// A discovery nudge must never turn a successful task operation into a
|
|
132
|
-
// failed command. Settings remains the durable recovery/control surface.
|
|
133
|
-
}
|
|
7
|
+
await (0, managed_instruction_setup_1.maybeOfferManagedInstructionSetup)({ log, trigger: 'task' });
|
|
134
8
|
}
|