toolroll 0.9.54 → 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 +19 -0
- package/README.md +29 -12
- package/dist/action-ledger.d.ts +2 -4
- package/dist/action-ledger.js +2 -10
- package/dist/agent-onboard.js +4 -1
- package/dist/approval-policy.d.ts +5 -5
- package/dist/approval-policy.js +4 -4
- package/dist/approval-rules-ui.d.ts +3 -2
- package/dist/approval-rules-ui.js +17 -22
- 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 +14 -15
- package/dist/browser-workspace.js +0 -3
- 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-polish.d.ts +5 -4
- package/dist/chat-polish.js +9 -10
- package/dist/chat-rooms.js +3 -3
- package/dist/chat-warmth.d.ts +2 -2
- 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 +15 -10
- 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-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/cli.d.ts +1 -3
- package/dist/contracts/console-api.d.ts +7 -7
- package/dist/contracts/console-api.js +13 -12
- 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/health.d.ts +1 -3
- 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/control-ui.d.ts +5 -4
- package/dist/control-ui.js +9 -34
- 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/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/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/discord-settings.d.ts +3 -2
- package/dist/discord-settings.js +17 -42
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +1 -1
- package/dist/envelope.js +10 -1
- 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 +7 -7
- package/dist/flow-engine.d.ts +2 -2
- package/dist/flow-engine.js +21 -21
- package/dist/flow-gallery-ui.d.ts +4 -3
- package/dist/flow-gallery-ui.js +28 -43
- package/dist/flow-insights.d.ts +1 -1
- package/dist/flow-share.js +13 -8
- package/dist/flow-starters-ui.d.ts +2 -1
- package/dist/flow-starters-ui.js +12 -15
- package/dist/flow-steps.d.ts +5 -5
- package/dist/flow-steps.js +19 -19
- package/dist/flow-triggers.d.ts +2 -1
- package/dist/flow-triggers.js +17 -15
- package/dist/flows-cli.js +1 -1
- package/dist/flows-ui.d.ts +4 -3
- package/dist/flows-ui.js +38 -49
- package/dist/flows.js +21 -20
- package/dist/guides.js +112 -6
- 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/invoke.js +1 -1
- package/dist/kits-ui.d.ts +5 -4
- package/dist/kits-ui.js +22 -24
- package/dist/kits.d.ts +12 -12
- package/dist/kits.js +31 -31
- package/dist/knowledge-ui.d.ts +6 -5
- package/dist/knowledge-ui.js +26 -25
- 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 +12 -2
- package/dist/lead-context.js +15 -17
- 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/ledger-view.d.ts +2 -1
- package/dist/ledger-view.js +27 -29
- package/dist/limits-ui.d.ts +3 -2
- package/dist/limits-ui.js +8 -8
- package/dist/live-bus.d.ts +50 -8
- package/dist/live-bus.js +133 -50
- package/dist/mcp-connect.d.ts +1 -1
- package/dist/mcp-connect.js +3 -3
- package/dist/mcp-core.js +1 -1
- package/dist/mcp-oauth.js +35 -36
- package/dist/memory-pass.d.ts +2 -2
- package/dist/memory-pass.js +7 -7
- package/dist/models-ui.d.ts +2 -1
- package/dist/models-ui.js +25 -35
- package/dist/monitoring-ui.d.ts +4 -3
- package/dist/monitoring-ui.js +13 -26
- package/dist/notification-rows.d.ts +2 -2
- package/dist/openrouter-models.d.ts +2 -1
- package/dist/openrouter-models.js +5 -9
- package/dist/operate.d.ts +3 -3
- package/dist/operate.js +46 -41
- package/dist/people-audit-ui.d.ts +2 -1
- package/dist/people-audit-ui.js +13 -13
- package/dist/policy-ui.d.ts +3 -2
- package/dist/policy-ui.js +17 -23
- 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.d.ts +4 -3
- package/dist/project-delete-ui.js +16 -28
- 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/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/retention-ui.d.ts +7 -1
- package/dist/retention-ui.js +7 -11
- 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.d.ts +11 -2
- package/dist/serve.js +105 -99
- package/dist/server/chat.d.ts +7 -10
- package/dist/server/chat.js +984 -1021
- 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 +854 -773
- package/dist/server/guards.d.ts +1 -1
- package/dist/server/guards.js +8 -5
- 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 +581 -573
- package/dist/server/remote.d.ts +4 -7
- package/dist/server/remote.js +39 -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 +154 -0
- package/dist/server/render-settings.js +580 -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 +167 -77
- package/dist/server/runtime.d.ts +28 -20
- 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 +2186 -2121
- 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 +1489 -1420
- package/dist/server-telemetry.d.ts +4 -3
- package/dist/server-telemetry.js +4 -8
- package/dist/setup-guide.d.ts +2 -2
- 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-chat.d.ts +2 -2
- package/dist/slack-chat.js +6 -6
- package/dist/slack-settings.d.ts +3 -2
- package/dist/slack-settings.js +17 -42
- package/dist/spend-ui.d.ts +5 -4
- package/dist/spend-ui.js +17 -40
- package/dist/spend.d.ts +14 -14
- package/dist/spend.js +31 -31
- 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-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/subagents-ui.js +137 -0
- 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 +20 -33
- 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-cli.d.ts +1 -0
- package/dist/team-cli.js +14 -2
- package/dist/team-http.d.ts +5 -9
- package/dist/team-http.js +5 -63
- package/dist/team-leads.js +13 -13
- package/dist/team-runtime.d.ts +2 -2
- package/dist/team-runtime.js +8 -8
- package/dist/team-ui.d.ts +2 -1
- package/dist/team-ui.js +2 -5
- package/dist/teams-chat.js +6 -6
- package/dist/teams-settings.d.ts +3 -2
- package/dist/teams-settings.js +20 -31
- 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-settings.d.ts +3 -2
- package/dist/telegram-settings.js +14 -25
- 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-ui.d.ts +3 -2
- package/dist/toolroll-update-ui.js +35 -39
- package/dist/toolroll-update.d.ts +8 -0
- package/dist/toolroll-update.js +45 -8
- 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-ui.d.ts +4 -2
- package/dist/workspace-ui.js +10 -10
- package/package.json +1 -2
- package/dist/server/shared.d.ts +0 -3151
- package/dist/server/shared.js +0 -12001
- package/dist/teammate-admin.d.ts +0 -53
- package/dist/teammates-ui.d.ts +0 -20
- package/dist/teammates-ui.js +0 -166
package/dist/knowledge-ui.d.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { type KnowledgeDraft, type KnowledgeSelection, type KnowledgeView } from './project-knowledge.js';
|
|
2
|
+
import { type Html } from './html.js';
|
|
2
3
|
export declare const KNOWLEDGE_CSS = ".knowledge{max-width:780px;min-width:0;overflow-wrap:anywhere}.knowledge .card{padding:20px;min-width:0;margin:16px 0}.knowledge h2{margin:0 0 12px}.knowledge form{display:grid;gap:12px;margin:0}.knowledge label{display:grid;gap:6px}.knowledge textarea,.knowledge input,.knowledge select{box-sizing:border-box;width:100%;min-width:0;max-width:100%}.knowledge textarea{resize:vertical;min-height:110px}.knowledge button,.knowledge summary,.knowledge .button-link{min-height:44px}.knowledge button{justify-self:start;white-space:nowrap}.knowledge summary{padding:12px 0;cursor:pointer}.knowledge pre{white-space:pre-wrap;overflow-wrap:anywhere;font:inherit}.knowledge .knowledge-actions{display:flex;gap:12px;flex-wrap:wrap}.knowledge .meta{font-size:.86rem}.knowledge .knowledge-source{display:block}.knowledge details+details{border-top:1px solid var(--so-line)}.memory-stats{display:flex;flex-wrap:wrap;gap:.4rem}.memory-stats span{padding:.15rem .55rem;border-radius:.375rem;background:var(--so-neutral-soft);color:var(--so-neutral-ink)}@media(max-width:600px){.knowledge .card{padding:16px}.knowledge h2{font-size:1.1rem}}";
|
|
3
|
-
export declare function knowledgeHtml(view: KnowledgeView, csrf: string, canManage: boolean, draft?: KnowledgeDraft, error?: string):
|
|
4
|
-
export declare function knowledgeContextHtml(snapshot: KnowledgeSelection | null):
|
|
4
|
+
export declare function knowledgeHtml(view: KnowledgeView, csrf: string, canManage: boolean, draft?: KnowledgeDraft, error?: string): Html;
|
|
5
|
+
export declare function knowledgeContextHtml(snapshot: KnowledgeSelection | null): Html | '';
|
|
5
6
|
import type { Decision, MemoryHit } from './project-memory.js';
|
|
6
7
|
export declare const MEMORY_INTRO = "What the lead and crew read before they work. Every change keeps its history.";
|
|
7
8
|
export declare function decisionsHtml(repo: string, decisions: Decision[], csrf: string, canManage: boolean, draft?: {
|
|
8
9
|
claim?: string;
|
|
9
10
|
why?: string;
|
|
10
|
-
}, error?: string):
|
|
11
|
-
export declare function memorySearchHtml(repo: string, query: string, hits: MemoryHit[] | null):
|
|
11
|
+
}, error?: string): Html;
|
|
12
|
+
export declare function memorySearchHtml(repo: string, query: string, hits: MemoryHit[] | null): Html;
|
|
12
13
|
import type { MemoryProposal } from './memory-pass.js';
|
|
13
14
|
export declare function proposalsHtml(repo: string, proposals: MemoryProposal[], status: {
|
|
14
15
|
surface: string;
|
|
@@ -21,4 +22,4 @@ export declare function proposalsHtml(repo: string, proposals: MemoryProposal[],
|
|
|
21
22
|
};
|
|
22
23
|
openGaps: number;
|
|
23
24
|
pending: number;
|
|
24
|
-
} | null, csrf: string, canManage: boolean):
|
|
25
|
+
} | null, csrf: string, canManage: boolean): Html;
|
package/dist/knowledge-ui.js
CHANGED
|
@@ -1,47 +1,48 @@
|
|
|
1
1
|
import { STALE_KNOWLEDGE } from './project-knowledge.js';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import { html, postForm } from './html.js';
|
|
3
|
+
// Hidden fields as they always were: a missing value is an empty field.
|
|
4
|
+
const fields = (data) => Object.fromEntries(Object.entries(data).map(([k, v]) => [k, String(v ?? '')]));
|
|
4
5
|
export const KNOWLEDGE_CSS = `.knowledge{max-width:780px;min-width:0;overflow-wrap:anywhere}.knowledge .card{padding:20px;min-width:0;margin:16px 0}.knowledge h2{margin:0 0 12px}.knowledge form{display:grid;gap:12px;margin:0}.knowledge label{display:grid;gap:6px}.knowledge textarea,.knowledge input,.knowledge select{box-sizing:border-box;width:100%;min-width:0;max-width:100%}.knowledge textarea{resize:vertical;min-height:110px}.knowledge button,.knowledge summary,.knowledge .button-link{min-height:44px}.knowledge button{justify-self:start;white-space:nowrap}.knowledge summary{padding:12px 0;cursor:pointer}.knowledge pre{white-space:pre-wrap;overflow-wrap:anywhere;font:inherit}.knowledge .knowledge-actions{display:flex;gap:12px;flex-wrap:wrap}.knowledge .meta{font-size:.86rem}.knowledge .knowledge-source{display:block}.knowledge details+details{border-top:1px solid var(--so-line)}.memory-stats{display:flex;flex-wrap:wrap;gap:.4rem}.memory-stats span{padding:.15rem .55rem;border-radius:.375rem;background:var(--so-neutral-soft);color:var(--so-neutral-ink)}@media(max-width:600px){.knowledge .card{padding:16px}.knowledge h2{font-size:1.1rem}}`;
|
|
5
6
|
export function knowledgeHtml(view, csrf, canManage, draft, error) {
|
|
6
7
|
const manage = canManage && !!csrf;
|
|
7
|
-
const base = {
|
|
8
|
-
const form = (action, body, extra = {}) =>
|
|
9
|
-
const referenceFields = (d) => `<label>Name<input name="title" maxlength="120" value="${
|
|
10
|
-
const refs = view.knowledge.references.map(ref => `<details class="card"${draft?.id === ref.id ?
|
|
11
|
-
const history = view.history.map(h => `<li><a class="button-link" href="/settings/knowledge?repo=${encodeURIComponent(view.repo)}&version=${h.revision}">Version ${h.revision}</a> · ${
|
|
8
|
+
const base = { repo: view.repo, identity: view.identity, revision: view.revision };
|
|
9
|
+
const form = (action, body, extra = {}) => postForm('/settings/knowledge/change', body, { hidden: fields({ ...base, action, ...extra }) });
|
|
10
|
+
const referenceFields = (d) => html `<label>Name<input name="title" maxlength="120" value="${d.title}" required></label><label>Reference text<textarea name="content" rows="5" maxlength="12000">${d.content}</textarea></label><details${d.path ? html ` open` : ''}><summary>Use a project document</summary><label>Committed .md or .txt path<input name="path" value="${d.path}" placeholder="docs/design-guide.md"></label><p class="meta">Uses the committed file instead of the text above. Save again to refresh it.</p></details><button type="submit">Save reference</button>`;
|
|
11
|
+
const refs = view.knowledge.references.map(ref => html `<details class="card"${draft?.id === ref.id ? html ` open` : ''}><summary><strong>${ref.title}</strong></summary>${ref.path ? html `<span class="meta knowledge-source">${ref.path} · ${ref.sourceRevision?.slice(0, 7)}</span>` : ''}<pre>${ref.content}</pre>${manage ? html `<details${draft?.id === ref.id ? html ` open` : ''}><summary>Edit reference</summary>${form('save', referenceFields(draft?.id === ref.id ? draft : { title: ref.title, content: ref.path ? '' : ref.content, path: ref.path ?? '' }), { id: ref.id })}<details><summary>Remove reference</summary>${form('remove', html `<p>Remove from future tasks. Previous run context stays available.</p><button>Remove reference</button>`, { id: ref.id })}</details></details>` : ''}</details>`);
|
|
12
|
+
const history = view.history.map(h => html `<li><a class="button-link" href="/settings/knowledge?repo=${encodeURIComponent(view.repo)}&version=${h.revision}">Version ${h.revision}</a> · ${h.actor} · ${h.at.slice(0, 16).replace('T', ' ')} UTC</li>`);
|
|
12
13
|
if (view.stale) {
|
|
13
14
|
// One notice, the saved knowledge on demand, one approver action. Editing waits until it is applied.
|
|
14
15
|
const saved = view.stale.knowledge;
|
|
15
|
-
const review = `<details><summary>Review saved knowledge</summary><pre class="knowledge-instructions">${
|
|
16
|
-
return `<section class="knowledge knowledge-library">${error ? `<p class="problem" role="alert">${
|
|
16
|
+
const review = html `<details><summary>Review saved knowledge</summary><pre class="knowledge-instructions">${saved.instructions || 'No project instructions.'}</pre>${saved.references.map(ref => html `<details><summary>${ref.title}</summary><pre>${ref.content}</pre></details>`)}</details>`;
|
|
17
|
+
return html `<section class="knowledge knowledge-library">${error ? html `<p class="problem" role="alert">${error}</p>` : ''}<section class="card knowledge-stale"><p role="status">${STALE_KNOWLEDGE}.</p>${review}${manage ? form('apply', html `<button>Apply saved knowledge</button>`) : ''}</section></section>`;
|
|
17
18
|
}
|
|
18
|
-
const instructions = `<pre class="knowledge-instructions">${
|
|
19
|
-
const editor = manage ? `<details class="knowledge-editor"${draft?.instructions !== undefined ?
|
|
20
|
-
return `<section class="knowledge knowledge-library">${error ? `<p class="problem" role="alert">${
|
|
19
|
+
const instructions = html `<pre class="knowledge-instructions">${view.knowledge.instructions || 'No project instructions yet.'}</pre>`;
|
|
20
|
+
const editor = manage ? html `<details class="knowledge-editor"${draft?.instructions !== undefined ? html ` open` : ''}><summary>${view.knowledge.instructions ? 'Edit instructions' : 'Add instructions'}</summary>${form('instructions', html `<textarea aria-label="Project instructions" name="instructions" rows="5" maxlength="4000" placeholder="Goals, preferences, and what good work looks like…">${draft?.instructions ?? view.knowledge.instructions}</textarea><button>Save instructions</button>`)}</details>` : '';
|
|
21
|
+
return html `<section class="knowledge knowledge-library">${error ? html `<p class="problem" role="alert">${error}</p>` : ''}<section class="knowledge-intro"><h2>Instructions</h2>${instructions}${editor}</section><section><h2>References</h2>${refs.length ? refs : html `<p class="meta">Add a spec, design guide, or useful project document.</p>`}${manage ? html `<details class="card"${draft?.title && !draft.id ? html ` open` : ''}><summary>Add reference</summary>${form('save', referenceFields(draft?.id ? {} : draft ?? {}))}</details>` : ''}</section>${history.length ? html `<details><summary>Change history</summary><ol>${history}</ol></details>` : ''}</section>`;
|
|
21
22
|
}
|
|
22
23
|
export function knowledgeContextHtml(snapshot) {
|
|
23
24
|
if (!snapshot)
|
|
24
25
|
return '';
|
|
25
|
-
return `<details class="knowledge result-knowledge"><summary>Context used</summary><p class="meta">Project knowledge · version ${snapshot.revision}${snapshot.inheritedFrom === null ? '' : ` · from run #${snapshot.inheritedFrom}`}</p>${snapshot.instructions ? `<details><summary>Instructions</summary><pre>${
|
|
26
|
+
return html `<details class="knowledge result-knowledge"><summary>Context used</summary><p class="meta">Project knowledge · version ${snapshot.revision}${snapshot.inheritedFrom === null ? '' : ` · from run #${snapshot.inheritedFrom}`}</p>${snapshot.instructions ? html `<details><summary>Instructions</summary><pre>${snapshot.instructions}</pre></details>` : html `<p>No project instructions were supplied.</p>`}${snapshot.references.map(r => html `<details><summary>${r.title}</summary>${r.path ? html `<p class="meta">${r.path} · ${r.sourceRevision}</p>` : ''}<pre>${r.content}</pre></details>`)}${snapshot.omitted.length ? html `<details><summary>Not included (${snapshot.omitted.length})</summary><ul>${snapshot.omitted.map(r => html `<li>${r.title} — ${r.reason}</li>`)}</ul></details>` : ''}</details>`;
|
|
26
27
|
}
|
|
27
28
|
export const MEMORY_INTRO = 'What the lead and crew read before they work. Every change keeps its history.';
|
|
28
29
|
export function decisionsHtml(repo, decisions, csrf, canManage, draft, error) {
|
|
29
30
|
const manage = canManage && !!csrf;
|
|
30
|
-
const base = {
|
|
31
|
-
const form = (action, body, extra = {}) =>
|
|
32
|
-
const rows = decisions.map(d => `<details class="card decision" id="decision-${d.id}"><summary><strong>${
|
|
33
|
-
const add = manage ? `<details class="knowledge-editor"${draft?.claim !== undefined ?
|
|
34
|
-
return `<section class="knowledge"><h2>Decisions</h2>${error ? `<p class="problem" role="alert">${
|
|
31
|
+
const base = { repo };
|
|
32
|
+
const form = (action, body, extra = {}) => postForm('/settings/knowledge/decision', body, { hidden: fields({ ...base, action, ...extra }) });
|
|
33
|
+
const rows = decisions.map(d => html `<details class="card decision" id="decision-${d.id}"><summary><strong>${d.claim}</strong> <span class="meta">#${d.id} · ${d.decidedBy} · ${d.decidedAt.slice(0, 10)}</span></summary><p>${d.why}</p><p class="meta">${d.sourceKind}${d.sourceRef ? ` · ${d.sourceRef}` : ''}${d.supersedes === null ? '' : ` · replaces #${d.supersedes}`}</p>${manage ? form('retire', html `<label>Why it no longer holds<input name="reason" maxlength="500" required></label><button type="submit">Retire</button>`, { decision: d.id }) : ''}</details>`);
|
|
34
|
+
const add = manage ? html `<details class="knowledge-editor"${draft?.claim !== undefined ? html ` open` : ''}><summary>Record a decision</summary>${form('record', html `<label>The choice, in one sentence<input name="claim" maxlength="240" value="${draft?.claim}" required></label><label>Why<textarea name="why" rows="3" maxlength="2000" required>${draft?.why}</textarea></label><button type="submit">Record</button>`)}</details>` : '';
|
|
35
|
+
return html `<section class="knowledge"><h2>Decisions</h2>${error ? html `<p class="problem" role="alert">${error}</p>` : ''}${rows.length ? rows : html `<p class="meta">No decisions yet. The lead suggests one when a conversation settles a choice.</p>`}${add}</section>`;
|
|
35
36
|
}
|
|
36
37
|
export function memorySearchHtml(repo, query, hits) {
|
|
37
|
-
const kind = (h) => h.kind === 'decision' ? `<a href="#decision-${
|
|
38
|
-
const results = hits === null ? '' : hits.length === 0 ?
|
|
39
|
-
return `<section class="knowledge memory-search"><form method="get" action="/settings/knowledge"><input type="hidden" name="repo" value="${
|
|
38
|
+
const kind = (h) => h.kind === 'decision' ? html `<a href="#decision-${h.ref}">decision #${h.ref}</a>` : h.kind === 'conversation' ? 'conversation' : h.kind;
|
|
39
|
+
const results = hits === null ? '' : hits.length === 0 ? html `<p class="meta">Nothing in project memory matches.</p>` : html `<ul class="memory-hits">${hits.map(h => html `<li><strong>${kind(h)}</strong> · ${h.title}<br><span class="meta">${h.snippet}</span></li>`)}</ul>`;
|
|
40
|
+
return html `<section class="knowledge memory-search"><form method="get" action="/settings/knowledge"><input type="hidden" name="repo" value="${repo}"><label>Search project memory<input name="memory" value="${query}" maxlength="300" placeholder="Search decisions, references, lessons…" type="search" autocomplete="off"></label><button type="submit">Search</button></form>${results}</section>`;
|
|
40
41
|
}
|
|
41
42
|
export function proposalsHtml(repo, proposals, status, csrf, canManage) {
|
|
42
43
|
const manage = canManage && !!csrf;
|
|
43
|
-
const line = status === null ? '' : `<p class="meta memory-stats"><span>${status.sessions.analyzed}/${status.sessions.total} sessions read${status.sessions.failed ? ` · ${status.sessions.failed} failed` : ''}</span><span>${status.openGaps} open gap${status.openGaps === 1 ? '' : 's'}</span><span>Instructions ${status.instructionBytes}/${status.budgetBytes} bytes</span></p
|
|
44
|
-
|
|
45
|
-
const cards = proposals.map(p => `<details class="card proposal" open><summary><strong>${
|
|
46
|
-
return `<section class="knowledge"><h2>Proposed from sessions</h2>${line}${cards
|
|
44
|
+
const line = status === null ? '' : html `<p class="meta memory-stats"><span>${status.sessions.analyzed}/${status.sessions.total} sessions read${status.sessions.failed ? ` · ${status.sessions.failed} failed` : ''}</span><span>${status.openGaps} open gap${status.openGaps === 1 ? '' : 's'}</span><span>Instructions ${status.instructionBytes}/${status.budgetBytes} bytes</span></p><details class="settings-more"><summary>Read new sessions</summary><p class="meta">Run <code>toolroll memory propose --repo ${repo}</code> on this computer.</p></details>`;
|
|
45
|
+
const decide = (p, decision, label) => postForm('/settings/knowledge/proposal', html `<button type="submit">${label}</button>`, { attrs: { class: 'inline' }, hidden: fields({ repo, proposal: p.id, decision }) });
|
|
46
|
+
const cards = proposals.map(p => html `<details class="card proposal" open><summary><strong>${p.title}</strong> <span class="meta">#${p.id} · ${p.kind} · ${p.sessions} sessions</span></summary><p>${p.rationale}</p>${p.beforeText ? html `<pre class="knowledge-instructions">- ${p.beforeText}</pre>` : ''}${p.afterText ? html `<pre class="knowledge-instructions">+ ${p.afterText}</pre>` : ''}<ul class="memory-evidence">${p.evidence.map(ev => html `<li>“${ev.quote.slice(0, 200)}” <span class="meta">${ev.session.split(':')[0] ?? ''}</span></li>`)}</ul>${manage ? html `${decide(p, 'accept', 'Accept')} ${decide(p, 'reject', 'Reject')}` : ''}</details>`);
|
|
47
|
+
return html `<section class="knowledge"><h2>Proposed from sessions</h2>${line}${cards.length ? cards : html `<p class="meta">Nothing to review. Suggestions appear when the same mistake shows up in two sessions.</p>`}</section>`;
|
|
47
48
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type LeadProposal, type Store } from "./store.js";
|
|
2
2
|
import { type ShapeOptions } from "./reply-shape.js";
|
|
3
|
-
import type {
|
|
4
|
-
export type
|
|
3
|
+
import type { SubscriptionLeadRunner } from "./subscription-chat.js";
|
|
4
|
+
export type LeadCliSeams = {
|
|
5
5
|
fetcher?: typeof fetch;
|
|
6
6
|
env?: Record<string, string | undefined>;
|
|
7
7
|
/** Lines the REPL reads instead of stdin (tests). */
|
|
8
8
|
lines?: AsyncIterable<string> | Iterable<string>;
|
|
9
9
|
clock?: () => Date;
|
|
10
10
|
/** Subscription harness seam; tests never consume a real membership turn. */
|
|
11
|
-
subscriptionRunner?:
|
|
11
|
+
subscriptionRunner?: SubscriptionLeadRunner;
|
|
12
12
|
};
|
|
13
|
-
export type
|
|
13
|
+
export type LeadCliInput = {
|
|
14
14
|
store: Store;
|
|
15
15
|
databaseFile: string;
|
|
16
16
|
write: (line: string) => void;
|
|
@@ -25,18 +25,18 @@ export type MateCliInput = {
|
|
|
25
25
|
end: boolean;
|
|
26
26
|
follow?: boolean;
|
|
27
27
|
ceilingUsd: number | undefined;
|
|
28
|
-
seams?:
|
|
28
|
+
seams?: LeadCliSeams;
|
|
29
29
|
/** Where evidence lives — a scout's report reads from here. */
|
|
30
30
|
evidenceRoot?: string;
|
|
31
31
|
/** The console's address(es): a reply's links there are named as its pages ("the task"), not by host. */
|
|
32
32
|
appOrigin?: ShapeOptions["appOrigin"];
|
|
33
33
|
};
|
|
34
|
-
export type
|
|
34
|
+
export type LeadCliResult = {
|
|
35
35
|
code: number;
|
|
36
36
|
reason?: string;
|
|
37
37
|
message?: string;
|
|
38
38
|
};
|
|
39
|
-
export declare const
|
|
39
|
+
export declare const LEAD_CLI_EXIT: {
|
|
40
40
|
readonly ok: 0;
|
|
41
41
|
readonly failed: 1;
|
|
42
42
|
readonly usage: 2;
|
|
@@ -49,7 +49,7 @@ export declare const MATE_CLI_EXIT: {
|
|
|
49
49
|
*/
|
|
50
50
|
export declare function answerContextLines(store: Store, payload: Record<string, unknown>): string[];
|
|
51
51
|
/** One line per proposal, numbered in thread order, for the operator to name. */
|
|
52
|
-
export declare function proposalLines(proposals: readonly
|
|
52
|
+
export declare function proposalLines(proposals: readonly LeadProposal[], repos: readonly string[], ordinal?: (proposal: LeadProposal) => number): string[];
|
|
53
53
|
/** The lines for one proposal, its answer context included when it is an answer. */
|
|
54
|
-
export declare function proposalBlock(store: Store, proposal:
|
|
55
|
-
export declare function
|
|
54
|
+
export declare function proposalBlock(store: Store, proposal: LeadProposal, repos: readonly string[], number: number): string[];
|
|
55
|
+
export declare function runLeadCli(input: LeadCliInput): Promise<LeadCliResult>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { configureLeadFollow, leadFollowStatus } from './lead-follow.js';
|
|
2
2
|
/**
|
|
3
3
|
* `toolroll chat` (mate arc §6): the same thread the console shows,
|
|
4
|
-
* driven from a terminal. The password is typed once — it mints the
|
|
4
|
+
* driven from a terminal. The password is typed once — it mints the lead
|
|
5
5
|
* session, the one ceremony a conversation gets — and every later turn
|
|
6
6
|
* debits that session without asking again. Confirming a card runs the
|
|
7
7
|
* same doors the console runs; password-class acts (approving a scope,
|
|
@@ -10,16 +10,16 @@ import { configureLeadFollow, leadFollowStatus } from './lead-follow.js';
|
|
|
10
10
|
import { createHash } from "node:crypto";
|
|
11
11
|
import { readFileSync } from "node:fs";
|
|
12
12
|
import { dirname, join } from "node:path";
|
|
13
|
-
import {
|
|
13
|
+
import { LEAD_ASK_OTHER } from "./store.js";
|
|
14
14
|
import { CHAT_KEY_ENV, credentialKeyOf, isDirectChatProvider, priceForConfig, subscriptionCredentialKey } from "./converse.js";
|
|
15
15
|
import { verifyApproverByPassword } from "./principal.js";
|
|
16
|
-
import {
|
|
16
|
+
import { runLeadTurn } from "./lead.js";
|
|
17
17
|
import { voiceReply } from "./reply-shape.js";
|
|
18
|
-
import {
|
|
18
|
+
import { confirmLeadProposal, dismissLeadProposal } from "./lead-doors.js";
|
|
19
19
|
import { projectName } from "./project.js";
|
|
20
20
|
import { CHAT_CONTROLS, chatControlHref, isChatControl } from "./chat-controls.js";
|
|
21
21
|
import { CHAT_TASK_ACTIONS, isChatTaskAction } from "./chat-task-actions.js";
|
|
22
|
-
export const
|
|
22
|
+
export const LEAD_CLI_EXIT = { ok: 0, failed: 1, usage: 2, refused: 3 };
|
|
23
23
|
function money(microusd) {
|
|
24
24
|
return `$${(microusd / 1_000_000).toFixed(2)}`;
|
|
25
25
|
}
|
|
@@ -119,7 +119,7 @@ async function* linesOf(seams) {
|
|
|
119
119
|
reader.close();
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
|
-
export async function
|
|
122
|
+
export async function runLeadCli(input) {
|
|
123
123
|
const { store, write, json } = input;
|
|
124
124
|
const seams = input.seams ?? {};
|
|
125
125
|
const clock = seams.clock ?? (() => new Date());
|
|
@@ -132,7 +132,7 @@ export async function runMateCli(input) {
|
|
|
132
132
|
if (json)
|
|
133
133
|
write(JSON.stringify({ command: "chat", ...envelope }));
|
|
134
134
|
};
|
|
135
|
-
const refuse = (reason, message, code =
|
|
135
|
+
const refuse = (reason, message, code = LEAD_CLI_EXIT.refused) => {
|
|
136
136
|
if (json)
|
|
137
137
|
write(JSON.stringify({ ok: false, command: "chat", reason, message }));
|
|
138
138
|
else
|
|
@@ -154,22 +154,22 @@ export async function runMateCli(input) {
|
|
|
154
154
|
return refuse("no-key", `no ${directProvider} key — export ${CHAT_KEY_ENV[directProvider]}, or paste one on the console's chat page`);
|
|
155
155
|
const repos = [...input.repos];
|
|
156
156
|
if (repos.length === 0)
|
|
157
|
-
return refuse("empty-ceiling", "The lead has no projects to look at. Name some with --repo, or add projects in the console.",
|
|
157
|
+
return refuse("empty-ceiling", "The lead has no projects to look at. Name some with --repo, or add projects in the console.", LEAD_CLI_EXIT.usage);
|
|
158
158
|
const verified = verifyApproverByPassword(store, input.credentials.name, input.credentials.token, repos);
|
|
159
159
|
if (!verified.ok)
|
|
160
160
|
return refuse("unauthenticated", "that is not an approver, or the password does not match");
|
|
161
161
|
const who = verified.who;
|
|
162
162
|
let now = clock();
|
|
163
163
|
if (input.end) {
|
|
164
|
-
const turns = store.
|
|
165
|
-
const sessions = store.
|
|
166
|
-
const threads = store.
|
|
164
|
+
const turns = store.failLiveLeadTurnsFor(who.name, "ended", now);
|
|
165
|
+
const sessions = store.endLeadSessionsFor(who.name, who.name, now);
|
|
166
|
+
const threads = store.closeLeadThreadsFor(who.name, now);
|
|
167
167
|
emit({ ok: true, ended: { sessions, threads, turns } });
|
|
168
168
|
say(sessions === 0 ? "No conversation was open, so there was nothing to end." : "The conversation has ended and its history is forgotten.");
|
|
169
|
-
return { code:
|
|
169
|
+
return { code: LEAD_CLI_EXIT.ok };
|
|
170
170
|
}
|
|
171
|
-
store.
|
|
172
|
-
let session = store.
|
|
171
|
+
store.sweepStaleLeadTurns(now);
|
|
172
|
+
let session = store.activeLeadSession(who.name);
|
|
173
173
|
const credentialKey = direct ? credentialKeyOf(directProvider, key) : subscriptionCredentialKey(subscriptionProvider);
|
|
174
174
|
if (session !== null && session.credentialKey !== credentialKey) {
|
|
175
175
|
// A session minted under another provider key cannot be spent by this
|
|
@@ -177,38 +177,38 @@ export async function runMateCli(input) {
|
|
|
177
177
|
return refuse("key-mismatch", "The open conversation was started with a different provider key. Use that key, or end it with --end and start a new one.");
|
|
178
178
|
}
|
|
179
179
|
if (session !== null && session.ceilingDigest !== who.ceilingDigest) {
|
|
180
|
-
store.
|
|
181
|
-
store.
|
|
180
|
+
store.endLeadSession(session.id, who.name, now);
|
|
181
|
+
store.closeLeadThreadsFor(who.name, now);
|
|
182
182
|
say("The projects you named differ from the open conversation's, so it ended. Starting a new one.");
|
|
183
183
|
session = null;
|
|
184
184
|
}
|
|
185
185
|
if (session === null) {
|
|
186
186
|
const ceilingUsd = direct ? (input.ceilingUsd ?? 5) : 0;
|
|
187
187
|
if (direct && (!Number.isFinite(ceilingUsd) || ceilingUsd <= 0 || ceilingUsd > 1_000))
|
|
188
|
-
return refuse("usage", "--ceiling-usd is a dollar amount between 0 and 1000",
|
|
188
|
+
return refuse("usage", "--ceiling-usd is a dollar amount between 0 and 1000", LEAD_CLI_EXIT.usage);
|
|
189
189
|
const ceilingMicrousd = Math.round(ceilingUsd * 1_000_000);
|
|
190
190
|
const termsDigest = createHash("sha256").update(`${ceilingMicrousd}\n${who.ceilingDigest}`).digest("hex");
|
|
191
|
-
const id = store.
|
|
192
|
-
session = store.
|
|
191
|
+
const id = store.mintLeadSession({ approver: who.name, approverGeneration: who.generation, credentialKey, ceilingMicrousd, ceilingDigest: who.ceilingDigest, termsDigest }, now);
|
|
192
|
+
session = store.getLeadSession(id);
|
|
193
193
|
if (session === null)
|
|
194
|
-
return refuse("failed", "A new conversation couldn't be started. Try again.",
|
|
194
|
+
return refuse("failed", "A new conversation couldn't be started. Try again.", LEAD_CLI_EXIT.failed);
|
|
195
195
|
if (!direct && input.ceilingUsd !== undefined)
|
|
196
196
|
say("the supplied --ceiling-usd value is ignored for membership usage");
|
|
197
|
-
say(`
|
|
197
|
+
say(`lead conversation started: ${direct ? `up to ${money(ceilingMicrousd)}` : "subscription usage (no dollar limit)"} over ${repos.map(one => projectName(one)).join(", ")} — live until you end it`);
|
|
198
198
|
if (direct)
|
|
199
199
|
say(`(the weekly chat limit, ${money(config.weeklyCeilingMicrousd)}, still applies)`);
|
|
200
200
|
}
|
|
201
201
|
else {
|
|
202
|
-
say(`
|
|
202
|
+
say(`lead conversation live: ${direct ? `${money(session.spentMicrousd)} of ${money(session.ceilingMicrousd)} spent` : "subscription usage (no dollar limit)"} — live until you end it`);
|
|
203
203
|
}
|
|
204
|
-
const thread = store.
|
|
204
|
+
const thread = store.openLeadThread(who.name, who.ceilingDigest, now).thread;
|
|
205
205
|
if (input.follow !== undefined) {
|
|
206
206
|
if (!configureLeadFollow(store, who, session, thread, input.follow, now))
|
|
207
207
|
return refuse("standing", "Conversation access changed.");
|
|
208
208
|
say(leadFollowStatus(store, who.name).detail);
|
|
209
209
|
emit({ ok: true, follow: leadFollowStatus(store, who.name) });
|
|
210
210
|
}
|
|
211
|
-
const pendingProposals = () => store.
|
|
211
|
+
const pendingProposals = () => store.listLeadProposals(thread.id, ["pending"]);
|
|
212
212
|
// Ordinals are assigned once per proposal and never reused within this
|
|
213
213
|
// run (slice-2 review, finding 4): `confirm 2` means the card printed as
|
|
214
214
|
// 2, whatever the console did to its neighbours meanwhile.
|
|
@@ -224,7 +224,7 @@ export async function runMateCli(input) {
|
|
|
224
224
|
const byOrdinal = (ordinal) => {
|
|
225
225
|
for (const [id, n] of ordinals)
|
|
226
226
|
if (n === ordinal)
|
|
227
|
-
return store.
|
|
227
|
+
return store.getLeadProposal(id);
|
|
228
228
|
return null;
|
|
229
229
|
};
|
|
230
230
|
const printProposals = () => {
|
|
@@ -239,12 +239,12 @@ export async function runMateCli(input) {
|
|
|
239
239
|
say(line);
|
|
240
240
|
};
|
|
241
241
|
const turn = async (message) => {
|
|
242
|
-
const live = store.
|
|
242
|
+
const live = store.activeLeadSession(who.name);
|
|
243
243
|
if (live === null) {
|
|
244
244
|
const outcome = { ok: false, refused: "session-ended", message: "This conversation has ended. Run chat again to start a new one." };
|
|
245
245
|
return outcome;
|
|
246
246
|
}
|
|
247
|
-
return
|
|
247
|
+
return runLeadTurn({ store, who, session: live, thread, config, key, message, channel: "terminal", ...(seams.fetcher === undefined ? {} : { fetcher: seams.fetcher }), ...(seams.subscriptionRunner === undefined ? {} : { subscriptionRunner: seams.subscriptionRunner }), ...(input.evidenceRoot === undefined ? {} : { evidenceRoot: input.evidenceRoot }), clock });
|
|
248
248
|
};
|
|
249
249
|
const report = (outcome, message) => {
|
|
250
250
|
if (outcome.ok && outcome.replayed) {
|
|
@@ -253,14 +253,14 @@ export async function runMateCli(input) {
|
|
|
253
253
|
return;
|
|
254
254
|
}
|
|
255
255
|
if (outcome.ok) {
|
|
256
|
-
const ask = store.
|
|
256
|
+
const ask = store.leadAsk(outcome.turn);
|
|
257
257
|
emit({ ok: true, turn: outcome.turn, reply: outcome.reply, activity: outcome.activity, steps: outcome.steps, settledMicrousd: outcome.settledMicrousd, proposals: pendingProposals().map(one => ({ id: one.id, ordinal: ordinalOf(one), kind: one.kind, payload: one.payload })),
|
|
258
|
-
...(ask === null ? {} : { ask: { question: ask.question, options: [...ask.options,
|
|
258
|
+
...(ask === null ? {} : { ask: { question: ask.question, options: [...ask.options, LEAD_ASK_OTHER] } }) });
|
|
259
259
|
say(` ${outcome.activity}`);
|
|
260
260
|
say(voiceReply(outcome.reply, "terminal", { appOrigin: input.appOrigin ?? null, ...(message === undefined ? {} : { asked: message }) }));
|
|
261
261
|
// The lead's question: the terminal has no buttons, so the options are listed to type back.
|
|
262
262
|
if (ask !== null)
|
|
263
|
-
say(`${ask.question}\n${ask.options.map(one => ` · ${one}`).join("\n")}\n · ${
|
|
263
|
+
say(`${ask.question}\n${ask.options.map(one => ` · ${one}`).join("\n")}\n · ${LEAD_ASK_OTHER} (type your answer)`);
|
|
264
264
|
printProposals();
|
|
265
265
|
return;
|
|
266
266
|
}
|
|
@@ -270,7 +270,7 @@ export async function runMateCli(input) {
|
|
|
270
270
|
if (input.say !== undefined) {
|
|
271
271
|
const outcome = await turn(input.say);
|
|
272
272
|
report(outcome, input.say);
|
|
273
|
-
return { code: outcome.ok ?
|
|
273
|
+
return { code: outcome.ok ? LEAD_CLI_EXIT.ok : LEAD_CLI_EXIT.refused };
|
|
274
274
|
}
|
|
275
275
|
// The REPL. Text is a turn; a few words are acts on the cards.
|
|
276
276
|
say("say something, or: proposals · confirm N · dismiss N · open N · end · quit");
|
|
@@ -311,12 +311,12 @@ export async function runMateCli(input) {
|
|
|
311
311
|
openTask(proposal);
|
|
312
312
|
}
|
|
313
313
|
else if (verb === "dismiss") {
|
|
314
|
-
const done =
|
|
314
|
+
const done = dismissLeadProposal(store, who, proposal.id, now);
|
|
315
315
|
emit({ ok: done, act: "dismiss", proposal: proposal.id });
|
|
316
316
|
say(done ? `dismissed ${act[2]}` : "that proposal was already acted on");
|
|
317
317
|
}
|
|
318
318
|
else {
|
|
319
|
-
const outcome =
|
|
319
|
+
const outcome = confirmLeadProposal(store, who, proposal.id, now, { confirm: act[3] !== undefined, via: "cli", chatProvider: () => {
|
|
320
320
|
const current = store.getChatConfig();
|
|
321
321
|
return current === null ? null : { config: current, key: isDirectChatProvider(current.provider) ? keyFor(current, input.databaseFile, env) : null };
|
|
322
322
|
}, ...(input.evidenceRoot === undefined ? {} : { evidenceRoot: input.evidenceRoot }) });
|
|
@@ -338,12 +338,12 @@ export async function runMateCli(input) {
|
|
|
338
338
|
if (word === "quit" || word === "exit")
|
|
339
339
|
break;
|
|
340
340
|
if (word === "end") {
|
|
341
|
-
store.
|
|
342
|
-
store.
|
|
343
|
-
store.
|
|
341
|
+
store.failLiveLeadTurnsFor(who.name, "ended", now);
|
|
342
|
+
store.endLeadSessionsFor(who.name, who.name, now);
|
|
343
|
+
store.closeLeadThreadsFor(who.name, now);
|
|
344
344
|
say("The conversation has ended and its history is forgotten.");
|
|
345
345
|
emit({ ok: true, ended: true });
|
|
346
|
-
return { code:
|
|
346
|
+
return { code: LEAD_CLI_EXIT.ok };
|
|
347
347
|
}
|
|
348
348
|
if (word === "help" || word === "?") {
|
|
349
349
|
say("say something, or: proposals · confirm N · dismiss N · open N · end · quit");
|
|
@@ -351,5 +351,5 @@ export async function runMateCli(input) {
|
|
|
351
351
|
}
|
|
352
352
|
report(await turn(line), line);
|
|
353
353
|
}
|
|
354
|
-
return { code:
|
|
354
|
+
return { code: LEAD_CLI_EXIT.ok };
|
|
355
355
|
}
|
package/dist/lead-commitments.js
CHANGED
|
@@ -90,7 +90,7 @@ export function getCommitment(store, id) {
|
|
|
90
90
|
/** The reply that made a promise was shown: its turn is over, and it was answered or its text reached the conversation
|
|
91
91
|
* before it failed. A turn still running has shown nothing yet, whatever it has written so far. */
|
|
92
92
|
const SHOWN = (turn) => `EXISTS (SELECT 1 FROM mate_turn t WHERE t.id = ${turn} AND (t.state = 'answered'
|
|
93
|
-
OR t.state = 'failed' AND EXISTS (SELECT 1 FROM
|
|
93
|
+
OR t.state = 'failed' AND EXISTS (SELECT 1 FROM lead_message m WHERE m.turn = t.id AND m.role = 'assistant')))`;
|
|
94
94
|
/** A promise only counts once the reply that made it was shown: one from a reply still being written, or one that
|
|
95
95
|
* failed without reaching the owner, was never heard. */
|
|
96
96
|
const HEARD = `(c.turn IS NULL OR ${SHOWN('c.turn')})`;
|
|
@@ -173,7 +173,7 @@ export function checkLeadCommitments(store, now, root) {
|
|
|
173
173
|
continue;
|
|
174
174
|
}
|
|
175
175
|
// A reply still being written may yet be delivered; one that was not is dropped above.
|
|
176
|
-
const turn = one.turn === null ? null : store.
|
|
176
|
+
const turn = one.turn === null ? null : store.getLeadTurn(one.turn);
|
|
177
177
|
if (turn !== null && (turn.state === 'queued' || turn.state === 'running'))
|
|
178
178
|
continue;
|
|
179
179
|
const account = store.accountOf(one.owner);
|
|
@@ -181,7 +181,7 @@ export function checkLeadCommitments(store, now, root) {
|
|
|
181
181
|
close('cancelled', 'Access to this project ended.');
|
|
182
182
|
continue;
|
|
183
183
|
}
|
|
184
|
-
const thread = store.
|
|
184
|
+
const thread = store.getLeadThread(one.thread);
|
|
185
185
|
if (thread === null || thread.approver !== one.owner || thread.closedAt !== null) {
|
|
186
186
|
close('cancelled', 'The conversation it was promised in was closed.');
|
|
187
187
|
continue;
|
|
@@ -203,7 +203,7 @@ export function checkLeadCommitments(store, now, root) {
|
|
|
203
203
|
return;
|
|
204
204
|
// The shared conversation always keeps the line; a promise made on a phone or team chat is also said there, as
|
|
205
205
|
// the lead's own message to its owner, on that chat alone (the usual delivery receipts apply).
|
|
206
|
-
store.
|
|
206
|
+
store.appendLeadMessage({ thread: one.thread, turn: null, role: 'assistant', text: line }, now);
|
|
207
207
|
if (one.channel !== 'chat')
|
|
208
208
|
store.enqueueNotification({ dedupeKey: `${PROMISE_KEY}${one.channel}:${one.id}`, kind: LEAD_SAY_KIND, subject: leadNameOf(store, one.owner),
|
|
209
209
|
body: line.slice(0, 300), recipient: one.owner, source: { installation: true } }, now);
|
package/dist/lead-context.d.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/** Bounded DB memory shared by browser and terminal lead turns. No provider,
|
|
2
|
+
* repository scan, mutation, or hidden approval happens while catching up.
|
|
3
|
+
*
|
|
4
|
+
* The bundle is ordered by importance and built fresh each turn: who the lead
|
|
5
|
+
* is (name, persona), who it is talking to (first name, time zone, today), what
|
|
6
|
+
* it knows about them (their confirmed lines), the people, subagents and team
|
|
7
|
+
* chats it works with (one line each), the channel, what needs them now,
|
|
8
|
+
* projects by name with their active decisions, then the rest. Over 8 KB, the
|
|
9
|
+
* least important goes first: the rest, then people, then decisions. */
|
|
10
|
+
import { type Html } from './html.js';
|
|
1
11
|
import type { Store } from './store.js';
|
|
2
12
|
import { type LeadChannel } from './contracts/lead-context.js';
|
|
3
13
|
import { type AssignmentCatchUp } from './assignment-brief.js';
|
|
@@ -31,5 +41,5 @@ export declare function firstNameOf(account: string): string;
|
|
|
31
41
|
export declare function leadChannelOf(label: string): LeadChannel | undefined;
|
|
32
42
|
export declare function leadContext(store: Store, repos: readonly string[], now: Date, options?: LeadContextOptions): string;
|
|
33
43
|
/** The same saved brief is useful before chat spending is authorized. */
|
|
34
|
-
export declare function leadBriefHtml(brief: AssignmentCatchUp):
|
|
35
|
-
export declare const LEAD_CONTEXT_CSS = ".lead-promise-list{list-style:none;margin:0;padding:0}.lead-promise-list li{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:.75rem;align-items:center;padding:.5rem 0;border-bottom:1px solid var(--border);min-width:0}.lead-promise-list li:last-child{border-bottom:0}.lead-promise-list p{margin:0;overflow-wrap:anywhere}.lead-promise-list form{grid-column:2;grid-row:1/span 2;margin:0}.lead-promise-list button{min-height:44px;width:auto;white-space:nowrap}.lead-promise-list .nowrap{white-space:nowrap}.lead-brief{margin:1rem 0;min-width:0}.lead-brief h2{font-size:1.1rem;margin:0 0 .8rem}.repository-context input[name=q]{display:block;box-sizing:border-box;min-height:44px;width:100%;margin:.4rem 0 .75rem;padding:.6rem .75rem;border:1px solid var(--border);border-radius:8px;background:var(--surface);color:inherit;font:inherit}.repository-context form{margin:.5rem 0 1rem}.repository-context summary{min-height:44px;padding:.75rem 0;overflow-wrap:anywhere}.lead-brief h3{font-size:.85rem;margin:1rem 0 .4rem;color:var(--muted-foreground)}.lead-brief ul{list-style:none;margin:0;padding:0}.lead-brief li{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:.75rem;align-items:center;padding:.35rem 0;border-bottom:1px solid var(--border);min-width:0}.lead-brief li a{display:flex;min-height:44px;align-items:center;font-weight:500;overflow-wrap:anywhere;text-decoration:none}.lead-brief li a:hover{text-decoration:underline}.lead-brief-state{font-size:.75rem;font-weight:600;padding:.15rem .5rem;border-radius:.375rem;background:var(--so-neutral-soft);color:var(--so-neutral-ink);white-space:nowrap}.lead-brief-state--needs-decision,.lead-brief-state--ready-to-check{background:var(--so-attention-soft);color:var(--so-attention)}.lead-brief-state--working,.lead-brief-state--checking{background:var(--so-info-soft);color:var(--so-info)}.lead-brief-state--complete{background:var(--so-success-soft);color:var(--so-success)}.lead-brief li a.lead-brief-act{grid-column:1/-1;justify-self:start;display:inline-flex;min-height:40px;margin:.15rem 0 .4rem;font-weight:600}@media(max-width:760px){.lead-brief li a.lead-brief-act{justify-self:stretch;justify-content:center;min-height:44px}}.lead-brief-detail{grid-column:1/-1;font-size:.85rem;color:var(--muted-foreground);overflow-wrap:anywhere;padding-bottom:.35rem}@media(max-width:760px){.lead-brief{margin:.5rem 0}.lead-brief h2{margin:0 0 .25rem}.lead-brief h3{margin:.5rem 0 0}.lead-brief li{padding:0 0 .375rem}.lead-brief-detail{margin-top:-.375rem;padding-bottom:0;line-height:1.35;pointer-events:none}}";
|
|
44
|
+
export declare function leadBriefHtml(brief: AssignmentCatchUp): Html;
|
|
45
|
+
export declare const LEAD_CONTEXT_CSS = ".lead-subagent-list{list-style:none;margin:0 0 .5rem;padding:0}.lead-subagent-list li{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:.75rem;align-items:center;border-bottom:1px solid var(--border);min-width:0}.lead-subagent-list li:last-child{border-bottom:0}.lead-subagent-list a{display:flex;min-height:44px;align-items:center;font-weight:500;overflow-wrap:anywhere;min-width:0}.lead-subagent-list .meta{text-align:right;overflow-wrap:anywhere}@media(max-width:600px){.lead-subagent-list li{grid-template-columns:minmax(0,1fr)}.lead-subagent-list .meta{text-align:left;padding-bottom:.4rem}}.lead-subagents .button-link{min-height:44px;display:inline-flex;align-items:center}.lead-promise-list{list-style:none;margin:0;padding:0}.lead-promise-list li{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:.75rem;align-items:center;padding:.5rem 0;border-bottom:1px solid var(--border);min-width:0}.lead-promise-list li:last-child{border-bottom:0}.lead-promise-list p{margin:0;overflow-wrap:anywhere}.lead-promise-list form{grid-column:2;grid-row:1/span 2;margin:0}.lead-promise-list button{min-height:44px;width:auto;white-space:nowrap}.lead-promise-list .nowrap{white-space:nowrap}.lead-brief{margin:1rem 0;min-width:0}.lead-brief h2{font-size:1.1rem;margin:0 0 .8rem}.repository-context input[name=q]{display:block;box-sizing:border-box;min-height:44px;width:100%;margin:.4rem 0 .75rem;padding:.6rem .75rem;border:1px solid var(--border);border-radius:8px;background:var(--surface);color:inherit;font:inherit}.repository-context form{margin:.5rem 0 1rem}.repository-context summary{min-height:44px;padding:.75rem 0;overflow-wrap:anywhere}.lead-brief h3{font-size:.85rem;margin:1rem 0 .4rem;color:var(--muted-foreground)}.lead-brief ul{list-style:none;margin:0;padding:0}.lead-brief li{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:.75rem;align-items:center;padding:.35rem 0;border-bottom:1px solid var(--border);min-width:0}.lead-brief li a{display:flex;min-height:44px;align-items:center;font-weight:500;overflow-wrap:anywhere;text-decoration:none}.lead-brief li a:hover{text-decoration:underline}.lead-brief-state{font-size:.75rem;font-weight:600;padding:.15rem .5rem;border-radius:.375rem;background:var(--so-neutral-soft);color:var(--so-neutral-ink);white-space:nowrap}.lead-brief-state--needs-decision,.lead-brief-state--ready-to-check{background:var(--so-attention-soft);color:var(--so-attention)}.lead-brief-state--working,.lead-brief-state--checking{background:var(--so-info-soft);color:var(--so-info)}.lead-brief-state--complete{background:var(--so-success-soft);color:var(--so-success)}.lead-brief li a.lead-brief-act{grid-column:1/-1;justify-self:start;display:inline-flex;min-height:40px;margin:.15rem 0 .4rem;font-weight:600}@media(max-width:760px){.lead-brief li a.lead-brief-act{justify-self:stretch;justify-content:center;min-height:44px}}.lead-brief-detail{grid-column:1/-1;font-size:.85rem;color:var(--muted-foreground);overflow-wrap:anywhere;padding-bottom:.35rem}@media(max-width:760px){.lead-brief{margin:.5rem 0}.lead-brief h2{margin:0 0 .25rem}.lead-brief h3{margin:.5rem 0 0}.lead-brief li{padding:0 0 .375rem}.lead-brief-detail{margin-top:-.375rem;padding-bottom:0;line-height:1.35;pointer-events:none}}";
|