toolroll 0.9.88 → 0.9.90

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.
Files changed (154) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +16 -10
  3. package/THIRD_PARTY_NOTICES.md +37 -0
  4. package/dist/agent-board.d.ts +9 -0
  5. package/dist/agent-board.js +20 -0
  6. package/dist/agent-fence.js +20 -2
  7. package/dist/approval-authority.d.ts +7 -0
  8. package/dist/approval-authority.js +13 -2
  9. package/dist/browser/THIRD_PARTY_NOTICES.txt +692 -28
  10. package/dist/browser/terminal.js +42 -42
  11. package/dist/browser/workspace.css +1 -1
  12. package/dist/browser/workspace.js +30 -30
  13. package/dist/browser-workspace.d.ts +13 -0
  14. package/dist/builder.js +5 -2
  15. package/dist/chat-actions.d.ts +5 -0
  16. package/dist/chat-actions.js +7 -1
  17. package/dist/chat-channel.js +11 -1
  18. package/dist/chat-delivery.js +2 -0
  19. package/dist/chat-task-actions.d.ts +1 -0
  20. package/dist/check-access.d.ts +3 -0
  21. package/dist/check-access.js +4 -1
  22. package/dist/cli-help.d.ts +1 -1
  23. package/dist/cli-help.js +6 -2
  24. package/dist/cli.d.ts +6 -0
  25. package/dist/cli.js +23 -0
  26. package/dist/coding-ui.js +4 -2
  27. package/dist/connect-cli.js +2 -1
  28. package/dist/console-instance.d.ts +34 -1
  29. package/dist/console-instance.js +124 -15
  30. package/dist/contracts/cli.d.ts +72 -0
  31. package/dist/contracts/cli.js +13 -0
  32. package/dist/contracts/console-api.d.ts +9 -2
  33. package/dist/contracts/console-api.js +9 -2
  34. package/dist/desktop-host.js +8 -3
  35. package/dist/desktop-update.js +2 -1
  36. package/dist/dispatch.d.ts +3 -0
  37. package/dist/dispatch.js +22 -2
  38. package/dist/easy-start-args.d.ts +13 -0
  39. package/dist/easy-start-args.js +24 -0
  40. package/dist/easy-start.d.ts +77 -0
  41. package/dist/easy-start.js +321 -0
  42. package/dist/egress.js +5 -0
  43. package/dist/first-run.d.ts +77 -0
  44. package/dist/first-run.js +45 -0
  45. package/dist/flow-starters.js +3 -0
  46. package/dist/flow-triggers.js +4 -0
  47. package/dist/folder-gate.d.ts +32 -0
  48. package/dist/folder-gate.js +43 -0
  49. package/dist/guides.js +1 -1
  50. package/dist/invoke.js +11 -6
  51. package/dist/laptop-background.d.ts +171 -0
  52. package/dist/laptop-background.js +550 -0
  53. package/dist/laptop-service.d.ts +111 -0
  54. package/dist/laptop-service.js +268 -0
  55. package/dist/lead-cli.js +2 -1
  56. package/dist/lead-doors.d.ts +6 -0
  57. package/dist/lead-doors.js +20 -2
  58. package/dist/live-records.d.ts +1 -1
  59. package/dist/live-records.js +3 -12
  60. package/dist/local-owner.d.ts +124 -0
  61. package/dist/local-owner.js +212 -0
  62. package/dist/login-secrets.d.ts +60 -0
  63. package/dist/login-secrets.js +195 -0
  64. package/dist/mcp-oauth.d.ts +4 -0
  65. package/dist/mcp-oauth.js +13 -7
  66. package/dist/model-choices.d.ts +43 -0
  67. package/dist/model-choices.js +80 -0
  68. package/dist/operate.d.ts +46 -1
  69. package/dist/operate.js +461 -40
  70. package/dist/person-proof.js +3 -0
  71. package/dist/project-access.js +15 -1
  72. package/dist/project-admission.d.ts +6 -1
  73. package/dist/project-admission.js +44 -7
  74. package/dist/project-identity.d.ts +8 -0
  75. package/dist/project-identity.js +43 -0
  76. package/dist/project-knowledge.d.ts +7 -7
  77. package/dist/project.d.ts +1 -0
  78. package/dist/project.js +6 -0
  79. package/dist/proposal.js +11 -1
  80. package/dist/quick-start.d.ts +3 -1
  81. package/dist/quick-start.js +6 -1
  82. package/dist/recipes.js +12 -1
  83. package/dist/release-cli.js +2 -1
  84. package/dist/runner-process.d.ts +9 -0
  85. package/dist/runner-process.js +18 -0
  86. package/dist/sample-project.d.ts +31 -0
  87. package/dist/sample-project.js +141 -0
  88. package/dist/scope.d.ts +24 -2
  89. package/dist/scope.js +74 -3
  90. package/dist/serve.js +157 -28
  91. package/dist/server/chat.js +10 -3
  92. package/dist/server/chrome.d.ts +10 -2
  93. package/dist/server/chrome.js +7 -5
  94. package/dist/server/console.css +10 -0
  95. package/dist/server/guards.d.ts +3 -0
  96. package/dist/server/guards.js +22 -2
  97. package/dist/server/http.d.ts +22 -0
  98. package/dist/server/http.js +58 -0
  99. package/dist/server/live.js +4 -14
  100. package/dist/server/mutation-key.d.ts +70 -0
  101. package/dist/server/mutation-key.js +142 -0
  102. package/dist/server/pages.js +12 -9
  103. package/dist/server/people-tokens.js +240 -20
  104. package/dist/server/remote.d.ts +2 -0
  105. package/dist/server/remote.js +19 -4
  106. package/dist/server/render-new-task.js +5 -1
  107. package/dist/server/render-pages.d.ts +2 -1
  108. package/dist/server/render-pages.js +1 -1
  109. package/dist/server/render-people.d.ts +36 -0
  110. package/dist/server/render-people.js +65 -1
  111. package/dist/server/render-projects.js +4 -2
  112. package/dist/server/render-tasks.d.ts +12 -0
  113. package/dist/server/render-tasks.js +16 -6
  114. package/dist/server/request-context.d.ts +6 -0
  115. package/dist/server/route-table.d.ts +16 -0
  116. package/dist/server/route-table.js +121 -0
  117. package/dist/server/runtime.d.ts +6 -4
  118. package/dist/server/session.d.ts +31 -1
  119. package/dist/server/session.js +12 -2
  120. package/dist/server/settings.js +63 -8
  121. package/dist/server/task-views.js +10 -1
  122. package/dist/server/tasks.d.ts +10 -0
  123. package/dist/server/tasks.js +59 -9
  124. package/dist/server/terminals.js +15 -2
  125. package/dist/server/welcome.d.ts +22 -16
  126. package/dist/server/welcome.js +150 -52
  127. package/dist/settings-groups-ui.d.ts +7 -1
  128. package/dist/settings-groups-ui.js +23 -2
  129. package/dist/settings-proofs.js +1 -0
  130. package/dist/setup-guide.d.ts +2 -2
  131. package/dist/setup-guide.js +6 -0
  132. package/dist/store.d.ts +124 -1
  133. package/dist/store.js +245 -12
  134. package/dist/surface.d.ts +10 -0
  135. package/dist/surface.js +40 -1
  136. package/dist/task-text.d.ts +6 -0
  137. package/dist/task-text.js +17 -0
  138. package/dist/teardown-git.js +16 -1
  139. package/dist/telegram-lead.js +2 -0
  140. package/dist/terminal-text.d.ts +11 -0
  141. package/dist/terminal-text.js +26 -0
  142. package/dist/toolroll-update.d.ts +8 -1
  143. package/dist/toolroll-update.js +151 -4
  144. package/dist/tui-contract.d.ts +118 -0
  145. package/dist/tui-contract.js +9 -0
  146. package/dist/tui-source.d.ts +14 -0
  147. package/dist/tui-source.js +182 -0
  148. package/dist/tui.js +129 -0
  149. package/dist/up-processes.d.ts +13 -1
  150. package/dist/up-processes.js +13 -3
  151. package/dist/welcome-facts.d.ts +18 -0
  152. package/dist/welcome-facts.js +79 -0
  153. package/dist/youiyoux-intake.js +11 -1
  154. package/package.json +4 -2
@@ -0,0 +1,182 @@
1
+ /**
2
+ * The terminal UI's view of this installation (tui-contract.ts TuiSource), in this process.
3
+ *
4
+ * Reads come straight from the database through a read-only handle (the task list and a task's own envelopes through
5
+ * `runOperate`, live output through peek's tail reader, the store's wake sequence as the change signal). Every write
6
+ * goes through `runOperate` inside runAsLocalOwner: the same commands, rows and refusals as the CLI, bound to local
7
+ * mode when each command opens the database, never to anything the screen says. Every command runs with --json, so
8
+ * nothing ever prompts on the terminal the screen owns.
9
+ */
10
+ import { dirname, join } from "node:path";
11
+ import { assignmentOf } from "./assignment.js";
12
+ import { runAsLocalOwner } from "./local-owner.js";
13
+ import { snapshotLiveRuns } from "./peek-cli.js";
14
+ import { loadProjectRegistry } from "./repos.js";
15
+ import { describeScope } from "./scope.js";
16
+ import { localModeOf, openStoreReadOnly } from "./store.js";
17
+ import { terminalText } from "./terminal-text.js";
18
+ import { welcomeHere, welcomeLines } from "./welcome-facts.js";
19
+ const record = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
20
+ const words = (value, fallback = "") => typeof value === "string" ? value : fallback;
21
+ /** Text for the screen: whatever wrote it (an agent, a person, a project's name), escapes and controls never reach the
22
+ * terminal (terminal-text.ts). Every displayed string below goes through here; ids and digests are only acted on. */
23
+ const shown = (value, fallback = "") => terminalText(words(value, fallback));
24
+ /** What a refused write says, and whether it is a local-owner refusal (the screen then leads to a password). */
25
+ function refusalOf(envelope) {
26
+ const message = shown(envelope.message, "That was refused.");
27
+ return { ok: false, message, needsPassword: envelope.reason === "refused" || envelope.reason === "machine-proof" || envelope.reason === "person-required" || /password/i.test(message) };
28
+ }
29
+ export function createTuiSource(options) {
30
+ const file = options.databaseFile;
31
+ const clock = options.clock ?? (() => new Date());
32
+ const evidenceRoot = join(dirname(file), "evidence");
33
+ const tails = new Map();
34
+ let reader = null;
35
+ const read = () => {
36
+ reader ??= openStoreReadOnly(file);
37
+ return reader;
38
+ };
39
+ /** One command as the local owner, with --json: its envelope (an unreadable answer reads as a refusal). */
40
+ async function command(argv) {
41
+ const [name = "", ...rest] = argv;
42
+ let out = "";
43
+ const { runOperate } = await import("./operate.js");
44
+ await runAsLocalOwner(() => runOperate(name, [...rest, "--json", "--db", file], text => { out += `${text}\n`; }, options.operate ?? {}));
45
+ try {
46
+ return record(JSON.parse(out.trim()));
47
+ }
48
+ catch {
49
+ const last = out.trim().split("\n").at(-1) ?? "";
50
+ try {
51
+ return record(JSON.parse(last));
52
+ }
53
+ catch {
54
+ return { ok: false, reason: "unreadable", message: "Toolroll's answer couldn't be read." };
55
+ }
56
+ }
57
+ }
58
+ let setupCache = null;
59
+ return {
60
+ async snapshot() {
61
+ const listed = await command(["task", "list"]);
62
+ const tasks = Array.isArray(listed["tasks"]) ? listed["tasks"] : [];
63
+ const rows = tasks.map(one => {
64
+ const row = record(one), status = record(row["status"]);
65
+ const views = Array.isArray(status["views"]) ? status["views"] : [];
66
+ return {
67
+ id: words(row["id"], words(row["rootId"])), title: shown(row["title"]), status: shown(status["label"], words(row["state"])), detail: shown(status["detail"]),
68
+ needsYou: views.includes("needs-you"), liveRunId: typeof row["liveRunId"] === "number" ? row["liveRunId"] : null, repo: typeof row["repo"] === "string" ? row["repo"] : null,
69
+ };
70
+ });
71
+ const waiting = rows.filter(one => one.needsYou);
72
+ const needsYou = waiting.length === 0 ? null : `${waiting.length === 1 ? "1 task needs" : `${waiting.length} tasks need`} you: ${waiting[0].title}`;
73
+ const registry = await loadProjectRegistry(join(dirname(file), "repos.json"));
74
+ const store = read();
75
+ const mode = store === null ? null : localModeOf(store);
76
+ const passwordSet = store !== null && mode !== null && store.accountOf(mode.owner)?.passwordSet === true;
77
+ return { rows, needsYou, projects: "error" in registry ? [] : registry.repos, passwordSet };
78
+ },
79
+ async task(id) {
80
+ const answer = await command(["task", "show", id]);
81
+ if (answer.ok !== true)
82
+ return null;
83
+ const task = record(answer["task"]), work = record(answer["work"]), status = record(work["status"]);
84
+ const store = read();
85
+ const scope = store === null ? null : store.getScope(id);
86
+ const plan = scope === null || scope.approvedDigest === scope.digest ? null : { digest: scope.digest, lines: describeScope(scope).map(line => terminalText(line)) };
87
+ let hasResult = false;
88
+ try {
89
+ hasResult = store !== null && assignmentOf(store, id, clock(), { principal: "operator", repos: null })?.receipt != null;
90
+ }
91
+ catch {
92
+ hasResult = false;
93
+ }
94
+ const decisions = store === null ? [] : store.listDecisions("unanswered").filter(one => one.taskId === id)
95
+ .map(one => ({ id: one.id, question: terminalText(one.question), options: one.options.map(option => ({ id: option.id, label: terminalText(option.label) })) }));
96
+ return {
97
+ id, title: shown(task["title"], id), status: shown(status["label"], words(work["state"])), detail: shown(status["detail"]),
98
+ plan, liveRunId: typeof work["liveRunId"] === "number" ? work["liveRunId"] : null, hasResult, decisions,
99
+ };
100
+ },
101
+ live(id) {
102
+ const store = read();
103
+ if (store === null)
104
+ return [];
105
+ try {
106
+ return snapshotLiveRuns(store, evidenceRoot, clock(), tails).find(one => one.taskId === id)?.lines.map(line => terminalText(line)) ?? [];
107
+ }
108
+ catch {
109
+ return [];
110
+ }
111
+ },
112
+ changed() {
113
+ try {
114
+ return read()?.wakeSeq() ?? 0;
115
+ }
116
+ catch {
117
+ return 0;
118
+ }
119
+ },
120
+ async act(act) {
121
+ let argv;
122
+ let done;
123
+ switch (act.kind) {
124
+ case "new":
125
+ argv = ["task", "add", act.text, ...(act.repo === null ? [] : ["--repo", act.repo])];
126
+ done = "Filed. Its plan will be ready for you to approve.";
127
+ break;
128
+ case "approve":
129
+ argv = ["task", "approve", act.id, "--yes", "--digest", act.digest];
130
+ done = "Approved. An agent starts on it.";
131
+ break;
132
+ case "stop":
133
+ argv = ["task", "stop", act.id, "--run", String(act.runId)];
134
+ done = "Stopping. Its work so far is kept.";
135
+ break;
136
+ case "revise":
137
+ argv = ["task", "revise", act.id, "--feedback", act.text];
138
+ done = "Revision requested.";
139
+ break;
140
+ case "answer":
141
+ argv = ["decide", String(act.decision), "--choose", act.option];
142
+ done = "Answered.";
143
+ break;
144
+ case "complete": {
145
+ const store = read();
146
+ let digest;
147
+ try {
148
+ digest = store === null ? undefined : assignmentOf(store, act.id, clock(), { principal: "operator", repos: null })?.receipt?.digest;
149
+ }
150
+ catch {
151
+ digest = undefined;
152
+ }
153
+ if (digest === undefined)
154
+ return { ok: false, message: "This task has no finished result to mark Complete.", needsPassword: false };
155
+ argv = ["task", "complete", act.id, "--digest", digest];
156
+ done = "Marked Complete.";
157
+ break;
158
+ }
159
+ }
160
+ const answer = await command(argv);
161
+ if (answer.ok !== true)
162
+ return refusalOf(answer);
163
+ const filed = act.kind === "new" ? words(record(answer["task"])["id"], words(answer["id"])) : "";
164
+ return { ok: true, message: done, ...(filed === "" ? {} : { id: filed }) };
165
+ },
166
+ async setup() {
167
+ if (setupCache !== null && Date.now() - setupCache.at < 30_000)
168
+ return setupCache.value;
169
+ const store = read();
170
+ if (store === null)
171
+ return null;
172
+ const here = await welcomeHere(store, file, clock(), options.check === undefined ? {} : { check: options.check });
173
+ const value = here.model.left === 0 ? null : { left: here.model.left, lines: welcomeLines(here.model).map(line => terminalText(line)) };
174
+ setupCache = { at: Date.now(), value };
175
+ return value;
176
+ },
177
+ close() {
178
+ reader?.close();
179
+ reader = null;
180
+ },
181
+ };
182
+ }