toolroll 0.9.52 → 0.9.54
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 +16 -0
- package/README.md +55 -80
- package/dist/agentconfig.d.ts +11 -36
- package/dist/agentconfig.js +3 -62
- package/dist/approval-policy.d.ts +1 -1
- package/dist/approval-policy.js +1 -1
- package/dist/board.d.ts +3 -19
- package/dist/board.js +4 -42
- package/dist/browser/workspace.js +18 -18
- package/dist/browser-workspace.d.ts +2 -1
- package/dist/builder.d.ts +9 -40
- package/dist/builder.js +50 -257
- package/dist/chat-actions.js +3 -14
- package/dist/chat-ask.js +8 -8
- package/dist/chat-controls.d.ts +0 -4
- package/dist/chat-controls.js +0 -1
- package/dist/chat-core.d.ts +171 -0
- package/dist/chat-core.js +288 -0
- package/dist/chat-decide.d.ts +10 -8
- package/dist/chat-decide.js +27 -24
- package/dist/chat-delivery-state.d.ts +51 -75
- package/dist/chat-delivery-state.js +140 -170
- package/dist/chat-delivery.d.ts +21 -4
- package/dist/chat-delivery.js +313 -195
- package/dist/chat-flow.d.ts +29 -1
- package/dist/chat-flow.js +24 -50
- package/dist/chat-messages.d.ts +319 -0
- package/dist/chat-messages.js +841 -0
- package/dist/chat-migration.d.ts +30 -0
- package/dist/chat-migration.js +802 -0
- package/dist/chat-quiet.d.ts +3 -0
- package/dist/chat-quiet.js +7 -2
- package/dist/chat-task-actions.d.ts +1 -1
- package/dist/chat-task-actions.js +0 -2
- package/dist/claim.d.ts +79 -244
- package/dist/claim.js +688 -1023
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +10 -2
- package/dist/contracts/chat-content.d.ts +71 -2
- package/dist/contracts/chat-content.js +22 -3
- package/dist/contracts/chat-tables.d.ts +11 -4
- package/dist/contracts/chat-tables.js +165 -87
- package/dist/contracts/cli.d.ts +0 -13
- package/dist/contracts/cli.js +0 -2
- package/dist/contracts/console-api.d.ts +5 -10
- package/dist/contracts/console-api.js +4 -10
- package/dist/contracts/discord-callback.js +2 -1
- package/dist/contracts/flow.d.ts +50 -0
- package/dist/contracts/flow.js +26 -1
- package/dist/contracts/lead-tools.d.ts +0 -13
- package/dist/contracts/lead-tools.js +3 -3
- package/dist/contracts/slack-callback.js +3 -2
- package/dist/contracts/store-json.d.ts +1 -29
- package/dist/contracts/store-json.js +4 -17
- package/dist/contracts/teams-callback.js +2 -1
- package/dist/converse.d.ts +1 -11
- package/dist/converse.js +6 -38
- package/dist/coordinator.d.ts +0 -1
- package/dist/coordinator.js +3 -5
- package/dist/demo.js +16 -26
- package/dist/desktop-update-gate.js +0 -1
- package/dist/desktop-update.js +1 -3
- package/dist/discord-chat.js +19 -38
- package/dist/discord-settings.js +4 -13
- package/dist/discord.js +4 -14
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +1 -1
- package/dist/dispose.d.ts +2 -3
- package/dist/dispose.js +17 -92
- package/dist/envelope.js +0 -3
- package/dist/exec.d.ts +0 -64
- package/dist/exec.js +3 -356
- package/dist/exhaustion.d.ts +22 -76
- package/dist/exhaustion.js +14 -140
- package/dist/export.js +8 -8
- package/dist/flow-engine.js +1 -1
- package/dist/flow-schedule.d.ts +154 -0
- package/dist/flow-schedule.js +321 -0
- package/dist/flow-share.js +1 -1
- package/dist/flow-triggers.d.ts +6 -1
- package/dist/flow-triggers.js +65 -10
- package/dist/flows-cli.js +8 -4
- package/dist/flows-ui.js +2 -0
- package/dist/flows.js +1 -1
- package/dist/guides.js +9 -29
- package/dist/invoke.d.ts +1 -24
- package/dist/invoke.js +17 -259
- package/dist/lead-status.js +2 -4
- package/dist/lead-voice.js +1 -1
- package/dist/mate-doors.d.ts +1 -2
- package/dist/mate-doors.js +12 -25
- package/dist/mate-tools.d.ts +2 -2
- package/dist/mate-tools.js +13 -24
- package/dist/modes.d.ts +19 -8
- package/dist/modes.js +24 -14
- package/dist/notification-rows.d.ts +30 -0
- package/dist/notification-rows.js +102 -0
- package/dist/operate-remote-arguments.js +2 -6
- package/dist/operate-remote.js +6 -7
- package/dist/operate.d.ts +0 -6
- package/dist/operate.js +226 -2248
- package/dist/phase-routing.d.ts +13 -23
- package/dist/phase-routing.js +13 -35
- package/dist/plan-auto.js +2 -2
- package/dist/plane-review.js +5 -11
- package/dist/planner-source.js +2 -1
- package/dist/policy.d.ts +1 -4
- package/dist/policy.js +0 -8
- package/dist/process-recovery-eligibility.js +2 -3
- package/dist/project-delete.js +24 -41
- package/dist/proposal.d.ts +4 -24
- package/dist/proposal.js +3 -88
- package/dist/provider-auth.d.ts +3 -3
- package/dist/provider-auth.js +4 -6
- package/dist/provider.d.ts +11 -25
- package/dist/provider.js +4 -36
- package/dist/push.js +1 -1
- package/dist/recipe-ui.js +6 -6
- package/dist/recipes.d.ts +3 -3
- package/dist/recipes.js +27 -23
- package/dist/result-shots.js +2 -2
- package/dist/retention.js +1 -1
- package/dist/run-closeout.d.ts +1 -1
- package/dist/run-closeout.js +1 -4
- package/dist/scope.d.ts +11 -65
- package/dist/scope.js +17 -82
- package/dist/serve.js +15 -24
- package/dist/server/chat.js +7 -30
- package/dist/server/flows.js +11 -10
- package/dist/server/guards.js +0 -1
- package/dist/server/pages-assets.js +1 -1
- package/dist/server/pages.js +0 -2
- package/dist/server/people-tokens.js +0 -4
- package/dist/server/route-table.d.ts +1 -1
- package/dist/server/route-table.js +2 -17
- package/dist/server/settings.js +6 -12
- package/dist/server/shared.d.ts +28 -212
- package/dist/server/shared.js +71 -780
- package/dist/server/task-views.js +9 -76
- package/dist/server/tasks.d.ts +1 -50
- package/dist/server/tasks.js +36 -946
- package/dist/setup-guide.d.ts +2 -2
- package/dist/slack-api.d.ts +5 -1
- package/dist/slack-api.js +2 -2
- package/dist/slack-chat.d.ts +9 -6
- package/dist/slack-chat.js +29 -53
- package/dist/slack-settings.js +6 -15
- package/dist/slack.js +6 -16
- package/dist/store.d.ts +200 -1702
- package/dist/store.js +811 -5439
- package/dist/surface.js +10 -24
- package/dist/task-composer.d.ts +1 -1
- package/dist/task-composer.js +1 -1
- package/dist/task-control.d.ts +3 -10
- package/dist/task-control.js +2 -7
- package/dist/teammate-desk.js +1 -1
- package/dist/teammate-question.js +12 -12
- package/dist/teammates-ui.js +1 -1
- package/dist/teams-chat.js +12 -9
- package/dist/teams-settings.js +2 -2
- package/dist/teams.js +4 -5
- package/dist/telegram-flow.js +5 -5
- package/dist/telegram-mate.d.ts +0 -3
- package/dist/telegram-mate.js +0 -1
- package/dist/telegram.js +4 -4
- package/dist/templates.d.ts +11 -7
- package/dist/templates.js +12 -9
- package/dist/toolroll-update.d.ts +20 -0
- package/dist/toolroll-update.js +104 -5
- package/dist/work-index.js +2 -6
- package/dist/workspace-revision.js +3 -1
- package/dist/workspace-ui.js +1 -1
- package/package.json +1 -1
- package/scripts/recovery-canary.mjs +3 -3
- package/dist/contest.d.ts +0 -318
- package/dist/contest.js +0 -753
- package/dist/held.d.ts +0 -150
- package/dist/held.js +0 -799
- package/dist/liveness.d.ts +0 -30
- package/dist/liveness.js +0 -42
- package/dist/pricing.d.ts +0 -45
- package/dist/pricing.js +0 -77
- package/dist/routine.d.ts +0 -228
- package/dist/routine.js +0 -764
- package/dist/slack-state.d.ts +0 -13
- package/dist/slack-state.js +0 -10
- package/dist/supervisor.mjs +0 -297
package/dist/mate-tools.js
CHANGED
|
@@ -43,7 +43,7 @@ import { parseAcceptanceCriteria } from "./scope.js";
|
|
|
43
43
|
import { diagnoseTaskDispatch, withDispatchDiagnoses } from "./dispatch.js";
|
|
44
44
|
import { agentChoicesFor, routeOfTask, INSTALLATION_SCOPE } from "./agentconfig.js";
|
|
45
45
|
import { isNewModel, modelWords, priceWords, runtimeStates, seenModels } from "./model-catalog.js";
|
|
46
|
-
import { agentsSummary, chosenWords, PHASES, postureWords,
|
|
46
|
+
import { agentsSummary, chosenWords, PHASES, postureWords, routeProblems, sameSpec, sizeSourceWords, sizeWords, specWords } from "./phase-routing.js";
|
|
47
47
|
import { TOOL_CATALOG, discoverTools, projectToolsOf, secretsSetFor, toolCommandLine, toolStanding } from "./project-tools.js";
|
|
48
48
|
import { deciderOf, durationWords, FLOW_KIND_WORDS, FLOW_TEMPLATES, flowFromSteps, stepsFor, withKeptSteps } from "./flows.js";
|
|
49
49
|
import { parseContract, toModelSchema } from "./contracts/contract.js";
|
|
@@ -320,8 +320,8 @@ function scopeStandingOf(store, taskId) {
|
|
|
320
320
|
const ROLE_WORD = { plan: "planner", build: "builder", repair: "repair", review: "reviewer" };
|
|
321
321
|
const ROLE_OF_WORD = { planner: "plan", plan: "plan", builder: "build", build: "build", repair: "repair", reviewer: "review", review: "review" };
|
|
322
322
|
/**
|
|
323
|
-
* THE AGENTS A TASK RUNS UNDER, as chat reads them (v48): the
|
|
324
|
-
*
|
|
323
|
+
* THE AGENTS A TASK RUNS UNDER, as chat reads them (v48): the task's size,
|
|
324
|
+
* the same one-line summary the task page and CLI
|
|
325
325
|
* print, each role's exact agent with its reasons, the standing of those
|
|
326
326
|
* agents (approved / awaiting approval / recommended), and — for a
|
|
327
327
|
* proposal — only the configured, role-valid choices an operator could
|
|
@@ -334,14 +334,11 @@ export function agentsOver(store, taskId, now) {
|
|
|
334
334
|
return null;
|
|
335
335
|
const routed = routeOfTask(store, taskId, ref, now);
|
|
336
336
|
const scope = store.getScope(taskId);
|
|
337
|
-
const
|
|
338
|
-
const
|
|
339
|
-
const editableWhy = store.hasLiveClaim(ref.id, now) ? "this task is running — its agents cannot change under a live claim" : store.activeTournamentTerms(ref.id) !== null ? "tournament terms decide the agents while the contest is open" : null;
|
|
337
|
+
const editable = !store.hasLiveClaim(ref.id, now);
|
|
338
|
+
const editableWhy = store.hasLiveClaim(ref.id, now) ? "this task is running — its agents cannot change under a live claim" : null;
|
|
340
339
|
const base = {
|
|
341
340
|
task: taskId,
|
|
342
|
-
risk: { level: risk, title: riskTitle(risk), consequence: riskConsequence(risk) },
|
|
343
341
|
size: ref.sizing == null ? null : { size: ref.sizing.size, risky: ref.sizing.risky, reason: ref.sizing.reason, source: sizeSourceWords(ref.sizing.source) },
|
|
344
|
-
riskChoices: RISK_CHOICES.map(one => ({ risk: one.risk, title: one.title, consequence: one.consequence })),
|
|
345
342
|
editable,
|
|
346
343
|
editableWhy,
|
|
347
344
|
approval: scope === null ? "none" : scopeStandingOf(store, taskId),
|
|
@@ -497,7 +494,7 @@ const MATE_TOOL_HANDLERS = {
|
|
|
497
494
|
description: "When the owner asks to approve one thing (a plan waiting on them, or a flow card waiting at a Person decides step), send that item's own Approve and Send back buttons to their paired chat right away. Their tap there is the approval (two taps, as on any decision card); you never approve. Give task for a plan, or card for a flow card (its number from get_flows). When it can't be approved in chat, the answer says why: say that in one line and open show_control approval (a plan) or the flow, never that you can't approve.",
|
|
498
495
|
handle: (ctx, args) => {
|
|
499
496
|
const pairedHere = ctx.channel === "telegram";
|
|
500
|
-
const paired = ctx.store.handle.prepare("SELECT 1 FROM
|
|
497
|
+
const paired = ctx.store.handle.prepare("SELECT 1 FROM chat_binding WHERE provider = 'telegram' AND approver = ? AND generation = ? AND revoked IS NULL LIMIT 1")
|
|
501
498
|
.get(ctx.who.name, ctx.store.accountOf(ctx.who.name)?.generation ?? -1) !== undefined;
|
|
502
499
|
const stamp = ctx.now.getTime();
|
|
503
500
|
if (args["card"] !== undefined) {
|
|
@@ -523,7 +520,8 @@ const MATE_TOOL_HANDLERS = {
|
|
|
523
520
|
if (task === null || admittedRef(ctx, task) === null)
|
|
524
521
|
return notFound();
|
|
525
522
|
const current = ctx.store.taskFamilyOf(task, ctx.who.repos, false)?.current.id ?? task;
|
|
526
|
-
|
|
523
|
+
// Its buttons go to the paired Telegram chat (pairedHere), so it is that chat's authority that counts.
|
|
524
|
+
const plan = planInChat(ctx.store, current, ctx.who.name, ctx.now, "telegram", ctx.evidenceRoot);
|
|
527
525
|
if (!plan.ok)
|
|
528
526
|
return { ok: true, body: { offered: false, task: current, why: plan.why, control: "approval" } };
|
|
529
527
|
if (!pairedHere || !paired)
|
|
@@ -1536,7 +1534,7 @@ const MATE_TOOL_HANDLERS = {
|
|
|
1536
1534
|
},
|
|
1537
1535
|
},
|
|
1538
1536
|
get_agents: {
|
|
1539
|
-
description: "Read current roles,
|
|
1537
|
+
description: "Read current roles, size, approval, configured alternatives and the organisation policy (allowed providers, models, tools, permission ceiling; changed only on Settings → Policy) before propose_agents.",
|
|
1540
1538
|
handle: (ctx, args) => {
|
|
1541
1539
|
const taskId = taskIdOf(args);
|
|
1542
1540
|
if (taskId === null)
|
|
@@ -1697,8 +1695,6 @@ const MATE_TOOL_HANDLERS = {
|
|
|
1697
1695
|
return { ok: false, message: `guidance is plain text up to ${LIMITS.note} characters` };
|
|
1698
1696
|
if (task.state === "done" || task.state === "cancelled")
|
|
1699
1697
|
return { ok: false, message: "that task is finished, so guidance has no next attempt to reach" };
|
|
1700
|
-
if (ctx.store.openContestFor(ref.id) !== null)
|
|
1701
|
-
return { ok: false, message: "agents are racing on that task — wait until the comparison finishes" };
|
|
1702
1698
|
const id = ctx.draft("steer", { task: taskId, taskTitle: task.title, repoId: ref.repoId, note: args["note"] });
|
|
1703
1699
|
if (id === null)
|
|
1704
1700
|
return tooMany();
|
|
@@ -1790,14 +1786,13 @@ const MATE_TOOL_HANDLERS = {
|
|
|
1790
1786
|
},
|
|
1791
1787
|
},
|
|
1792
1788
|
propose_agents: {
|
|
1793
|
-
description: "Read get_agents. Change
|
|
1789
|
+
description: "Read get_agents. Change size (small: fast model, no plan; large or risky: strongest agents), configured role model, or clear override; stales approval, refuses running work.",
|
|
1794
1790
|
handle: (ctx, args) => {
|
|
1795
1791
|
const taskId = taskIdOf(args);
|
|
1796
1792
|
const ref = taskId === null ? null : admittedRef(ctx, taskId);
|
|
1797
1793
|
const task = taskId === null ? null : ctx.store.getTask(taskId);
|
|
1798
1794
|
if (taskId === null || ref === null || task === null)
|
|
1799
1795
|
return notFound();
|
|
1800
|
-
const risk = args["risk"];
|
|
1801
1796
|
const roleWord = args["role"];
|
|
1802
1797
|
const phase = roleWord === undefined ? null : typeof roleWord === "string" ? ROLE_OF_WORD[roleWord] ?? null : null;
|
|
1803
1798
|
if (roleWord !== undefined && (phase === null || phase === "review"))
|
|
@@ -1808,8 +1803,8 @@ const MATE_TOOL_HANDLERS = {
|
|
|
1808
1803
|
const risky = args["risky"];
|
|
1809
1804
|
const sized = ctx.store.refForId(ref.id)?.sizing ?? null;
|
|
1810
1805
|
const sizeChange = size === undefined && risky === undefined ? null : { size: size ?? sized?.size ?? "medium", risky: risky ?? sized?.risky ?? false };
|
|
1811
|
-
if (
|
|
1812
|
-
return { ok: false, message: "say what changes: a
|
|
1806
|
+
if (phase === null && sizeChange === null)
|
|
1807
|
+
return { ok: false, message: "say what changes: a size, or a role with an agent (or clear: true)" };
|
|
1813
1808
|
if (phase !== null && !clear && (agent === null || typeof agent !== "object"))
|
|
1814
1809
|
return { ok: false, message: "a role change names an agent from get_agents, or clear: true" };
|
|
1815
1810
|
if (phase === null && (clear || agent !== undefined))
|
|
@@ -1818,8 +1813,6 @@ const MATE_TOOL_HANDLERS = {
|
|
|
1818
1813
|
return { ok: false, message: "why is plain text ≤400" };
|
|
1819
1814
|
if (ctx.store.hasLiveClaim(ref.id, ctx.now))
|
|
1820
1815
|
return { ok: false, message: "a worker is building that task right now — its agents cannot change under it" };
|
|
1821
|
-
if (ctx.store.activeTournamentTerms(ref.id) !== null)
|
|
1822
|
-
return { ok: false, message: "tournament terms decide this task's agents while the contest is open" };
|
|
1823
1816
|
const view = agentsOver(ctx.store, taskId, ctx.now);
|
|
1824
1817
|
if (view === null)
|
|
1825
1818
|
return notFound();
|
|
@@ -1840,19 +1833,16 @@ const MATE_TOOL_HANDLERS = {
|
|
|
1840
1833
|
}
|
|
1841
1834
|
chosen = { provider: match.provider, model: match.model };
|
|
1842
1835
|
const currentLeg = view["agents"].find(one => one.role === ROLE_WORD[phase]);
|
|
1843
|
-
if (currentLeg !== undefined && sameSpec(currentLeg, chosen)
|
|
1836
|
+
if (currentLeg !== undefined && sameSpec(currentLeg, chosen))
|
|
1844
1837
|
return { ok: false, message: `${specWords(chosen)} already runs the ${ROLE_WORD[phase]} role` };
|
|
1845
1838
|
}
|
|
1846
1839
|
if (phase !== null && clear && !(current?.routeOverrides ?? []).some(one => one.phase === phase)) {
|
|
1847
1840
|
return { ok: false, message: `nobody chose a ${ROLE_WORD[phase]} for this task by hand — there is nothing to clear` };
|
|
1848
1841
|
}
|
|
1849
|
-
if (risk !== undefined && phase === null && risk === view["risk"].level)
|
|
1850
|
-
return { ok: false, message: `this task is already declared ${riskTitle(risk).toLowerCase()}` };
|
|
1851
1842
|
const id = ctx.draft("agents", {
|
|
1852
1843
|
task: taskId,
|
|
1853
1844
|
taskTitle: task.title,
|
|
1854
1845
|
repoId: ref.repoId,
|
|
1855
|
-
...(risk === undefined ? {} : { risk, riskConsequence: riskConsequence(risk) }),
|
|
1856
1846
|
...(sizeChange === null ? {} : { size: sizeChange.size, risky: sizeChange.risky }),
|
|
1857
1847
|
...(phase === null ? {} : { phase, role: ROLE_WORD[phase] }),
|
|
1858
1848
|
...(chosen === null ? {} : { provider: chosen.provider, model: chosen.model }),
|
|
@@ -1870,7 +1860,6 @@ const MATE_TOOL_HANDLERS = {
|
|
|
1870
1860
|
proposal: id,
|
|
1871
1861
|
kind: "agents",
|
|
1872
1862
|
task: taskId,
|
|
1873
|
-
...(risk === undefined ? {} : { risk }),
|
|
1874
1863
|
...(sizeChange === null ? {} : { size: sizeChange.size, risky: sizeChange.risky }),
|
|
1875
1864
|
...(phase === null ? {} : { role: ROLE_WORD[phase], ...(chosen === null ? { clear: true } : { agent: chosen }) }),
|
|
1876
1865
|
awaiting: view["approval"] === "approved" ? "the operator's confirmation — the current approval will then need renewing" : "the operator's confirmation",
|
package/dist/modes.d.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* owns the transactions; the tick owns the rails; serve owns the
|
|
14
14
|
* ceremony screens.
|
|
15
15
|
*/
|
|
16
|
+
import { type ChatProvider } from "./contracts/chat-tables.js";
|
|
16
17
|
export type ModeName = "standard" | "hands-off";
|
|
17
18
|
export type ModeTerms = {
|
|
18
19
|
name: ModeName;
|
|
@@ -27,7 +28,8 @@ export type ModeTerms = {
|
|
|
27
28
|
/** Explicit opt-in: a verified planner may approve a plan that preserves
|
|
28
29
|
* the signer's pre-authorized filed contract and execution terms exactly. */
|
|
29
30
|
planAuto: boolean;
|
|
30
|
-
/**
|
|
31
|
+
/** Historical signed field (watched sessions without a per-session
|
|
32
|
+
* password, removed in v115); new modes leave it false and nothing reads it. */
|
|
31
33
|
quickMint: boolean;
|
|
32
34
|
/** Historical signed field; new modes leave it false and no worker consumes
|
|
33
35
|
* it. Automatic review is the project's review switch (review-switch.ts),
|
|
@@ -47,15 +49,13 @@ export type ModeTerms = {
|
|
|
47
49
|
* "automerge" = the mode's signature substitutes for the per-merge
|
|
48
50
|
* human authorization, through the grant machinery only (D1/E1). */
|
|
49
51
|
publication: "notify" | "automerge";
|
|
50
|
-
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* must be an explicit, freshly-signed grant. A subscription->subscription
|
|
54
|
-
* fallback is not "paid" and needs no grant. */
|
|
52
|
+
/** Historical signed term (v30-v114: a grant for automatic paid
|
|
53
|
+
* fallback; fallback chains were removed in v115). Always false on new
|
|
54
|
+
* modes; retained for digest and audit compatibility. */
|
|
55
55
|
allowPaidFallback: boolean;
|
|
56
56
|
/** Whether this mode AUTHORIZES the bounded repair loop to draft AND
|
|
57
57
|
* auto-approve its own repair attempts (v40, evidence-review-v1) — the
|
|
58
|
-
*
|
|
58
|
+
* same precedent as the old paid-fallback grant: legacy modes default FALSE, a
|
|
59
59
|
* new authority is never inherited, only freshly signed. Without it, a
|
|
60
60
|
* short/refuted run with named unresolved criteria still gets exactly
|
|
61
61
|
* one drafted repair — it simply waits unapproved. */
|
|
@@ -65,12 +65,16 @@ export type ModeTerms = {
|
|
|
65
65
|
* `repairAuto` is also true — a mode may sign a cap without signing the
|
|
66
66
|
* authority, but never the reverse. */
|
|
67
67
|
repairMaxAttempts: number;
|
|
68
|
-
/** Explicit opt-in: the signer's paired
|
|
68
|
+
/** Explicit opt-in: the signer's paired chat may approve this
|
|
69
69
|
* repository's plans and merge its ready pull requests with two taps,
|
|
70
70
|
* for the mode's lifetime. A plan that widens permissions, exceeds the
|
|
71
71
|
* per-attempt budget or touches protected paths still opens Toolroll.
|
|
72
72
|
* Legacy modes read FALSE — never inherited, only freshly signed. */
|
|
73
73
|
chatApprove: boolean;
|
|
74
|
+
/** The chat apps `chatApprove` names, signed with it. Absent on a mode signed before chat apps other than Telegram
|
|
75
|
+
* could approve: its words said "your paired Telegram chat", so it stays Telegram only (chatApproveChatsOf). A wider
|
|
76
|
+
* grant is only ever a fresh signature naming the apps. */
|
|
77
|
+
chatApproveChats?: readonly ChatProvider[];
|
|
74
78
|
absoluteExpiry: string;
|
|
75
79
|
};
|
|
76
80
|
export declare const MODE_MAX_DAYS = 7;
|
|
@@ -83,6 +87,13 @@ export declare function modeTermsJson(terms: ModeTerms): string;
|
|
|
83
87
|
export declare function modeDigestOf(terms: ModeTerms): string;
|
|
84
88
|
/** Strict rehydration — anything unexpected is null, never a guess. */
|
|
85
89
|
export declare function modeTermsFromJson(json: string | null): ModeTerms | null;
|
|
90
|
+
/** The chat apps a mode lets its signer approve from: none without chatApprove; Telegram alone for a grant signed
|
|
91
|
+
* before it named its apps (that is what its words said); otherwise exactly the apps it names. */
|
|
92
|
+
export declare function chatApproveChatsOf(terms: Pick<ModeTerms, "chatApprove" | "chatApproveChats">): readonly ChatProvider[];
|
|
93
|
+
/** What a new chatApprove signature names: every chat app, said in its words. */
|
|
94
|
+
export declare const CHAT_APPROVE_ALL: readonly ChatProvider[];
|
|
95
|
+
/** "Telegram", "Telegram or Slack", "Telegram, Slack, Discord or Teams". */
|
|
96
|
+
export declare const chatNames: (chats: readonly ChatProvider[]) => string;
|
|
86
97
|
/** Every term in words — what the ceremony renders and the password
|
|
87
98
|
* signs. The reversal sentence is verbatim from the chain (C1). */
|
|
88
99
|
export declare function modeWords(terms: ModeTerms): string[];
|
package/dist/modes.js
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* ceremony screens.
|
|
15
15
|
*/
|
|
16
16
|
import { createHash } from "node:crypto";
|
|
17
|
+
import { CHAT_PROVIDERS, isChatProvider } from "./contracts/chat-tables.js";
|
|
17
18
|
export const MODE_MAX_DAYS = 7;
|
|
18
19
|
/** The presets are STARTING POINTS the ceremony renders in full — the
|
|
19
20
|
* signature always covers the resolved terms, never a label. */
|
|
@@ -24,7 +25,7 @@ export function presetTerms(name, absoluteExpiry) {
|
|
|
24
25
|
permissionDefault: "safe",
|
|
25
26
|
autoApproveFiling: false,
|
|
26
27
|
planAuto: false,
|
|
27
|
-
quickMint:
|
|
28
|
+
quickMint: false,
|
|
28
29
|
reviewAuto: false,
|
|
29
30
|
reviewRetryAuto: false,
|
|
30
31
|
perAttemptBudgetMicrousd: null,
|
|
@@ -42,7 +43,7 @@ export function presetTerms(name, absoluteExpiry) {
|
|
|
42
43
|
permissionDefault: "escalated",
|
|
43
44
|
autoApproveFiling: true,
|
|
44
45
|
planAuto: false,
|
|
45
|
-
quickMint:
|
|
46
|
+
quickMint: false,
|
|
46
47
|
reviewAuto: false,
|
|
47
48
|
reviewRetryAuto: false,
|
|
48
49
|
perAttemptBudgetMicrousd: null,
|
|
@@ -108,10 +109,8 @@ export function modeTermsFromJson(json) {
|
|
|
108
109
|
measured !== undefined &&
|
|
109
110
|
runs !== undefined &&
|
|
110
111
|
(t["publication"] === "notify" || t["publication"] === "automerge") &&
|
|
111
|
-
// allowPaidFallback:
|
|
112
|
-
//
|
|
113
|
-
// freshly-signed grant). A present value must be a strict boolean;
|
|
114
|
-
// anything else is a bad envelope, null.
|
|
112
|
+
// allowPaidFallback (historical): absent reads as false; a present
|
|
113
|
+
// value must be a strict boolean, anything else is a bad envelope.
|
|
115
114
|
(t["allowPaidFallback"] === undefined || typeof t["allowPaidFallback"] === "boolean") &&
|
|
116
115
|
// repairAuto/repairMaxAttempts: the SAME precedent, verbatim (v40). A
|
|
117
116
|
// legacy mode has NO such fields — that MUST read as false/0, never
|
|
@@ -122,6 +121,10 @@ export function modeTermsFromJson(json) {
|
|
|
122
121
|
(t["repairMaxAttempts"] === undefined ||
|
|
123
122
|
(typeof t["repairMaxAttempts"] === "number" && Number.isInteger(t["repairMaxAttempts"]) && t["repairMaxAttempts"] >= 0 && t["repairMaxAttempts"] <= 3)) &&
|
|
124
123
|
(t["chatApprove"] === undefined || typeof t["chatApprove"] === "boolean") &&
|
|
124
|
+
// chatApproveChats: absent (a Telegram-only grant, or none), or the apps a chatApprove term names, each once.
|
|
125
|
+
(t["chatApproveChats"] === undefined ||
|
|
126
|
+
(t["chatApprove"] === true && Array.isArray(t["chatApproveChats"]) && t["chatApproveChats"].length > 0 &&
|
|
127
|
+
t["chatApproveChats"].every(isChatProvider) && new Set(t["chatApproveChats"]).size === t["chatApproveChats"].length)) &&
|
|
125
128
|
typeof t["absoluteExpiry"] === "string" &&
|
|
126
129
|
!Number.isNaN(Date.parse(t["absoluteExpiry"]))) {
|
|
127
130
|
return {
|
|
@@ -140,11 +143,22 @@ export function modeTermsFromJson(json) {
|
|
|
140
143
|
repairAuto: t["repairAuto"] === true,
|
|
141
144
|
repairMaxAttempts: typeof t["repairMaxAttempts"] === "number" ? t["repairMaxAttempts"] : 0,
|
|
142
145
|
chatApprove: t["chatApprove"] === true,
|
|
146
|
+
...(Array.isArray(t["chatApproveChats"]) ? { chatApproveChats: [...t["chatApproveChats"]] } : {}),
|
|
143
147
|
absoluteExpiry: t["absoluteExpiry"],
|
|
144
148
|
};
|
|
145
149
|
}
|
|
146
150
|
return null;
|
|
147
151
|
}
|
|
152
|
+
/** The chat apps a mode lets its signer approve from: none without chatApprove; Telegram alone for a grant signed
|
|
153
|
+
* before it named its apps (that is what its words said); otherwise exactly the apps it names. */
|
|
154
|
+
export function chatApproveChatsOf(terms) {
|
|
155
|
+
return !terms.chatApprove ? [] : terms.chatApproveChats ?? ["telegram"];
|
|
156
|
+
}
|
|
157
|
+
/** What a new chatApprove signature names: every chat app, said in its words. */
|
|
158
|
+
export const CHAT_APPROVE_ALL = CHAT_PROVIDERS;
|
|
159
|
+
const CHAT_NAMES = { telegram: "Telegram", slack: "Slack", discord: "Discord", teams: "Teams" };
|
|
160
|
+
/** "Telegram", "Telegram or Slack", "Telegram, Slack, Discord or Teams". */
|
|
161
|
+
export const chatNames = (chats) => chats.length <= 1 ? chats.map(one => CHAT_NAMES[one]).join("") : `${chats.slice(0, -1).map(one => CHAT_NAMES[one]).join(", ")} or ${CHAT_NAMES[chats[chats.length - 1]]}`;
|
|
148
162
|
/** Every term in words — what the ceremony renders and the password
|
|
149
163
|
* signs. The reversal sentence is verbatim from the chain (C1). */
|
|
150
164
|
export function modeWords(terms) {
|
|
@@ -155,11 +169,8 @@ export function modeWords(terms) {
|
|
|
155
169
|
terms.autoApproveFiling
|
|
156
170
|
? "every scope YOU file — signed-in console or credentialed CLI — is approved the moment you file it; while this mode is active, your signed-in browser session becomes a spend credential for this repository"
|
|
157
171
|
: "filings still wait for their own approval ceremony",
|
|
158
|
-
terms.quickMint
|
|
159
|
-
? "you start watched sessions without re-typing your password — the confirm screen still shows every term"
|
|
160
|
-
: "watched sessions keep the per-session password",
|
|
161
172
|
terms.planAuto
|
|
162
|
-
? "plans for your pre-authorized filings auto-approve only when the goal, exclusions, paths, acceptance criteria,
|
|
173
|
+
? "plans for your pre-authorized filings auto-approve only when the goal, exclusions, paths, acceptance criteria, budget, and agent route remain exactly unchanged; provide a goal, paths and acceptance criteria upfront; amendments and unresolved questions still wait for you"
|
|
163
174
|
: "planner-generated plans wait for your approval",
|
|
164
175
|
terms.name === "hands-off"
|
|
165
176
|
? "automatic review is on for this project unless you turn it off (`toolroll review off --repo <path>`): each finished build whose check passes (or that finishes, with checks Off) gets one read-only review by the project's review agent; a HIGH finding sends it back once as a revision filed under this mode, a HIGH on that revision comes to you, MEDIUM and LOW findings come to you as suggested follow-ups, and a review that fails or times out never holds the work — it reaches you marked not reviewed"
|
|
@@ -178,13 +189,12 @@ export function modeWords(terms) {
|
|
|
178
189
|
terms.publication === "automerge"
|
|
179
190
|
? "pull requests merge THEMSELVES when CI is seen green on the exact commit — you are told afterwards (requires a merge-capable publication grant)"
|
|
180
191
|
: "merges wait for you — even where a grant could merge on its own, while this mode is active",
|
|
181
|
-
terms.allowPaidFallback
|
|
182
|
-
? "
|
|
183
|
-
: "automatic fallback never switches to a paid API key on its own; a subscription that runs out stops and waits for you",
|
|
192
|
+
...(terms.allowPaidFallback
|
|
193
|
+
? ["a historical paid-fallback grant is retained on record but no longer used"] : []),
|
|
184
194
|
...(terms.repairAuto
|
|
185
195
|
? ["historical automatic repair grants are retained on record but no longer schedule work"] : []),
|
|
186
196
|
...(terms.chatApprove
|
|
187
|
-
? [
|
|
197
|
+
? [`your paired ${chatNames(chatApproveChatsOf(terms))} chat may approve this repository's plans and merge its ready pull requests, two taps each, without your password; a plan that widens permissions, exceeds the per-attempt cap above or touches protected paths still opens Toolroll`] : []),
|
|
188
198
|
`everything above ends at ${terms.absoluteExpiry.slice(0, 16).replace("T", " ")} — revoking it earlier is one click, and every act it covered falls back to its own ceremony`,
|
|
189
199
|
];
|
|
190
200
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Saved notifications, read and told apart without a store: the row readers, the lifecycle key and the predicates
|
|
2
|
+
* the store and the chat core (chat-messages.ts) share. A leaf: it imports types only. */
|
|
3
|
+
import type { MateProposal, Notification, NotificationReceipt } from "./store.js";
|
|
4
|
+
/** The one task a card is about: a task its confirmation created (a new
|
|
5
|
+
* task, a revision), else the task it names (and, for feedback on a result,
|
|
6
|
+
* that result). Null for a card about no single task. A pointer for
|
|
7
|
+
* replies, never an authority. */
|
|
8
|
+
export declare function proposalTaskOf(proposal: MateProposal | null): {
|
|
9
|
+
task: string;
|
|
10
|
+
run: number | null;
|
|
11
|
+
} | null;
|
|
12
|
+
/** Every lifecycle dedupe key starts here: `life:<kind>:<identity>:<ordinal>`. */
|
|
13
|
+
export declare const LIFECYCLE_KEY_PREFIX = "life:";
|
|
14
|
+
/**
|
|
15
|
+
* Task lifecycle updates (Telegram task updates, 2026-09-16): the CLOSED
|
|
16
|
+
* vocabulary of routine progress facts the shared mutations record beside
|
|
17
|
+
* the change that made them true. None carries a push class — they are
|
|
18
|
+
* digest-eligible progress, never a page — and every one is project-bound
|
|
19
|
+
* through the task it names. A decision, incident, gap, stall, publication
|
|
20
|
+
* or merge page keeps its own producer; nothing here repeats one.
|
|
21
|
+
*/
|
|
22
|
+
export declare const LIFECYCLE_KINDS: readonly ["task-filed", "scope-approved", "approval-withdrawn", "task-held", "task-released", "task-queued", "task-requeued", "task-cancelled", "run-started", "run-phase", "check-progress", "run-finished", "run-stopping", "run-stopped", "run-resumed", "review-requested", "review-finished", "acceptance-evidence", "acceptance-ready"];
|
|
23
|
+
export type LifecycleKind = (typeof LIFECYCLE_KINDS)[number];
|
|
24
|
+
/** A progress fact, told apart by its durable key — never by display text. */
|
|
25
|
+
export declare function isLifecycleNotification(row: Pick<Notification, "dedupeKey">): boolean;
|
|
26
|
+
/** Only known progress producers can repaint a card. Decisions and urgent
|
|
27
|
+
* incidents keep their own alerts; a routine retry updates its saved attempt. */
|
|
28
|
+
export declare function isTelegramProgressNotification(row: Pick<Notification, "dedupeKey" | "kind" | "pushClass" | "run">): boolean;
|
|
29
|
+
export declare function readNotification(row: Record<string, unknown>): Notification;
|
|
30
|
+
export declare function readNotificationReceipt(row: Record<string, unknown>): NotificationReceipt;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/** The one task a card is about: a task its confirmation created (a new
|
|
2
|
+
* task, a revision), else the task it names (and, for feedback on a result,
|
|
3
|
+
* that result). Null for a card about no single task. A pointer for
|
|
4
|
+
* replies, never an authority. */
|
|
5
|
+
export function proposalTaskOf(proposal) {
|
|
6
|
+
if (proposal === null)
|
|
7
|
+
return null;
|
|
8
|
+
const named = typeof proposal.payload["task"] === "string" && proposal.payload["task"] !== "" ? proposal.payload["task"] : null;
|
|
9
|
+
const creates = proposal.kind === "task" || (proposal.kind === "review" && proposal.payload["operation"] === "revise");
|
|
10
|
+
const made = creates && proposal.state === "confirmed" ? proposal.outcome?.["taskId"] : undefined;
|
|
11
|
+
if (typeof made === "string" && made !== "" && made !== named)
|
|
12
|
+
return { task: made, run: null };
|
|
13
|
+
if (named === null)
|
|
14
|
+
return null;
|
|
15
|
+
const run = proposal.kind === "review" ? proposal.payload["run"] : null;
|
|
16
|
+
return { task: named, run: typeof run === "number" && Number.isSafeInteger(run) ? run : null };
|
|
17
|
+
}
|
|
18
|
+
/** Every lifecycle dedupe key starts here: `life:<kind>:<identity>:<ordinal>`. */
|
|
19
|
+
export const LIFECYCLE_KEY_PREFIX = "life:";
|
|
20
|
+
/**
|
|
21
|
+
* Task lifecycle updates (Telegram task updates, 2026-09-16): the CLOSED
|
|
22
|
+
* vocabulary of routine progress facts the shared mutations record beside
|
|
23
|
+
* the change that made them true. None carries a push class — they are
|
|
24
|
+
* digest-eligible progress, never a page — and every one is project-bound
|
|
25
|
+
* through the task it names. A decision, incident, gap, stall, publication
|
|
26
|
+
* or merge page keeps its own producer; nothing here repeats one.
|
|
27
|
+
*/
|
|
28
|
+
export const LIFECYCLE_KINDS = [
|
|
29
|
+
"task-filed",
|
|
30
|
+
"scope-approved",
|
|
31
|
+
"approval-withdrawn",
|
|
32
|
+
"task-held",
|
|
33
|
+
"task-released",
|
|
34
|
+
"task-queued",
|
|
35
|
+
"task-requeued",
|
|
36
|
+
"task-cancelled",
|
|
37
|
+
"run-started",
|
|
38
|
+
"run-phase",
|
|
39
|
+
"check-progress",
|
|
40
|
+
"run-finished",
|
|
41
|
+
"run-stopping",
|
|
42
|
+
"run-stopped",
|
|
43
|
+
"run-resumed",
|
|
44
|
+
"review-requested",
|
|
45
|
+
"review-finished",
|
|
46
|
+
"acceptance-evidence",
|
|
47
|
+
"acceptance-ready",
|
|
48
|
+
];
|
|
49
|
+
/** A progress fact, told apart by its durable key — never by display text. */
|
|
50
|
+
export function isLifecycleNotification(row) {
|
|
51
|
+
return row.dedupeKey.startsWith(LIFECYCLE_KEY_PREFIX);
|
|
52
|
+
}
|
|
53
|
+
/** Only known progress producers can repaint a card. Decisions and urgent
|
|
54
|
+
* incidents keep their own alerts; a routine retry updates its saved attempt. */
|
|
55
|
+
export function isTelegramProgressNotification(row) {
|
|
56
|
+
if (row.kind === "check-progress" && row.pushClass === "progress" && row.run !== null)
|
|
57
|
+
return isLifecycleNotification(row);
|
|
58
|
+
if (row.pushClass !== null)
|
|
59
|
+
return false;
|
|
60
|
+
if (row.kind === "build-failed" && row.run !== null && row.dedupeKey === `run:${row.run}:failed`)
|
|
61
|
+
return true;
|
|
62
|
+
// The owner's lead took the attempt on, or let it lapse (lead-voice.ts): its card repaints in place.
|
|
63
|
+
if ((row.kind === "lead-on-it" || row.kind === "lead-lapsed") && row.run !== null)
|
|
64
|
+
return true;
|
|
65
|
+
return isLifecycleNotification(row) &&
|
|
66
|
+
["run-started", "run-phase", "run-finished", "review-requested", "review-finished", "run-stopping", "run-stopped", "run-resumed", "task-held", "task-released"].includes(row.kind);
|
|
67
|
+
}
|
|
68
|
+
export function readNotification(row) {
|
|
69
|
+
return {
|
|
70
|
+
id: Number(row["id"]),
|
|
71
|
+
recipient: row["recipient"] == null ? null : String(row["recipient"]),
|
|
72
|
+
dedupeKey: String(row["dedupe_key"]),
|
|
73
|
+
scope: row["provenance_scope"],
|
|
74
|
+
project: row["project"] == null ? null : String(row["project"]),
|
|
75
|
+
taskRef: row["task_ref"] == null ? null : Number(row["task_ref"]),
|
|
76
|
+
taskId: row["task_id"] == null ? null : String(row["task_id"]),
|
|
77
|
+
run: row["source_run"] == null ? null : Number(row["source_run"]),
|
|
78
|
+
kind: String(row["kind"]),
|
|
79
|
+
subject: String(row["subject"]),
|
|
80
|
+
body: String(row["body"]),
|
|
81
|
+
createdAt: String(row["created_at"]),
|
|
82
|
+
resolvedAt: row["resolved_at"] === null || row["resolved_at"] === undefined
|
|
83
|
+
? null
|
|
84
|
+
: String(row["resolved_at"]),
|
|
85
|
+
pushClass: (row["push_class"] === null || row["push_class"] === undefined) && String(row["kind"]) === "check-progress"
|
|
86
|
+
? "progress"
|
|
87
|
+
: row["push_class"] === null || row["push_class"] === undefined
|
|
88
|
+
? null
|
|
89
|
+
: String(row["push_class"]),
|
|
90
|
+
link: row["link"] === null || row["link"] === undefined ? null : String(row["link"]),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export function readNotificationReceipt(row) {
|
|
94
|
+
return {
|
|
95
|
+
...readNotification(row),
|
|
96
|
+
attempts: Number(row["attempts"]),
|
|
97
|
+
lastAttemptAt: row["last_attempt_at"] == null ? null : String(row["last_attempt_at"]),
|
|
98
|
+
lastError: row["last_error"] == null ? null : String(row["last_error"]),
|
|
99
|
+
deliveredAt: row["delivered_at"] == null ? null : String(row["delivered_at"]),
|
|
100
|
+
receipt: row["receipt"] == null ? null : String(row["receipt"]),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
@@ -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
|
-
'
|
|
13
|
+
'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.
|
|
@@ -31,7 +31,7 @@ export const REMOTE_ARGUMENTS = new Map([
|
|
|
31
31
|
['task next', args('id:task', 'key undo')],
|
|
32
32
|
['task steer', args('id:task', 'note')],
|
|
33
33
|
['task assign', args('id:task', 'key runner anyone')],
|
|
34
|
-
['task scope', args('id:task', 'key goal not touches budget-usd risk acceptance candidate
|
|
34
|
+
['task scope', args('id:task', 'key goal not touches budget-usd risk acceptance candidate model provider repair-model')],
|
|
35
35
|
['task plan', args('id:task', 'key provider model')],
|
|
36
36
|
['task hold', args('id:task', 'key reason until')],
|
|
37
37
|
['task unhold', args('id:task', 'key')],
|
|
@@ -47,13 +47,9 @@ export const REMOTE_ARGUMENTS = new Map([
|
|
|
47
47
|
['cap list', args()], ['cap add', args('name', 'kind probe expires')],
|
|
48
48
|
// These objects are installation-scoped at the outer boundary; only an all-project principal reaches them.
|
|
49
49
|
['incident resolve', args('incident')],
|
|
50
|
-
['routine show', args('id')],
|
|
51
|
-
['routine add', args('name', 'goal schedule acceptance ceiling budget-usd not touches require')],
|
|
52
|
-
...['refresh', 'pause', 'resume', 'run-now'].map(action => [`routine ${action}`, args('name')]),
|
|
53
50
|
['config show', args('phase?')], ['verify show', args()],
|
|
54
51
|
['intake preview', args()], ['intake pr-comments', args('', 'limit')],
|
|
55
52
|
['template show', args('name')],
|
|
56
|
-
['contest show', args('id')], ['contest exclude', args('contest ordinal')],
|
|
57
53
|
...['search', 'impact'].map(action => [`knowledge ${action}`, args('query', 'base')]),
|
|
58
54
|
['knowledge refresh', args('', 'base')],
|
|
59
55
|
// Decision reads and supersession are already project-bound in project-memory.ts. Proposal IDs are
|
package/dist/operate-remote.js
CHANGED
|
@@ -43,10 +43,9 @@ export const REMOTE_SCOPES = new Map([
|
|
|
43
43
|
["task list", listing],
|
|
44
44
|
["runner list", installation], ["coordinator list", installation], ["outbox list", installation], ["incident list", installation], ["incident resolve", installation],
|
|
45
45
|
["cap list", repo], ["cap add", repo],
|
|
46
|
-
...["list", "show", "add", "refresh", "pause", "resume", "run-now"].map(action => [`routine ${action}`, installation]),
|
|
47
46
|
["config show", installation], ["verify show", repo], ["intake show", installation], ["intake run", installation], ["intake preview", installation],
|
|
48
|
-
["intake pr-comments", installation], ["template list", installation], ["template show", installation],
|
|
49
|
-
["
|
|
47
|
+
["intake pr-comments", installation], ["template list", installation], ["template show", installation],
|
|
48
|
+
["webhook status", installation], ["review show", installation],
|
|
50
49
|
["chat-approval show", self], ["chat-approval off", self],
|
|
51
50
|
// The person's own remote actions, or everyone's within their projects for an approver (remote-audit.ts).
|
|
52
51
|
["audit", self],
|
|
@@ -63,11 +62,11 @@ export const REMOTE_SCOPES = new Map([
|
|
|
63
62
|
*/
|
|
64
63
|
export const REMOTE_ALL_PROJECTS_ONLY = new Map([
|
|
65
64
|
// Settings, connections and acts that belong to the installation as a whole, not to any one project.
|
|
66
|
-
...["integrations", "grants", "sync", "incident resolve",
|
|
67
|
-
"config show", "intake run", "
|
|
65
|
+
...["integrations", "grants", "sync", "incident resolve",
|
|
66
|
+
"config show", "intake run", "webhook status"].map(row => [row, "installation-wide"]),
|
|
68
67
|
// Cross-project lists and reads a limited person is still refused; scoping them is later work.
|
|
69
|
-
...["runner list", "coordinator list", "outbox list", "incident list", "
|
|
70
|
-
"intake pr-comments", "template list", "template show", "
|
|
68
|
+
...["runner list", "coordinator list", "outbox list", "incident list", "intake show", "intake preview",
|
|
69
|
+
"intake pr-comments", "template list", "template show", "review show"].map(row => [row, "not yet scoped"]),
|
|
71
70
|
]);
|
|
72
71
|
/** The projects a listing or task reference may disclose: null for someone with access to all of them. */
|
|
73
72
|
export function remoteLensOf(store, scope, allows) {
|
package/dist/operate.d.ts
CHANGED
|
@@ -73,10 +73,6 @@ export type OperateOptions = {
|
|
|
73
73
|
integrationIo?: Partial<IntegrationIo>;
|
|
74
74
|
/** Injected by tests: the mate's provider fetch, key environment, and stdin lines. */
|
|
75
75
|
mateSeams?: MateCliSeams;
|
|
76
|
-
/** Injected by tests: a held-session coordinator, so a `tick` exercises
|
|
77
|
-
* the attended road exactly as a co-located `up` would (production wires
|
|
78
|
-
* one only inside `up`). */
|
|
79
|
-
heldCoordinator?: import("./held.js").HeldSessionCoordinator;
|
|
80
76
|
/** Test seam for the short indexed wait loop. */
|
|
81
77
|
waitSleep?: (milliseconds: number) => Promise<void>;
|
|
82
78
|
/** Injected by tests: `onboard`'s home folder, terminal and probes. */
|
|
@@ -110,8 +106,6 @@ export declare const TASK_ACTIONS: readonly ["add", "list", "show", "wait", "sta
|
|
|
110
106
|
export declare const PUBLISH_ACTIONS: readonly ["setup", "grant", "revoke", "status", "unblock", "rearm", "merge", "refire"];
|
|
111
107
|
export declare const CONFIG_ACTIONS: readonly ["show", "set", "clear"];
|
|
112
108
|
export declare const APPROVER_ACTIONS: readonly ["list", "add"];
|
|
113
|
-
export declare const ROUTINE_ACTIONS: readonly ["list", "add", "show", "approve", "refresh", "pause", "resume", "run-now"];
|
|
114
|
-
export declare const CONTEST_ACTIONS: readonly ["show", "exclude"];
|
|
115
109
|
export declare const PEOPLE_ACTIONS: readonly ["list", "invite", "projects", "revoke"];
|
|
116
110
|
export declare const KEYS_ACTIONS: readonly ["status", "set", "clear", "verify", "auth"];
|
|
117
111
|
/**
|