toolroll 0.9.53 → 0.9.55
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 +17 -0
- package/README.md +5 -4
- package/dist/agent-onboard.js +4 -1
- package/dist/approval-rules-ui.d.ts +3 -2
- package/dist/approval-rules-ui.js +15 -20
- package/dist/assignment-ui.d.ts +3 -2
- package/dist/assignment-ui.js +4 -11
- package/dist/backup-ui.d.ts +2 -1
- package/dist/backup-ui.js +16 -27
- package/dist/brand-mark.d.ts +3 -2
- package/dist/brand-mark.js +4 -4
- package/dist/browser/workspace.css +1 -1
- package/dist/browser/workspace.js +25 -25
- package/dist/browser-shell.d.ts +2 -1
- package/dist/browser-shell.js +9 -9
- package/dist/browser-workspace.d.ts +2 -3
- package/dist/browser-workspace.js +0 -3
- package/dist/chat-ask.js +8 -8
- 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 +26 -21
- package/dist/chat-delivery-state.d.ts +51 -75
- package/dist/chat-delivery-state.js +140 -170
- package/dist/chat-delivery.d.ts +21 -2
- package/dist/chat-delivery.js +313 -194
- 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-polish.d.ts +5 -4
- package/dist/chat-polish.js +9 -10
- package/dist/chat-quiet.d.ts +3 -0
- package/dist/chat-quiet.js +5 -0
- package/dist/check-levels-ui.d.ts +2 -1
- package/dist/check-levels-ui.js +26 -53
- package/dist/cli.d.ts +3 -1
- package/dist/cli.js +9 -3
- package/dist/coding-shipping-ui.d.ts +2 -1
- package/dist/coding-shipping-ui.js +6 -6
- package/dist/coding-ui.d.ts +3 -1
- package/dist/coding-ui.js +30 -29
- 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 +1 -3
- package/dist/contracts/console-api.d.ts +1 -1
- package/dist/contracts/console-api.js +6 -5
- package/dist/contracts/discord-callback.js +2 -1
- package/dist/contracts/health.d.ts +1 -3
- package/dist/contracts/slack-callback.js +3 -2
- package/dist/contracts/store-json.d.ts +1 -5
- package/dist/contracts/store-json.js +1 -4
- package/dist/contracts/teams-callback.js +2 -1
- package/dist/control-ui.d.ts +5 -4
- package/dist/control-ui.js +9 -34
- package/dist/credentials-ui.d.ts +5 -4
- package/dist/credentials-ui.js +23 -24
- package/dist/demo-chat.d.ts +3 -3
- package/dist/demo-chat.js +29 -76
- package/dist/discord-chat.js +19 -38
- package/dist/discord-settings.d.ts +3 -2
- package/dist/discord-settings.js +21 -55
- package/dist/discord.js +4 -14
- package/dist/envelope.js +10 -0
- package/dist/evidence-pack.d.ts +2 -1
- package/dist/evidence-pack.js +45 -49
- package/dist/export-ui.d.ts +7 -2
- package/dist/export-ui.js +4 -10
- package/dist/export.js +4 -4
- package/dist/flow-gallery-ui.d.ts +4 -3
- package/dist/flow-gallery-ui.js +28 -43
- package/dist/flow-starters-ui.d.ts +2 -1
- package/dist/flow-starters-ui.js +12 -15
- package/dist/flow-triggers.d.ts +1 -0
- package/dist/flow-triggers.js +16 -14
- package/dist/flows-ui.d.ts +4 -3
- package/dist/flows-ui.js +19 -30
- package/dist/flows.js +2 -1
- package/dist/guides.js +108 -3
- package/dist/html.d.ts +76 -0
- package/dist/html.js +173 -0
- package/dist/integrations-ui.d.ts +2 -1
- package/dist/integrations-ui.js +19 -23
- package/dist/kits-ui.d.ts +5 -4
- package/dist/kits-ui.js +18 -20
- package/dist/knowledge-ui.d.ts +6 -5
- package/dist/knowledge-ui.js +26 -25
- package/dist/lead-context.d.ts +11 -1
- package/dist/lead-context.js +6 -8
- package/dist/ledger-view.d.ts +2 -1
- package/dist/ledger-view.js +27 -29
- package/dist/limits-ui.d.ts +2 -1
- package/dist/limits-ui.js +7 -7
- package/dist/live-bus.d.ts +50 -8
- package/dist/live-bus.js +133 -50
- package/dist/mate-tools.js +3 -2
- package/dist/mcp-oauth.js +35 -36
- package/dist/models-ui.d.ts +2 -1
- package/dist/models-ui.js +25 -35
- package/dist/modes.d.ts +13 -1
- package/dist/modes.js +17 -1
- package/dist/monitoring-ui.d.ts +4 -3
- package/dist/monitoring-ui.js +13 -26
- package/dist/notification-rows.d.ts +30 -0
- package/dist/notification-rows.js +102 -0
- package/dist/openrouter-models.d.ts +2 -1
- package/dist/openrouter-models.js +5 -9
- package/dist/operate.js +16 -9
- package/dist/people-audit-ui.d.ts +2 -1
- package/dist/people-audit-ui.js +13 -13
- package/dist/plane-review.js +5 -11
- package/dist/policy-ui.d.ts +3 -2
- package/dist/policy-ui.js +17 -23
- package/dist/project-delete-ui.d.ts +4 -3
- package/dist/project-delete-ui.js +15 -27
- package/dist/project-delete.js +21 -26
- package/dist/pull-request-ui.d.ts +2 -1
- package/dist/pull-request-ui.js +17 -32
- package/dist/recipe-ui.d.ts +8 -7
- package/dist/recipe-ui.js +39 -32
- package/dist/release-adapters.d.ts +60 -0
- package/dist/release-adapters.js +435 -0
- package/dist/release-cli.d.ts +24 -0
- package/dist/release-cli.js +181 -0
- package/dist/release-gate.d.ts +80 -0
- package/dist/release-gate.js +150 -0
- package/dist/release-links.d.ts +29 -0
- package/dist/release-links.js +102 -0
- package/dist/release.d.ts +331 -0
- package/dist/release.js +550 -0
- package/dist/reply-shape.d.ts +2 -1
- package/dist/reply-shape.js +5 -5
- package/dist/repository-context-ui.d.ts +2 -1
- package/dist/repository-context-ui.js +2 -7
- package/dist/request-budget-ui.d.ts +2 -1
- package/dist/request-budget-ui.js +16 -16
- package/dist/result-review.d.ts +2 -3
- package/dist/result-review.js +3 -9
- package/dist/result-shots.js +2 -2
- package/dist/retention-ui.d.ts +7 -1
- package/dist/retention-ui.js +7 -11
- package/dist/retention.js +1 -1
- package/dist/serve.d.ts +11 -2
- package/dist/serve.js +69 -58
- package/dist/server/chat.d.ts +3 -6
- package/dist/server/chat.js +969 -1006
- package/dist/server/chrome.d.ts +291 -0
- package/dist/server/chrome.js +747 -0
- package/dist/server/console.css +2819 -0
- package/dist/server/flows.d.ts +2 -6
- package/dist/server/flows.js +840 -766
- package/dist/server/guards.d.ts +1 -1
- package/dist/server/guards.js +5 -2
- package/dist/server/handler-context.d.ts +1 -1
- package/dist/server/handler-context.js +1 -1
- package/dist/server/handler-registry.d.ts +8 -6
- package/dist/server/handler-registry.js +14 -2
- package/dist/server/http.d.ts +274 -0
- package/dist/server/http.js +239 -0
- package/dist/server/live.d.ts +34 -0
- package/dist/server/live.js +309 -0
- package/dist/server/pages.d.ts +2 -6
- package/dist/server/pages.js +808 -789
- package/dist/server/people-tokens.d.ts +1 -6
- package/dist/server/people-tokens.js +580 -572
- package/dist/server/remote.d.ts +4 -7
- package/dist/server/remote.js +37 -70
- package/dist/server/render-chat.d.ts +402 -0
- package/dist/server/render-chat.js +927 -0
- package/dist/server/render-pages.d.ts +535 -0
- package/dist/server/render-pages.js +1277 -0
- package/dist/server/render-people.d.ts +32 -0
- package/dist/server/render-people.js +121 -0
- package/dist/server/render-results.d.ts +744 -0
- package/dist/server/render-results.js +2237 -0
- package/dist/server/render-settings.d.ts +147 -0
- package/dist/server/render-settings.js +577 -0
- package/dist/server/render-tasks.d.ts +632 -0
- package/dist/server/render-tasks.js +2345 -0
- package/dist/server/request-context.d.ts +46 -0
- package/dist/server/request-context.js +17 -0
- package/dist/server/route-table.d.ts +25 -3
- package/dist/server/route-table.js +163 -75
- package/dist/server/runtime.d.ts +15 -7
- package/dist/server/runtime.js +7 -1
- package/dist/server/session.d.ts +138 -0
- package/dist/server/session.js +94 -0
- package/dist/server/settings.d.ts +1 -5
- package/dist/server/settings.js +2182 -2117
- package/dist/server/task-views.d.ts +11 -4
- package/dist/server/task-views.js +26 -22
- package/dist/server/tasks.d.ts +9 -9
- package/dist/server/tasks.js +1486 -1418
- package/dist/server-telemetry.d.ts +4 -3
- package/dist/server-telemetry.js +4 -8
- package/dist/skills-ui.d.ts +4 -3
- package/dist/skills-ui.js +14 -17
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +2 -1
- package/dist/slack-api.d.ts +5 -1
- package/dist/slack-api.js +2 -2
- package/dist/slack-chat.d.ts +9 -4
- package/dist/slack-chat.js +29 -52
- package/dist/slack-settings.d.ts +3 -2
- package/dist/slack-settings.js +23 -57
- package/dist/slack.js +6 -16
- package/dist/spend-ui.d.ts +2 -1
- package/dist/spend-ui.js +9 -32
- package/dist/sso-ui.d.ts +3 -2
- package/dist/sso-ui.js +26 -27
- package/dist/storage-ui.d.ts +2 -1
- package/dist/storage-ui.js +14 -33
- package/dist/store.d.ts +97 -364
- package/dist/store.js +207 -1531
- package/dist/surface.js +14 -3
- package/dist/task-composer.d.ts +2 -1
- package/dist/task-composer.js +7 -7
- package/dist/task-status.d.ts +4 -3
- package/dist/task-status.js +15 -16
- package/dist/team-http.d.ts +5 -9
- package/dist/team-http.js +5 -63
- package/dist/team-ui.d.ts +2 -1
- package/dist/team-ui.js +2 -5
- package/dist/teammate-question.js +12 -12
- package/dist/teammates-ui.d.ts +5 -4
- package/dist/teammates-ui.js +61 -90
- package/dist/teams-chat.js +12 -9
- package/dist/teams-settings.d.ts +3 -2
- package/dist/teams-settings.js +22 -33
- package/dist/teams.js +4 -5
- package/dist/telegram-flow.js +5 -5
- package/dist/telegram-settings.d.ts +3 -2
- package/dist/telegram-settings.js +14 -25
- package/dist/telegram.js +4 -4
- package/dist/toolroll-update-ui.d.ts +3 -2
- package/dist/toolroll-update-ui.js +35 -39
- package/dist/toolroll-update.d.ts +10 -0
- package/dist/toolroll-update.js +50 -3
- package/dist/tools-ui.d.ts +5 -2
- package/dist/tools-ui.js +31 -31
- package/dist/when-html.d.ts +11 -3
- package/dist/when-html.js +5 -6
- package/dist/workspace-revision.js +3 -1
- package/dist/workspace-ui.d.ts +4 -2
- package/dist/workspace-ui.js +10 -10
- package/package.json +1 -1
- package/dist/server/shared.d.ts +0 -3151
- package/dist/server/shared.js +0 -12001
- package/dist/slack-state.d.ts +0 -13
- package/dist/slack-state.js +0 -10
package/dist/chat-decide.d.ts
CHANGED
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
* their own chat; otherwise, and for a plan that widens permissions, exceeds the limit or touches protected paths, the
|
|
10
10
|
* card keeps its link.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
* tokens (the `channel` column). Every act runs through the door the
|
|
12
|
+
* The same in every chat app: Telegram's bridge and the shared engine Slack, Discord and Teams run on (chat-delivery.ts)
|
|
13
|
+
* offer, mint and answer these through the same tokens (the `channel` column). Every act runs through the door the
|
|
14
|
+
* console uses. */
|
|
14
15
|
import { DECIDE_ACTS } from "./contracts/chat-callback-rows.js";
|
|
15
16
|
import { type ChatApprovalLimits } from "./chat-approval.js";
|
|
16
17
|
import { type VerifiedApprover } from "./principal.js";
|
|
@@ -78,10 +79,11 @@ export type DecideOffer = {
|
|
|
78
79
|
text: string | null;
|
|
79
80
|
rows: Array<Array<ActSpec | DecideLink>>;
|
|
80
81
|
};
|
|
81
|
-
/** What lets this person's chat approve on this repository now: their lasting chat-approval setting
|
|
82
|
-
* or else a live signed mode carrying the chatApprove term, signed by them
|
|
82
|
+
/** What lets this person's chat on `channel` approve on this repository now: their lasting chat-approval setting
|
|
83
|
+
* (chat-approval.ts), or else a live signed mode carrying the chatApprove term, signed by them, that names this chat
|
|
84
|
+
* app (a mode signed before the term named its apps covers Telegram alone). `digest` names that authority for the
|
|
83
85
|
* ledger; the yes itself is the person's tap and is sealed as theirs, so it doesn't lapse when the authority does. */
|
|
84
|
-
export declare function chatApproveMode(store: Store, repo: string | null, approver: string, now: Date): {
|
|
86
|
+
export declare function chatApproveMode(store: Store, repo: string | null, approver: string, now: Date, channel: DecideChannel): {
|
|
85
87
|
ok: true;
|
|
86
88
|
digest: string;
|
|
87
89
|
limits: ChatApprovalLimits;
|
|
@@ -94,7 +96,7 @@ export declare function chatApproveMode(store: Store, repo: string | null, appro
|
|
|
94
96
|
export declare function permissionPlainWords(profile: Scope["profile"] | null | undefined): string | null;
|
|
95
97
|
/** A plan this person's chat may approve now: the term, the plan's exact bytes, and none of the reasons it must open
|
|
96
98
|
* Toolroll instead. `digest` binds the scope and the plan document the card shows. */
|
|
97
|
-
export declare function planInChat(store: Store, taskId: string, approver: string, now: Date, root?: string): {
|
|
99
|
+
export declare function planInChat(store: Store, taskId: string, approver: string, now: Date, channel: DecideChannel, root?: string): {
|
|
98
100
|
ok: true;
|
|
99
101
|
modeDigest: string;
|
|
100
102
|
source: "setting" | "mode";
|
|
@@ -105,7 +107,7 @@ export declare function planInChat(store: Store, taskId: string, approver: strin
|
|
|
105
107
|
why: string;
|
|
106
108
|
};
|
|
107
109
|
/** A ready pull request this person's chat may merge now, bound to the exact commit. */
|
|
108
|
-
export declare function mergeInChat(store: Store, taskId: string, run: number, approver: string, now: Date): {
|
|
110
|
+
export declare function mergeInChat(store: Store, taskId: string, run: number, approver: string, now: Date, channel: DecideChannel): {
|
|
109
111
|
ok: true;
|
|
110
112
|
modeDigest: string;
|
|
111
113
|
source: "setting" | "mode";
|
|
@@ -119,7 +121,7 @@ export declare function mergeInChat(store: Store, taskId: string, run: number, a
|
|
|
119
121
|
export declare function planCardText(store: Store, taskId: string, scope: Scope, root?: string, channel?: DecideChannel): string;
|
|
120
122
|
/** The acts a card about this target can take in chat right now, or null when none can (the card keeps its own
|
|
121
123
|
* link). Reads only; nothing is minted. */
|
|
122
|
-
export declare function decideOffer(store: Store, target: DecideTarget, who: VerifiedApprover, now: Date,
|
|
124
|
+
export declare function decideOffer(store: Store, target: DecideTarget, who: VerifiedApprover, now: Date, channel: DecideChannel, root?: string): DecideOffer | null;
|
|
123
125
|
/** One fingerprint of what the card offers, without its tokens: a repaint with the same offer keeps its buttons. */
|
|
124
126
|
export declare function offerFingerprint(offer: DecideOffer): string;
|
|
125
127
|
/** The card's buttons, minted now (message unknown until it is sent: `placeDecideTokens` puts them on it). */
|
package/dist/chat-decide.js
CHANGED
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
* their own chat; otherwise, and for a plan that widens permissions, exceeds the limit or touches protected paths, the
|
|
10
10
|
* card keeps its link.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
* tokens (the `channel` column). Every act runs through the door the
|
|
12
|
+
* The same in every chat app: Telegram's bridge and the shared engine Slack, Discord and Teams run on (chat-delivery.ts)
|
|
13
|
+
* offer, mint and answer these through the same tokens (the `channel` column). Every act runs through the door the
|
|
14
|
+
* console uses. */
|
|
14
15
|
import { DECIDE_ACTS, readDecideActionRow } from "./contracts/chat-callback-rows.js";
|
|
15
16
|
import { createHash, randomBytes } from "node:crypto";
|
|
16
17
|
import { acceptAndCompleteAsOperator, assignmentOf, owedAcceptance } from "./assignment.js";
|
|
@@ -19,7 +20,7 @@ import { applyChatTaskAction, chatTaskStamp } from "./chat-task-actions.js";
|
|
|
19
20
|
import { chatTitle } from "./chat-voice.js";
|
|
20
21
|
import { readVerifiedArtifact } from "./evidence.js";
|
|
21
22
|
import { effectiveChatApproval } from "./chat-approval.js";
|
|
22
|
-
import { modeTermsFromJson } from "./modes.js";
|
|
23
|
+
import { chatApproveChatsOf, chatNames, modeTermsFromJson } from "./modes.js";
|
|
23
24
|
import { parseExecutionPlanDocument } from "./plan.js";
|
|
24
25
|
import { verifyApproverStanding } from "./principal.js";
|
|
25
26
|
import { pullRequestFollowOf } from "./pull-request-flow.js";
|
|
@@ -47,10 +48,11 @@ const sha = (text) => createHash("sha256").update(text).digest("hex");
|
|
|
47
48
|
const isAct = (one) => "act" in one;
|
|
48
49
|
const title = (store, taskId) => phoneText(chatTitle(store, taskId), 60);
|
|
49
50
|
// ---- the chatApprove term ----------------------------------------------------------
|
|
50
|
-
/** What lets this person's chat approve on this repository now: their lasting chat-approval setting
|
|
51
|
-
* or else a live signed mode carrying the chatApprove term, signed by them
|
|
51
|
+
/** What lets this person's chat on `channel` approve on this repository now: their lasting chat-approval setting
|
|
52
|
+
* (chat-approval.ts), or else a live signed mode carrying the chatApprove term, signed by them, that names this chat
|
|
53
|
+
* app (a mode signed before the term named its apps covers Telegram alone). `digest` names that authority for the
|
|
52
54
|
* ledger; the yes itself is the person's tap and is sealed as theirs, so it doesn't lapse when the authority does. */
|
|
53
|
-
export function chatApproveMode(store, repo, approver, now) {
|
|
55
|
+
export function chatApproveMode(store, repo, approver, now, channel) {
|
|
54
56
|
if (repo === null)
|
|
55
57
|
return { ok: false, why: "Approving from chat isn't turned on for this project." };
|
|
56
58
|
const setting = effectiveChatApproval(store, repo, approver);
|
|
@@ -62,6 +64,9 @@ export function chatApproveMode(store, repo, approver, now) {
|
|
|
62
64
|
return setting;
|
|
63
65
|
if (mode.signedBy !== approver || !store.accountCanAccess(approver, repo))
|
|
64
66
|
return { ok: false, why: "Only the person who signed this project's mode can approve from chat." };
|
|
67
|
+
const chats = chatApproveChatsOf(terms);
|
|
68
|
+
if (!chats.includes(channel))
|
|
69
|
+
return { ok: false, why: `Your mode approves from ${chatNames(chats)} only. Sign it again to approve from ${chatNames([channel])}.` };
|
|
65
70
|
return { ok: true, digest: mode.digest, limits: { fullAccess: terms.permissionDefault === "escalated", capMicrousd: terms.perAttemptBudgetMicrousd }, source: "mode" };
|
|
66
71
|
}
|
|
67
72
|
/** What a plan's yes allows an agent to do, in a few plain words (the approval sheet's "You're allowing"). */
|
|
@@ -87,7 +92,7 @@ function fullAccess(profile) {
|
|
|
87
92
|
const money = (micro) => `$${(micro / 1_000_000).toFixed(2)}`;
|
|
88
93
|
/** A plan this person's chat may approve now: the term, the plan's exact bytes, and none of the reasons it must open
|
|
89
94
|
* Toolroll instead. `digest` binds the scope and the plan document the card shows. */
|
|
90
|
-
export function planInChat(store, taskId, approver, now, root) {
|
|
95
|
+
export function planInChat(store, taskId, approver, now, channel, root) {
|
|
91
96
|
const ref = store.lookupRef(taskId);
|
|
92
97
|
const scope = store.getScope(taskId);
|
|
93
98
|
if (ref === null || ref.repo === null || scope === null)
|
|
@@ -96,7 +101,7 @@ export function planInChat(store, taskId, approver, now, root) {
|
|
|
96
101
|
return { ok: false, why: "This plan is already approved." };
|
|
97
102
|
if (ref.plan === "requested")
|
|
98
103
|
return { ok: false, why: "The plan is still being written." };
|
|
99
|
-
const mode = chatApproveMode(store, ref.repo, approver, now);
|
|
104
|
+
const mode = chatApproveMode(store, ref.repo, approver, now, channel);
|
|
100
105
|
if (!mode.ok)
|
|
101
106
|
return mode;
|
|
102
107
|
if (store.getTask(taskId)?.state === "cancelled" || store.getTask(taskId)?.state === "done")
|
|
@@ -148,7 +153,7 @@ export function planInChat(store, taskId, approver, now, root) {
|
|
|
148
153
|
return { ok: true, modeDigest: mode.digest, source: mode.source, scope, digest: sha(`${scope.digest}:${plan?.sha256 ?? ""}`) };
|
|
149
154
|
}
|
|
150
155
|
/** A ready pull request this person's chat may merge now, bound to the exact commit. */
|
|
151
|
-
export function mergeInChat(store, taskId, run, approver, now) {
|
|
156
|
+
export function mergeInChat(store, taskId, run, approver, now, channel) {
|
|
152
157
|
const ref = store.lookupRef(taskId);
|
|
153
158
|
const publication = store.publicationForRun(run);
|
|
154
159
|
const follow = publication === null ? null : pullRequestFollowOf(store, publication.id);
|
|
@@ -158,7 +163,7 @@ export function mergeInChat(store, taskId, run, approver, now) {
|
|
|
158
163
|
return { ok: false, why: "This pull request is already merged." };
|
|
159
164
|
if (follow.readyHead !== publication.headSha)
|
|
160
165
|
return { ok: false, why: "This pull request changed since this card was sent." };
|
|
161
|
-
const mode = chatApproveMode(store, ref.repo, approver, now);
|
|
166
|
+
const mode = chatApproveMode(store, ref.repo, approver, now, channel);
|
|
162
167
|
if (!mode.ok)
|
|
163
168
|
return mode;
|
|
164
169
|
return { ok: true, modeDigest: mode.digest, source: mode.source, head: publication.headSha };
|
|
@@ -216,7 +221,7 @@ export function planCardText(store, taskId, scope, root, channel) {
|
|
|
216
221
|
// ---- what a card offers ---------------------------------------------------------------
|
|
217
222
|
/** The acts a card about this target can take in chat right now, or null when none can (the card keeps its own
|
|
218
223
|
* link). Reads only; nothing is minted. */
|
|
219
|
-
export function decideOffer(store, target, who, now,
|
|
224
|
+
export function decideOffer(store, target, who, now, channel, root) {
|
|
220
225
|
const ref = store.lookupRef(target.taskId);
|
|
221
226
|
if (ref === null || ref.repo === null || !who.repos.includes(ref.repo))
|
|
222
227
|
return null;
|
|
@@ -241,14 +246,14 @@ export function decideOffer(store, target, who, now, root, channel) {
|
|
|
241
246
|
return { text: null, rows: [[{ act: "retry", run: null, digest: stamp }], [{ label: DECIDE_LABELS.look, path: chatControlHref("task", target.taskId) }]] };
|
|
242
247
|
}
|
|
243
248
|
case "plan": {
|
|
244
|
-
const plan = planInChat(store, target.taskId, who.name, now, root);
|
|
249
|
+
const plan = planInChat(store, target.taskId, who.name, now, channel, root);
|
|
245
250
|
if (!plan.ok)
|
|
246
251
|
return null;
|
|
247
252
|
return { text: planCardText(store, target.taskId, plan.scope, root, channel),
|
|
248
253
|
rows: [[{ act: "approve", run: null, digest: plan.digest }], [{ label: DECIDE_LABELS.edit, path: chatControlHref("approval", target.taskId) }, { act: "not-now", run: null, digest: plan.digest }]] };
|
|
249
254
|
}
|
|
250
255
|
case "merge": {
|
|
251
|
-
const merge = mergeInChat(store, target.taskId, target.run, who.name, now);
|
|
256
|
+
const merge = mergeInChat(store, target.taskId, target.run, who.name, now, channel);
|
|
252
257
|
if (!merge.ok)
|
|
253
258
|
return null;
|
|
254
259
|
return { text: null, rows: [[{ act: "merge", run: target.run, digest: merge.head }], [{ label: DECIDE_LABELS.look, path: chatResultHref(target.taskId, target.run, "changes") }]] };
|
|
@@ -348,7 +353,7 @@ function targetOf(row) {
|
|
|
348
353
|
}
|
|
349
354
|
}
|
|
350
355
|
/** Why the card's act no longer applies, or null while it still does — checked at the offer and again at the yes. */
|
|
351
|
-
function staleWhy(store, row, who, now, root) {
|
|
356
|
+
function staleWhy(store, row, who, now, channel, root) {
|
|
352
357
|
switch (row.act) {
|
|
353
358
|
case "accept":
|
|
354
359
|
case "changes": {
|
|
@@ -366,13 +371,13 @@ function staleWhy(store, row, who, now, root) {
|
|
|
366
371
|
}
|
|
367
372
|
case "approve":
|
|
368
373
|
case "not-now": {
|
|
369
|
-
const plan = planInChat(store, row.taskId, who.name, now, root);
|
|
374
|
+
const plan = planInChat(store, row.taskId, who.name, now, channel, root);
|
|
370
375
|
if (!plan.ok)
|
|
371
376
|
return plan.why;
|
|
372
377
|
return plan.digest === row.digest ? null : "The plan changed since this card was sent.";
|
|
373
378
|
}
|
|
374
379
|
case "merge": {
|
|
375
|
-
const merge = mergeInChat(store, row.taskId, row.run ?? 0, who.name, now);
|
|
380
|
+
const merge = mergeInChat(store, row.taskId, row.run ?? 0, who.name, now, channel);
|
|
376
381
|
if (!merge.ok)
|
|
377
382
|
return merge.why;
|
|
378
383
|
return merge.head === row.digest ? null : "This pull request changed since this card was sent.";
|
|
@@ -459,13 +464,13 @@ export function applyDecideTap(store, seat, input) {
|
|
|
459
464
|
}
|
|
460
465
|
if (row.phase === "cancel") {
|
|
461
466
|
spend();
|
|
462
|
-
const offer = decideOffer(store, target, who, now,
|
|
467
|
+
const offer = decideOffer(store, target, who, now, seat.channel, input.root);
|
|
463
468
|
if (offer === null)
|
|
464
469
|
return { ack: "Cancelled.", edit: { text: body, rows: linksFor(target), tokens: [] } };
|
|
465
470
|
const minted = mintDecideButtons(store, seat, target, offer, now, input.message);
|
|
466
471
|
return { ack: "Cancelled.", edit: { text: offer.text ?? body, ...minted } };
|
|
467
472
|
}
|
|
468
|
-
const why = staleWhy(store, row, who, now, input.root);
|
|
473
|
+
const why = staleWhy(store, row, who, now, seat.channel, input.root);
|
|
469
474
|
if (why !== null)
|
|
470
475
|
return stale(why);
|
|
471
476
|
if (row.phase === "offer") {
|
|
@@ -503,7 +508,7 @@ export function applyDecideTap(store, seat, input) {
|
|
|
503
508
|
return retried.ok ? done("✓ Queued again. Existing approvals and holds still apply.") : notDone(retried.message);
|
|
504
509
|
}
|
|
505
510
|
case "approve": {
|
|
506
|
-
const plan = planInChat(store, row.taskId, who.name, now, input.root);
|
|
511
|
+
const plan = planInChat(store, row.taskId, who.name, now, seat.channel, input.root);
|
|
507
512
|
if (!plan.ok)
|
|
508
513
|
return notDone(plan.why);
|
|
509
514
|
// The owner's own yes, sealed as theirs ("chat"), never as a mode's: it stands like the console's after the mode or setting ends.
|
|
@@ -514,7 +519,7 @@ export function applyDecideTap(store, seat, input) {
|
|
|
514
519
|
return done("✓ Approved. Work starts when a worker is free.");
|
|
515
520
|
}
|
|
516
521
|
case "merge": {
|
|
517
|
-
const merge = mergeInChat(store, row.taskId, row.run ?? 0, who.name, now);
|
|
522
|
+
const merge = mergeInChat(store, row.taskId, row.run ?? 0, who.name, now, seat.channel);
|
|
518
523
|
if (!merge.ok)
|
|
519
524
|
return notDone(merge.why);
|
|
520
525
|
const via = `via ${seat.channel} · chat binding #${seat.binding} · ${merge.source} ${merge.modeDigest} · ${merge.head.slice(0, 12)}`;
|
|
@@ -567,7 +572,7 @@ export function applyDecideFeedback(store, seat, prompt, text, repos, root, now)
|
|
|
567
572
|
const verified = verifyApproverStanding(store, seat.approver, seat.generation, repos);
|
|
568
573
|
if (!verified.ok)
|
|
569
574
|
return { said: "That result isn't available here now. Nothing was sent.", link: null };
|
|
570
|
-
const why = staleWhy(store, { act: "changes", taskId: prompt.taskId, run: prompt.run, digest: prompt.digest }, verified.who, now, root);
|
|
575
|
+
const why = staleWhy(store, { act: "changes", taskId: prompt.taskId, run: prompt.run, digest: prompt.digest }, verified.who, now, seat.channel, root);
|
|
571
576
|
if (why !== null)
|
|
572
577
|
return { said: `${why} Your feedback wasn't sent.`, link: { label: "Open task", path: chatControlHref("task", prompt.taskId) } };
|
|
573
578
|
if (root === undefined)
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import {
|
|
1
|
+
import { ChatCore, chatHash, type ChatBinding, type ChatProvider, type ChatRoom } from "./chat-core.js";
|
|
2
|
+
import { ChatMessages } from "./chat-messages.js";
|
|
3
3
|
import { savedChatPart, type ChatContent, type ChatEventBody } from "./contracts/chat-content.js";
|
|
4
|
-
export { savedChatPart, type ChatContent, type ChatEventBody };
|
|
5
|
-
export { chatSchema, chatTables };
|
|
4
|
+
export { savedChatPart, chatHash, type ChatContent, type ChatEventBody, type ChatBinding, type ChatProvider, type ChatRoom };
|
|
6
5
|
export type ChatIdentity = {
|
|
7
6
|
installation: string;
|
|
8
7
|
team?: string;
|
|
@@ -10,18 +9,6 @@ export type ChatIdentity = {
|
|
|
10
9
|
bot: string;
|
|
11
10
|
workspace: string;
|
|
12
11
|
};
|
|
13
|
-
export type ChatBinding = {
|
|
14
|
-
id: number;
|
|
15
|
-
installation: string;
|
|
16
|
-
team: string;
|
|
17
|
-
app: string;
|
|
18
|
-
member: string;
|
|
19
|
-
channel: string;
|
|
20
|
-
approver: string;
|
|
21
|
-
generation: number;
|
|
22
|
-
created: string;
|
|
23
|
-
revoked: string | null;
|
|
24
|
-
};
|
|
25
12
|
export type ChatEvent = {
|
|
26
13
|
id: string;
|
|
27
14
|
installation: string;
|
|
@@ -51,64 +38,20 @@ export type ChatPart = {
|
|
|
51
38
|
next_at: string | null;
|
|
52
39
|
created: string;
|
|
53
40
|
};
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
kind: "group" | "private";
|
|
59
|
-
conversation: string;
|
|
60
|
-
boundBy: string;
|
|
61
|
-
binding: number;
|
|
62
|
-
cursor: number;
|
|
63
|
-
};
|
|
64
|
-
export declare const chatHash: (text: string) => string;
|
|
65
|
-
export declare class ChatState {
|
|
66
|
-
readonly store: Store;
|
|
67
|
-
readonly channel: "slack" | "discord" | "teams";
|
|
68
|
-
constructor(store: Store, channel: "slack" | "discord" | "teams");
|
|
69
|
-
prepare(sql: string): import("./store.js").Statement;
|
|
70
|
-
/** Small transport facts a channel must remember per chat (a Teams service URL). Never credentials. */
|
|
71
|
-
meta(installation: string, key: string): string | null;
|
|
72
|
-
setMeta(installation: string, key: string, value: string, now: Date): void;
|
|
73
|
-
private readRoom;
|
|
74
|
-
room(installation: string, chat: string): ChatRoom | null;
|
|
75
|
-
rooms(installation: string): ChatRoom[];
|
|
76
|
-
/** Point a chat at a conversation; an earlier choice for the same chat is revoked and delivery starts from now. */
|
|
77
|
-
bindRoom(args: {
|
|
78
|
-
installation: string;
|
|
79
|
-
chat: string;
|
|
80
|
-
kind: "group" | "private";
|
|
81
|
-
conversation: string;
|
|
82
|
-
by: string;
|
|
83
|
-
binding: number;
|
|
84
|
-
}, now: Date): {
|
|
85
|
-
ok: true;
|
|
86
|
-
} | {
|
|
87
|
-
ok: false;
|
|
88
|
-
reason: "group-taken";
|
|
89
|
-
};
|
|
90
|
-
unbindRoom(installation: string, chat: string, by: string, now: Date): boolean;
|
|
91
|
-
/** The shared rooms core's view of this installation's room records. */
|
|
92
|
-
roomBackend(installation: string, now: Date): import("./chat-rooms.js").RoomBackend;
|
|
93
|
-
advanceRoomCursor(id: number, messageId: number): boolean;
|
|
94
|
-
get db(): import("./store.js").Database;
|
|
95
|
-
/** Every unrevoked binding for an installation, oldest first: one per
|
|
96
|
-
* paired person (v73). Liveness is checked per binding with `live`. */
|
|
97
|
-
bindings(installation: string): ChatBinding[];
|
|
98
|
-
/** The unrevoked binding one channel member holds, if any. */
|
|
99
|
-
bindingFor(installation: string, member: string): ChatBinding | null;
|
|
100
|
-
bindingById(id: number): ChatBinding | null;
|
|
101
|
-
/** The oldest unrevoked binding — the single-person reading kept for
|
|
102
|
-
* status lines and fixtures; inbound, delivery and notices read
|
|
103
|
-
* `bindingFor` / `bindingById` / `bindings`. */
|
|
104
|
-
binding(installation: string): ChatBinding | null;
|
|
105
|
-
live(binding: ChatBinding): boolean;
|
|
106
|
-
/** End one person's pairing and everything their chat could still do; teammates' bindings stay. */
|
|
107
|
-
revokeBinding(binding: ChatBinding, now?: Date): void;
|
|
108
|
-
revoke(installation: string, now?: Date): void;
|
|
41
|
+
/** One app's chats on the shared core (the same object Telegram's run on): its events, planned parts and their buttons. */
|
|
42
|
+
export declare class ChatState extends ChatMessages {
|
|
43
|
+
constructor(store: ChatCore["store"], provider: ChatProvider);
|
|
44
|
+
/** Pair-time half kept for the settings pages: mint a code for this installation and return it (only its hash is kept). */
|
|
109
45
|
pairing(installation: string, approver: string, generation: number, now?: Date): string;
|
|
110
|
-
|
|
111
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Consume a code sent in a chat (the shared rules, chat-core.ts). The installation's notice cursor starts from now
|
|
48
|
+
* on its FIRST pairing; a later person joins the running cursor (their own history is fenced by their binding's
|
|
49
|
+
* creation time).
|
|
50
|
+
*/
|
|
51
|
+
pair(identity: ChatIdentity, hash: string, member: string, channel: string, now: Date, event?: string | null): ChatBinding | null;
|
|
52
|
+
/** The 60-second lease the Slack, Discord and Teams workers renew. */
|
|
53
|
+
lease(installation: string, owner: string, now: Date): boolean;
|
|
54
|
+
/** Save a received event with its body (contracts/chat-content.ts), versioned. False: it was already here. */
|
|
112
55
|
enqueue(event: Omit<ChatEvent, "session" | "state" | "next_at" | "payload"> & {
|
|
113
56
|
payload: ChatEventBody;
|
|
114
57
|
}): boolean;
|
|
@@ -116,11 +59,44 @@ export declare class ChatState {
|
|
|
116
59
|
next(installation: string, now: Date): ChatEvent | null;
|
|
117
60
|
defer(event: string, problem: string, until: Date): void;
|
|
118
61
|
finish(event: string, dropped?: boolean): void;
|
|
62
|
+
/** Point an event at the binding its pairing made. */
|
|
63
|
+
setEventBinding(event: string, binding: number): void;
|
|
119
64
|
part(id: number): ChatPart | null;
|
|
65
|
+
/** The reply to an event, part by part, with each part's buttons minted with it; the event is then handled. Planned once. */
|
|
120
66
|
plan(event: string, parts: ChatContent[], now: Date): void;
|
|
67
|
+
/** A proposal card's buttons on its part: earlier ones on that part are spent. Yes and Cancel last ten minutes. */
|
|
121
68
|
tokens(part: number, proposal: number, phases: Array<"confirm" | "dismiss" | "yes" | "cancel">, now: Date): void;
|
|
122
|
-
|
|
123
|
-
|
|
69
|
+
/** A proposal card's live buttons on one part, in the order they were minted. */
|
|
70
|
+
partTokens(part: number, now: Date): {
|
|
71
|
+
token: string;
|
|
72
|
+
phase: string;
|
|
73
|
+
}[];
|
|
74
|
+
/** The next part to send for an installation: notices only while notifications may go out. */
|
|
75
|
+
nextPart(installation: string, notices: boolean, now: Date, order?: "id" | "created"): ChatPart | null;
|
|
76
|
+
/** A part that will not go: why, in words the saved chat shows. */
|
|
77
|
+
dropPart(id: number, problem: string): void;
|
|
78
|
+
/** Try again no earlier than then (a screenshot waiting for its result's message). */
|
|
79
|
+
holdPart(id: number, until: string): void;
|
|
80
|
+
/** The app's upload identity for a part's file, and whether its bytes are up. */
|
|
81
|
+
setPartFile(id: number, file: string | null, uploaded?: boolean, message?: string | null): void;
|
|
82
|
+
/**
|
|
83
|
+
* Sent: on the app's own message id when it gave one (an uploaded file may not). A card's decide buttons
|
|
84
|
+
* (chat-decide.ts) now ride that message, and any older ones on it stop working; a "What should change?" names it.
|
|
85
|
+
*/
|
|
86
|
+
partSent(id: number, message: string | null, now: Date, attempt?: boolean): void;
|
|
87
|
+
/** Not sent this time: counted, named, and (when the answer was lost rather than refused) counted as uncertain. */
|
|
88
|
+
partFailed(id: number, failure: {
|
|
89
|
+
problem: string;
|
|
90
|
+
until: string;
|
|
91
|
+
uncertain: boolean;
|
|
92
|
+
}, giveUpAfter?: number): void;
|
|
93
|
+
/** One person's replies still waiting to send, and those that could not be delivered (settings show both). */
|
|
94
|
+
partCounts(binding: number): {
|
|
95
|
+
pending: number;
|
|
96
|
+
dropped: number;
|
|
97
|
+
};
|
|
98
|
+
/** Replace a part's content and send it again (a repaint after a tap). */
|
|
99
|
+
repaint(id: number, content: ChatContent): void;
|
|
124
100
|
}
|
|
125
101
|
/** A saved part's content. One that can't be read is a delivery problem that names the field, never a guess. */
|
|
126
102
|
export declare function partContent(payload: string): ChatContent;
|