@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,194 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// This bootstrap uses only Node built-ins: npm may replace the package while
|
|
4
|
+
// the updater runs, so admission and the worker must not depend on its modules.
|
|
5
|
+
const fs = require('node:fs');
|
|
6
|
+
const os = require('node:os');
|
|
7
|
+
const path = require('node:path');
|
|
8
|
+
const crypto = require('node:crypto');
|
|
9
|
+
const { execFileSync } = require('node:child_process');
|
|
10
|
+
// Protocol 1: bakery admission lock, immutable PID/birth/token leases, and
|
|
11
|
+
// process-group mutation ownership. Its wire/locking contract is immutable.
|
|
12
|
+
// Future protocols must coexist with these sessions or require an external
|
|
13
|
+
// package-manager update; selecting a separate lock must never bypass them.
|
|
14
|
+
const COORDINATION_VERSION = 1;
|
|
15
|
+
|
|
16
|
+
function runtimeDir(packageRoot) {
|
|
17
|
+
const key = crypto
|
|
18
|
+
.createHash('sha256')
|
|
19
|
+
.update(path.resolve(packageRoot))
|
|
20
|
+
.digest('hex')
|
|
21
|
+
.slice(0, 24);
|
|
22
|
+
// Installation leases deliberately ignore SKRR_CONFIG_DIR: two profiles or
|
|
23
|
+
// config roots still share the same npm installation.
|
|
24
|
+
return path.join(os.homedir(), '.skrr', 'cli-update-runtime', key);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function readJson(file) {
|
|
28
|
+
try {
|
|
29
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
30
|
+
} catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function writeJson(file, value) {
|
|
36
|
+
fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
|
|
37
|
+
const temporary = `${file}.${process.pid}.${crypto.randomBytes(6).toString('hex')}.tmp`;
|
|
38
|
+
try {
|
|
39
|
+
fs.writeFileSync(temporary, JSON.stringify(value), { mode: 0o600, flag: 'wx' });
|
|
40
|
+
fs.renameSync(temporary, file);
|
|
41
|
+
} finally {
|
|
42
|
+
fs.rmSync(temporary, { force: true });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function processIdentity(pid) {
|
|
47
|
+
if (process.platform === 'win32') return null;
|
|
48
|
+
try {
|
|
49
|
+
return (
|
|
50
|
+
execFileSync('ps', ['-p', String(pid), '-o', 'lstart='], {
|
|
51
|
+
timeout: 500,
|
|
52
|
+
encoding: 'utf8',
|
|
53
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
54
|
+
}).trim() || null
|
|
55
|
+
);
|
|
56
|
+
} catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function isAlive(owner) {
|
|
62
|
+
if (!owner || !Number.isSafeInteger(owner.pid) || owner.pid <= 0) return false;
|
|
63
|
+
try {
|
|
64
|
+
process.kill(owner.group && process.platform !== 'win32' ? -owner.pid : owner.pid, 0);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
return error.code !== 'ESRCH';
|
|
67
|
+
}
|
|
68
|
+
// A recycled PID is not the process that created this lease. If the OS
|
|
69
|
+
// cannot disclose its identity, remain conservative rather than expiring a
|
|
70
|
+
// live session on a wall-clock timeout.
|
|
71
|
+
const identity = owner.identity && processIdentity(owner.pid);
|
|
72
|
+
return !identity || identity === owner.identity;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function wait(milliseconds) {
|
|
76
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function acquireLock(directory, timeoutMs = 1000) {
|
|
80
|
+
// Lamport's bakery algorithm, with one immutable participant filename per
|
|
81
|
+
// acquisition. Reaping a crashed participant never removes a replacement
|
|
82
|
+
// owner's lock (the stale-directory removal race of mkdir mutexes).
|
|
83
|
+
const deadline = Date.now() + timeoutMs;
|
|
84
|
+
fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
85
|
+
const owner = {
|
|
86
|
+
pid: process.pid,
|
|
87
|
+
identity: processIdentity(process.pid),
|
|
88
|
+
token: crypto.randomUUID(),
|
|
89
|
+
};
|
|
90
|
+
const participant = path.join(directory, `${owner.pid}-${owner.token}.json`);
|
|
91
|
+
const participants = () => {
|
|
92
|
+
const active = [];
|
|
93
|
+
for (const file of fs.readdirSync(directory)) {
|
|
94
|
+
if (!file.endsWith('.json')) continue;
|
|
95
|
+
const target = path.join(directory, file);
|
|
96
|
+
const record = readJson(target);
|
|
97
|
+
if (record && isAlive(record)) active.push(record);
|
|
98
|
+
else if (record) fs.rmSync(target, { force: true });
|
|
99
|
+
}
|
|
100
|
+
return active;
|
|
101
|
+
};
|
|
102
|
+
try {
|
|
103
|
+
writeJson(participant, { ...owner, choosing: true, ticket: 0 });
|
|
104
|
+
const ticket = Math.max(0, ...participants().map((record) => record.ticket || 0)) + 1;
|
|
105
|
+
writeJson(participant, { ...owner, choosing: false, ticket });
|
|
106
|
+
while (true) {
|
|
107
|
+
const blocked = participants().some(
|
|
108
|
+
(other) =>
|
|
109
|
+
other.token !== owner.token &&
|
|
110
|
+
(other.choosing ||
|
|
111
|
+
(other.ticket > 0 &&
|
|
112
|
+
(other.ticket < ticket || (other.ticket === ticket && other.token < owner.token)))),
|
|
113
|
+
);
|
|
114
|
+
if (!blocked)
|
|
115
|
+
return () => {
|
|
116
|
+
fs.rmSync(participant, { force: true });
|
|
117
|
+
};
|
|
118
|
+
if (Date.now() >= deadline)
|
|
119
|
+
throw Object.assign(new Error('CLI update lock is busy'), { code: 'CLI_UPDATE_BUSY' });
|
|
120
|
+
wait(25);
|
|
121
|
+
}
|
|
122
|
+
} catch (error) {
|
|
123
|
+
fs.rmSync(participant, { force: true });
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function liveLeases(directory) {
|
|
129
|
+
const leaseDir = path.join(directory, 'sessions');
|
|
130
|
+
fs.mkdirSync(leaseDir, { recursive: true, mode: 0o700 });
|
|
131
|
+
const live = [];
|
|
132
|
+
for (const file of fs.readdirSync(leaseDir)) {
|
|
133
|
+
const target = path.join(leaseDir, file);
|
|
134
|
+
const lease = readJson(target);
|
|
135
|
+
if (lease && isAlive(lease)) live.push(lease);
|
|
136
|
+
else fs.rmSync(target, { force: true });
|
|
137
|
+
}
|
|
138
|
+
return live;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function registerSession(packageRoot, timeoutMs = 60000) {
|
|
142
|
+
const directory = runtimeDir(packageRoot);
|
|
143
|
+
const deadline = Date.now() + timeoutMs;
|
|
144
|
+
while (true) {
|
|
145
|
+
const release = acquireLock(path.join(directory, 'admission.lock'), 1000);
|
|
146
|
+
try {
|
|
147
|
+
const mutationFile = path.join(directory, 'mutation.json');
|
|
148
|
+
const mutation = readJson(mutationFile);
|
|
149
|
+
if (!mutation || !isAlive(mutation)) {
|
|
150
|
+
if (mutation) fs.rmSync(mutationFile, { force: true });
|
|
151
|
+
const token = crypto.randomUUID();
|
|
152
|
+
const leaseFile = path.join(directory, 'sessions', `${process.pid}-${token}.json`);
|
|
153
|
+
writeJson(leaseFile, {
|
|
154
|
+
pid: process.pid,
|
|
155
|
+
identity: processIdentity(process.pid),
|
|
156
|
+
token,
|
|
157
|
+
coordinationVersion: COORDINATION_VERSION,
|
|
158
|
+
});
|
|
159
|
+
const cleanup = () => {
|
|
160
|
+
try {
|
|
161
|
+
fs.rmSync(leaseFile, { force: true });
|
|
162
|
+
} catch {
|
|
163
|
+
/* read-only home */
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
process.once('exit', cleanup);
|
|
167
|
+
return cleanup;
|
|
168
|
+
}
|
|
169
|
+
} finally {
|
|
170
|
+
release();
|
|
171
|
+
}
|
|
172
|
+
if (Date.now() >= deadline) {
|
|
173
|
+
throw Object.assign(
|
|
174
|
+
new Error(
|
|
175
|
+
'skrr is being updated by npm. Retry shortly; inspect `skrr update --check` after the update finishes.',
|
|
176
|
+
),
|
|
177
|
+
{ code: 'CLI_UPDATE_BUSY' },
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
wait(100);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
module.exports = {
|
|
185
|
+
COORDINATION_VERSION,
|
|
186
|
+
runtimeDir,
|
|
187
|
+
readJson,
|
|
188
|
+
writeJson,
|
|
189
|
+
processIdentity,
|
|
190
|
+
isAlive,
|
|
191
|
+
acquireLock,
|
|
192
|
+
liveLeases,
|
|
193
|
+
registerSession,
|
|
194
|
+
};
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Copied next to update-session.cjs outside the npm package before launch.
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
const crypto = require('node:crypto');
|
|
7
|
+
const { execFile, spawn } = require('node:child_process');
|
|
8
|
+
const { promisify } = require('node:util');
|
|
9
|
+
const runtime = require('./update-session.cjs');
|
|
10
|
+
const execFileAsync = promisify(execFile);
|
|
11
|
+
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
12
|
+
const MAX_WAIT_MS = 5 * 60 * 1000;
|
|
13
|
+
const INSTALL_TIMEOUT_MS = 10 * 60 * 1000;
|
|
14
|
+
const MAX_LOG_BYTES = 256 * 1024;
|
|
15
|
+
|
|
16
|
+
async function run(directory, options = {}) {
|
|
17
|
+
let releaseWorker;
|
|
18
|
+
try {
|
|
19
|
+
releaseWorker = runtime.acquireLock(path.join(directory, 'worker.lock'), 1000);
|
|
20
|
+
} catch (error) {
|
|
21
|
+
if (error.code === 'CLI_UPDATE_BUSY') return;
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
const stateFile = path.join(directory, 'result.json');
|
|
25
|
+
let mutation = false;
|
|
26
|
+
let mutationChild = null;
|
|
27
|
+
let attempt = runtime.readJson(stateFile);
|
|
28
|
+
const persist = (changes) => {
|
|
29
|
+
attempt = { ...attempt, ...changes, updatedAt: Date.now() };
|
|
30
|
+
runtime.writeJson(stateFile, attempt);
|
|
31
|
+
};
|
|
32
|
+
try {
|
|
33
|
+
if (!attempt || !['queued', 'running'].includes(attempt.status)) return;
|
|
34
|
+
if (
|
|
35
|
+
attempt.coordinationVersion != null &&
|
|
36
|
+
attempt.coordinationVersion !== runtime.COORDINATION_VERSION
|
|
37
|
+
)
|
|
38
|
+
throw new Error(
|
|
39
|
+
'Incompatible CLI update coordination protocol; use the owning package manager',
|
|
40
|
+
);
|
|
41
|
+
if (
|
|
42
|
+
!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(attempt.version) ||
|
|
43
|
+
!path.isAbsolute(attempt.packageRoot) ||
|
|
44
|
+
!path.isAbsolute(attempt.npmPath)
|
|
45
|
+
) {
|
|
46
|
+
throw new Error('Invalid persisted CLI update request');
|
|
47
|
+
}
|
|
48
|
+
// Serialize admission and the empty-session check. Newly starting CLIs
|
|
49
|
+
// then wait before loading oclif/package modules until npm has finished.
|
|
50
|
+
const deadline = Date.now() + (options.maxWaitMs ?? MAX_WAIT_MS);
|
|
51
|
+
while (true) {
|
|
52
|
+
const releaseAdmission = runtime.acquireLock(path.join(directory, 'admission.lock'), 1000);
|
|
53
|
+
try {
|
|
54
|
+
const previousMutation = runtime.readJson(path.join(directory, 'mutation.json'));
|
|
55
|
+
if (
|
|
56
|
+
(!previousMutation || !runtime.isAlive(previousMutation)) &&
|
|
57
|
+
runtime.liveLeases(directory).length === 0
|
|
58
|
+
) {
|
|
59
|
+
runtime.writeJson(path.join(directory, 'mutation.json'), {
|
|
60
|
+
pid: process.pid,
|
|
61
|
+
identity: runtime.processIdentity(process.pid),
|
|
62
|
+
});
|
|
63
|
+
mutation = true;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
} finally {
|
|
67
|
+
releaseAdmission();
|
|
68
|
+
}
|
|
69
|
+
if (Date.now() >= deadline) {
|
|
70
|
+
persist({
|
|
71
|
+
status: 'queued',
|
|
72
|
+
message: 'Waiting for active CLI sessions; the next invocation resumes this request.',
|
|
73
|
+
});
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
await delay(250);
|
|
77
|
+
}
|
|
78
|
+
if (
|
|
79
|
+
runtime.readJson(path.join(attempt.packageRoot, 'package.json'))?.version === attempt.version
|
|
80
|
+
) {
|
|
81
|
+
persist({
|
|
82
|
+
status: 'succeeded',
|
|
83
|
+
finishedAt: Date.now(),
|
|
84
|
+
installedVersion: attempt.version,
|
|
85
|
+
message: 'The requested CLI version is already installed.',
|
|
86
|
+
});
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const rootResult = await execFileAsync(attempt.npmPath, ['root', '-g'], {
|
|
90
|
+
timeout: 1500,
|
|
91
|
+
maxBuffer: 64 * 1024,
|
|
92
|
+
shell: process.platform === 'win32',
|
|
93
|
+
});
|
|
94
|
+
const npmRoot = fs.realpathSync(rootResult.stdout.trim());
|
|
95
|
+
const expectedPackage = path.join(npmRoot, '@skrr-ai', 'cli');
|
|
96
|
+
if (fs.realpathSync(expectedPackage) !== fs.realpathSync(attempt.packageRoot)) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
'npm global prefix changed; run the update with the package manager that owns this CLI',
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
persist({
|
|
102
|
+
status: 'running',
|
|
103
|
+
startedAt: Date.now(),
|
|
104
|
+
workerPid: process.pid,
|
|
105
|
+
message: 'npm is installing the requested CLI version.',
|
|
106
|
+
});
|
|
107
|
+
const logFile = path.join(directory, 'update.log');
|
|
108
|
+
fs.writeFileSync(logFile, '', { mode: 0o600 });
|
|
109
|
+
let logBytes = 0;
|
|
110
|
+
const log = (chunk) => {
|
|
111
|
+
const bytes = Buffer.from(chunk);
|
|
112
|
+
if (logBytes >= MAX_LOG_BYTES) return;
|
|
113
|
+
const bounded = bytes.subarray(0, MAX_LOG_BYTES - logBytes);
|
|
114
|
+
fs.appendFileSync(logFile, bounded);
|
|
115
|
+
logBytes += bounded.length;
|
|
116
|
+
};
|
|
117
|
+
await new Promise((resolve, reject) => {
|
|
118
|
+
const requestFile = path.join(directory, `runner-${crypto.randomUUID()}.json`);
|
|
119
|
+
const token = crypto.randomUUID();
|
|
120
|
+
runtime.writeJson(requestFile, { token, npmPath: attempt.npmPath, version: attempt.version });
|
|
121
|
+
const child = spawn(
|
|
122
|
+
process.execPath,
|
|
123
|
+
[path.join(__dirname, 'update-npm-runner.cjs'), requestFile],
|
|
124
|
+
{
|
|
125
|
+
detached: process.platform !== 'win32',
|
|
126
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
127
|
+
},
|
|
128
|
+
);
|
|
129
|
+
if (child.pid) {
|
|
130
|
+
mutationChild = { pid: child.pid, group: process.platform !== 'win32' };
|
|
131
|
+
runtime.writeJson(path.join(directory, 'mutation.json'), mutationChild);
|
|
132
|
+
runtime.writeJson(`${requestFile}.go`, { pid: child.pid, token });
|
|
133
|
+
}
|
|
134
|
+
child.stdout.on('data', log);
|
|
135
|
+
child.stderr.on('data', log);
|
|
136
|
+
let timedOut = false;
|
|
137
|
+
let forceTimer;
|
|
138
|
+
const signal = (name) => {
|
|
139
|
+
try {
|
|
140
|
+
if (process.platform !== 'win32' && child.pid) process.kill(-child.pid, name);
|
|
141
|
+
else child.kill(name);
|
|
142
|
+
} catch {
|
|
143
|
+
/* already exited */
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
const timer = setTimeout(() => {
|
|
147
|
+
timedOut = true;
|
|
148
|
+
signal('SIGTERM');
|
|
149
|
+
forceTimer = setTimeout(() => {
|
|
150
|
+
signal('SIGKILL');
|
|
151
|
+
}, 5000);
|
|
152
|
+
}, options.installTimeoutMs ?? INSTALL_TIMEOUT_MS);
|
|
153
|
+
child.once('error', (error) => {
|
|
154
|
+
clearTimeout(timer);
|
|
155
|
+
clearTimeout(forceTimer);
|
|
156
|
+
reject(error);
|
|
157
|
+
});
|
|
158
|
+
child.once('exit', async (code, exitSignal) => {
|
|
159
|
+
clearTimeout(timer);
|
|
160
|
+
if (timedOut) {
|
|
161
|
+
// npm can exit on TERM while a descendant keeps writing. Complete
|
|
162
|
+
// KILL escalation for the whole group before releasing admission.
|
|
163
|
+
signal('SIGKILL');
|
|
164
|
+
const stopDeadline = Date.now() + 5000;
|
|
165
|
+
while (mutationChild && runtime.isAlive(mutationChild) && Date.now() < stopDeadline)
|
|
166
|
+
await delay(50);
|
|
167
|
+
}
|
|
168
|
+
clearTimeout(forceTimer);
|
|
169
|
+
fs.rmSync(requestFile, { force: true });
|
|
170
|
+
fs.rmSync(`${requestFile}.go`, { force: true });
|
|
171
|
+
if (timedOut) reject(new Error('npm update exceeded the 10-minute time limit'));
|
|
172
|
+
else if (code === 0) resolve();
|
|
173
|
+
else reject(new Error(`npm update failed (${exitSignal || code}); see ${logFile}`));
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
const installedVersion = runtime.readJson(
|
|
177
|
+
path.join(attempt.packageRoot, 'package.json'),
|
|
178
|
+
)?.version;
|
|
179
|
+
if (installedVersion !== attempt.version)
|
|
180
|
+
throw new Error(
|
|
181
|
+
`npm completed but installed ${installedVersion || 'an unknown version'} instead of ${attempt.version}`,
|
|
182
|
+
);
|
|
183
|
+
persist({
|
|
184
|
+
status: 'succeeded',
|
|
185
|
+
finishedAt: Date.now(),
|
|
186
|
+
installedVersion,
|
|
187
|
+
message: 'The new CLI version is ready for the next invocation.',
|
|
188
|
+
});
|
|
189
|
+
} catch (error) {
|
|
190
|
+
persist({ status: 'failed', finishedAt: Date.now(), message: String(error.message || error) });
|
|
191
|
+
} finally {
|
|
192
|
+
// A crashed worker/terminated npm parent can leave a mutating process
|
|
193
|
+
// group alive. Keep the gate until the group is confirmed gone.
|
|
194
|
+
if (mutation && (!mutationChild || !runtime.isAlive(mutationChild)))
|
|
195
|
+
fs.rmSync(path.join(directory, 'mutation.json'), { force: true });
|
|
196
|
+
releaseWorker();
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (require.main === module) {
|
|
201
|
+
const directory = process.argv[2];
|
|
202
|
+
if (!directory || !path.isAbsolute(directory)) process.exitCode = 1;
|
|
203
|
+
else
|
|
204
|
+
run(directory).catch(() => {
|
|
205
|
+
process.exitCode = 1;
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
module.exports = { run };
|
package/dist/base-command.js
CHANGED
|
@@ -52,7 +52,6 @@ const daemonBroker_1 = require("./lib/daemonBroker");
|
|
|
52
52
|
const daemonBrokerRefusal_1 = require("./lib/daemonBrokerRefusal");
|
|
53
53
|
const refresh_1 = require("./lib/refresh");
|
|
54
54
|
const auth_storage_1 = require("./lib/auth-storage");
|
|
55
|
-
const update_check_1 = require("./lib/update-check");
|
|
56
55
|
const web_url_1 = require("./lib/web-url");
|
|
57
56
|
const edge_error_page_1 = require("./lib/edge-error-page");
|
|
58
57
|
const step_up_1 = require("./lib/step-up");
|
|
@@ -541,20 +540,6 @@ class BaseCommand extends core_1.Command {
|
|
|
541
540
|
}
|
|
542
541
|
(0, node_adapter_1.setAdapterCredentialOverride)(this.resolvedCredential);
|
|
543
542
|
(0, data_provider_1.setHttpAdapter)((0, node_adapter_1.createNodeAdapter)());
|
|
544
|
-
// Non-blocking "a newer skrr is available" advisory. Decides from a ~4h
|
|
545
|
-
// on-disk cache (zero added latency) and refreshes in the background.
|
|
546
|
-
// Writes at most one line to stderr, never stdout, so --json consumers
|
|
547
|
-
// are unaffected; self-suppresses in bundled/non-TTY/opted-out contexts.
|
|
548
|
-
// Wrapped so an advisory can never break the command it precedes.
|
|
549
|
-
try {
|
|
550
|
-
(0, update_check_1.maybeWarnOutdatedCli)({
|
|
551
|
-
currentVersion: this.config.version,
|
|
552
|
-
baseURL: this.cliConfig.baseURL,
|
|
553
|
-
});
|
|
554
|
-
}
|
|
555
|
-
catch {
|
|
556
|
-
/* advisory is strictly best-effort */
|
|
557
|
-
}
|
|
558
543
|
}
|
|
559
544
|
/**
|
|
560
545
|
* Read only the two global base flags. A narrow parser — oclif's
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
export default class AgentOperatingPlan extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static args: {
|
|
5
|
+
id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
6
|
+
};
|
|
7
|
+
static flags: {
|
|
8
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
};
|
|
10
|
+
run(): Promise<void>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const base_command_1 = require("../../base-command");
|
|
5
|
+
const roles_1 = require("../../lib/roles");
|
|
6
|
+
class AgentOperatingPlan extends base_command_1.BaseCommand {
|
|
7
|
+
static description = 'Read responsibilities, evidence, inquiries, work, delayed evaluation and existing planning loops without scheduling work';
|
|
8
|
+
static args = {
|
|
9
|
+
id: core_1.Args.string({ required: true, description: 'Agent ID', ignoreStdin: true }),
|
|
10
|
+
};
|
|
11
|
+
static flags = {
|
|
12
|
+
json: core_1.Flags.boolean({ description: 'Output full joined state and source coverage as JSON' }),
|
|
13
|
+
};
|
|
14
|
+
async run() {
|
|
15
|
+
this.requireAuth();
|
|
16
|
+
const { args, flags } = await this.parse(AgentOperatingPlan);
|
|
17
|
+
try {
|
|
18
|
+
const plan = await roles_1.roleApi.plan(args.id);
|
|
19
|
+
if (flags.json) {
|
|
20
|
+
this.log(JSON.stringify(plan, null, 2));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
this.log(`Operating plan — ${args.id} (${plan.generatedAt})`);
|
|
24
|
+
for (const r of plan.responsibilities) {
|
|
25
|
+
this.log(`\n${r.title} · ${r.status} · ${r.kind} v${r.version}`);
|
|
26
|
+
this.log(` Responsibility: ${r.purpose}`);
|
|
27
|
+
this.log(` Evidence: ${r.evidence.status}${r.evidence.issues?.length ? ` (${r.evidence.issues.join(', ')})` : ''}`);
|
|
28
|
+
this.log(" Execution authority: tools, sandbox and approvals use the Agent's runtime permissions.");
|
|
29
|
+
for (const q of r.inquiries)
|
|
30
|
+
this.log(` Inquiry: ${q.question} [${q.status}] — ${q.decisionImpact}`);
|
|
31
|
+
for (const w of r.work)
|
|
32
|
+
this.log(` Work: ${w.title} [${w.status}]`);
|
|
33
|
+
for (const w of r.waiting)
|
|
34
|
+
this.log(` Evaluation: ${w.status} — ${w.reason}${w.nextAt ? `; next ${w.nextAt}` : ''}`);
|
|
35
|
+
this.log(` Next intervention: ${r.lifecycle !== 'active' ? 'inactive; requires activation' : r.nextIntervention?.nextAt || r.nextIntervention?.status || 'not recorded'}`);
|
|
36
|
+
if (r.blocker)
|
|
37
|
+
this.log(` Blocker: ${r.blocker.code} — ${r.blocker.remediation || ''}`);
|
|
38
|
+
}
|
|
39
|
+
this.log(`\n${plan.planning.loops.length} existing planning/reflection loops; ${plan.planning.todos.length} scheduled work blocks.`);
|
|
40
|
+
if (plan.learning?.skillValidation)
|
|
41
|
+
this.log(`Skill validation: ${plan.learning.skillValidation.enabled ? 'enabled' : 'disabled'} (${plan.learning.skillValidation.scope}); external effects validated: ${plan.learning.skillValidation.externalEffectsValidated}.`);
|
|
42
|
+
if (!plan.coverage.complete) {
|
|
43
|
+
this.log(`Incomplete coverage${plan.coverage.truncated ? '; view limits reached' : ''}.`);
|
|
44
|
+
for (const s of plan.coverage.sources.filter((s) => s.status !== 'available'))
|
|
45
|
+
this.log(` ${s.name}: ${s.status} (${s.code || 'unknown'})`);
|
|
46
|
+
}
|
|
47
|
+
this.log('Task or Run completion does not establish a verified outcome.');
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
this.handleApiError(error);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.default = AgentOperatingPlan;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base-command';
|
|
2
|
+
export default class RolesExample extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static args: {
|
|
5
|
+
role: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
6
|
+
};
|
|
7
|
+
static flags: {
|
|
8
|
+
output: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
9
|
+
};
|
|
10
|
+
run(): Promise<void>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
6
|
+
const base_command_1 = require("../../../base-command");
|
|
7
|
+
class RolesExample extends base_command_1.BaseCommand {
|
|
8
|
+
static description = 'Start a portable DevOps, Financial Tech or Research Operations role using one generic schema';
|
|
9
|
+
static args = {
|
|
10
|
+
role: core_1.Args.string({
|
|
11
|
+
required: true,
|
|
12
|
+
options: ['devops', 'financial', 'research'],
|
|
13
|
+
description: 'Example role',
|
|
14
|
+
ignoreStdin: true,
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
static flags = {
|
|
18
|
+
output: core_1.Flags.string({ description: 'Save the example JSON to a file; otherwise print JSON' }),
|
|
19
|
+
};
|
|
20
|
+
async run() {
|
|
21
|
+
const { args, flags } = await this.parse(RolesExample);
|
|
22
|
+
const example = data_provider_1.ROLE_OPERATING_SPEC_EXAMPLES[args.role];
|
|
23
|
+
const json = `${JSON.stringify(example, null, 2)}\n`;
|
|
24
|
+
if (flags.output)
|
|
25
|
+
(0, node_fs_1.writeFileSync)(flags.output, json, { mode: 0o600 });
|
|
26
|
+
else
|
|
27
|
+
this.log(json.trimEnd());
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.default = RolesExample;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { BaseCommand } from '
|
|
2
|
-
export default class
|
|
1
|
+
import { BaseCommand } from '../../../base-command';
|
|
2
|
+
export default class RolesExport extends BaseCommand {
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
5
|
static args: {
|
|
6
6
|
id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
-
|
|
7
|
+
key: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
8
8
|
};
|
|
9
9
|
static flags: {
|
|
10
|
+
summary: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
output: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
10
12
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
11
|
-
verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
12
|
-
reason: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
13
13
|
};
|
|
14
14
|
run(): Promise<void>;
|
|
15
15
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const base_command_1 = require("../../../base-command");
|
|
5
|
+
const roles_1 = require("../../../lib/roles");
|
|
6
|
+
const artifact_export_1 = require("../../../lib/artifact-export");
|
|
7
|
+
/** Shape version of the portable role spec this command writes. */
|
|
8
|
+
const ROLE_EXPORT_VERSION = 1;
|
|
9
|
+
class RolesExport extends base_command_1.BaseCommand {
|
|
10
|
+
static description = 'Export portable role authoring intent; credentials, installation IDs and runtime state are excluded';
|
|
11
|
+
static examples = [
|
|
12
|
+
'<%= config.bin %> agents roles export <agent> <key> --summary',
|
|
13
|
+
'<%= config.bin %> agents roles export <agent> <key> --output role.json',
|
|
14
|
+
'<%= config.bin %> agents roles export <agent> <key> --output - | jq .',
|
|
15
|
+
];
|
|
16
|
+
static args = {
|
|
17
|
+
id: core_1.Args.string({ required: true, description: 'Agent ID', ignoreStdin: true }),
|
|
18
|
+
key: core_1.Args.string({ required: true, description: 'Role key', ignoreStdin: true }),
|
|
19
|
+
};
|
|
20
|
+
static flags = {
|
|
21
|
+
...(0, artifact_export_1.standardExportFlags)(),
|
|
22
|
+
};
|
|
23
|
+
async run() {
|
|
24
|
+
this.requireAuth();
|
|
25
|
+
const { args, flags } = await this.parse(RolesExport);
|
|
26
|
+
let selection;
|
|
27
|
+
try {
|
|
28
|
+
selection = (0, artifact_export_1.resolveExportSelection)(flags);
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
if (err instanceof artifact_export_1.ExportContractError) {
|
|
32
|
+
this.failWithCliError({ message: err.message, code: err.code, exit: 2, retryable: false });
|
|
33
|
+
}
|
|
34
|
+
throw err;
|
|
35
|
+
}
|
|
36
|
+
let spec;
|
|
37
|
+
try {
|
|
38
|
+
spec = await roles_1.roleApi.export(args.id, args.key);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
this.handleApiError(error);
|
|
42
|
+
}
|
|
43
|
+
if (selection.summary) {
|
|
44
|
+
const summary = (0, artifact_export_1.contentFreeSummary)({
|
|
45
|
+
command: 'agents roles export',
|
|
46
|
+
artifactSchemaVersion: ROLE_EXPORT_VERSION,
|
|
47
|
+
itemCount: 1,
|
|
48
|
+
counts: {},
|
|
49
|
+
});
|
|
50
|
+
this.log(selection.json ? JSON.stringify(summary, null, 2) : (0, artifact_export_1.humanExportSummary)(summary));
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const serialized = (0, artifact_export_1.serializedArtifact)(spec);
|
|
54
|
+
if (selection.output === '-') {
|
|
55
|
+
this.log(serialized.trimEnd());
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
let receipt;
|
|
59
|
+
try {
|
|
60
|
+
receipt = await (0, artifact_export_1.writeExportArtifact)({
|
|
61
|
+
command: 'agents roles export',
|
|
62
|
+
artifactSchemaVersion: ROLE_EXPORT_VERSION,
|
|
63
|
+
format: 'json',
|
|
64
|
+
output: selection.output,
|
|
65
|
+
content: serialized,
|
|
66
|
+
itemCount: 1,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
this.failWithCliError({
|
|
71
|
+
message: `Could not write ${selection.output}: ${err.message}`,
|
|
72
|
+
code: 'ROLE_EXPORT_WRITE_FAILED',
|
|
73
|
+
exit: 1,
|
|
74
|
+
retryable: false,
|
|
75
|
+
details: { path: selection.output },
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
this.log(selection.json ? JSON.stringify(receipt, null, 2) : (0, artifact_export_1.humanExportReceipt)(receipt));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.default = RolesExport;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base-command';
|
|
2
|
+
export default class RolesInstall extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static args: {
|
|
5
|
+
id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
6
|
+
};
|
|
7
|
+
static flags: {
|
|
8
|
+
preview: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
9
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
};
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
}
|