toolroll 0.9.55 → 0.9.56
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 +10 -0
- package/README.md +24 -8
- package/dist/action-ledger.d.ts +2 -4
- package/dist/action-ledger.js +2 -10
- package/dist/approval-policy.d.ts +5 -5
- package/dist/approval-policy.js +4 -4
- package/dist/approval-rules-ui.js +2 -2
- package/dist/browser/workspace.js +5 -5
- package/dist/browser-workspace.d.ts +12 -12
- package/dist/budget-alerts.js +3 -3
- package/dist/chat-actions.d.ts +23 -18
- package/dist/chat-actions.js +110 -88
- package/dist/chat-ask.d.ts +2 -2
- package/dist/chat-ask.js +5 -5
- package/dist/chat-channel.d.ts +15 -15
- package/dist/chat-channel.js +20 -20
- package/dist/chat-controls.d.ts +0 -4
- package/dist/chat-controls.js +0 -1
- package/dist/chat-core.js +1 -1
- package/dist/chat-delivery-state.js +2 -2
- package/dist/chat-delivery.d.ts +2 -2
- package/dist/chat-delivery.js +27 -34
- package/dist/chat-flow.js +3 -3
- package/dist/chat-messages.d.ts +1 -1
- package/dist/chat-messages.js +4 -4
- package/dist/chat-migration.d.ts +1 -1
- package/dist/chat-migration.js +11 -11
- package/dist/chat-rooms.js +3 -3
- package/dist/chat-warmth.d.ts +2 -2
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +6 -7
- package/dist/contracts/chat-actions.d.ts +32 -27
- package/dist/contracts/chat-actions.js +29 -11
- package/dist/contracts/chat-content.d.ts +1 -1
- package/dist/contracts/chat-content.js +1 -1
- package/dist/contracts/chat-tables.js +4 -4
- package/dist/contracts/console-api.d.ts +6 -6
- package/dist/contracts/console-api.js +7 -7
- package/dist/contracts/flow-propose.d.ts +3 -3
- package/dist/contracts/flow.d.ts +132 -125
- package/dist/contracts/flow.js +27 -12
- package/dist/contracts/lead-context.d.ts +1 -1
- package/dist/contracts/lead-context.js +2 -2
- package/dist/contracts/lead-tools.d.ts +20 -18
- package/dist/contracts/lead-tools.js +15 -15
- package/dist/contracts/stage-output.d.ts +1 -1
- package/dist/contracts/stage-output.js +1 -1
- package/dist/contracts/store-json.d.ts +23 -22
- package/dist/contracts/store-json.js +17 -17
- package/dist/contracts/{teammate-turn.d.ts → subagent-turn.d.ts} +5 -5
- package/dist/contracts/{teammate-turn.js → subagent-turn.js} +7 -7
- package/dist/converse.d.ts +23 -23
- package/dist/converse.js +28 -28
- package/dist/coordinator-proposals.d.ts +2 -2
- package/dist/coordinator-proposals.js +1 -1
- package/dist/coordinator.js +1 -1
- package/dist/deprecations.d.ts +12 -0
- package/dist/deprecations.js +20 -0
- package/dist/desktop-update-gate.js +8 -4
- package/dist/desktop-update.js +6 -1
- package/dist/discord-chat.js +6 -6
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +1 -1
- package/dist/envelope.js +0 -1
- package/dist/export-ui.js +1 -1
- package/dist/export.js +7 -7
- package/dist/flow-engine.d.ts +2 -2
- package/dist/flow-engine.js +21 -21
- package/dist/flow-insights.d.ts +1 -1
- package/dist/flow-share.js +13 -8
- package/dist/flow-steps.d.ts +5 -5
- package/dist/flow-steps.js +19 -19
- package/dist/flow-triggers.d.ts +1 -1
- package/dist/flow-triggers.js +1 -1
- package/dist/flows-cli.js +1 -1
- package/dist/flows-ui.js +20 -20
- package/dist/flows.js +19 -19
- package/dist/guides.js +4 -3
- package/dist/invoke.js +1 -1
- package/dist/kits-ui.js +5 -5
- package/dist/kits.d.ts +12 -12
- package/dist/kits.js +31 -31
- package/dist/{mate-cli.d.ts → lead-cli.d.ts} +11 -11
- package/dist/{mate-cli.js → lead-cli.js} +38 -38
- package/dist/lead-commitments.js +4 -4
- package/dist/lead-context.d.ts +2 -2
- package/dist/lead-context.js +9 -9
- package/dist/{mate-contract.d.ts → lead-contract.d.ts} +3 -3
- package/dist/{mate-contract.js → lead-contract.js} +7 -6
- package/dist/{mate-doors.d.ts → lead-doors.d.ts} +6 -6
- package/dist/{mate-doors.js → lead-doors.js} +24 -24
- package/dist/lead-follow.d.ts +5 -5
- package/dist/lead-follow.js +9 -9
- package/dist/lead-people.d.ts +5 -5
- package/dist/lead-people.js +14 -14
- package/dist/{mate-progress.d.ts → lead-progress.d.ts} +9 -9
- package/dist/{mate-progress.js → lead-progress.js} +3 -3
- package/dist/{mate-tools.d.ts → lead-tools.d.ts} +19 -19
- package/dist/{mate-tools.js → lead-tools.js} +109 -101
- package/dist/{mate.d.ts → lead.d.ts} +27 -27
- package/dist/{mate.js → lead.js} +102 -102
- package/dist/limits-ui.d.ts +1 -1
- package/dist/limits-ui.js +1 -1
- package/dist/mcp-connect.d.ts +1 -1
- package/dist/mcp-connect.js +3 -3
- package/dist/mcp-core.js +1 -1
- package/dist/memory-pass.d.ts +2 -2
- package/dist/memory-pass.js +7 -7
- package/dist/notification-rows.d.ts +2 -2
- package/dist/operate.d.ts +3 -3
- package/dist/operate.js +35 -34
- package/dist/policy.d.ts +1 -1
- package/dist/principal.d.ts +1 -1
- package/dist/principal.js +2 -2
- package/dist/project-delete-ui.js +1 -1
- package/dist/project-delete.d.ts +1 -1
- package/dist/project-delete.js +26 -26
- package/dist/project-memory.js +1 -1
- package/dist/project-tools.d.ts +1 -1
- package/dist/project-tools.js +1 -1
- package/dist/recipe-ui.js +1 -1
- package/dist/retention.js +4 -4
- package/dist/scope.d.ts +2 -2
- package/dist/scout-report.d.ts +1 -1
- package/dist/scout-report.js +1 -1
- package/dist/serve.js +40 -45
- package/dist/server/chat.d.ts +4 -4
- package/dist/server/chat.js +97 -97
- package/dist/server/chrome.js +3 -3
- package/dist/server/flows.js +69 -62
- package/dist/server/guards.js +3 -3
- package/dist/server/http.d.ts +3 -3
- package/dist/server/http.js +1 -1
- package/dist/server/live.js +6 -6
- package/dist/server/people-tokens.js +1 -1
- package/dist/server/remote.js +12 -10
- package/dist/server/render-chat.d.ts +30 -30
- package/dist/server/render-chat.js +33 -33
- package/dist/server/render-pages.js +2 -2
- package/dist/server/render-settings.d.ts +7 -0
- package/dist/server/render-settings.js +3 -0
- package/dist/server/route-table.js +9 -7
- package/dist/server/runtime.d.ts +13 -13
- package/dist/server/settings.js +14 -13
- package/dist/server/tasks.js +6 -5
- package/dist/setup-guide.d.ts +2 -2
- package/dist/slack-chat.d.ts +2 -2
- package/dist/slack-chat.js +6 -6
- package/dist/spend-ui.d.ts +3 -3
- package/dist/spend-ui.js +9 -9
- package/dist/spend.d.ts +14 -14
- package/dist/spend.js +31 -31
- package/dist/store-baseline.d.ts +19 -0
- package/dist/store-baseline.js +2873 -0
- package/dist/store.d.ts +197 -249
- package/dist/store.js +747 -3084
- package/dist/subagent-admin.d.ts +53 -0
- package/dist/{teammate-admin.js → subagent-admin.js} +37 -37
- package/dist/{teammate-desk.d.ts → subagent-desk.d.ts} +22 -23
- package/dist/{teammate-desk.js → subagent-desk.js} +26 -35
- package/dist/{teammate-memory.d.ts → subagent-memory.d.ts} +17 -17
- package/dist/{teammate-memory.js → subagent-memory.js} +41 -41
- package/dist/{teammate-question.d.ts → subagent-question.d.ts} +6 -6
- package/dist/{teammate-question.js → subagent-question.js} +17 -17
- package/dist/{teammate-tools.d.ts → subagent-tools.d.ts} +18 -18
- package/dist/{teammate-tools.js → subagent-tools.js} +36 -36
- package/dist/{teammate-week.d.ts → subagent-week.d.ts} +10 -10
- package/dist/{teammate-week.js → subagent-week.js} +23 -23
- package/dist/{teammate-work.d.ts → subagent-work.d.ts} +21 -21
- package/dist/{teammate-work.js → subagent-work.js} +50 -50
- package/dist/subagents-ui.d.ts +22 -0
- package/dist/{teammates-ui.js → subagents-ui.js} +45 -45
- package/dist/{teammates.d.ts → subagents.d.ts} +11 -11
- package/dist/{teammates.js → subagents.js} +21 -21
- package/dist/subscription-chat.d.ts +13 -13
- package/dist/subscription-chat.js +19 -19
- package/dist/surface.d.ts +19 -2
- package/dist/surface.js +7 -31
- package/dist/team-cli.d.ts +1 -0
- package/dist/team-cli.js +14 -2
- package/dist/team-leads.js +13 -13
- package/dist/team-runtime.d.ts +2 -2
- package/dist/team-runtime.js +8 -8
- package/dist/teams-chat.js +6 -6
- package/dist/telegram-flow.d.ts +3 -3
- package/dist/telegram-flow.js +3 -3
- package/dist/{telegram-mate.d.ts → telegram-lead.d.ts} +5 -5
- package/dist/{telegram-mate.js → telegram-lead.js} +27 -27
- package/dist/telegram-status.js +1 -1
- package/dist/telegram-team.d.ts +1 -1
- package/dist/telegram-team.js +5 -5
- package/dist/telegram.d.ts +1 -1
- package/dist/telegram.js +9 -30
- package/dist/text-limits.d.ts +18 -18
- package/dist/text-limits.js +18 -18
- package/dist/toolroll-update.d.ts +8 -0
- package/dist/toolroll-update.js +45 -8
- package/package.json +1 -2
- package/dist/teammate-admin.d.ts +0 -53
- package/dist/teammates-ui.d.ts +0 -21
package/dist/server/chat.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { handlersOf } from './handler-registry.js';
|
|
2
|
+
import { DEPRECATED_PAGE } from "../deprecations.js";
|
|
2
3
|
/** chat handlers, moved without changing their route bodies. */
|
|
3
4
|
import { randomBytes } from "node:crypto";
|
|
4
5
|
import { chmodSync, rmSync as rmFileSync, writeFileSync as writeFsFileSync } from "node:fs";
|
|
@@ -18,8 +19,8 @@ import { leadBriefHtml } from '../lead-context.js';
|
|
|
18
19
|
import { configureLeadFollow, leadFollowStatus } from '../lead-follow.js';
|
|
19
20
|
import { leadActivity } from "../lead-voice.js";
|
|
20
21
|
import { limitsView } from "../limits-ui.js";
|
|
21
|
-
import { confirmCoordinatorProposal,
|
|
22
|
-
import {
|
|
22
|
+
import { confirmCoordinatorProposal, confirmLeadProposal, dismissCoordinatorProposal, dismissLeadProposal } from "../lead-doors.js";
|
|
23
|
+
import { LEAD_MESSAGE_MAX_CHARS, runLeadTurn } from "../lead.js";
|
|
23
24
|
import { livePin, modelOptions } from "../model-catalog.js";
|
|
24
25
|
import { verifyApproverByPassword, verifyApproverStanding } from "../principal.js";
|
|
25
26
|
import { projectName } from "../project.js";
|
|
@@ -37,12 +38,12 @@ import { html, htmlString, postForm } from "../html.js";
|
|
|
37
38
|
import { requestContext } from "./request-context.js";
|
|
38
39
|
import { refuse, screen } from "./chrome.js";
|
|
39
40
|
import { chatResultHref, chatReturnWithLatest, chatReturnWithSaid, projectChatHref, redirect, respond, safeChatReturn, safeReturn, taskChatHref, taskHref } from "./http.js";
|
|
40
|
-
import { chatAckPage, chatPage, coordinatorProposalsSection, decisionsFor,
|
|
41
|
+
import { chatAckPage, chatPage, coordinatorProposalsSection, decisionsFor, leadAfterComposerHtml, leadChatVersion, leadMintCard, leadPage, leadThreadHtml, PHONE_CARD_FACT, TASK_COMPOSER_MODES, taskChatLiveRegion, teamProposalCardParts } from "./render-chat.js";
|
|
41
42
|
import {} from "./render-pages.js";
|
|
42
43
|
import { completionForm, homePhaseWords, owedAcceptanceOf, resultPanelHtml } from "./render-results.js";
|
|
43
44
|
import { browserCaller, oneLineUa } from "./session.js";
|
|
44
45
|
export function createChatHandlers(runtime) {
|
|
45
|
-
const { firstRunStepsNow, managedRepos, leadWords, store, options, phoneSetup, visible, liveTurns,
|
|
46
|
+
const { firstRunStepsNow, managedRepos, leadWords, store, options, phoneSetup, visible, liveTurns, leadSaid, evidenceRoot, clock, sessions, CHAT_CANDIDATE_TTL_MS, chatFetcher, CHAT_CANDIDATES_PER_APPROVER, chatCeilingDigest, workAccess, familyOf, firstTasks, leadPrincipal, taskChatFocus, chatScopeOf, leadConversationRows, demoLeadHere, sendScreen, chromeFor, teamBrowserReply, team, teamChatProvider, runVisible, runIsLive, resultDetailOf, pullRequestTargetOf, chatEnablement, startLeadConversation, projectFamilyPeek, needsYouBadge, liveRefreshSeconds, chatKeyFor, chatCatalog, providerHome, mintApprovalNonce, checkLocalAgents, agentSignInCommand, bustBadge, authenticateApprover, revisionDestination, armTaskResume, consumeApprovalNonce } = runtime;
|
|
46
47
|
// The read-only refresh (package 2): the same JSON status as before —
|
|
47
48
|
// session binding, the send receipt, the live turn — plus a version
|
|
48
49
|
// of the DISPLAYED facts and, only when the caller's version differs,
|
|
@@ -52,14 +53,14 @@ export function createChatHandlers(runtime) {
|
|
|
52
53
|
async function mateStatus(ctx) {
|
|
53
54
|
const { url, response, now } = ctx;
|
|
54
55
|
const who = browserCaller(ctx.who);
|
|
55
|
-
const session = store.
|
|
56
|
-
const principal =
|
|
56
|
+
const session = store.activeLeadSession(who.name);
|
|
57
|
+
const principal = leadPrincipal(who);
|
|
57
58
|
if (session === null || principal === null || session.ceilingDigest !== principal.ceilingDigest || session.approverGeneration !== principal.generation) {
|
|
58
59
|
return respond(response, 200, "application/json", JSON.stringify({ session: null }));
|
|
59
60
|
}
|
|
60
|
-
store.
|
|
61
|
+
store.sweepStaleLeadTurns(now);
|
|
61
62
|
const request = url.searchParams.get("request") ?? "";
|
|
62
|
-
const receipt = /^[a-f0-9]{32}$/.test(request) ? store.
|
|
63
|
+
const receipt = /^[a-f0-9]{32}$/.test(request) ? store.leadRequestReceipt(session.id, request) : null;
|
|
63
64
|
const requestedTask = url.searchParams.get("task");
|
|
64
65
|
const focusTask = requestedTask === null || requestedTask === "" ? null : taskChatFocus(requestedTask, now, who, { mintNonce: false });
|
|
65
66
|
if (requestedTask !== null && requestedTask !== "" && focusTask === null) {
|
|
@@ -70,15 +71,15 @@ export function createChatHandlers(runtime) {
|
|
|
70
71
|
const chatProject = focusTask !== null ? null : chatProjectOf(url.searchParams.getAll("project").filter(one => one !== ""));
|
|
71
72
|
if (chatProject === undefined)
|
|
72
73
|
return respond(response, 200, "application/json", JSON.stringify({ session: session.id, unavailable: true, received: receipt !== null }));
|
|
73
|
-
const rows =
|
|
74
|
-
const version =
|
|
74
|
+
const rows = leadConversationRows(who, principal, focusTask, now, chatProject);
|
|
75
|
+
const version = leadChatVersion({ ...rows, focusTask });
|
|
75
76
|
const known = url.searchParams.get("version") ?? "";
|
|
76
77
|
const csrf = who.session.csrf;
|
|
77
78
|
const fragments = known === version
|
|
78
79
|
? null
|
|
79
80
|
: {
|
|
80
|
-
thread: htmlString(
|
|
81
|
-
after: htmlString(
|
|
81
|
+
thread: htmlString(leadThreadHtml({ ...rows, focusTask, csrf, now, problem: takeLeadNote(csrf, session.id), chatProject })),
|
|
82
|
+
after: htmlString(leadAfterComposerHtml({ messages: rows.messages, pending: rows.pending, focusTask })),
|
|
82
83
|
live: focusTask === null ? null : htmlString(taskChatLiveRegion(focusTask, csrf, true, rows.pending !== null)),
|
|
83
84
|
};
|
|
84
85
|
return respond(response, 200, "application/json", JSON.stringify({
|
|
@@ -118,7 +119,8 @@ export function createChatHandlers(runtime) {
|
|
|
118
119
|
// THIS session's memory; a bearer caller has nowhere to keep them.
|
|
119
120
|
if (who.via !== "cookie")
|
|
120
121
|
return refuse(response, who, 403, "chat is a browser surface — it keeps your drafts in the session");
|
|
121
|
-
|
|
122
|
+
const teamAsked = url.searchParams.get('team') === '1' || url.searchParams.has('conversation') || url.searchParams.has('lead') || url.searchParams.has('proposal');
|
|
123
|
+
if (teamAsked && url.searchParams.get('private') !== '1' && !url.searchParams.has('task') && !url.searchParams.has('result') && !url.searchParams.has('project')) {
|
|
122
124
|
const reply = teamBrowserReply(await team.execute({ name: who.name, generation: who.session.generation }, {
|
|
123
125
|
operation: url.searchParams.has('conversation') ? 'show' : 'list',
|
|
124
126
|
args: { ...(url.searchParams.has('conversation') ? { conversationId: url.searchParams.get('conversation') } : {}),
|
|
@@ -128,7 +130,7 @@ export function createChatHandlers(runtime) {
|
|
|
128
130
|
return refuse(response, who, 403, reply.message, '/chat?private=1');
|
|
129
131
|
if (url.searchParams.has('proposal')) {
|
|
130
132
|
const id = Number(url.searchParams.get('proposal')), selected = reply.snapshot.selected;
|
|
131
|
-
const proposal = Number.isSafeInteger(id) && id > 0 ? store.
|
|
133
|
+
const proposal = Number.isSafeInteger(id) && id > 0 ? store.getLeadProposal(id) : null;
|
|
132
134
|
if (!selected || !proposal || proposal.thread !== selected.threadId)
|
|
133
135
|
return refuse(response, who, 404, 'This proposal is unavailable.', '/chat');
|
|
134
136
|
const back = '/chat?conversation=' + encodeURIComponent(selected.id);
|
|
@@ -136,15 +138,13 @@ export function createChatHandlers(runtime) {
|
|
|
136
138
|
const card = teamProposalCardParts(store, { name: who.name, generation: who.session.generation }, proposal, reply.snapshot, who.session.csrf, decision, clock(), teamChatProvider).html;
|
|
137
139
|
return sendScreen(response, 200, screen('Review action', html `<p><a href="${back}">Back to conversation</a></p>${card}`, { chrome: chromeFor(null, 'chat', undefined, 'all') }));
|
|
138
140
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}));
|
|
144
|
-
}
|
|
141
|
+
const said = url.searchParams.get('said')?.slice(0, 1_000);
|
|
142
|
+
return sendScreen(response, 200, screen('Chat', html `<p class="problem" role="status" data-deprecated="team">${DEPRECATED_PAGE.team}</p>${said ? html `<p role="alert">${said}</p>` : ''}${teamWorkspaceHtml(reply.snapshot)}`, {
|
|
143
|
+
chrome: chromeFor(null, 'chat', undefined, 'all'), workspace: { team: reply.snapshot, notices: [DEPRECATED_PAGE.team, ...(said ? [said] : [])] },
|
|
144
|
+
}));
|
|
145
145
|
}
|
|
146
146
|
store.sweepStaleChatTurns(now);
|
|
147
|
-
store.
|
|
147
|
+
store.sweepStaleLeadTurns(now);
|
|
148
148
|
store.sweepCoordinatorProposals(now);
|
|
149
149
|
sweepChatDrafts(Date.now());
|
|
150
150
|
const requestedTask = url.searchParams.get("task");
|
|
@@ -233,8 +233,8 @@ export function createChatHandlers(runtime) {
|
|
|
233
233
|
// The mate (mate arc §5): while a mate session is live, /chat IS the
|
|
234
234
|
// thread — the same rows the CLI reads. Without one, fleet chat as
|
|
235
235
|
// before, plus the card that mints a session.
|
|
236
|
-
let
|
|
237
|
-
const principal = enabled.ok && who.role === "approver" ?
|
|
236
|
+
let leadSession = enabled.ok && who.role === "approver" ? store.activeLeadSession(who.name) : null;
|
|
237
|
+
const principal = enabled.ok && who.role === "approver" ? leadPrincipal(who) : null;
|
|
238
238
|
// Chat opens ready to talk (2026-09-23): an approver in good standing
|
|
239
239
|
// needs no second password to start their own conversation. The one
|
|
240
240
|
// exception to "a GET writes nothing": the strict same-site session
|
|
@@ -243,14 +243,14 @@ export function createChatHandlers(runtime) {
|
|
|
243
243
|
// Membership chat only: it spends no dollars. Direct-API chat keeps a
|
|
244
244
|
// one-tap Start with its visible spending limit (no password).
|
|
245
245
|
const settingsView = url.searchParams.get("settings") === "1";
|
|
246
|
-
if (!settingsView && enabled.ok && enabled.billing === "subscription" && principal !== null && (
|
|
247
|
-
|
|
248
|
-
|
|
246
|
+
if (!settingsView && enabled.ok && enabled.billing === "subscription" && principal !== null && (leadSession === null || leadSession.ceilingDigest !== principal.ceilingDigest) && !requestContext.getStore()?.workspaceRead) {
|
|
247
|
+
startLeadConversation(who, principal, enabled, 0, false, now);
|
|
248
|
+
leadSession = store.activeLeadSession(who.name);
|
|
249
249
|
}
|
|
250
250
|
// A session under another ceiling is not continuable from here; a GET
|
|
251
251
|
// writes nothing (slice-2 review, finding 7) — the mint card below
|
|
252
252
|
// starts a new conversation, and minting ends the old session.
|
|
253
|
-
const ceilingStale = enabled.ok &&
|
|
253
|
+
const ceilingStale = enabled.ok && leadSession !== null && principal !== null && leadSession.ceilingDigest !== principal.ceilingDigest;
|
|
254
254
|
const catchUp = leadBriefHtml(assignmentCatchUp(store, now, { principal: "operator", repos }, { limit: 6 }, evidenceRoot));
|
|
255
255
|
const chatProjects = repos.map((repo, index) => {
|
|
256
256
|
let peek = null;
|
|
@@ -284,12 +284,12 @@ export function createChatHandlers(runtime) {
|
|
|
284
284
|
const withFirstRun = (shown) => firstRun === undefined && phone === undefined && home === null ? shown
|
|
285
285
|
: { ...shown, ...(home === null ? {} : { refreshSeconds: liveRefreshSeconds() }),
|
|
286
286
|
workspace: { ...shown.workspace, ...(firstRun === undefined ? {} : { firstRun }), ...(phone === undefined ? {} : { phone }), ...(home === null ? {} : { home }) } };
|
|
287
|
-
if (enabled.ok &&
|
|
287
|
+
if (enabled.ok && leadSession !== null && principal !== null && !ceilingStale) {
|
|
288
288
|
{
|
|
289
|
-
const said =
|
|
290
|
-
return sendScreen(response, 200, withFirstRun(
|
|
291
|
-
session:
|
|
292
|
-
...
|
|
289
|
+
const said = takeLeadNote(who.session.csrf, leadSession.id);
|
|
290
|
+
return sendScreen(response, 200, withFirstRun(leadPage(chromeFor(null, "chat", undefined, "all"), {
|
|
291
|
+
session: leadSession,
|
|
292
|
+
...leadConversationRows(who, principal, focusTask, now, chatProject),
|
|
293
293
|
chatProject,
|
|
294
294
|
latched,
|
|
295
295
|
config: enabled.config,
|
|
@@ -338,9 +338,9 @@ export function createChatHandlers(runtime) {
|
|
|
338
338
|
problem: url.searchParams.get("said") ??
|
|
339
339
|
focusProblem ??
|
|
340
340
|
(ceilingStale ? "Project access changed. Your tasks and results are saved. Start a conversation with the current projects to continue." : null) ??
|
|
341
|
-
|
|
341
|
+
takeLeadNote(who.session.csrf, null),
|
|
342
342
|
resultPanel,
|
|
343
|
-
...(enabled.ok && who.role === "approver" ? {
|
|
343
|
+
...(enabled.ok && who.role === "approver" ? { leadMint: leadMintCard(enabled, focusTask === null ? "/chat" : taskChatHref(focusTask.id)) } : {}),
|
|
344
344
|
...(who.role === "approver" ? { coordinatorProposals: coordinatorProposalsSection(coordinatorRows, decisionsFor(store, coordinatorRows), now, true, focusTask === null ? null : taskChatHref(focusTask.id)) } : {}),
|
|
345
345
|
})));
|
|
346
346
|
}
|
|
@@ -361,7 +361,7 @@ export function createChatHandlers(runtime) {
|
|
|
361
361
|
const { url, response } = ctx;
|
|
362
362
|
const who = browserCaller(ctx.who);
|
|
363
363
|
const proposalId = Number(url.pathname.split("/")[3]);
|
|
364
|
-
const reviewProposal = store.
|
|
364
|
+
const reviewProposal = store.getLeadProposal(proposalId);
|
|
365
365
|
const sharedConversation = reviewProposal ? store.handle.prepare('SELECT id FROM team_conversation WHERE thread=?').get(reviewProposal.thread) : null;
|
|
366
366
|
let principal = null;
|
|
367
367
|
if (sharedConversation) {
|
|
@@ -375,12 +375,12 @@ export function createChatHandlers(runtime) {
|
|
|
375
375
|
}
|
|
376
376
|
}
|
|
377
377
|
else
|
|
378
|
-
principal =
|
|
378
|
+
principal = leadPrincipal(who);
|
|
379
379
|
if (principal === null)
|
|
380
380
|
return refuse(response, who, 403, 'Your access changed. Sign in again.', '/chat');
|
|
381
381
|
try {
|
|
382
|
-
const id = proposalId, saved = store.
|
|
383
|
-
if (saved && savedAction && saved.state !== 'pending' && (sharedConversation !== null || store.
|
|
382
|
+
const id = proposalId, saved = store.getLeadProposal(id), savedAction = saved?.kind === 'action' ? sharedActionPayload(saved.payload) : null;
|
|
383
|
+
if (saved && savedAction && saved.state !== 'pending' && (sharedConversation !== null || store.getLeadThread(saved.thread)?.approver === principal.name) && principal.repos.includes(savedAction.repo) && store.accountCanAccess(principal.name, savedAction.repo)) {
|
|
384
384
|
const task = typeof saved.outcome?.['taskId'] === 'string' ? saved.outcome['taskId'] : typeof savedAction.request['task'] === 'string' ? savedAction.request['task'] : null;
|
|
385
385
|
const destination = task ? taskHref(task) : `/settings/${savedAction.operation.startsWith('skill_') ? 'skills' : 'knowledge'}?repo=${encodeURIComponent(savedAction.repo)}`;
|
|
386
386
|
const said = typeof saved.outcome?.['said'] === 'string' ? saved.outcome['said'] : saved.state === 'dismissed' ? 'Action dismissed.' : saved.state === 'expired' ? 'This proposal expired. Ask for a fresh proposal.' : 'This action has no completed outcome yet.';
|
|
@@ -459,7 +459,7 @@ export function createChatHandlers(runtime) {
|
|
|
459
459
|
: verb === "change" ? lead.change(id, note, now)
|
|
460
460
|
: verb === "revise" ? lead.requestChanges(id, note, now)
|
|
461
461
|
: lead.complete(id, now, (taskId, runId) => {
|
|
462
|
-
const principal =
|
|
462
|
+
const principal = leadPrincipal(who);
|
|
463
463
|
if (principal === null)
|
|
464
464
|
return { ok: false, message: "Your access changed. Sign in again." };
|
|
465
465
|
const current = assignmentOf(store, taskId, now, { principal: "operator", repos: principal.repos }, evidenceRoot);
|
|
@@ -613,11 +613,11 @@ export function createChatHandlers(runtime) {
|
|
|
613
613
|
return redirect(response, back);
|
|
614
614
|
}
|
|
615
615
|
// ---- the mate (mate arc §5) ------------------------------------------
|
|
616
|
-
async function
|
|
616
|
+
async function leadMint(ctx) {
|
|
617
617
|
const { who, response, now, posted } = ctx;
|
|
618
|
-
const body = readForm(posted, CONSOLE_FORMS.
|
|
618
|
+
const body = readForm(posted, CONSOLE_FORMS.leadMint);
|
|
619
619
|
if (who.via !== "cookie")
|
|
620
|
-
return refuse(response, who, 403, "the
|
|
620
|
+
return refuse(response, who, 403, "the lead is a browser surface");
|
|
621
621
|
const back = safeChatReturn(body.get("return"));
|
|
622
622
|
const enabled = chatEnablement();
|
|
623
623
|
if (!enabled.ok)
|
|
@@ -636,60 +636,60 @@ export function createChatHandlers(runtime) {
|
|
|
636
636
|
const verified = token === "" ? verifyApproverStanding(store, who.name, who.session.generation, managedRepos()) : verifyApproverByPassword(store, who.name, token, managedRepos());
|
|
637
637
|
if (!verified.ok)
|
|
638
638
|
return redirect(response, chatReturnWithSaid(back, token === "" ? "Your access changed. Sign in again to start chat." : "That password did not match."));
|
|
639
|
-
|
|
639
|
+
startLeadConversation(who, verified.who, enabled, ceilingUsd, body.get("follow") === "yes", now);
|
|
640
640
|
return redirect(response, back);
|
|
641
641
|
}
|
|
642
|
-
async function
|
|
642
|
+
async function leadFollow(ctx) {
|
|
643
643
|
const { who, response, now, posted } = ctx;
|
|
644
|
-
const body = readForm(posted, CONSOLE_FORMS.
|
|
644
|
+
const body = readForm(posted, CONSOLE_FORMS.leadFollow);
|
|
645
645
|
if (who.via !== "cookie")
|
|
646
646
|
return refuse(response, who, 403, "Open the conversation to change automatic updates.");
|
|
647
|
-
const principal =
|
|
647
|
+
const principal = leadPrincipal(who), session = store.activeLeadSession(who.name), thread = store.liveLeadThreadFor(who.name);
|
|
648
648
|
if (!principal || !session || !thread || !configureLeadFollow(store, principal, session, thread, body.get("enabled") === "yes", now))
|
|
649
649
|
return refuse(response, who, 409, "Conversation access changed. Start chat again.", "/chat");
|
|
650
650
|
return redirect(response, safeChatReturn(body.get("return")));
|
|
651
651
|
}
|
|
652
|
-
async function
|
|
652
|
+
async function leadEnd(ctx) {
|
|
653
653
|
const { who, response, now, posted } = ctx;
|
|
654
|
-
const body = readForm(posted, CONSOLE_FORMS.
|
|
654
|
+
const body = readForm(posted, CONSOLE_FORMS.leadEnd);
|
|
655
655
|
if (who.via !== "cookie")
|
|
656
|
-
return refuse(response, who, 403, "the
|
|
656
|
+
return refuse(response, who, 403, "the lead is a browser surface");
|
|
657
657
|
const back = safeChatReturn(body.get("return"));
|
|
658
658
|
// Ending spend and forgetting the thread takes no password: any
|
|
659
659
|
// approver may revoke (§1), and the thread is theirs to drop (ruling 11).
|
|
660
|
-
store.
|
|
661
|
-
store.
|
|
662
|
-
store.
|
|
663
|
-
|
|
660
|
+
store.failLiveLeadTurnsFor(who.name, "ended", now);
|
|
661
|
+
store.endLeadSessionsFor(who.name, who.name, now);
|
|
662
|
+
store.closeLeadThreadsFor(who.name, now);
|
|
663
|
+
leadSaid.delete(who.session.csrf);
|
|
664
664
|
return redirect(response, back);
|
|
665
665
|
}
|
|
666
|
-
async function
|
|
666
|
+
async function leadStop(ctx) {
|
|
667
667
|
const { who, response, now, posted } = ctx;
|
|
668
|
-
const body = readForm(posted, CONSOLE_FORMS.
|
|
668
|
+
const body = readForm(posted, CONSOLE_FORMS.leadStop);
|
|
669
669
|
if (who.via !== "cookie")
|
|
670
|
-
return refuse(response, who, 403, "the
|
|
670
|
+
return refuse(response, who, 403, "the lead is a browser surface");
|
|
671
671
|
const back = safeChatReturn(body.get("return"));
|
|
672
672
|
const wanted = Number(body.get("turn") ?? "");
|
|
673
|
-
const live = store.
|
|
673
|
+
const live = store.liveLeadTurnFor(who.name);
|
|
674
674
|
if (!Number.isInteger(wanted) || live === null || live.id !== wanted) {
|
|
675
|
-
|
|
675
|
+
noteLead(who.session.csrf, null, "that turn has already finished");
|
|
676
676
|
return redirect(response, chatReturnWithLatest(back));
|
|
677
677
|
}
|
|
678
678
|
// A stopped direct-API turn is conservatively charged its reserved
|
|
679
679
|
// worst case: dispatch may already have happened. Membership turns
|
|
680
680
|
// reserve zero. The conversation itself stays live.
|
|
681
|
-
store.
|
|
682
|
-
|
|
681
|
+
store.failLiveLeadTurnsFor(who.name, "stopped", now);
|
|
682
|
+
noteLead(who.session.csrf, live.id, "stopped — the conversation is still open");
|
|
683
683
|
return redirect(response, chatReturnWithLatest(back));
|
|
684
684
|
}
|
|
685
685
|
const chatProposalAct = (op) => async (ctx) => {
|
|
686
686
|
const { url, who, request, response, now, posted } = ctx;
|
|
687
|
-
const body = readForm(posted, CONSOLE_FORMS.
|
|
687
|
+
const body = readForm(posted, CONSOLE_FORMS.leadProposal);
|
|
688
688
|
if (who.via !== "cookie")
|
|
689
|
-
return refuse(response, who, 403, "the
|
|
689
|
+
return refuse(response, who, 403, "the lead is a browser surface");
|
|
690
690
|
const back = safeChatReturn(body.get("return"));
|
|
691
691
|
const id = Number(url.pathname.split("/")[3]);
|
|
692
|
-
const proposalRow = store.
|
|
692
|
+
const proposalRow = store.getLeadProposal(id);
|
|
693
693
|
const shared = proposalRow && store.handle.prepare('SELECT id FROM team_conversation WHERE thread=?').get(proposalRow.thread);
|
|
694
694
|
const proposalTaskHref = (taskId) => taskChatHref(taskId) + (shared ? '&conversation=' + encodeURIComponent(String(shared['id'])) : '');
|
|
695
695
|
let principal = null;
|
|
@@ -704,7 +704,7 @@ export function createChatHandlers(runtime) {
|
|
|
704
704
|
}
|
|
705
705
|
}
|
|
706
706
|
else
|
|
707
|
-
principal =
|
|
707
|
+
principal = leadPrincipal(who);
|
|
708
708
|
// Confirm in place (chat cards): the same door and checks, answered in
|
|
709
709
|
// JSON so the conversation stays where it is; the card's refreshed
|
|
710
710
|
// state carries the result. The secure review screen stays a form.
|
|
@@ -713,14 +713,14 @@ export function createChatHandlers(runtime) {
|
|
|
713
713
|
if (principal === null)
|
|
714
714
|
return cardJson ? cardAnswer(403, false, "Your approver standing changed. Sign in again.") : refuse(response, who, 403, "your approver standing changed — sign in again", back);
|
|
715
715
|
if (op === "dismiss") {
|
|
716
|
-
const dismissed =
|
|
716
|
+
const dismissed = dismissLeadProposal(store, principal, id, now);
|
|
717
717
|
if (cardJson)
|
|
718
718
|
return cardAnswer(dismissed ? 200 : 409, dismissed, dismissed ? "Dismissed." : "That card was already acted on.");
|
|
719
719
|
if (!dismissed)
|
|
720
|
-
|
|
720
|
+
noteLead(who.session.csrf, null, "that proposal was already acted on");
|
|
721
721
|
return redirect(response, chatReturnWithLatest(back));
|
|
722
722
|
}
|
|
723
|
-
const outcome =
|
|
723
|
+
const outcome = confirmLeadProposal(store, principal, id, now, { chatProvider: teamChatProvider, confirm: body.get("confirm") === "yes", via: "web", evidenceRoot, ...(body.has("nonce") ? { actionReview: { nonce: body.get("nonce") ?? "", password: body.get("token") ?? "" } } : {}) });
|
|
724
724
|
if (cardJson) {
|
|
725
725
|
if (!outcome.ok)
|
|
726
726
|
return cardAnswer(outcome.reason === "standing" ? 403 : outcome.reason === "not-yours" ? 404 : 409, false, outcome.said);
|
|
@@ -737,7 +737,7 @@ export function createChatHandlers(runtime) {
|
|
|
737
737
|
if (!outcome.ok && shared)
|
|
738
738
|
return redirect(response, chatReturnWithSaid(back, outcome.said));
|
|
739
739
|
if (!outcome.ok && outcome.reason === "needs-confirm")
|
|
740
|
-
|
|
740
|
+
noteLead(who.session.csrf, null, outcome.said);
|
|
741
741
|
// A confirmed task proposal leads to the task it actually created
|
|
742
742
|
// (package 2): the lens over this same conversation, whose journey
|
|
743
743
|
// and plan are the next step. The id is the door's recorded
|
|
@@ -748,7 +748,7 @@ export function createChatHandlers(runtime) {
|
|
|
748
748
|
return redirect(response, `${proposalTaskHref(outcome.taskId)}#task-chat-live`);
|
|
749
749
|
}
|
|
750
750
|
if (outcome.ok && outcome.kind === "review" && outcome.taskId !== null) {
|
|
751
|
-
const proposal = store.
|
|
751
|
+
const proposal = store.getLeadProposal(id);
|
|
752
752
|
// A revision confirmed here returns to its receipt: the newest
|
|
753
753
|
// reply, whose confirmed card names the revision and links to the
|
|
754
754
|
// plan. Landing at the top left that message under the phone's
|
|
@@ -758,7 +758,7 @@ export function createChatHandlers(runtime) {
|
|
|
758
758
|
: `${proposalTaskHref(outcome.taskId)}&result=${Number(proposal.payload["run"])}#request-changes`);
|
|
759
759
|
}
|
|
760
760
|
if (outcome.ok && outcome.kind === "task_action" && outcome.taskId !== null) {
|
|
761
|
-
const proposal = store.
|
|
761
|
+
const proposal = store.getLeadProposal(id);
|
|
762
762
|
if (proposal.payload["operation"] === "resume") {
|
|
763
763
|
return armTaskResume(response, who, outcome.taskId, String(proposal.payload["run"]), "chat", now);
|
|
764
764
|
}
|
|
@@ -773,7 +773,7 @@ export function createChatHandlers(runtime) {
|
|
|
773
773
|
const body = readForm(posted, CONSOLE_FORMS.coordinatorProposal);
|
|
774
774
|
if (who.via !== "cookie")
|
|
775
775
|
return refuse(response, who, 403, "proposals are confirmed from the browser or the CLI");
|
|
776
|
-
const principal =
|
|
776
|
+
const principal = leadPrincipal(who);
|
|
777
777
|
if (principal === null)
|
|
778
778
|
return refuse(response, who, 403, "your approver standing changed — sign in again", "/chat");
|
|
779
779
|
const id = Number(url.pathname.split("/")[2]);
|
|
@@ -835,34 +835,34 @@ export function createChatHandlers(runtime) {
|
|
|
835
835
|
// A live mate session: the message is a mate turn — no password, the
|
|
836
836
|
// session's ceremony already covered it (§1); the engine refuses on
|
|
837
837
|
// its own terms and the thread shows why.
|
|
838
|
-
const
|
|
839
|
-
if (
|
|
838
|
+
const leadSession = who.role === "approver" ? store.activeLeadSession(who.name) : null;
|
|
839
|
+
if (leadSession !== null) {
|
|
840
840
|
const requestId = body.get("request");
|
|
841
|
-
if (requestId !== null && (body.getAll("request").length !== 1 || body.getAll("request-session").length !== 1 || body.get("request-session") !== String(
|
|
841
|
+
if (requestId !== null && (body.getAll("request").length !== 1 || body.getAll("request-session").length !== 1 || body.get("request-session") !== String(leadSession.id))) {
|
|
842
842
|
return said(409, "This conversation changed. Reload it before sending your message.");
|
|
843
843
|
}
|
|
844
|
-
const principal =
|
|
844
|
+
const principal = leadPrincipal(who);
|
|
845
845
|
if (principal === null)
|
|
846
846
|
return wantsJson ? said(403, "your approver standing changed — sign in again") : refuse(response, who, 403, "your approver standing changed — sign in again", back);
|
|
847
847
|
const message = (body.get("message") ?? "").trim();
|
|
848
|
-
if (message === "" || message.length >
|
|
849
|
-
return said(400, `a message is 1 to ${
|
|
848
|
+
if (message === "" || message.length > LEAD_MESSAGE_MAX_CHARS) {
|
|
849
|
+
return said(400, `a message is 1 to ${LEAD_MESSAGE_MAX_CHARS} characters`, leadSession.id);
|
|
850
850
|
}
|
|
851
|
-
const opened = store.
|
|
851
|
+
const opened = store.openLeadThread(who.name, principal.ceilingDigest, now, chatScopeOf(focusTask, chatProject));
|
|
852
852
|
const onProgress = beginLiveTurn(opened.thread.id);
|
|
853
|
-
void
|
|
853
|
+
void runLeadTurn({ store, who: principal, session: leadSession, thread: opened.thread, config: enabled.config, key: enabled.key, message, onProgress, channel: "console", ...(requestId === null ? {} : { requestId }), ...(focusTask === null && chatProject !== null ? { context: `Current project: ${projectName(chatProject)} (${chatProject}). Keep this conversation about that project unless the operator explicitly asks to broaden it; use it as the repo for project tools.` } : {}), ...(focusTask === null ? {} : { context: `Current task: ${focusTask.id}. Read it with get_task before answering or proposing changes. Read its currentExecution next and bind new actions to that exact execution. Never replace the target of a prior proposal with a newer revision. Keep this turn about that task unless the operator explicitly asks to broaden it.${resultContext}${modeContext}` }), fetcher: chatFetcher, ...(options.subscriptionChatRunner === undefined ? {} : { subscriptionRunner: options.subscriptionChatRunner }), clock, evidenceRoot })
|
|
854
854
|
.then(outcome => {
|
|
855
855
|
// A turn that saved its outcome in the thread (one stopped at its deadline) is said there, once.
|
|
856
856
|
if (!outcome.ok && !("saved" in outcome && outcome.saved === true))
|
|
857
|
-
|
|
857
|
+
noteLead(who.session.csrf, "turn" in outcome ? outcome.turn : null, outcome.message);
|
|
858
858
|
endLiveTurn(opened.thread.id, outcome.ok);
|
|
859
859
|
})
|
|
860
|
-
.catch(() => {
|
|
860
|
+
.catch(() => { noteLead(who.session.csrf, null, "the turn failed unexpectedly"); endLiveTurn(opened.thread.id, false); });
|
|
861
861
|
// Accepted for the engine, not received: the receipt is written by
|
|
862
862
|
// the turn's own admission, and the status poll is where the page
|
|
863
863
|
// learns of it — the same road as after a native send.
|
|
864
864
|
if (wantsJson)
|
|
865
|
-
return respond(response, 202, "application/json", JSON.stringify({ ok: true, session:
|
|
865
|
+
return respond(response, 202, "application/json", JSON.stringify({ ok: true, session: leadSession.id, task: focusTask?.id ?? "", ...(chatProject === null ? {} : { project: chatProject }), request: requestId }));
|
|
866
866
|
return redirect(response, chatReturnWithLatest(back));
|
|
867
867
|
}
|
|
868
868
|
if (wantsJson)
|
|
@@ -1089,22 +1089,22 @@ export function createChatHandlers(runtime) {
|
|
|
1089
1089
|
liveTurns.delete(thread); }, 60_000);
|
|
1090
1090
|
live.expiry.unref();
|
|
1091
1091
|
}
|
|
1092
|
-
function
|
|
1093
|
-
if (
|
|
1094
|
-
const oldest =
|
|
1092
|
+
function noteLead(csrf, turn, message) {
|
|
1093
|
+
if (leadSaid.size >= 500) {
|
|
1094
|
+
const oldest = leadSaid.keys().next().value;
|
|
1095
1095
|
if (oldest !== undefined)
|
|
1096
|
-
|
|
1096
|
+
leadSaid.delete(oldest);
|
|
1097
1097
|
}
|
|
1098
|
-
|
|
1098
|
+
leadSaid.set(csrf, { turn, message });
|
|
1099
1099
|
}
|
|
1100
|
-
function
|
|
1101
|
-
const noted =
|
|
1100
|
+
function takeLeadNote(csrf, liveSession) {
|
|
1101
|
+
const noted = leadSaid.get(csrf);
|
|
1102
1102
|
if (noted === undefined)
|
|
1103
1103
|
return null;
|
|
1104
|
-
|
|
1104
|
+
leadSaid.delete(csrf);
|
|
1105
1105
|
if (noted.turn === null)
|
|
1106
1106
|
return noted.message;
|
|
1107
|
-
const turn = store.
|
|
1107
|
+
const turn = store.getLeadTurn(noted.turn);
|
|
1108
1108
|
return turn !== null && turn.session === liveSession ? noted.message : null;
|
|
1109
1109
|
}
|
|
1110
1110
|
/** A finished demo exchange's result, read back from the evidence its run actually stored. */
|
|
@@ -1312,7 +1312,7 @@ export function createChatHandlers(runtime) {
|
|
|
1312
1312
|
return href === null ? null : { label: one.primaryAction.label, href };
|
|
1313
1313
|
})(),
|
|
1314
1314
|
}));
|
|
1315
|
-
const windows = who.via === "cookie" && store.isInstanceOperator(who.name) ? limitsView(store.providerLimits(), [], { project: projectName,
|
|
1315
|
+
const windows = who.via === "cookie" && store.isInstanceOperator(who.name) ? limitsView(store.providerLimits(), [], { project: projectName, subagent: id => `Subagent ${id}` }, now) : null;
|
|
1316
1316
|
// One line: what this person's lead is doing now and when it last acted.
|
|
1317
1317
|
const activity = leadActivity(store, who.name);
|
|
1318
1318
|
const leadTask = activity?.taskId == null ? null : store.lookupRef(activity.taskId);
|
|
@@ -1382,10 +1382,10 @@ export function createChatHandlers(runtime) {
|
|
|
1382
1382
|
"push.remove": pushRemove,
|
|
1383
1383
|
"onboarding.phone-dismiss": phoneDismiss,
|
|
1384
1384
|
"chat.config": chatConfig,
|
|
1385
|
-
"chat.mate-mint":
|
|
1386
|
-
"chat.mate-follow":
|
|
1387
|
-
"chat.mate-end":
|
|
1388
|
-
"chat.mate-stop":
|
|
1385
|
+
"chat.mate-mint": leadMint,
|
|
1386
|
+
"chat.mate-follow": leadFollow,
|
|
1387
|
+
"chat.mate-end": leadEnd,
|
|
1388
|
+
"chat.mate-stop": leadStop,
|
|
1389
1389
|
"chat.proposal.confirm": chatProposalAct("confirm"),
|
|
1390
1390
|
"chat.proposal.dismiss": chatProposalAct("dismiss"),
|
|
1391
1391
|
"coordinator.proposal.confirm": coordinatorProposalAct("confirm"),
|
|
@@ -1394,5 +1394,5 @@ export function createChatHandlers(runtime) {
|
|
|
1394
1394
|
"chat.file": chatFile,
|
|
1395
1395
|
"chat.ack-send": chatAckSend,
|
|
1396
1396
|
});
|
|
1397
|
-
return { registrations, chatFirstRun, phoneCard, chatProjectOf, beginLiveTurn, endLiveTurn,
|
|
1397
|
+
return { registrations, chatFirstRun, phoneCard, chatProjectOf, beginLiveTurn, endLiveTurn, noteLead, takeLeadNote, demoResultView, storeChatKey, forgetChatKey, sweepChatDrafts, runChatTurn, chatHomeOf, firstTasksFor, approverCandidateCount, evictOldestCandidate };
|
|
1398
1398
|
}
|
package/dist/server/chrome.js
CHANGED
|
@@ -41,7 +41,7 @@ import {} from "../store.js";
|
|
|
41
41
|
import { styleAsset } from "../style-asset.js";
|
|
42
42
|
import { spendLine } from "../summary.js";
|
|
43
43
|
import { TASK_STATUS_CSS } from "../task-status.js";
|
|
44
|
-
import {
|
|
44
|
+
import { SUBAGENT_CSS } from "../subagents-ui.js";
|
|
45
45
|
import { UPDATES_CSS } from "../toolroll-update-ui.js";
|
|
46
46
|
import { TOOLS_CSS } from "../tools-ui.js";
|
|
47
47
|
import { TRANSITIONS_CSS } from "../transitions-recipes.js";
|
|
@@ -144,7 +144,7 @@ export const INBOX_TABS_CSS = '.inbox-tabs{display:inline-flex;gap:2px;max-width
|
|
|
144
144
|
'.inbox-ask{margin:18px 0 0}.inbox-ask>h2{display:flex;align-items:baseline;gap:8px;margin:0 0 4px;font-size:15px;font-weight:600}.inbox-ask>h2 .count{font:500 12px var(--so-mono,ui-monospace,monospace);font-variant-numeric:tabular-nums;color:var(--so-muted)}.inbox-ask h3{font-size:13px;font-weight:600;margin:12px 0 4px}' +
|
|
145
145
|
'.inbox-unread{display:none;position:absolute;top:4px;right:3px;width:6px;height:6px;border-radius:50%;background:var(--so-signal)}' +
|
|
146
146
|
'@media (max-width:760px){.inbox-tabs{display:flex;width:100%}.inbox-tabs a{flex:1;justify-content:center;min-height:44px;padding:0 6px}.inbox-unread{display:block}}';
|
|
147
|
-
export const WORKSPACE_STYLE = styleAsset(STYLE + BRAND_MARK_CSS + INBOX_TABS_CSS + APPROVAL_RULES_CSS + SPEND_CSS + RETENTION_CSS + STORAGE_CSS + UPDATES_CSS + LIMITS_CSS + MONITORING_CSS + INTEGRATIONS_CSS + BACKUP_CSS + EXPORT_CSS + PROJECT_DELETE_CSS + POLICY_CSS + EVIDENCE_PACK_CSS + THEME_CONTROLS_CSS + CODING_CSS + CODING_SHIPPING_CSS + RECIPE_CSS + SKILLS_CSS + TOOLS_CSS + FLOWS_CSS +
|
|
147
|
+
export const WORKSPACE_STYLE = styleAsset(STYLE + BRAND_MARK_CSS + INBOX_TABS_CSS + APPROVAL_RULES_CSS + SPEND_CSS + RETENTION_CSS + STORAGE_CSS + UPDATES_CSS + LIMITS_CSS + MONITORING_CSS + INTEGRATIONS_CSS + BACKUP_CSS + EXPORT_CSS + PROJECT_DELETE_CSS + POLICY_CSS + EVIDENCE_PACK_CSS + THEME_CONTROLS_CSS + CODING_CSS + CODING_SHIPPING_CSS + RECIPE_CSS + SKILLS_CSS + TOOLS_CSS + FLOWS_CSS + SUBAGENT_CSS + KITS_CSS + STARTERS_CSS + GALLERY_CSS + SSO_CSS + CREDENTIALS_CSS + REQUEST_LIMITS_CSS + PEOPLE_AUDIT_CSS + KNOWLEDGE_CSS + MODELS_CSS + CHAT_POLISH_CSS + TRANSITIONS_CSS + WORKSPACE_MOTION_CSS + ASSIGNMENT_CSS + TASK_STATUS_CSS + LEAD_CONTEXT_CSS + PULL_REQUEST_SETTINGS_CSS + CHECK_SETTINGS_CSS + DISCLOSURE_CSS + '.learning{min-width:0;overflow-wrap:anywhere}.learning .card{min-width:0}.learning code,.learning blockquote,.learning pre{white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word}.learning button,.learning summary,.learning .button-link{min-height:44px}.learning button{white-space:nowrap}.learning summary{padding:12px 0;cursor:pointer}.learning form{margin:12px 0}.learning select{max-width:100%}.learning blockquote{margin:8px 0}.learning ul{padding-left:20px}');
|
|
148
148
|
/**
|
|
149
149
|
* A server-rendered region that stays current: when the page's live stream
|
|
150
150
|
* says something changed (GET /live, live-bus.ts), fetch this page's own
|
|
@@ -675,7 +675,7 @@ export const NAV_ICONS = {
|
|
|
675
675
|
*/
|
|
676
676
|
export function workToolRows(scoped = false, _offersChat = false, offersCode = false) {
|
|
677
677
|
const rows = [
|
|
678
|
-
|
|
678
|
+
// D5: coding sessions are deprecated; /code still opens this release, but nothing links to it.
|
|
679
679
|
{ key: "inbox", href: "/inbox", label: "Inbox", hint: "questions, approvals, and repairs to act on" },
|
|
680
680
|
{ key: "board", href: "/board", label: "Board", hint: "lanes by state, with the order view" },
|
|
681
681
|
{ key: "tasks", href: "/tasks", label: "Task list", hint: "everything, filterable by state" },
|