@skrr-ai/cli 0.1.87 → 0.1.88
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/dist/commands/agents/chat.js +27 -1
- package/dist/commands/computer/index.d.ts +19 -0
- package/dist/commands/computer/index.js +37 -0
- package/dist/commands/labels/create.d.ts +1 -0
- package/dist/commands/labels/create.js +2 -0
- package/dist/commands/labels/restore.d.ts +1 -0
- package/dist/commands/labels/restore.js +6 -3
- package/dist/commands/labels/update.d.ts +1 -0
- package/dist/commands/labels/update.js +2 -0
- package/dist/commands/machines/computer-adoption.d.ts +15 -0
- package/dist/commands/machines/computer-adoption.js +33 -0
- package/dist/commands/machines/dedicated/archive.d.ts +26 -0
- package/dist/commands/machines/dedicated/archive.js +113 -0
- package/dist/commands/machines/dedicated/audit.d.ts +25 -0
- package/dist/commands/machines/dedicated/audit.js +113 -0
- package/dist/commands/machines/dedicated/computer.d.ts +23 -0
- package/dist/commands/machines/dedicated/computer.js +64 -0
- package/dist/commands/machines/dedicated/cp.d.ts +2 -0
- package/dist/commands/machines/dedicated/cp.js +74 -2
- package/dist/commands/machines/dedicated/git-status.d.ts +15 -0
- package/dist/commands/machines/dedicated/git-status.js +56 -0
- package/dist/commands/machines/dedicated/index.js +15 -1
- package/dist/commands/machines/dedicated/ls.d.ts +27 -0
- package/dist/commands/machines/dedicated/ls.js +100 -0
- package/dist/commands/machines/dedicated/mkdir.d.ts +18 -0
- package/dist/commands/machines/dedicated/mkdir.js +57 -0
- package/dist/commands/machines/dedicated/mv.d.ts +24 -0
- package/dist/commands/machines/dedicated/mv.js +83 -0
- package/dist/commands/machines/dedicated/rm.d.ts +26 -0
- package/dist/commands/machines/dedicated/rm.js +100 -0
- package/dist/commands/machines/dedicated/search.d.ts +24 -0
- package/dist/commands/machines/dedicated/search.js +78 -0
- package/dist/commands/machines/dedicated/stat.d.ts +22 -0
- package/dist/commands/machines/dedicated/stat.js +92 -0
- package/dist/commands/machines/hosted/index.js +1 -1
- package/dist/commands/machines/hosted/list.js +1 -1
- package/dist/commands/machines/hosted/start.js +1 -1
- package/dist/commands/machines/services/declare.d.ts +24 -0
- package/dist/commands/machines/services/declare.js +73 -0
- package/dist/commands/machines/services/index.d.ts +15 -0
- package/dist/commands/machines/services/index.js +31 -0
- package/dist/commands/machines/services/ls.d.ts +17 -0
- package/dist/commands/machines/services/ls.js +60 -0
- package/dist/commands/machines/services/withdraw.d.ts +19 -0
- package/dist/commands/machines/services/withdraw.js +47 -0
- package/dist/commands/machines/share.d.ts +29 -0
- package/dist/commands/machines/share.js +100 -0
- package/dist/commands/machines/shared.d.ts +19 -0
- package/dist/commands/machines/shared.js +62 -0
- package/dist/commands/machines/shares.d.ts +16 -0
- package/dist/commands/machines/shares.js +69 -0
- package/dist/commands/machines/unshare.d.ts +19 -0
- package/dist/commands/machines/unshare.js +61 -0
- package/dist/commands/tasks/labels/create.d.ts +1 -0
- package/dist/commands/tasks/labels/create.js +3 -0
- package/dist/commands/views/create.d.ts +1 -0
- package/dist/commands/views/create.js +5 -0
- package/dist/lib/agent-home-workspace.d.ts +7 -0
- package/dist/lib/agent-home-workspace.js +147 -0
- package/dist/lib/computer-adoption.d.ts +55 -0
- package/dist/lib/computer-adoption.js +67 -0
- package/dist/lib/computer-consent.d.ts +13 -0
- package/dist/lib/computer-consent.js +33 -0
- package/dist/lib/computer-files.d.ts +239 -0
- package/dist/lib/computer-files.js +707 -0
- package/dist/lib/dedicated-copy.d.ts +45 -9
- package/dist/lib/dedicated-copy.js +141 -44
- package/dist/lib/dedicated-machines.d.ts +49 -0
- package/dist/lib/dedicated-machines.js +97 -6
- package/dist/lib/label-scope.d.ts +12 -0
- package/dist/lib/label-scope.js +15 -1
- package/dist/lib/machine-audit.d.ts +34 -0
- package/dist/lib/machine-audit.js +50 -0
- package/dist/lib/machine-grants.d.ts +70 -0
- package/dist/lib/machine-grants.js +47 -0
- package/dist/lib/machine-services.d.ts +64 -0
- package/dist/lib/machine-services.js +60 -0
- package/dist/lib/task-view-render.d.ts +2 -0
- package/dist/lib/task-view-render.js +1 -1
- package/dist/lib/views/vocabulary.d.ts +1 -1
- package/dist/lib/views/vocabulary.js +2 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/computerWire.d.ts +955 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/computerWire.js +1070 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonToolApproval.js +7 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/computerWire.d.ts +955 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/computerWire.js +1051 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonToolApproval.js +7 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +11 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +22143 -20728
- package/dist/node_modules/@skrr-ai/data-provider/package.json +1 -1
- package/oclif.manifest.json +11550 -9963
- package/package.json +2 -2
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* `skrr machines share` — grant a person a tier on one of your machines
|
|
4
|
+
* (design §9, D10; OSK-13558).
|
|
5
|
+
*
|
|
6
|
+
* The two tiers are the honest ones: `watch` sees every surface and its
|
|
7
|
+
* activity; `operate` can also take control and read and write files — "the
|
|
8
|
+
* machine's account in another person's hands". `power` and grant management
|
|
9
|
+
* stay with the owner, so there is no tier flag for them. The grantee may be
|
|
10
|
+
* any user — nothing here assumes a shared workspace.
|
|
11
|
+
*
|
|
12
|
+
* One verb for issue and change: the stated tier is the end state asked for.
|
|
13
|
+
* The server refuses a bare re-issue at a different tier (a retried issue can
|
|
14
|
+
* never silently escalate a grant), so an existing grant is changed through
|
|
15
|
+
* PATCH — and the output says which of the two happened.
|
|
16
|
+
*/
|
|
17
|
+
export default class MachinesShare extends BaseCommand {
|
|
18
|
+
static description: string;
|
|
19
|
+
static examples: string[];
|
|
20
|
+
static args: {
|
|
21
|
+
machine: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
22
|
+
user: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
23
|
+
};
|
|
24
|
+
static flags: {
|
|
25
|
+
tier: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
26
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
27
|
+
};
|
|
28
|
+
run(): Promise<void>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
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 api_fetch_1 = require("../../lib/api-fetch");
|
|
6
|
+
const machines_1 = require("../../lib/machines");
|
|
7
|
+
const machine_grants_1 = require("../../lib/machine-grants");
|
|
8
|
+
/**
|
|
9
|
+
* `skrr machines share` — grant a person a tier on one of your machines
|
|
10
|
+
* (design §9, D10; OSK-13558).
|
|
11
|
+
*
|
|
12
|
+
* The two tiers are the honest ones: `watch` sees every surface and its
|
|
13
|
+
* activity; `operate` can also take control and read and write files — "the
|
|
14
|
+
* machine's account in another person's hands". `power` and grant management
|
|
15
|
+
* stay with the owner, so there is no tier flag for them. The grantee may be
|
|
16
|
+
* any user — nothing here assumes a shared workspace.
|
|
17
|
+
*
|
|
18
|
+
* One verb for issue and change: the stated tier is the end state asked for.
|
|
19
|
+
* The server refuses a bare re-issue at a different tier (a retried issue can
|
|
20
|
+
* never silently escalate a grant), so an existing grant is changed through
|
|
21
|
+
* PATCH — and the output says which of the two happened.
|
|
22
|
+
*/
|
|
23
|
+
class MachinesShare extends base_command_1.BaseCommand {
|
|
24
|
+
static description = 'Share a machine with a person — `watch` lets them see every surface; `operate` also gives control and file access';
|
|
25
|
+
static examples = [
|
|
26
|
+
'<%= config.bin %> machines share 03548116 68db4b2f0b4f5a9c1d2e3f40 --tier watch',
|
|
27
|
+
'<%= config.bin %> machines share lease:rtl_abc123 68db4b2f0b4f5a9c1d2e3f40 --tier operate',
|
|
28
|
+
];
|
|
29
|
+
static args = {
|
|
30
|
+
machine: core_1.Args.string({
|
|
31
|
+
ignoreStdin: true,
|
|
32
|
+
description: 'Machine id, uuid, daemon id, name, or a unique prefix',
|
|
33
|
+
required: true,
|
|
34
|
+
}),
|
|
35
|
+
user: core_1.Args.string({
|
|
36
|
+
ignoreStdin: true,
|
|
37
|
+
description: 'The user id of the person to share with',
|
|
38
|
+
required: true,
|
|
39
|
+
}),
|
|
40
|
+
};
|
|
41
|
+
static flags = {
|
|
42
|
+
tier: core_1.Flags.string({
|
|
43
|
+
description: 'watch: see every surface and its activity. operate: also take control, open surfaces, and read/write files',
|
|
44
|
+
required: true,
|
|
45
|
+
options: [...machine_grants_1.MACHINE_GRANT_TIERS],
|
|
46
|
+
}),
|
|
47
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
48
|
+
};
|
|
49
|
+
async run() {
|
|
50
|
+
this.requireAuth();
|
|
51
|
+
const { args, flags } = await this.parse(MachinesShare);
|
|
52
|
+
const tier = flags.tier;
|
|
53
|
+
let target;
|
|
54
|
+
try {
|
|
55
|
+
target = (0, machines_1.resolveMachineRef)(await (0, machines_1.listMachines)(), args.machine);
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
this.handleApiError(err);
|
|
59
|
+
}
|
|
60
|
+
if (!target) {
|
|
61
|
+
this.error('Machine not found.', { exit: 1 });
|
|
62
|
+
}
|
|
63
|
+
let result;
|
|
64
|
+
try {
|
|
65
|
+
result = await (0, machine_grants_1.shareMachine)(target.id, args.user, tier);
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
// A grant already held at another tier is a change, not an issue: the
|
|
69
|
+
// user named the tier they want, so PATCH it. The 409 is the server
|
|
70
|
+
// stopping a retried ISSUE from silently escalating — this is not that.
|
|
71
|
+
if (err instanceof api_fetch_1.ApiFetchError && err.code === 'COMPUTER_GRANT_EXISTS') {
|
|
72
|
+
result = await (0, machine_grants_1.changeMachineGrant)(target.id, args.user, tier);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
this.handleApiError(err);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (flags.json) {
|
|
79
|
+
this.log(JSON.stringify(result, null, 2));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const label = target.preferences?.name || target.name || target.id;
|
|
83
|
+
if (result?.created === false) {
|
|
84
|
+
this.log(`${label} is already shared with ${args.user} at ${tier}.`);
|
|
85
|
+
}
|
|
86
|
+
else if (result?.changed === false) {
|
|
87
|
+
this.log(`${label} stays shared with ${args.user} at ${tier}.`);
|
|
88
|
+
}
|
|
89
|
+
else if (result?.changed === true) {
|
|
90
|
+
this.log(`Changed ${args.user} to ${tier} on ${label}.`);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
this.log(`Shared ${label} with ${args.user} at ${tier}.`);
|
|
94
|
+
if (tier === 'operate') {
|
|
95
|
+
this.log(" operate is the machine's account in their hands: control of surfaces, and file read/write.");
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
exports.default = MachinesShare;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* `skrr machines shared` — the machines other people shared with you
|
|
4
|
+
* (design §9, D4/D10; OSK-13567): how a grantee finds a computer without being
|
|
5
|
+
* sent a link. The grantee may be outside every workspace the owner is in, so
|
|
6
|
+
* nothing here assumes one.
|
|
7
|
+
*
|
|
8
|
+
* Each row says who shared it, at which tier (`watch` sees every surface and
|
|
9
|
+
* its activity; `operate` adds control and file read/write), and the machine's
|
|
10
|
+
* live power phase. `skrr machines dedicated computer <id>` opens one.
|
|
11
|
+
*/
|
|
12
|
+
export default class MachinesShared extends BaseCommand {
|
|
13
|
+
static description: string;
|
|
14
|
+
static examples: string[];
|
|
15
|
+
static flags: {
|
|
16
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
17
|
+
};
|
|
18
|
+
run(): Promise<void>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
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 format_1 = require("../../lib/format");
|
|
6
|
+
const machine_grants_1 = require("../../lib/machine-grants");
|
|
7
|
+
/**
|
|
8
|
+
* `skrr machines shared` — the machines other people shared with you
|
|
9
|
+
* (design §9, D4/D10; OSK-13567): how a grantee finds a computer without being
|
|
10
|
+
* sent a link. The grantee may be outside every workspace the owner is in, so
|
|
11
|
+
* nothing here assumes one.
|
|
12
|
+
*
|
|
13
|
+
* Each row says who shared it, at which tier (`watch` sees every surface and
|
|
14
|
+
* its activity; `operate` adds control and file read/write), and the machine's
|
|
15
|
+
* live power phase. `skrr machines dedicated computer <id>` opens one.
|
|
16
|
+
*/
|
|
17
|
+
class MachinesShared extends base_command_1.BaseCommand {
|
|
18
|
+
static description = 'List the computers shared with you — machine, owner, tier, and live state';
|
|
19
|
+
static examples = [
|
|
20
|
+
'<%= config.bin %> machines shared',
|
|
21
|
+
'<%= config.bin %> machines shared --json',
|
|
22
|
+
];
|
|
23
|
+
static flags = {
|
|
24
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
25
|
+
};
|
|
26
|
+
async run() {
|
|
27
|
+
this.requireAuth();
|
|
28
|
+
const { flags } = await this.parse(MachinesShared);
|
|
29
|
+
let result;
|
|
30
|
+
try {
|
|
31
|
+
result = await (0, machine_grants_1.listSharedMachines)();
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
this.handleApiError(err);
|
|
35
|
+
}
|
|
36
|
+
if (flags.json) {
|
|
37
|
+
this.log(JSON.stringify(result, null, 2));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const machines = result?.machines ?? [];
|
|
41
|
+
if (machines.length === 0) {
|
|
42
|
+
this.log('No computers are shared with you.');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
(0, format_1.renderTable)(machines.map((machine) => ({
|
|
46
|
+
id: (0, format_1.formatCell)(machine.machineId),
|
|
47
|
+
name: (0, format_1.formatCell)(machine.name),
|
|
48
|
+
owner: (0, format_1.formatCell)(machine.owner?.name || machine.owner?.username),
|
|
49
|
+
tier: (0, format_1.formatCell)(machine.tier),
|
|
50
|
+
power: (0, format_1.formatCell)(machine.power?.phase),
|
|
51
|
+
since: (0, format_1.localStamp)(machine.grantedAt),
|
|
52
|
+
})), [
|
|
53
|
+
{ key: 'id', header: 'ID', verbatim: true },
|
|
54
|
+
{ key: 'name', header: 'NAME', maxWidth: 28 },
|
|
55
|
+
{ key: 'owner', header: 'OWNER' },
|
|
56
|
+
{ key: 'tier', header: 'TIER' },
|
|
57
|
+
{ key: 'power', header: 'STATE' },
|
|
58
|
+
{ key: 'since', header: `SHARED (${(0, format_1.localZone)()})` },
|
|
59
|
+
], (line) => this.log(line));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.default = MachinesShared;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* `skrr machines shares` — who a machine is shared with, and at which tier
|
|
4
|
+
* (design §9; OSK-13558). Owner-only: the server answers 403 to anyone else.
|
|
5
|
+
*/
|
|
6
|
+
export default class MachinesShares extends BaseCommand {
|
|
7
|
+
static description: string;
|
|
8
|
+
static examples: string[];
|
|
9
|
+
static args: {
|
|
10
|
+
machine: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
11
|
+
};
|
|
12
|
+
static flags: {
|
|
13
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
};
|
|
15
|
+
run(): Promise<void>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
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 format_1 = require("../../lib/format");
|
|
6
|
+
const machines_1 = require("../../lib/machines");
|
|
7
|
+
const machine_grants_1 = require("../../lib/machine-grants");
|
|
8
|
+
/**
|
|
9
|
+
* `skrr machines shares` — who a machine is shared with, and at which tier
|
|
10
|
+
* (design §9; OSK-13558). Owner-only: the server answers 403 to anyone else.
|
|
11
|
+
*/
|
|
12
|
+
class MachinesShares extends base_command_1.BaseCommand {
|
|
13
|
+
static description = 'List the people a machine is shared with — grantee, tier, and when the grant was made';
|
|
14
|
+
static examples = [
|
|
15
|
+
'<%= config.bin %> machines shares 03548116',
|
|
16
|
+
'<%= config.bin %> machines shares lease:rtl_abc123 --json',
|
|
17
|
+
];
|
|
18
|
+
static args = {
|
|
19
|
+
machine: core_1.Args.string({
|
|
20
|
+
ignoreStdin: true,
|
|
21
|
+
description: 'Machine id, uuid, daemon id, name, or a unique prefix',
|
|
22
|
+
required: true,
|
|
23
|
+
}),
|
|
24
|
+
};
|
|
25
|
+
static flags = {
|
|
26
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
27
|
+
};
|
|
28
|
+
async run() {
|
|
29
|
+
this.requireAuth();
|
|
30
|
+
const { args, flags } = await this.parse(MachinesShares);
|
|
31
|
+
let target;
|
|
32
|
+
try {
|
|
33
|
+
target = (0, machines_1.resolveMachineRef)(await (0, machines_1.listMachines)(), args.machine);
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
this.handleApiError(err);
|
|
37
|
+
}
|
|
38
|
+
if (!target) {
|
|
39
|
+
this.error('Machine not found.', { exit: 1 });
|
|
40
|
+
}
|
|
41
|
+
let result;
|
|
42
|
+
try {
|
|
43
|
+
result = await (0, machine_grants_1.listMachineGrants)(target.id);
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
this.handleApiError(err);
|
|
47
|
+
}
|
|
48
|
+
if (flags.json) {
|
|
49
|
+
this.log(JSON.stringify(result, null, 2));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const grants = result?.grants ?? [];
|
|
53
|
+
if (grants.length === 0) {
|
|
54
|
+
this.log('Not shared with anyone.');
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
this.log(`Shared with ${grants.length} ${grants.length === 1 ? 'person' : 'people'}:`);
|
|
58
|
+
(0, format_1.renderTable)(grants.map((grant) => ({
|
|
59
|
+
user: (0, format_1.formatCell)(grant.granteeUserId),
|
|
60
|
+
tier: (0, format_1.formatCell)(grant.tier),
|
|
61
|
+
since: (0, format_1.localStamp)(grant.createdAt),
|
|
62
|
+
})), [
|
|
63
|
+
{ key: 'user', header: 'USER', verbatim: true },
|
|
64
|
+
{ key: 'tier', header: 'TIER' },
|
|
65
|
+
{ key: 'since', header: `SINCE (${(0, format_1.localZone)()})` },
|
|
66
|
+
], (line) => this.log(line));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.default = MachinesShares;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* `skrr machines unshare` — revoke one person's grant on a machine (design §9;
|
|
4
|
+
* OSK-13558). Revocation bumps the machine's grant-set version, so its daemon
|
|
5
|
+
* detaches that person's attachments and releases any lease they hold when
|
|
6
|
+
* the new set arrives. Reversible — `machines share` grants again.
|
|
7
|
+
*/
|
|
8
|
+
export default class MachinesUnshare extends BaseCommand {
|
|
9
|
+
static description: string;
|
|
10
|
+
static examples: string[];
|
|
11
|
+
static args: {
|
|
12
|
+
machine: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
13
|
+
user: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
14
|
+
};
|
|
15
|
+
static flags: {
|
|
16
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
17
|
+
};
|
|
18
|
+
run(): Promise<void>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
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 machines_1 = require("../../lib/machines");
|
|
6
|
+
const machine_grants_1 = require("../../lib/machine-grants");
|
|
7
|
+
/**
|
|
8
|
+
* `skrr machines unshare` — revoke one person's grant on a machine (design §9;
|
|
9
|
+
* OSK-13558). Revocation bumps the machine's grant-set version, so its daemon
|
|
10
|
+
* detaches that person's attachments and releases any lease they hold when
|
|
11
|
+
* the new set arrives. Reversible — `machines share` grants again.
|
|
12
|
+
*/
|
|
13
|
+
class MachinesUnshare extends base_command_1.BaseCommand {
|
|
14
|
+
static description = 'Stop sharing a machine with a person — detaches their surfaces and releases their control lease';
|
|
15
|
+
static examples = [
|
|
16
|
+
'<%= config.bin %> machines unshare 03548116 68db4b2f0b4f5a9c1d2e3f40',
|
|
17
|
+
];
|
|
18
|
+
static args = {
|
|
19
|
+
machine: core_1.Args.string({
|
|
20
|
+
ignoreStdin: true,
|
|
21
|
+
description: 'Machine id, uuid, daemon id, name, or a unique prefix',
|
|
22
|
+
required: true,
|
|
23
|
+
}),
|
|
24
|
+
user: core_1.Args.string({
|
|
25
|
+
ignoreStdin: true,
|
|
26
|
+
description: 'The user id of the person to stop sharing with',
|
|
27
|
+
required: true,
|
|
28
|
+
}),
|
|
29
|
+
};
|
|
30
|
+
static flags = {
|
|
31
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
32
|
+
};
|
|
33
|
+
async run() {
|
|
34
|
+
this.requireAuth();
|
|
35
|
+
const { args, flags } = await this.parse(MachinesUnshare);
|
|
36
|
+
let target;
|
|
37
|
+
try {
|
|
38
|
+
target = (0, machines_1.resolveMachineRef)(await (0, machines_1.listMachines)(), args.machine);
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
this.handleApiError(err);
|
|
42
|
+
}
|
|
43
|
+
if (!target) {
|
|
44
|
+
this.error('Machine not found.', { exit: 1 });
|
|
45
|
+
}
|
|
46
|
+
let result;
|
|
47
|
+
try {
|
|
48
|
+
result = await (0, machine_grants_1.unshareMachine)(target.id, args.user);
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
this.handleApiError(err);
|
|
52
|
+
}
|
|
53
|
+
if (flags.json) {
|
|
54
|
+
this.log(JSON.stringify(result, null, 2));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const label = target.preferences?.name || target.name || target.id;
|
|
58
|
+
this.log(`Stopped sharing ${label} with ${args.user}.`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.default = MachinesUnshare;
|
|
@@ -3,6 +3,7 @@ export default class TasksLabelsCreate extends BaseCommand {
|
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
5
|
static flags: {
|
|
6
|
+
'allow-duplicate-name': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
6
7
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
7
8
|
'from-json': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
8
9
|
name: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
@@ -4,6 +4,7 @@ const core_1 = require("@oclif/core");
|
|
|
4
4
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
5
|
const base_command_1 = require("../../../base-command");
|
|
6
6
|
const prompt_1 = require("../../../lib/prompt");
|
|
7
|
+
const label_scope_1 = require("../../../lib/label-scope");
|
|
7
8
|
// Accept both `#e11d48` and `e11d48` forms; the server's Zod regex
|
|
8
9
|
// (`api/server/routes/tasks.js:206`) is `/^[0-9a-fA-F]{6}$/` — NO leading
|
|
9
10
|
// `#`. We normalize before sending so users can pass either form.
|
|
@@ -24,6 +25,7 @@ class TasksLabelsCreate extends base_command_1.BaseCommand {
|
|
|
24
25
|
color: core_1.Flags.string({
|
|
25
26
|
description: 'Label color as 6-digit hex, e.g. e11d48 (leading # is accepted and stripped)',
|
|
26
27
|
}),
|
|
28
|
+
...label_scope_1.allowDuplicateNameFlags,
|
|
27
29
|
};
|
|
28
30
|
async run() {
|
|
29
31
|
this.requireAuth();
|
|
@@ -38,6 +40,7 @@ class TasksLabelsCreate extends base_command_1.BaseCommand {
|
|
|
38
40
|
const payload = (0, prompt_1.mergeDefined)(jsonBody, {
|
|
39
41
|
name: flags.name,
|
|
40
42
|
color: flags.color,
|
|
43
|
+
allowDuplicateName: flags['allow-duplicate-name'] ? true : undefined,
|
|
41
44
|
});
|
|
42
45
|
if (!payload.name || typeof payload.name !== 'string') {
|
|
43
46
|
this.error('A label name is required. Pass --name "..." or include it in --from-json.', {
|
|
@@ -14,6 +14,7 @@ export default class ViewsCreate extends BaseCommand {
|
|
|
14
14
|
priority: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
15
15
|
assignee: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
16
16
|
label: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
17
|
+
'label-match': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
17
18
|
goal: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
18
19
|
project: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
19
20
|
search: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
@@ -35,6 +35,10 @@ class ViewsCreate extends base_command_1.BaseCommand {
|
|
|
35
35
|
}),
|
|
36
36
|
assignee: core_1.Flags.string({ multiple: true, description: 'Filter by agent or user ID' }),
|
|
37
37
|
label: core_1.Flags.string({ multiple: true, description: 'Filter by label ID' }),
|
|
38
|
+
'label-match': core_1.Flags.string({
|
|
39
|
+
options: [...vocabulary_1.VIEW_LABEL_MATCH_VALUES],
|
|
40
|
+
description: 'How --label values combine: any (default) or all',
|
|
41
|
+
}),
|
|
38
42
|
goal: core_1.Flags.string({ multiple: true, description: 'Filter by goal ID' }),
|
|
39
43
|
project: core_1.Flags.string({ multiple: true, description: 'Filter by project ID' }),
|
|
40
44
|
search: core_1.Flags.string({ description: 'Filter by title, identifier, or description' }),
|
|
@@ -67,6 +71,7 @@ class ViewsCreate extends base_command_1.BaseCommand {
|
|
|
67
71
|
priorities: flags.priority,
|
|
68
72
|
assignees: flags.assignee,
|
|
69
73
|
labels: flags.label,
|
|
74
|
+
labelMatch: flags['label-match'],
|
|
70
75
|
goalIds: flags.goal,
|
|
71
76
|
projectIds: flags.project,
|
|
72
77
|
search: flags.search,
|
|
@@ -36,3 +36,10 @@ export declare function lookupAgentHomeWorkspaceDefault(agentId: string, lookup:
|
|
|
36
36
|
* Agent process.
|
|
37
37
|
*/
|
|
38
38
|
export declare function commitAgentHomeWorkspaceDefault(workspaceId: string | null, env?: NodeJS.ProcessEnv): string | null;
|
|
39
|
+
/** Does this origin's server default a headerless chat turn's workspace itself? */
|
|
40
|
+
export declare function serverAppliesAgentHomeDefault(cacheDir: string | undefined, baseURL: string | undefined, now?: number): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Record what an acceptance says about the server, and return it. Writes only
|
|
43
|
+
* when the verdict changes or the observation is getting old.
|
|
44
|
+
*/
|
|
45
|
+
export declare function recordAgentHomeDefaultObservation(cacheDir: string | undefined, baseURL: string | undefined, accepted: unknown, now?: number): 'supported' | 'unsupported';
|
|
@@ -1,8 +1,45 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.applyAgentHomeWorkspaceDefault = applyAgentHomeWorkspaceDefault;
|
|
4
37
|
exports.lookupAgentHomeWorkspaceDefault = lookupAgentHomeWorkspaceDefault;
|
|
5
38
|
exports.commitAgentHomeWorkspaceDefault = commitAgentHomeWorkspaceDefault;
|
|
39
|
+
exports.serverAppliesAgentHomeDefault = serverAppliesAgentHomeDefault;
|
|
40
|
+
exports.recordAgentHomeDefaultObservation = recordAgentHomeDefaultObservation;
|
|
41
|
+
const fs = __importStar(require("node:fs"));
|
|
42
|
+
const path = __importStar(require("node:path"));
|
|
6
43
|
/**
|
|
7
44
|
* The workspace an `agents chat` turn runs in when the caller named none.
|
|
8
45
|
*
|
|
@@ -64,3 +101,113 @@ function commitAgentHomeWorkspaceDefault(workspaceId, env = process.env) {
|
|
|
64
101
|
env.OVERSKY_WORKSPACE_ID = workspaceId;
|
|
65
102
|
return workspaceId;
|
|
66
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* OSK-13599 — whether the server this CLI talks to chooses the agent-home
|
|
106
|
+
* workspace itself.
|
|
107
|
+
*
|
|
108
|
+
* A server that does (it defaults a headerless `POST /api/agentic/chat` to the
|
|
109
|
+
* agent's CURRENT home workspace, under exactly the checks the header would
|
|
110
|
+
* pass) makes the pre-flight agent read above redundant, and that read is a
|
|
111
|
+
* full round trip (~480ms at production RTT) on every turn.
|
|
112
|
+
*
|
|
113
|
+
* What is remembered is a fact about the SERVER, never the agent's workspace:
|
|
114
|
+
* agents move between workspaces, so caching their workspace could start a turn
|
|
115
|
+
* in the wrong one, while "this origin applies the default" stays true until
|
|
116
|
+
* the server is rolled back. The evidence is the acceptance itself — a server
|
|
117
|
+
* that applies the default always answers with a `workspaceSource` key (null
|
|
118
|
+
* included); an older one never does. So:
|
|
119
|
+
*
|
|
120
|
+
* - first turn against an origin: no observation → the agent read happens,
|
|
121
|
+
* exactly as before; the acceptance records the observation;
|
|
122
|
+
* - later turns: the read is skipped and the server chooses;
|
|
123
|
+
* - a rollback: the acceptance lacks the key, the observation is dropped and
|
|
124
|
+
* the NEXT turn reads again. The one turn in between ran with no workspace
|
|
125
|
+
* (the pre-OSK-9937 behaviour), which the command reports on stderr.
|
|
126
|
+
*
|
|
127
|
+
* Best-effort everywhere: an unreadable or unwritable cache is "not observed",
|
|
128
|
+
* which is today's behaviour, never an error.
|
|
129
|
+
*/
|
|
130
|
+
const SERVER_FEATURES_FILE = 'server-features.json';
|
|
131
|
+
/** Re-confirm at most this often, so a supported server is not a write per turn. */
|
|
132
|
+
const OBSERVATION_REFRESH_MS = 24 * 60 * 60 * 1000;
|
|
133
|
+
/** An observation nobody has re-confirmed for this long is not trusted. */
|
|
134
|
+
const OBSERVATION_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;
|
|
135
|
+
function originOf(baseURL) {
|
|
136
|
+
try {
|
|
137
|
+
return new URL(baseURL).origin;
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function featuresPath(cacheDir) {
|
|
144
|
+
return path.join(cacheDir, SERVER_FEATURES_FILE);
|
|
145
|
+
}
|
|
146
|
+
function readFeatures(cacheDir) {
|
|
147
|
+
try {
|
|
148
|
+
const parsed = JSON.parse(fs.readFileSync(featuresPath(cacheDir), 'utf8'));
|
|
149
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
|
|
150
|
+
? parsed
|
|
151
|
+
: {};
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return {};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/** Does this origin's server default a headerless chat turn's workspace itself? */
|
|
158
|
+
function serverAppliesAgentHomeDefault(cacheDir, baseURL, now = Date.now()) {
|
|
159
|
+
if (!cacheDir || !baseURL)
|
|
160
|
+
return false;
|
|
161
|
+
const origin = originOf(baseURL);
|
|
162
|
+
if (!origin)
|
|
163
|
+
return false;
|
|
164
|
+
const seen = readFeatures(cacheDir)[origin];
|
|
165
|
+
if (seen?.agentHomeWorkspaceDefault !== true)
|
|
166
|
+
return false;
|
|
167
|
+
const at = Date.parse(seen.observedAt);
|
|
168
|
+
return Number.isFinite(at) && now - at <= OBSERVATION_MAX_AGE_MS;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Record what an acceptance says about the server, and return it. Writes only
|
|
172
|
+
* when the verdict changes or the observation is getting old.
|
|
173
|
+
*/
|
|
174
|
+
function recordAgentHomeDefaultObservation(cacheDir, baseURL, accepted, now = Date.now()) {
|
|
175
|
+
const supported = !!accepted && typeof accepted === 'object' && 'workspaceSource' in accepted;
|
|
176
|
+
const verdict = supported ? 'supported' : 'unsupported';
|
|
177
|
+
if (!cacheDir || !baseURL)
|
|
178
|
+
return verdict;
|
|
179
|
+
const origin = originOf(baseURL);
|
|
180
|
+
if (!origin)
|
|
181
|
+
return verdict;
|
|
182
|
+
try {
|
|
183
|
+
const features = readFeatures(cacheDir);
|
|
184
|
+
const previous = features[origin];
|
|
185
|
+
if (!supported && !previous)
|
|
186
|
+
return verdict;
|
|
187
|
+
const previousAt = previous ? Date.parse(previous.observedAt) : NaN;
|
|
188
|
+
if (supported &&
|
|
189
|
+
previous?.agentHomeWorkspaceDefault === true &&
|
|
190
|
+
Number.isFinite(previousAt) &&
|
|
191
|
+
now - previousAt < OBSERVATION_REFRESH_MS) {
|
|
192
|
+
return verdict;
|
|
193
|
+
}
|
|
194
|
+
if (supported) {
|
|
195
|
+
features[origin] = {
|
|
196
|
+
agentHomeWorkspaceDefault: true,
|
|
197
|
+
observedAt: new Date(now).toISOString(),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
delete features[origin];
|
|
202
|
+
}
|
|
203
|
+
fs.mkdirSync(cacheDir, { recursive: true, mode: 0o700 });
|
|
204
|
+
const file = featuresPath(cacheDir);
|
|
205
|
+
const tmp = `${file}.${process.pid}.${now}.tmp`;
|
|
206
|
+
fs.writeFileSync(tmp, JSON.stringify(features), { mode: 0o600 });
|
|
207
|
+
fs.renameSync(tmp, file);
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
// Best-effort: the next turn simply reads the agent again.
|
|
211
|
+
}
|
|
212
|
+
return verdict;
|
|
213
|
+
}
|