@skrr-ai/cli 0.1.86 → 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/bin/run.js +11 -0
- package/dist/base-command.js +1 -0
- package/dist/commands/agents/chat.d.ts +58 -1
- package/dist/commands/agents/chat.js +206 -4
- 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 +26 -0
- package/dist/lib/agent-home-workspace.js +174 -0
- package/dist/lib/agentic-stream.d.ts +135 -0
- package/dist/lib/agentic-stream.js +341 -6
- package/dist/lib/auth-storage.d.ts +4 -0
- package/dist/lib/auth-storage.js +33 -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/keychain.d.ts +1 -0
- package/dist/lib/keychain.js +67 -14
- 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/refresh.d.ts +7 -0
- package/dist/lib/refresh.js +2 -1
- 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 +18855 -17260
- package/package.json +2 -2
package/dist/lib/keychain.js
CHANGED
|
@@ -43,6 +43,7 @@ exports.isLegacySlotCurrent = isLegacySlotCurrent;
|
|
|
43
43
|
exports.__currentServiceForTest = __currentServiceForTest;
|
|
44
44
|
exports.isAvailable = isAvailable;
|
|
45
45
|
exports.resetAvailability = resetAvailability;
|
|
46
|
+
exports.withKeychainReadPass = withKeychainReadPass;
|
|
46
47
|
exports.readToken = readToken;
|
|
47
48
|
exports.writeToken = writeToken;
|
|
48
49
|
exports.readRefreshToken = readRefreshToken;
|
|
@@ -256,17 +257,56 @@ function isSecretAccount(account) {
|
|
|
256
257
|
return account === ACCOUNT_TOKEN || account === ACCOUNT_REFRESH;
|
|
257
258
|
}
|
|
258
259
|
/**
|
|
259
|
-
*
|
|
260
|
-
*
|
|
260
|
+
* One synchronous read of a bundle, memoised per (service, account).
|
|
261
|
+
*
|
|
262
|
+
* Every `security` call is a process spawn costing ~15-20ms, and a bundle read
|
|
263
|
+
* used to make eight of them for six items: each secret's envelope decrypt
|
|
264
|
+
* re-read the owner record (`foreignOwnerRootAt`), and the bundle read it a
|
|
265
|
+
* third time for itself. Measured on `skrr agents show`, that was 17 serial
|
|
266
|
+
* spawns and ~280ms before the first request could leave.
|
|
267
|
+
*
|
|
268
|
+
* A pass is SYNCHRONOUS by construction (`execFileSync` throughout, and the
|
|
269
|
+
* callback is not awaited), so nothing else in this process can interleave a
|
|
270
|
+
* write; a write made inside the pass drops the memo for that item. Another
|
|
271
|
+
* process's write is no more or less visible than before — the eight separate
|
|
272
|
+
* reads were never one atomic snapshot either. Outside a pass nothing is
|
|
273
|
+
* memoised: a later read always reaches the Keychain, which is what the
|
|
274
|
+
* refresh path's re-read under the auth lock depends on.
|
|
261
275
|
*/
|
|
262
|
-
|
|
263
|
-
|
|
276
|
+
let readPassMemo = null;
|
|
277
|
+
function withKeychainReadPass(fn) {
|
|
278
|
+
if (readPassMemo)
|
|
279
|
+
return fn();
|
|
280
|
+
readPassMemo = new Map();
|
|
281
|
+
try {
|
|
282
|
+
return fn();
|
|
283
|
+
}
|
|
284
|
+
finally {
|
|
285
|
+
readPassMemo = null;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
function memoKey(service, account) {
|
|
289
|
+
return `${service}\u0000${account}`;
|
|
290
|
+
}
|
|
291
|
+
function forgetSlotInPass(account, service) {
|
|
292
|
+
readPassMemo?.delete(memoKey(service, account));
|
|
293
|
+
}
|
|
294
|
+
/** The stored string exactly as `security` returns it, or null. */
|
|
295
|
+
function readRawSlot(account, service) {
|
|
296
|
+
const key = memoKey(service, account);
|
|
297
|
+
if (readPassMemo?.has(key))
|
|
298
|
+
return readPassMemo.get(key) ?? null;
|
|
299
|
+
const value = execReadSlot(account, service);
|
|
300
|
+
readPassMemo?.set(key, value);
|
|
301
|
+
return value;
|
|
302
|
+
}
|
|
303
|
+
function execReadSlot(account, service) {
|
|
264
304
|
try {
|
|
265
305
|
const out = (0, node_child_process_1.execFileSync)('security', ['find-generic-password', '-s', service, '-a', account, '-w'], { stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf-8' });
|
|
266
306
|
const trimmed = out.replace(/\n$/, '');
|
|
267
307
|
if (trimmed.length === 0)
|
|
268
308
|
return null;
|
|
269
|
-
|
|
309
|
+
return trimmed;
|
|
270
310
|
}
|
|
271
311
|
catch (err) {
|
|
272
312
|
const status = err.status;
|
|
@@ -280,6 +320,15 @@ function readSlot(account, service = currentService(), raw_ = false) {
|
|
|
280
320
|
}
|
|
281
321
|
return null;
|
|
282
322
|
}
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* `raw` returns the stored string exactly, with no envelope transform — for
|
|
326
|
+
* copying another config's item, which may be sealed under a key we lack.
|
|
327
|
+
*/
|
|
328
|
+
function readSlot(account, service = currentService(), raw_ = false) {
|
|
329
|
+
const raw = readRawSlot(account, service);
|
|
330
|
+
if (raw === null)
|
|
331
|
+
return null;
|
|
283
332
|
if (raw_ || !isSecretAccount(account))
|
|
284
333
|
return raw;
|
|
285
334
|
// L12 — route secret slots through the envelope.
|
|
@@ -339,6 +388,7 @@ function quoteForSecurityInteractive(v) {
|
|
|
339
388
|
return '"' + v.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"';
|
|
340
389
|
}
|
|
341
390
|
function writeSlot(account, value, service = currentService(), raw = false) {
|
|
391
|
+
forgetSlotInPass(account, service);
|
|
342
392
|
try {
|
|
343
393
|
// L12 — wrap secret-bearing slots through the envelope when active.
|
|
344
394
|
// Empty / non-secret slots are passthrough, and so is a raw copy.
|
|
@@ -364,6 +414,7 @@ function writeSlot(account, value, service = currentService(), raw = false) {
|
|
|
364
414
|
}
|
|
365
415
|
}
|
|
366
416
|
function deleteSlot(account, service = currentService()) {
|
|
417
|
+
forgetSlotInPass(account, service);
|
|
367
418
|
try {
|
|
368
419
|
(0, node_child_process_1.execFileSync)('security', ['delete-generic-password', '-s', service, '-a', account], {
|
|
369
420
|
stdio: ['ignore', 'ignore', 'ignore'],
|
|
@@ -484,15 +535,17 @@ function readBundleAt(slot) {
|
|
|
484
535
|
if (!isAvailable())
|
|
485
536
|
return null;
|
|
486
537
|
const service = serviceForSlot(slot);
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
538
|
+
return withKeychainReadPass(() => {
|
|
539
|
+
const token = readEntryAt(service, ACCOUNT_TOKEN, ACCOUNT_EXPIRES);
|
|
540
|
+
if (!token)
|
|
541
|
+
return null;
|
|
542
|
+
return {
|
|
543
|
+
token,
|
|
544
|
+
refresh: readEntryAt(service, ACCOUNT_REFRESH, ACCOUNT_REFRESH_EXPIRES),
|
|
545
|
+
serverOrigin: readSlot(ACCOUNT_SERVER_ORIGIN, service) || null,
|
|
546
|
+
owner: readSlot(ACCOUNT_OWNER, service) || null,
|
|
547
|
+
};
|
|
548
|
+
});
|
|
496
549
|
}
|
|
497
550
|
const BUNDLE_ACCOUNTS = [
|
|
498
551
|
ACCOUNT_TOKEN,
|
|
@@ -39,6 +39,18 @@ export declare const labelScopeFlags: {
|
|
|
39
39
|
scope: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
40
40
|
'scope-id': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
41
41
|
};
|
|
42
|
+
/**
|
|
43
|
+
* `--allow-duplicate-name`, shared by every command that can put a live name
|
|
44
|
+
* into a scope (create, rename, restore).
|
|
45
|
+
*
|
|
46
|
+
* The SERVER owns the rule (`LabelService.assertNameFreeInOtherScope`): a name
|
|
47
|
+
* another label you can use already carries is refused with
|
|
48
|
+
* `409 duplicate_name_other_scope`, and the refusal names that label. The CLI
|
|
49
|
+
* only relays the override, so every surface — web, MCP, CLI — gets one answer.
|
|
50
|
+
*/
|
|
51
|
+
export declare const allowDuplicateNameFlags: {
|
|
52
|
+
'allow-duplicate-name': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
53
|
+
};
|
|
42
54
|
export interface ResolvedLabelScope {
|
|
43
55
|
scope: LabelScope;
|
|
44
56
|
scopeId?: string;
|
package/dist/lib/label-scope.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* id the server can infer (it falls back to the caller).
|
|
12
12
|
*/
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.labelScopeFlags = exports.HEX_COLOR_RE = exports.LABEL_APPLICABLE = exports.LABEL_SCOPES_INFERRED = exports.LABEL_SCOPES_REQUIRING_ID = exports.LABEL_SCOPES = void 0;
|
|
14
|
+
exports.allowDuplicateNameFlags = exports.labelScopeFlags = exports.HEX_COLOR_RE = exports.LABEL_APPLICABLE = exports.LABEL_SCOPES_INFERRED = exports.LABEL_SCOPES_REQUIRING_ID = exports.LABEL_SCOPES = void 0;
|
|
15
15
|
exports.normalizeLabelColor = normalizeLabelColor;
|
|
16
16
|
exports.resolveLabelScope = resolveLabelScope;
|
|
17
17
|
exports.resolveApplicableTo = resolveApplicableTo;
|
|
@@ -56,6 +56,20 @@ exports.labelScopeFlags = {
|
|
|
56
56
|
description: `Scope owner ID — required for ${joinScopes(scopesRequiringId())}. Omit for ${joinScopes(exports.LABEL_SCOPES_INFERRED)} (defaults to you).`,
|
|
57
57
|
}),
|
|
58
58
|
};
|
|
59
|
+
/**
|
|
60
|
+
* `--allow-duplicate-name`, shared by every command that can put a live name
|
|
61
|
+
* into a scope (create, rename, restore).
|
|
62
|
+
*
|
|
63
|
+
* The SERVER owns the rule (`LabelService.assertNameFreeInOtherScope`): a name
|
|
64
|
+
* another label you can use already carries is refused with
|
|
65
|
+
* `409 duplicate_name_other_scope`, and the refusal names that label. The CLI
|
|
66
|
+
* only relays the override, so every surface — web, MCP, CLI — gets one answer.
|
|
67
|
+
*/
|
|
68
|
+
exports.allowDuplicateNameFlags = {
|
|
69
|
+
'allow-duplicate-name': core_1.Flags.boolean({
|
|
70
|
+
description: 'Proceed even though another label you can use (your user scope, or a workspace you belong to) already has this name. Refused by default: two labels with one name make `--label <name>` ambiguous.',
|
|
71
|
+
}),
|
|
72
|
+
};
|
|
59
73
|
/**
|
|
60
74
|
* Validate the scope pair. Throws a plain `Error` so callers can surface it
|
|
61
75
|
* through `this.error(..., { exit: 1 })` with the rest of their flag checks.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { COMPUTER_AUDIT_KINDS, type ComputerAuditPage } from '@skrr-ai/data-provider';
|
|
2
|
+
/**
|
|
3
|
+
* machine-audit.ts — request client for `GET /api/machines/:machineId/audit`
|
|
4
|
+
* (design §9, D8/D10; OSK-13607): who did what on a machine, after the
|
|
5
|
+
* daemon's live Activity window has rolled off.
|
|
6
|
+
*
|
|
7
|
+
* The owner reads it always; a grantee at any tier reads it too, without the
|
|
8
|
+
* `grant_*` events (those name the other people the machine is shared with).
|
|
9
|
+
* Vocabulary and the page shape are owned by `@skrr-ai/data-provider`.
|
|
10
|
+
*
|
|
11
|
+
* ## Inline path literal
|
|
12
|
+
*
|
|
13
|
+
* `domain-api-parity` resolves a command to an endpoint by reading this
|
|
14
|
+
* string; a helper that assembled the URL would read as unreachable.
|
|
15
|
+
*/
|
|
16
|
+
export { COMPUTER_AUDIT_KINDS };
|
|
17
|
+
export type { ComputerAuditPage };
|
|
18
|
+
export interface MachineAuditQuery {
|
|
19
|
+
kinds?: string[];
|
|
20
|
+
actorUserId?: string;
|
|
21
|
+
/** ISO time or epoch ms — occurredAt >= since. */
|
|
22
|
+
since?: string | number;
|
|
23
|
+
/** ISO time or epoch ms — occurredAt < until. */
|
|
24
|
+
until?: string | number;
|
|
25
|
+
cursor?: string;
|
|
26
|
+
limit?: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A `--since` / `--until` value as an ISO time: an absolute time as typed
|
|
30
|
+
* (`2026-09-24`, `2026-09-24T10:00:00Z`), or an age such as `90m`, `12h`,
|
|
31
|
+
* `7d`, `2w` counted back from `now`. Throws on anything else, naming the flag.
|
|
32
|
+
*/
|
|
33
|
+
export declare function parseAuditTime(value: string, flagName: string, now?: number): string;
|
|
34
|
+
export declare function listMachineAudit(machineId: string, query?: MachineAuditQuery): Promise<ComputerAuditPage>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.COMPUTER_AUDIT_KINDS = void 0;
|
|
4
|
+
exports.parseAuditTime = parseAuditTime;
|
|
5
|
+
exports.listMachineAudit = listMachineAudit;
|
|
6
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
7
|
+
Object.defineProperty(exports, "COMPUTER_AUDIT_KINDS", { enumerable: true, get: function () { return data_provider_1.COMPUTER_AUDIT_KINDS; } });
|
|
8
|
+
const api_fetch_1 = require("./api-fetch");
|
|
9
|
+
const DURATION_MS = {
|
|
10
|
+
s: 1000,
|
|
11
|
+
m: 60_000,
|
|
12
|
+
h: 3_600_000,
|
|
13
|
+
d: 86_400_000,
|
|
14
|
+
w: 7 * 86_400_000,
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* A `--since` / `--until` value as an ISO time: an absolute time as typed
|
|
18
|
+
* (`2026-09-24`, `2026-09-24T10:00:00Z`), or an age such as `90m`, `12h`,
|
|
19
|
+
* `7d`, `2w` counted back from `now`. Throws on anything else, naming the flag.
|
|
20
|
+
*/
|
|
21
|
+
function parseAuditTime(value, flagName, now = Date.now()) {
|
|
22
|
+
const trimmed = value.trim();
|
|
23
|
+
const age = trimmed.match(/^(\d+)([smhdw])$/i);
|
|
24
|
+
if (age) {
|
|
25
|
+
return new Date(now - Number(age[1]) * DURATION_MS[age[2].toLowerCase()]).toISOString();
|
|
26
|
+
}
|
|
27
|
+
const absolute = new Date(trimmed);
|
|
28
|
+
if (!trimmed || Number.isNaN(absolute.getTime())) {
|
|
29
|
+
throw new Error(`Invalid ${flagName} value: ${value}. Use a time such as 2026-09-24 or an age such as 7d.`);
|
|
30
|
+
}
|
|
31
|
+
return absolute.toISOString();
|
|
32
|
+
}
|
|
33
|
+
async function listMachineAudit(machineId, query = {}) {
|
|
34
|
+
const params = new URLSearchParams();
|
|
35
|
+
for (const kind of query.kinds ?? [])
|
|
36
|
+
params.append('kind', kind);
|
|
37
|
+
if (query.actorUserId)
|
|
38
|
+
params.set('actor', query.actorUserId);
|
|
39
|
+
if (query.since != null)
|
|
40
|
+
params.set('since', String(query.since));
|
|
41
|
+
if (query.until != null)
|
|
42
|
+
params.set('until', String(query.until));
|
|
43
|
+
if (query.cursor)
|
|
44
|
+
params.set('cursor', query.cursor);
|
|
45
|
+
if (query.limit != null)
|
|
46
|
+
params.set('limit', String(query.limit));
|
|
47
|
+
const qs = params.toString();
|
|
48
|
+
const suffix = qs ? `?${qs}` : '';
|
|
49
|
+
return (0, api_fetch_1.apiFetch)(`/api/machines/${encodeURIComponent(machineId)}/audit` + suffix);
|
|
50
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* machine-grants.ts — request client for `/api/machines/:machineId/grants`
|
|
3
|
+
* (design §9, D10; OSK-13558): who the owner shares a machine with.
|
|
4
|
+
*
|
|
5
|
+
* A grant gives one person, on one machine, one of two fixed tiers — `watch`
|
|
6
|
+
* (see every surface and its activity; no input, no file browsing) or
|
|
7
|
+
* `operate` (everything watch has, plus control and file read/write). `power`,
|
|
8
|
+
* closing other people's surfaces and grant management stay with the owner,
|
|
9
|
+
* which is why every verb here resolves machine OWNERSHIP server-side rather
|
|
10
|
+
* than checking a grant. The grantee may be any user, inside the owner's
|
|
11
|
+
* workspace or not.
|
|
12
|
+
*
|
|
13
|
+
* ## Inline path literals
|
|
14
|
+
*
|
|
15
|
+
* `domain-api-parity` resolves a command to an endpoint by reading these
|
|
16
|
+
* strings. A helper that assembles the URL is opaque to it, so the endpoint
|
|
17
|
+
* would read as unreachable and get allow-listed — a check going green on an
|
|
18
|
+
* assertion it never made.
|
|
19
|
+
*/
|
|
20
|
+
export declare const MACHINE_GRANT_TIERS: readonly ["watch", "operate"];
|
|
21
|
+
export type MachineGrantTier = (typeof MACHINE_GRANT_TIERS)[number];
|
|
22
|
+
/** One grant, as `ComputerGrantService.publicGrant` emits it. */
|
|
23
|
+
export interface MachineGrant {
|
|
24
|
+
grantId: string;
|
|
25
|
+
machineId: string;
|
|
26
|
+
ownerUserId: string;
|
|
27
|
+
granteeUserId: string;
|
|
28
|
+
tier: MachineGrantTier;
|
|
29
|
+
createdAt?: number;
|
|
30
|
+
updatedAt?: number;
|
|
31
|
+
}
|
|
32
|
+
export interface MachineGrantList {
|
|
33
|
+
version: number;
|
|
34
|
+
grants: MachineGrant[];
|
|
35
|
+
}
|
|
36
|
+
export interface MachineGrantMutation {
|
|
37
|
+
grant: MachineGrant;
|
|
38
|
+
version: number;
|
|
39
|
+
/** POST only: false when the person already held this exact grant. */
|
|
40
|
+
created?: boolean;
|
|
41
|
+
/** PATCH only: false when the grant already held this tier. */
|
|
42
|
+
changed?: boolean;
|
|
43
|
+
}
|
|
44
|
+
export interface MachineGrantRevocation {
|
|
45
|
+
revoked: MachineGrant;
|
|
46
|
+
version: number;
|
|
47
|
+
}
|
|
48
|
+
export declare function listMachineGrants(machineId: string): Promise<MachineGrantList>;
|
|
49
|
+
export declare function shareMachine(machineId: string, granteeUserId: string, tier: MachineGrantTier): Promise<MachineGrantMutation>;
|
|
50
|
+
export declare function changeMachineGrant(machineId: string, granteeUserId: string, tier: MachineGrantTier): Promise<MachineGrantMutation>;
|
|
51
|
+
export declare function unshareMachine(machineId: string, granteeUserId: string): Promise<MachineGrantRevocation>;
|
|
52
|
+
export interface SharedMachine {
|
|
53
|
+
machineId: string;
|
|
54
|
+
name: string | null;
|
|
55
|
+
owner: {
|
|
56
|
+
userId: string;
|
|
57
|
+
name: string;
|
|
58
|
+
username?: string;
|
|
59
|
+
avatar?: string;
|
|
60
|
+
} | null;
|
|
61
|
+
tier: MachineGrantTier;
|
|
62
|
+
grantedAt?: number;
|
|
63
|
+
power?: {
|
|
64
|
+
phase: string;
|
|
65
|
+
} | null;
|
|
66
|
+
}
|
|
67
|
+
export interface SharedMachineList {
|
|
68
|
+
machines: SharedMachine[];
|
|
69
|
+
}
|
|
70
|
+
export declare function listSharedMachines(): Promise<SharedMachineList>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MACHINE_GRANT_TIERS = void 0;
|
|
4
|
+
exports.listMachineGrants = listMachineGrants;
|
|
5
|
+
exports.shareMachine = shareMachine;
|
|
6
|
+
exports.changeMachineGrant = changeMachineGrant;
|
|
7
|
+
exports.unshareMachine = unshareMachine;
|
|
8
|
+
exports.listSharedMachines = listSharedMachines;
|
|
9
|
+
const api_fetch_1 = require("./api-fetch");
|
|
10
|
+
/**
|
|
11
|
+
* machine-grants.ts — request client for `/api/machines/:machineId/grants`
|
|
12
|
+
* (design §9, D10; OSK-13558): who the owner shares a machine with.
|
|
13
|
+
*
|
|
14
|
+
* A grant gives one person, on one machine, one of two fixed tiers — `watch`
|
|
15
|
+
* (see every surface and its activity; no input, no file browsing) or
|
|
16
|
+
* `operate` (everything watch has, plus control and file read/write). `power`,
|
|
17
|
+
* closing other people's surfaces and grant management stay with the owner,
|
|
18
|
+
* which is why every verb here resolves machine OWNERSHIP server-side rather
|
|
19
|
+
* than checking a grant. The grantee may be any user, inside the owner's
|
|
20
|
+
* workspace or not.
|
|
21
|
+
*
|
|
22
|
+
* ## Inline path literals
|
|
23
|
+
*
|
|
24
|
+
* `domain-api-parity` resolves a command to an endpoint by reading these
|
|
25
|
+
* strings. A helper that assembles the URL is opaque to it, so the endpoint
|
|
26
|
+
* would read as unreachable and get allow-listed — a check going green on an
|
|
27
|
+
* assertion it never made.
|
|
28
|
+
*/
|
|
29
|
+
exports.MACHINE_GRANT_TIERS = ['watch', 'operate'];
|
|
30
|
+
async function listMachineGrants(machineId) {
|
|
31
|
+
return (0, api_fetch_1.apiFetch)(`/api/machines/${encodeURIComponent(machineId)}/grants`);
|
|
32
|
+
}
|
|
33
|
+
async function shareMachine(machineId, granteeUserId, tier) {
|
|
34
|
+
return (0, api_fetch_1.apiFetch)(`/api/machines/${encodeURIComponent(machineId)}/grants`, {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
body: { granteeUserId, tier },
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
async function changeMachineGrant(machineId, granteeUserId, tier) {
|
|
40
|
+
return (0, api_fetch_1.apiFetch)(`/api/machines/${encodeURIComponent(machineId)}/grants/${encodeURIComponent(granteeUserId)}`, { method: 'PATCH', body: { tier } });
|
|
41
|
+
}
|
|
42
|
+
async function unshareMachine(machineId, granteeUserId) {
|
|
43
|
+
return (0, api_fetch_1.apiFetch)(`/api/machines/${encodeURIComponent(machineId)}/grants/${encodeURIComponent(granteeUserId)}`, { method: 'DELETE' });
|
|
44
|
+
}
|
|
45
|
+
async function listSharedMachines() {
|
|
46
|
+
return (0, api_fetch_1.apiFetch)('/api/machines/shared-with-me');
|
|
47
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* machine-services.ts — request client for `/api/machines/:machineId/services`
|
|
3
|
+
* (design §20.5; 9-17, OSK-13579): a machine's declared services, the web
|
|
4
|
+
* services an agent or a person started on it, named so the computer can open
|
|
5
|
+
* them in its own browser.
|
|
6
|
+
*
|
|
7
|
+
* Not the same thing as `skrr machines dedicated service`: those are always-on
|
|
8
|
+
* WORKLOADS a Dedicated Runtime keeps running. A declared service is an
|
|
9
|
+
* address — a port on the machine's own loopback, and an optional path — on
|
|
10
|
+
* any computer, a personal machine's included. Declaring one starts nothing.
|
|
11
|
+
*
|
|
12
|
+
* Who may: the owner and an `operate` grantee declare and withdraw; a `watch`
|
|
13
|
+
* grantee may list. The server decides (`ComputerAccess`), and so does the
|
|
14
|
+
* machine's daemon, against the grant set it holds.
|
|
15
|
+
*
|
|
16
|
+
* ## Inline path literals
|
|
17
|
+
*
|
|
18
|
+
* `domain-api-parity` resolves a command to an endpoint by reading these
|
|
19
|
+
* strings, so each one is written out here rather than assembled by a helper.
|
|
20
|
+
*/
|
|
21
|
+
export declare const DECLARED_SERVICE_PROTOCOLS: readonly ["http", "https"];
|
|
22
|
+
export type DeclaredServiceProtocol = (typeof DECLARED_SERVICE_PROTOCOLS)[number];
|
|
23
|
+
export type DeclaredServiceActor = {
|
|
24
|
+
kind: 'agent';
|
|
25
|
+
agentId: string;
|
|
26
|
+
sessionId: string;
|
|
27
|
+
label: string;
|
|
28
|
+
} | {
|
|
29
|
+
kind: 'human';
|
|
30
|
+
userId: string;
|
|
31
|
+
label: string;
|
|
32
|
+
};
|
|
33
|
+
/** One declared service, as the machine's manifest carries it. */
|
|
34
|
+
export interface DeclaredService {
|
|
35
|
+
name: string;
|
|
36
|
+
port: number;
|
|
37
|
+
path: string;
|
|
38
|
+
protocol: DeclaredServiceProtocol;
|
|
39
|
+
declaredBy: DeclaredServiceActor;
|
|
40
|
+
declaredAt: number;
|
|
41
|
+
}
|
|
42
|
+
export interface DeclaredServicesResult {
|
|
43
|
+
services: DeclaredService[];
|
|
44
|
+
service?: DeclaredService;
|
|
45
|
+
replaced?: boolean;
|
|
46
|
+
withdrawn?: DeclaredService;
|
|
47
|
+
}
|
|
48
|
+
/** Where a service opens: always the machine's own loopback. */
|
|
49
|
+
export declare function declaredServiceAddress(service: Pick<DeclaredService, 'port' | 'path' | 'protocol'>): string;
|
|
50
|
+
export declare function listMachineServices(machineId: string): Promise<DeclaredServicesResult>;
|
|
51
|
+
export declare function declareMachineService(machineId: string, service: {
|
|
52
|
+
name: string;
|
|
53
|
+
port: number;
|
|
54
|
+
path?: string;
|
|
55
|
+
protocol?: DeclaredServiceProtocol;
|
|
56
|
+
}): Promise<DeclaredServicesResult>;
|
|
57
|
+
export declare function withdrawMachineService(machineId: string, name: string): Promise<DeclaredServicesResult>;
|
|
58
|
+
/**
|
|
59
|
+
* The machine id a services command addresses. A machine the person owns
|
|
60
|
+
* resolves from their inventory by any of its names; a machine shared WITH
|
|
61
|
+
* them is not in that inventory, so a full machine id (`lease:…`,
|
|
62
|
+
* `daemon:…`, `machine:…`) is taken as written — the server decides access.
|
|
63
|
+
*/
|
|
64
|
+
export declare function servicesMachineId(ref: string): Promise<string>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DECLARED_SERVICE_PROTOCOLS = void 0;
|
|
4
|
+
exports.declaredServiceAddress = declaredServiceAddress;
|
|
5
|
+
exports.listMachineServices = listMachineServices;
|
|
6
|
+
exports.declareMachineService = declareMachineService;
|
|
7
|
+
exports.withdrawMachineService = withdrawMachineService;
|
|
8
|
+
exports.servicesMachineId = servicesMachineId;
|
|
9
|
+
const api_fetch_1 = require("./api-fetch");
|
|
10
|
+
const machines_1 = require("./machines");
|
|
11
|
+
/**
|
|
12
|
+
* machine-services.ts — request client for `/api/machines/:machineId/services`
|
|
13
|
+
* (design §20.5; 9-17, OSK-13579): a machine's declared services, the web
|
|
14
|
+
* services an agent or a person started on it, named so the computer can open
|
|
15
|
+
* them in its own browser.
|
|
16
|
+
*
|
|
17
|
+
* Not the same thing as `skrr machines dedicated service`: those are always-on
|
|
18
|
+
* WORKLOADS a Dedicated Runtime keeps running. A declared service is an
|
|
19
|
+
* address — a port on the machine's own loopback, and an optional path — on
|
|
20
|
+
* any computer, a personal machine's included. Declaring one starts nothing.
|
|
21
|
+
*
|
|
22
|
+
* Who may: the owner and an `operate` grantee declare and withdraw; a `watch`
|
|
23
|
+
* grantee may list. The server decides (`ComputerAccess`), and so does the
|
|
24
|
+
* machine's daemon, against the grant set it holds.
|
|
25
|
+
*
|
|
26
|
+
* ## Inline path literals
|
|
27
|
+
*
|
|
28
|
+
* `domain-api-parity` resolves a command to an endpoint by reading these
|
|
29
|
+
* strings, so each one is written out here rather than assembled by a helper.
|
|
30
|
+
*/
|
|
31
|
+
exports.DECLARED_SERVICE_PROTOCOLS = ['http', 'https'];
|
|
32
|
+
/** Where a service opens: always the machine's own loopback. */
|
|
33
|
+
function declaredServiceAddress(service) {
|
|
34
|
+
return `${service.protocol}://localhost:${service.port}${service.path}`;
|
|
35
|
+
}
|
|
36
|
+
async function listMachineServices(machineId) {
|
|
37
|
+
return (0, api_fetch_1.apiFetch)(`/api/machines/${encodeURIComponent(machineId)}/services`);
|
|
38
|
+
}
|
|
39
|
+
async function declareMachineService(machineId, service) {
|
|
40
|
+
return (0, api_fetch_1.apiFetch)(`/api/machines/${encodeURIComponent(machineId)}/services`, { method: 'POST', body: { service } });
|
|
41
|
+
}
|
|
42
|
+
async function withdrawMachineService(machineId, name) {
|
|
43
|
+
return (0, api_fetch_1.apiFetch)(`/api/machines/${encodeURIComponent(machineId)}/services/${encodeURIComponent(name)}`, { method: 'DELETE' });
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The machine id a services command addresses. A machine the person owns
|
|
47
|
+
* resolves from their inventory by any of its names; a machine shared WITH
|
|
48
|
+
* them is not in that inventory, so a full machine id (`lease:…`,
|
|
49
|
+
* `daemon:…`, `machine:…`) is taken as written — the server decides access.
|
|
50
|
+
*/
|
|
51
|
+
async function servicesMachineId(ref) {
|
|
52
|
+
try {
|
|
53
|
+
return (0, machines_1.resolveMachineRef)(await (0, machines_1.listMachines)(), ref).id;
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (/^(lease|daemon|machine|stable-daemon):\S+$/.test(ref))
|
|
57
|
+
return ref;
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
}
|
package/dist/lib/refresh.d.ts
CHANGED
|
@@ -38,6 +38,13 @@ export interface EnsureFreshCliCredentialOptions {
|
|
|
38
38
|
force?: boolean;
|
|
39
39
|
/** Respect `--bare`: do not mutate persisted credentials in bare mode. */
|
|
40
40
|
bareMode?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* `credential` was produced by the resolver a moment ago; decide from the
|
|
43
|
+
* Keychain read it made rather than reading every slot again
|
|
44
|
+
* (`takeResolvedKeychainRead`). Falls back to a fresh read whenever that read
|
|
45
|
+
* does not describe exactly this credential.
|
|
46
|
+
*/
|
|
47
|
+
reuseResolvedRead?: boolean;
|
|
41
48
|
}
|
|
42
49
|
export interface EnsureFreshCliCredentialResult {
|
|
43
50
|
credential: ResolvedCredential;
|
package/dist/lib/refresh.js
CHANGED
|
@@ -133,7 +133,8 @@ async function ensureFreshCliCredential(opts = {}) {
|
|
|
133
133
|
return { credential, refreshed: false, skippedReason: 'external_source' };
|
|
134
134
|
}
|
|
135
135
|
const cfg = (0, config_1.loadConfig)();
|
|
136
|
-
const read = (0, auth_storage_1.
|
|
136
|
+
const read = (opts.reuseResolvedRead ? (0, auth_storage_1.takeResolvedKeychainRead)(credential, cfg.baseURL) : null) ??
|
|
137
|
+
(0, auth_storage_1.readFromBackend)(cfg.baseURL);
|
|
137
138
|
// If a sibling process already rotated the stored access token, adopt it
|
|
138
139
|
// instead of needlessly consuming the latest refresh token again.
|
|
139
140
|
if (read.bundle?.token && read.bundle.token !== credential.token) {
|
|
@@ -113,7 +113,7 @@ function describeTaskView(view) {
|
|
|
113
113
|
['status types', f.statusTypes],
|
|
114
114
|
['priorities', f.priorities],
|
|
115
115
|
['assignees', f.assignees],
|
|
116
|
-
['labels', f.labels],
|
|
116
|
+
[f.labelMatch === 'all' ? 'labels (all)' : 'labels (any)', f.labels],
|
|
117
117
|
['goals', f.goalIds],
|
|
118
118
|
['projects', f.projectIds],
|
|
119
119
|
['cycles', f.cycleIds],
|
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
* a re-export, not a second CLI vocabulary: adding a saved-view capability is
|
|
6
6
|
* one data-provider registration followed by renderer work on each surface.
|
|
7
7
|
*/
|
|
8
|
-
export { SPACE_RENDERABLE_VIEW_TYPES, TASK_VIEW_DEFAULT_GROUP_BY, TASK_VIEW_DEFAULT_TYPE, TASK_RENDERABLE_VIEW_TYPES, VIEW_GROUP_BY_REGISTRY, VIEW_GROUP_BY_VALUES, VIEW_QUICK_FILTER_REGISTRY, VIEW_QUICK_FILTERS, VIEW_SORT_DIRECTIONS, VIEW_SORT_KEY_REGISTRY, VIEW_SORT_KEYS, VIEW_TYPE_REGISTRY, VIEW_TYPES, viewTypesForSurface, } from '@skrr-ai/data-provider';
|
|
8
|
+
export { SPACE_RENDERABLE_VIEW_TYPES, TASK_VIEW_DEFAULT_GROUP_BY, TASK_VIEW_DEFAULT_TYPE, TASK_RENDERABLE_VIEW_TYPES, VIEW_GROUP_BY_REGISTRY, VIEW_GROUP_BY_VALUES, VIEW_LABEL_MATCH_VALUES, VIEW_QUICK_FILTER_REGISTRY, VIEW_QUICK_FILTERS, VIEW_SORT_DIRECTIONS, VIEW_SORT_KEY_REGISTRY, VIEW_SORT_KEYS, VIEW_TYPE_REGISTRY, VIEW_TYPES, viewTypesForSurface, } from '@skrr-ai/data-provider';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.viewTypesForSurface = exports.VIEW_TYPES = exports.VIEW_TYPE_REGISTRY = exports.VIEW_SORT_KEYS = exports.VIEW_SORT_KEY_REGISTRY = exports.VIEW_SORT_DIRECTIONS = exports.VIEW_QUICK_FILTERS = exports.VIEW_QUICK_FILTER_REGISTRY = exports.VIEW_GROUP_BY_VALUES = exports.VIEW_GROUP_BY_REGISTRY = exports.TASK_RENDERABLE_VIEW_TYPES = exports.TASK_VIEW_DEFAULT_TYPE = exports.TASK_VIEW_DEFAULT_GROUP_BY = exports.SPACE_RENDERABLE_VIEW_TYPES = void 0;
|
|
3
|
+
exports.viewTypesForSurface = exports.VIEW_TYPES = exports.VIEW_TYPE_REGISTRY = exports.VIEW_SORT_KEYS = exports.VIEW_SORT_KEY_REGISTRY = exports.VIEW_SORT_DIRECTIONS = exports.VIEW_QUICK_FILTERS = exports.VIEW_QUICK_FILTER_REGISTRY = exports.VIEW_LABEL_MATCH_VALUES = exports.VIEW_GROUP_BY_VALUES = exports.VIEW_GROUP_BY_REGISTRY = exports.TASK_RENDERABLE_VIEW_TYPES = exports.TASK_VIEW_DEFAULT_TYPE = exports.TASK_VIEW_DEFAULT_GROUP_BY = exports.SPACE_RENDERABLE_VIEW_TYPES = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* CLI parity re-export for persisted task views.
|
|
6
6
|
*
|
|
@@ -15,6 +15,7 @@ Object.defineProperty(exports, "TASK_VIEW_DEFAULT_TYPE", { enumerable: true, get
|
|
|
15
15
|
Object.defineProperty(exports, "TASK_RENDERABLE_VIEW_TYPES", { enumerable: true, get: function () { return data_provider_1.TASK_RENDERABLE_VIEW_TYPES; } });
|
|
16
16
|
Object.defineProperty(exports, "VIEW_GROUP_BY_REGISTRY", { enumerable: true, get: function () { return data_provider_1.VIEW_GROUP_BY_REGISTRY; } });
|
|
17
17
|
Object.defineProperty(exports, "VIEW_GROUP_BY_VALUES", { enumerable: true, get: function () { return data_provider_1.VIEW_GROUP_BY_VALUES; } });
|
|
18
|
+
Object.defineProperty(exports, "VIEW_LABEL_MATCH_VALUES", { enumerable: true, get: function () { return data_provider_1.VIEW_LABEL_MATCH_VALUES; } });
|
|
18
19
|
Object.defineProperty(exports, "VIEW_QUICK_FILTER_REGISTRY", { enumerable: true, get: function () { return data_provider_1.VIEW_QUICK_FILTER_REGISTRY; } });
|
|
19
20
|
Object.defineProperty(exports, "VIEW_QUICK_FILTERS", { enumerable: true, get: function () { return data_provider_1.VIEW_QUICK_FILTERS; } });
|
|
20
21
|
Object.defineProperty(exports, "VIEW_SORT_DIRECTIONS", { enumerable: true, get: function () { return data_provider_1.VIEW_SORT_DIRECTIONS; } });
|