toolroll 0.9.50 → 0.9.52
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/CHANGELOG.md +21 -0
- package/dist/backup.d.ts +8 -0
- package/dist/backup.js +10 -1
- package/dist/browser/workspace.css +1 -1
- package/dist/browser/workspace.js +1 -1
- package/dist/browser-workspace.d.ts +1 -0
- package/dist/database-reclaim.d.ts +4 -0
- package/dist/database-reclaim.js +13 -0
- package/dist/demo.d.ts +1 -1
- package/dist/demo.js +1 -1
- package/dist/desktop-update.d.ts +1 -1
- package/dist/live-bus.d.ts +3 -3
- package/dist/live-bus.js +3 -3
- package/dist/mcp-oauth.d.ts +1 -1
- package/dist/mcp-oauth.js +3 -2
- package/dist/monitoring.js +32 -8
- package/dist/notification-delivery.d.ts +19 -0
- package/dist/notification-delivery.js +37 -0
- package/dist/operate-remote-arguments.js +1 -1
- package/dist/operate-remote.js +2 -2
- package/dist/operate.d.ts +1 -1
- package/dist/operate.js +54 -120
- package/dist/process-recovery-settlement.js +1 -0
- package/dist/request-budget.d.ts +5 -2
- package/dist/request-budget.js +7 -3
- package/dist/retention.js +6 -5
- package/dist/scope.d.ts +1 -0
- package/dist/scope.js +19 -9
- package/dist/serve.js +15 -10
- package/dist/server/people-tokens.js +1 -2
- package/dist/server/remote.js +19 -4
- package/dist/server/settings.js +3 -1
- package/dist/server/shared.d.ts +1 -0
- package/dist/server/shared.js +2 -0
- package/dist/sign-in-guard.d.ts +41 -16
- package/dist/sign-in-guard.js +147 -24
- package/dist/source-key.d.ts +2 -0
- package/dist/source-key.js +49 -0
- package/dist/store.d.ts +38 -43
- package/dist/store.js +255 -134
- package/dist/surface.js +1 -2
- package/dist/team-http.d.ts +3 -0
- package/dist/team-http.js +3 -0
- package/dist/toolroll-update.d.ts +14 -3
- package/dist/toolroll-update.js +105 -14
- package/dist/webhooks.d.ts +10 -22
- package/dist/webhooks.js +43 -81
- package/dist/work-index.js +2 -2
- package/dist/workspace-revision.d.ts +28 -1
- package/dist/workspace-revision.js +276 -49
- package/package.json +1 -3
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Database } from "./store.js";
|
|
2
|
+
/** Reclaim whole free pages on databases created without auto_vacuum. Call only after committing writes.
|
|
3
|
+
* A migration needs at least 1 MiB to justify the I/O; retention reclaims whenever more than 25% is free. */
|
|
4
|
+
export declare function reclaimDatabase(db: Database, reason: "migration" | "retention"): boolean;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Reclaim whole free pages on databases created without auto_vacuum. Call only after committing writes.
|
|
2
|
+
* A migration needs at least 1 MiB to justify the I/O; retention reclaims whenever more than 25% is free. */
|
|
3
|
+
export function reclaimDatabase(db, reason) {
|
|
4
|
+
const free = Number(db.prepare("PRAGMA freelist_count").get()["freelist_count"]);
|
|
5
|
+
const pages = Number(db.prepare("PRAGMA page_count").get()["page_count"]);
|
|
6
|
+
const size = Number(db.prepare("PRAGMA page_size").get()["page_size"]);
|
|
7
|
+
if (reason === "migration" ? free * size < 1024 * 1024 : free * 4 <= pages)
|
|
8
|
+
return false;
|
|
9
|
+
db.exec("VACUUM");
|
|
10
|
+
// VACUUM writes through WAL too: checkpoint so the main file (and its backups) shrinks now.
|
|
11
|
+
db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
|
|
12
|
+
return true;
|
|
13
|
+
}
|
package/dist/demo.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - The database is stamped `demo` BEFORE any row exists — an append-only
|
|
9
9
|
* installation fact with no unset API. Every spending or external-effect
|
|
10
10
|
* command (tick, watch, build, publish, reconcile, daemon, bridge,
|
|
11
|
-
*
|
|
11
|
+
* intake) fails closed on the stamp, so a kept sandbox
|
|
12
12
|
* can never be mistaken for real work by a worker pointed at it later.
|
|
13
13
|
* The console banner is decoration; the fence is enforcement.
|
|
14
14
|
* - The seeded history is SYNTHETIC and does not pretend otherwise: runs
|
package/dist/demo.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - The database is stamped `demo` BEFORE any row exists — an append-only
|
|
9
9
|
* installation fact with no unset API. Every spending or external-effect
|
|
10
10
|
* command (tick, watch, build, publish, reconcile, daemon, bridge,
|
|
11
|
-
*
|
|
11
|
+
* intake) fails closed on the stamp, so a kept sandbox
|
|
12
12
|
* can never be mistaken for real work by a worker pointed at it later.
|
|
13
13
|
* The console banner is decoration; the fence is enforcement.
|
|
14
14
|
* - The seeded history is SYNTHETIC and does not pretend otherwise: runs
|
package/dist/desktop-update.d.ts
CHANGED
|
@@ -94,13 +94,13 @@ export declare function prepareDesktopUpdate(stateDir: string, installed: string
|
|
|
94
94
|
export declare function sqliteLock(file: string, busyTimeoutMs?: number): DatabaseSync | null;
|
|
95
95
|
export declare const installationLock: (j: UpdateJournal) => DatabaseSync | null;
|
|
96
96
|
export declare function desktopUpdateStatus(stateDir: string): {
|
|
97
|
-
error?: never;
|
|
98
97
|
active: boolean;
|
|
99
98
|
phase: string;
|
|
100
99
|
detail: string;
|
|
101
100
|
running: boolean;
|
|
102
101
|
canResume: boolean;
|
|
103
102
|
canCancel: boolean;
|
|
103
|
+
error?: never;
|
|
104
104
|
automaticRecovery?: never;
|
|
105
105
|
recoveryAttempts?: never;
|
|
106
106
|
recoveryRepairs?: never;
|
package/dist/live-bus.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Live views push on write. Nothing here polls once a second.
|
|
3
3
|
*
|
|
4
|
-
* - The bus.
|
|
5
|
-
*
|
|
4
|
+
* - The bus. Every connection's write wrapper (workspace-revision.ts)
|
|
5
|
+
* moves one counter per committed meaningful write. After each in-process
|
|
6
6
|
* transact() COMMIT, and whenever another process (the worker, the CLI)
|
|
7
7
|
* writes the database's write-ahead log, the revision is read once; when
|
|
8
8
|
* it moved, every subscriber hears `{ revision }`. A rolled-back or quiet
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* gets one `reload` and ends so its EventSource can reconnect.
|
|
21
21
|
*
|
|
22
22
|
* Transport seam: a future WebSocket (live cursors) subscribes to the same
|
|
23
|
-
* LiveBus beside these SSE rooms; nothing in the Store or
|
|
23
|
+
* LiveBus beside these SSE rooms; nothing in the Store or its write wrapper changes.
|
|
24
24
|
*/
|
|
25
25
|
import { type FSWatcher } from "node:fs";
|
|
26
26
|
import type { ServerResponse } from "node:http";
|
package/dist/live-bus.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Live views push on write. Nothing here polls once a second.
|
|
3
3
|
*
|
|
4
|
-
* - The bus.
|
|
5
|
-
*
|
|
4
|
+
* - The bus. Every connection's write wrapper (workspace-revision.ts)
|
|
5
|
+
* moves one counter per committed meaningful write. After each in-process
|
|
6
6
|
* transact() COMMIT, and whenever another process (the worker, the CLI)
|
|
7
7
|
* writes the database's write-ahead log, the revision is read once; when
|
|
8
8
|
* it moved, every subscriber hears `{ revision }`. A rolled-back or quiet
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* gets one `reload` and ends so its EventSource can reconnect.
|
|
21
21
|
*
|
|
22
22
|
* Transport seam: a future WebSocket (live cursors) subscribes to the same
|
|
23
|
-
* LiveBus beside these SSE rooms; nothing in the Store or
|
|
23
|
+
* LiveBus beside these SSE rooms; nothing in the Store or its write wrapper changes.
|
|
24
24
|
*/
|
|
25
25
|
import { watch } from "node:fs";
|
|
26
26
|
import { WORKSPACE_REVISION_KEY } from "./workspace-revision.js";
|
package/dist/mcp-oauth.d.ts
CHANGED
|
@@ -62,7 +62,7 @@ export type OAuthHttpOptions = {
|
|
|
62
62
|
clock: () => Date;
|
|
63
63
|
/** This console's canonical origin for the request (the https public address, or this computer's loopback one); null: no sign-in here. */
|
|
64
64
|
originOf: (request: IncomingMessage) => string | null;
|
|
65
|
-
/** Trusted direct peer, or the last hop appended by the console's loopback proxy. */
|
|
65
|
+
/** Trusted direct peer, or the last hop appended by the console's loopback proxy (native IPv6 counted by its /64). */
|
|
66
66
|
requesterKey: (request: IncomingMessage) => string;
|
|
67
67
|
/** The browser session signed in by cookie, or null. A bearer never consents. */
|
|
68
68
|
session: (request: IncomingMessage) => OAuthSession | null;
|
package/dist/mcp-oauth.js
CHANGED
|
@@ -2,6 +2,7 @@ import { adapterPolicy } from "./server/route-policy.js";
|
|
|
2
2
|
import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
3
3
|
import { hashSecret, mintApiToken } from "./api-tokens.js";
|
|
4
4
|
import { limitWords } from "./request-budget.js";
|
|
5
|
+
import { sourceKey } from "./source-key.js";
|
|
5
6
|
import { PKCE_CHALLENGE, readOAuthRegistration, readOAuthTokenRequest } from "./contracts/mcp-oauth.js";
|
|
6
7
|
/** How long each piece lives. A code is spent at once; a grant ends after 30 days and the person consents again. */
|
|
7
8
|
export const OAUTH_TIMES = { requestMs: 10 * 60_000, codeMs: 60_000, accessSeconds: 3600, grantDays: 30 };
|
|
@@ -176,7 +177,7 @@ export function createOAuthHttp(options) {
|
|
|
176
177
|
const name = clean(read.value.client_name ?? "") || "MCP client";
|
|
177
178
|
const now = options.clock();
|
|
178
179
|
prune(now.getTime());
|
|
179
|
-
const kept = store.registerOAuthClient({ id: randomBytes(16).toString("hex"), name, redirectUris: redirects, source: sha256(options.requesterKey(request)) }, now, OAUTH_LIMITS.clients, OAUTH_LIMITS.clientsPerSource, [...waiting.values()].map(one => one.client));
|
|
180
|
+
const kept = store.registerOAuthClient({ id: randomBytes(16).toString("hex"), name, redirectUris: redirects, source: sha256(sourceKey(options.requesterKey(request))) }, now, OAUTH_LIMITS.clients, OAUTH_LIMITS.clientsPerSource, [...waiting.values()].map(one => one.client));
|
|
180
181
|
if (kept === null) {
|
|
181
182
|
response.setHeader("retry-after", "600");
|
|
182
183
|
return oauthError(response, 429, "temporarily_unavailable", "Too many clients are waiting to connect. Try again later.");
|
|
@@ -214,7 +215,7 @@ export function createOAuthHttp(options) {
|
|
|
214
215
|
const scopes = (params.get("scope") ?? "").split(" ").filter(one => one !== "");
|
|
215
216
|
if (!scopes.every(one => OAUTH_SCOPES.includes(one)))
|
|
216
217
|
return fail("The client requested access Toolroll doesn't offer.");
|
|
217
|
-
const source = sha256(options.requesterKey(request));
|
|
218
|
+
const source = sha256(sourceKey(options.requesterKey(request)));
|
|
218
219
|
if (waiting.size >= OAUTH_LIMITS.requests || [...waiting.values()].filter(one => one.source === source).length >= OAUTH_LIMITS.requestsPerSource) {
|
|
219
220
|
response.setHeader("retry-after", "600");
|
|
220
221
|
return problemPage(response, 429, "Too many sign-ins waiting", "Try again in ten minutes from your MCP client.");
|
package/dist/monitoring.js
CHANGED
|
@@ -24,6 +24,7 @@ export const SIGNATURE_HEADER = "x-standing-orders-signature";
|
|
|
24
24
|
const BATCH = 200;
|
|
25
25
|
const LEASE_MS = 60_000;
|
|
26
26
|
const TIMEOUT_MS = 10_000;
|
|
27
|
+
const CHECKPOINT_EVERY_MS = 60 * 60_000;
|
|
27
28
|
/** An audit event: the ledger entry and its seal, as the stream sends it. */
|
|
28
29
|
export function auditEvent(entry, instance) {
|
|
29
30
|
return {
|
|
@@ -41,15 +42,34 @@ const nanos = (at) => `${BigInt(Date.parse(at)) * 1000000n}`;
|
|
|
41
42
|
/** One pass over every destination that's set up. Returns what it sent, per destination. */
|
|
42
43
|
export async function monitoringPass(store, settings, deps) {
|
|
43
44
|
const sent = {};
|
|
45
|
+
const heads = [];
|
|
46
|
+
const audit = (delivered) => { if (delivered.head !== null)
|
|
47
|
+
heads.push(delivered.head); return delivered.count; };
|
|
44
48
|
// A new destination gets the whole audit history; traces start from now.
|
|
45
49
|
if (settings.webhook !== null)
|
|
46
|
-
sent.webhook = await deliver(store, "webhook", targetOf(settings.webhook.url), () => 0, deps, entries => postSigned(settings.webhook, entries, store, deps));
|
|
50
|
+
sent.webhook = audit(await deliver(store, "webhook", targetOf(settings.webhook.url), () => 0, deps, entries => postSigned(settings.webhook, entries, store, deps)));
|
|
47
51
|
if (settings.folder !== null)
|
|
48
|
-
sent.folder = await deliver(store, "folder", targetOf(settings.folder.path), () => 0, deps, async (entries) => { appendFolder(settings.folder.path, entries, deps.instance); return entries.length; });
|
|
52
|
+
sent.folder = audit(await deliver(store, "folder", targetOf(settings.folder.path), () => 0, deps, async (entries) => { appendFolder(settings.folder.path, entries, deps.instance); return entries.length; }));
|
|
49
53
|
if (settings.traces !== null)
|
|
50
|
-
sent.traces = await deliver(store, "traces", targetOf(settings.traces.endpoint), () => store.ledgerHeadId(), deps, entries => postTraces(settings.traces, entries, store, deps));
|
|
54
|
+
sent.traces = (await deliver(store, "traces", targetOf(settings.traces.endpoint), () => store.ledgerHeadId(), deps, entries => postTraces(settings.traces, entries, store, deps))).count;
|
|
55
|
+
checkpointSent(store, heads, (deps.now ?? (() => new Date()))());
|
|
51
56
|
return sent;
|
|
52
57
|
}
|
|
58
|
+
/** The furthest head the audit stream delivered, kept as an automatic checkpoint once the whole chain verifies.
|
|
59
|
+
* Automatic checkpoints write no ledger entry, so recording one gives the stream nothing new to send (and checkpoint)
|
|
60
|
+
* next pass. At most one an hour, so a busy stream neither floods the table nor walks the whole chain every pass. */
|
|
61
|
+
function checkpointSent(store, heads, now) {
|
|
62
|
+
const head = heads.reduce((best, one) => best === null || (one !== null && one.through > best.through) ? one : best, null);
|
|
63
|
+
if (head === null)
|
|
64
|
+
return;
|
|
65
|
+
const newest = store.ledgerCheckpoints(1)[0];
|
|
66
|
+
if (newest !== undefined && (newest.through >= head.through || now.getTime() - Date.parse(newest.at) < CHECKPOINT_EVERY_MS))
|
|
67
|
+
return;
|
|
68
|
+
try {
|
|
69
|
+
store.ledgerCheckpoint("system", now, { head });
|
|
70
|
+
}
|
|
71
|
+
catch { /* a busy database: the next delivery tries again */ }
|
|
72
|
+
}
|
|
53
73
|
/** A destination's name in its status row: a digest of its address (the address itself may carry a key). */
|
|
54
74
|
export const targetOf = (address) => hex(`standing-orders/monitoring/${address}`, 16);
|
|
55
75
|
/** Send what's due to one destination: hold it, start it over if it now points elsewhere, read after its cursor,
|
|
@@ -57,26 +77,30 @@ export const targetOf = (address) => hex(`standing-orders/monitoring/${address}`
|
|
|
57
77
|
async function deliver(store, sink, target, start, deps, send) {
|
|
58
78
|
const now = deps.now ?? (() => new Date());
|
|
59
79
|
const at = now();
|
|
80
|
+
const none = { count: 0, head: null };
|
|
60
81
|
if (!store.holdMonitoring(sink, deps.holder, at, new Date(at.getTime() + LEASE_MS)))
|
|
61
|
-
return
|
|
82
|
+
return none;
|
|
62
83
|
let status = store.monitoringStatus(sink)[0];
|
|
63
84
|
if (status === undefined || status.target !== target) {
|
|
64
85
|
store.resetMonitoring(sink, target, start());
|
|
65
86
|
status = store.monitoringStatus(sink)[0];
|
|
66
87
|
}
|
|
67
88
|
if (status.nextTryAt != null && Date.parse(status.nextTryAt) > at.getTime())
|
|
68
|
-
return
|
|
89
|
+
return none;
|
|
69
90
|
const from = status.through;
|
|
70
91
|
const entries = store.sealedAfter(from, BATCH);
|
|
71
92
|
if (entries.length === 0)
|
|
72
|
-
return
|
|
93
|
+
return none;
|
|
94
|
+
const last = entries[entries.length - 1];
|
|
73
95
|
try {
|
|
74
96
|
const count = await send(entries);
|
|
75
|
-
|
|
97
|
+
if (!store.monitoringDelivered(sink, deps.holder, target, from, last.id, count, now()))
|
|
98
|
+
return none;
|
|
99
|
+
return { count, head: last.seal === null ? null : { through: last.id, hash: last.seal.hash } };
|
|
76
100
|
}
|
|
77
101
|
catch (error) {
|
|
78
102
|
store.monitoringFailed(sink, deps.holder, target, error instanceof Error ? error.message : String(error), now(), new Date(now().getTime() + backoff(status.failures + 1)));
|
|
79
|
-
return
|
|
103
|
+
return none;
|
|
80
104
|
}
|
|
81
105
|
}
|
|
82
106
|
async function post(url, body, headers, deps) {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Notification, Store } from "./store.js";
|
|
2
|
+
type Claim = Notification & {
|
|
3
|
+
destination: string;
|
|
4
|
+
generation: number;
|
|
5
|
+
};
|
|
6
|
+
/** URLs and shell commands can contain secrets. Only a destination hash enters saved receipts. */
|
|
7
|
+
export declare function notificationDestination(kind: string, target: string): string;
|
|
8
|
+
/** One-release compatibility for operator-configured, installation-wide senders. Personal notifications never leave here. */
|
|
9
|
+
export declare function claimNotifications(store: Store, destination: string, owner: string, now: Date): Claim[];
|
|
10
|
+
export declare function finalizeNotification(store: Store, row: Claim, owner: string, outcome: {
|
|
11
|
+
ok: true;
|
|
12
|
+
receipt: string | null;
|
|
13
|
+
} | {
|
|
14
|
+
ok: false;
|
|
15
|
+
error: string;
|
|
16
|
+
}, now: Date): boolean;
|
|
17
|
+
/** Recheck after earlier network sends: expiry or resolution must stop this send, not just its receipt. */
|
|
18
|
+
export declare function notificationClaimHeld(store: Store, row: Claim, owner: string, now: Date): boolean;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
/** URLs and shell commands can contain secrets. Only a destination hash enters saved receipts. */
|
|
3
|
+
export function notificationDestination(kind, target) {
|
|
4
|
+
return `${kind}:${createHash("sha256").update(target).digest("hex")}`;
|
|
5
|
+
}
|
|
6
|
+
/** One-release compatibility for operator-configured, installation-wide senders. Personal notifications never leave here. */
|
|
7
|
+
export function claimNotifications(store, destination, owner, now) {
|
|
8
|
+
return store.transact(() => {
|
|
9
|
+
const db = store.handle, stamp = now.toISOString();
|
|
10
|
+
db.prepare(`INSERT OR IGNORE INTO notification_delivery(notification, destination)
|
|
11
|
+
SELECT id, ? FROM notification WHERE resolved_at IS NULL AND recipient IS NULL`).run(destination);
|
|
12
|
+
const claims = db.prepare(`SELECT d.notification, d.claim_generation FROM notification_delivery d
|
|
13
|
+
JOIN notification n ON n.id = d.notification WHERE d.destination = ? AND n.resolved_at IS NULL AND n.recipient IS NULL
|
|
14
|
+
AND d.delivered_at IS NULL AND (d.receipt IS NULL OR d.receipt NOT LIKE 'skipped:%')
|
|
15
|
+
AND (d.claim_owner IS NULL OR d.claim_expires_at <= ?) ORDER BY n.id`).all(destination, stamp);
|
|
16
|
+
return claims.map(raw => {
|
|
17
|
+
const id = Number(raw["notification"]), generation = Number(raw["claim_generation"]) + 1;
|
|
18
|
+
db.prepare(`UPDATE notification_delivery SET claim_owner = ?, claim_expires_at = ?, claim_generation = ?
|
|
19
|
+
WHERE notification = ? AND destination = ?`).run(owner, new Date(now.getTime() + 60_000).toISOString(), generation, id, destination);
|
|
20
|
+
return { ...store.notificationById(id), destination, generation };
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
export function finalizeNotification(store, row, owner, outcome, now) {
|
|
25
|
+
const skipped = outcome.ok && outcome.receipt?.startsWith("skipped:");
|
|
26
|
+
return Number(store.handle.prepare(`UPDATE notification_delivery SET attempts = attempts + 1, last_attempt_at = ?,
|
|
27
|
+
delivered_at = ?, receipt = ?, last_error = ?, claim_owner = NULL, claim_expires_at = NULL
|
|
28
|
+
WHERE notification = ? AND destination = ? AND claim_owner = ? AND claim_generation = ?
|
|
29
|
+
AND claim_expires_at > ? AND delivered_at IS NULL`).run(now.toISOString(), outcome.ok && !skipped ? now.toISOString() : null, outcome.ok ? outcome.receipt : null, outcome.ok ? null : outcome.error, row.id, row.destination, owner, row.generation, now.toISOString()).changes) === 1;
|
|
30
|
+
}
|
|
31
|
+
/** Recheck after earlier network sends: expiry or resolution must stop this send, not just its receipt. */
|
|
32
|
+
export function notificationClaimHeld(store, row, owner, now) {
|
|
33
|
+
return store.handle.prepare(`SELECT 1 FROM notification_delivery d JOIN notification n ON n.id = d.notification
|
|
34
|
+
WHERE d.notification = ? AND d.destination = ? AND d.claim_owner = ? AND d.claim_generation = ?
|
|
35
|
+
AND d.claim_expires_at > ? AND d.delivered_at IS NULL AND n.resolved_at IS NULL AND n.recipient IS NULL`)
|
|
36
|
+
.get(row.id, row.destination, owner, row.generation, now.toISOString()) !== undefined;
|
|
37
|
+
}
|
|
@@ -10,7 +10,7 @@ const args = (positionals = '', values = '', references = {}) => ({
|
|
|
10
10
|
* digest. Neither dereferences a conversation, task or proposal. Creation IDs are never looked up. */
|
|
11
11
|
export const REMOTE_ARGUMENTS = new Map([
|
|
12
12
|
...['status', 'ready', 'grants', 'gaps', 'sync', 'runner list', 'coordinator list', 'incident list',
|
|
13
|
-
'routine list', 'intake show', 'intake run', 'template list', 'webhook status', '
|
|
13
|
+
'routine list', 'intake show', 'intake run', 'template list', 'webhook status', 'review show',
|
|
14
14
|
'chat-approval show', 'chat-approval off'].map(row => [row, args()]),
|
|
15
15
|
['integrations', args('', 'saved')],
|
|
16
16
|
// --person and --token-name are names compared inside the reader's own view; --token stays a refused credential.
|
package/dist/operate-remote.js
CHANGED
|
@@ -46,7 +46,7 @@ export const REMOTE_SCOPES = new Map([
|
|
|
46
46
|
...["list", "show", "add", "refresh", "pause", "resume", "run-now"].map(action => [`routine ${action}`, installation]),
|
|
47
47
|
["config show", installation], ["verify show", repo], ["intake show", installation], ["intake run", installation], ["intake preview", installation],
|
|
48
48
|
["intake pr-comments", installation], ["template list", installation], ["template show", installation], ["contest show", installation],
|
|
49
|
-
["contest exclude", installation], ["webhook status", installation], ["
|
|
49
|
+
["contest exclude", installation], ["webhook status", installation], ["review show", installation],
|
|
50
50
|
["chat-approval show", self], ["chat-approval off", self],
|
|
51
51
|
// The person's own remote actions, or everyone's within their projects for an approver (remote-audit.ts).
|
|
52
52
|
["audit", self],
|
|
@@ -64,7 +64,7 @@ export const REMOTE_SCOPES = new Map([
|
|
|
64
64
|
export const REMOTE_ALL_PROJECTS_ONLY = new Map([
|
|
65
65
|
// Settings, connections and acts that belong to the installation as a whole, not to any one project.
|
|
66
66
|
...["integrations", "grants", "sync", "incident resolve", "routine add", "routine refresh", "routine pause", "routine resume", "routine run-now",
|
|
67
|
-
"config show", "intake run", "contest exclude", "webhook status"
|
|
67
|
+
"config show", "intake run", "contest exclude", "webhook status"].map(row => [row, "installation-wide"]),
|
|
68
68
|
// Cross-project lists and reads a limited person is still refused; scoping them is later work.
|
|
69
69
|
...["runner list", "coordinator list", "outbox list", "incident list", "routine list", "routine show", "intake show", "intake preview",
|
|
70
70
|
"intake pr-comments", "template list", "template show", "contest show", "review show"].map(row => [row, "not yet scoped"]),
|
package/dist/operate.d.ts
CHANGED
|
@@ -124,7 +124,7 @@ export declare const OPERATE_BOOLEAN_FLAGS: ReadonlySet<string>;
|
|
|
124
124
|
export declare function parseOperateArgs(argv: readonly string[], ownValues?: ReadonlySet<string>): Args | {
|
|
125
125
|
error: string;
|
|
126
126
|
};
|
|
127
|
-
/** Route
|
|
127
|
+
/** Route a native command and return its exit code. Its password source cannot be selected by an HTTP request. */
|
|
128
128
|
export declare function runOperate(command: string, argv: readonly string[], write: Write, options?: OperateOptions): Promise<number>;
|
|
129
129
|
export type { Principal };
|
|
130
130
|
/**
|