@huseynsnmz/pi-suite 0.0.0-stage → 0.1.0

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 (219) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/LICENSE +21 -0
  3. package/README.md +87 -2
  4. package/SECURITY.md +5 -0
  5. package/package.json +113 -4
  6. package/packages/board/CHANGELOG.md +340 -0
  7. package/packages/board/CONTRIBUTING.md +7 -0
  8. package/packages/board/LICENSE +21 -0
  9. package/packages/board/README.md +88 -0
  10. package/packages/board/SECURITY.md +19 -0
  11. package/packages/board/docs/how-it-works.md +31 -0
  12. package/packages/board/docs/reference.md +278 -0
  13. package/packages/board/package.json +83 -0
  14. package/packages/board/runner/job-runner-legacy.mjs +68 -0
  15. package/packages/board/runner/job-runner.mjs +834 -0
  16. package/packages/board/runner/pty-runner-legacy.mjs +50 -0
  17. package/packages/board/runner/pty-runner.mjs +2175 -0
  18. package/packages/board/runner/state-coordinator.mjs +673 -0
  19. package/packages/board/runner/state-runner.mjs +203 -0
  20. package/packages/board/runner/title-runner.mjs +80 -0
  21. package/packages/board/src/commands/agent-board.ts +394 -0
  22. package/packages/board/src/commands/attach-decision.mjs +66 -0
  23. package/packages/board/src/commands/attach-flow.ts +251 -0
  24. package/packages/board/src/commands/bg.ts +103 -0
  25. package/packages/board/src/commands/board-model.ts +21 -0
  26. package/packages/board/src/core/atomic.mjs +184 -0
  27. package/packages/board/src/core/attach-delete.mjs +24 -0
  28. package/packages/board/src/core/attach-frame-proof.mjs +870 -0
  29. package/packages/board/src/core/attach-frame-reporter.mjs +648 -0
  30. package/packages/board/src/core/attach-frame-stream.mjs +266 -0
  31. package/packages/board/src/core/attach-view-proof.mjs +709 -0
  32. package/packages/board/src/core/auto-state.mjs +377 -0
  33. package/packages/board/src/core/background-runs.mjs +273 -0
  34. package/packages/board/src/core/code-refs-store.mjs +315 -0
  35. package/packages/board/src/core/code-refs.mjs +913 -0
  36. package/packages/board/src/core/config.mjs +77 -0
  37. package/packages/board/src/core/control-protocol.mjs +482 -0
  38. package/packages/board/src/core/coordinator-client.mjs +633 -0
  39. package/packages/board/src/core/coordinator-journal.mjs +282 -0
  40. package/packages/board/src/core/coordinator-protocol.mjs +14 -0
  41. package/packages/board/src/core/cwd-stats.mjs +114 -0
  42. package/packages/board/src/core/dashboard-render.mjs +10 -0
  43. package/packages/board/src/core/derive.mjs +117 -0
  44. package/packages/board/src/core/diagnostics.mjs +133 -0
  45. package/packages/board/src/core/double-press.mjs +26 -0
  46. package/packages/board/src/core/editor-state-reporter.mjs +112 -0
  47. package/packages/board/src/core/events.mjs +286 -0
  48. package/packages/board/src/core/evidence.mjs +245 -0
  49. package/packages/board/src/core/follow-up-queue.mjs +211 -0
  50. package/packages/board/src/core/foreground-preview-cache.mjs +117 -0
  51. package/packages/board/src/core/foreground-projection-cache.mjs +99 -0
  52. package/packages/board/src/core/frame-witness-update.mjs +35 -0
  53. package/packages/board/src/core/heuristics.mjs +313 -0
  54. package/packages/board/src/core/hold-input.mjs +27 -0
  55. package/packages/board/src/core/host-coordination.mjs +300 -0
  56. package/packages/board/src/core/host-crash.mjs +79 -0
  57. package/packages/board/src/core/host-probe.mjs +207 -0
  58. package/packages/board/src/core/host-protocol.mjs +73 -0
  59. package/packages/board/src/core/ids.mjs +35 -0
  60. package/packages/board/src/core/ime-cursor-coalesce.mjs +193 -0
  61. package/packages/board/src/core/invocation.mjs +43 -0
  62. package/packages/board/src/core/launch-options.mjs +418 -0
  63. package/packages/board/src/core/launch.mjs +157 -0
  64. package/packages/board/src/core/load-config.mjs +4 -0
  65. package/packages/board/src/core/locks.mjs +530 -0
  66. package/packages/board/src/core/paths.mjs +183 -0
  67. package/packages/board/src/core/pid.mjs +75 -0
  68. package/packages/board/src/core/prewarm-schedule.mjs +41 -0
  69. package/packages/board/src/core/process-identity-probe.mjs +228 -0
  70. package/packages/board/src/core/prompt-transport.mjs +13 -0
  71. package/packages/board/src/core/pty-attach-jiggle-controller.mjs +356 -0
  72. package/packages/board/src/core/pty-attach-jiggle-retry.mjs +109 -0
  73. package/packages/board/src/core/pty-attach-reconnect.mjs +61 -0
  74. package/packages/board/src/core/pty-attach-render.mjs +229 -0
  75. package/packages/board/src/core/pty-links.mjs +81 -0
  76. package/packages/board/src/core/pty-scroll.mjs +522 -0
  77. package/packages/board/src/core/pty-support.mjs +327 -0
  78. package/packages/board/src/core/repo.mjs +103 -0
  79. package/packages/board/src/core/rows.mjs +398 -0
  80. package/packages/board/src/core/screen-log-gc.mjs +198 -0
  81. package/packages/board/src/core/screen-log.mjs +160 -0
  82. package/packages/board/src/core/session-view.mjs +174 -0
  83. package/packages/board/src/core/slash-commands.mjs +52 -0
  84. package/packages/board/src/core/state-commands.mjs +757 -0
  85. package/packages/board/src/core/status-consistency.mjs +98 -0
  86. package/packages/board/src/core/steering-prompts.mjs +34 -0
  87. package/packages/board/src/core/steering.mjs +133 -0
  88. package/packages/board/src/core/stop-latch.mjs +41 -0
  89. package/packages/board/src/core/store.mjs +523 -0
  90. package/packages/board/src/core/suspend.mjs +36 -0
  91. package/packages/board/src/core/terminal-attach-client.mjs +981 -0
  92. package/packages/board/src/core/terminal-attach-protocol.mjs +460 -0
  93. package/packages/board/src/core/terminal-model.mjs +222 -0
  94. package/packages/board/src/core/terminal-query-sequences.mjs +239 -0
  95. package/packages/board/src/core/terminal-reply-guard.mjs +222 -0
  96. package/packages/board/src/core/terminal-snapshot.mjs +440 -0
  97. package/packages/board/src/core/test-knobs.mjs +28 -0
  98. package/packages/board/src/core/title.mjs +43 -0
  99. package/packages/board/src/core/types.mjs +414 -0
  100. package/packages/board/src/core/warm-host-sweeper.mjs +168 -0
  101. package/packages/board/src/core/worktree.mjs +65 -0
  102. package/packages/board/src/index.ts +303 -0
  103. package/packages/board/src/runtime/service.mjs +3222 -0
  104. package/packages/board/src/ui/chrome.ts +20 -0
  105. package/packages/board/src/ui/dashboard-decisions.mjs +55 -0
  106. package/packages/board/src/ui/dashboard-evidence.mjs +85 -0
  107. package/packages/board/src/ui/dashboard.ts +2221 -0
  108. package/packages/board/src/ui/double-left.ts +30 -0
  109. package/packages/board/src/ui/external-editor.ts +25 -0
  110. package/packages/board/src/ui/focus.ts +32 -0
  111. package/packages/board/src/ui/pty-attach.ts +3184 -0
  112. package/packages/board/src/ui/waiting.ts +30 -0
  113. package/packages/frame/CHANGELOG.md +113 -0
  114. package/packages/frame/CONTRIBUTING.md +7 -0
  115. package/packages/frame/LICENSE +22 -0
  116. package/packages/frame/README.md +105 -0
  117. package/packages/frame/SECURITY.md +16 -0
  118. package/packages/frame/docs/how-it-works.md +53 -0
  119. package/packages/frame/docs/reference.md +78 -0
  120. package/packages/frame/package.json +75 -0
  121. package/packages/frame/src/data/git.ts +90 -0
  122. package/packages/frame/src/data/github.ts +140 -0
  123. package/packages/frame/src/data/gitlab.ts +63 -0
  124. package/packages/frame/src/data/mode.ts +23 -0
  125. package/packages/frame/src/data/past-prompts.ts +57 -0
  126. package/packages/frame/src/data/runner.ts +32 -0
  127. package/packages/frame/src/data/snapshot.ts +223 -0
  128. package/packages/frame/src/data/start-notes.ts +104 -0
  129. package/packages/frame/src/data/telemetry.ts +337 -0
  130. package/packages/frame/src/data/todos.ts +162 -0
  131. package/packages/frame/src/data/totals.ts +94 -0
  132. package/packages/frame/src/data/visits.ts +45 -0
  133. package/packages/frame/src/index.ts +676 -0
  134. package/packages/frame/src/render/diff.ts +104 -0
  135. package/packages/frame/src/render/fit.ts +86 -0
  136. package/packages/frame/src/render/format.ts +108 -0
  137. package/packages/frame/src/render/frame.ts +106 -0
  138. package/packages/frame/src/render/glyphs.ts +189 -0
  139. package/packages/frame/src/render/keys.ts +43 -0
  140. package/packages/frame/src/render/lead.ts +37 -0
  141. package/packages/frame/src/render/paint.ts +135 -0
  142. package/packages/frame/src/render/safe.ts +19 -0
  143. package/packages/frame/src/render/segments.ts +735 -0
  144. package/packages/frame/src/render/streaming.ts +223 -0
  145. package/packages/frame/src/render/timing.ts +106 -0
  146. package/packages/frame/src/render/tools.ts +167 -0
  147. package/packages/frame/src/settings.ts +105 -0
  148. package/packages/frame/src/ui/editor.ts +272 -0
  149. package/packages/frame/src/ui/effort.ts +36 -0
  150. package/packages/frame/src/ui/footer.ts +165 -0
  151. package/packages/frame/src/ui/header.ts +362 -0
  152. package/packages/frame/src/ui/history-search.ts +23 -0
  153. package/packages/frame/src/ui/interrupt.ts +21 -0
  154. package/packages/frame/src/ui/outputs.ts +170 -0
  155. package/packages/frame/src/ui/pi-entries.ts +276 -0
  156. package/packages/frame/src/ui/previews.ts +72 -0
  157. package/packages/frame/src/ui/queue.ts +75 -0
  158. package/packages/frame/src/ui/screen.ts +59 -0
  159. package/packages/frame/src/ui/timings.ts +48 -0
  160. package/packages/frame/src/ui/todos.ts +205 -0
  161. package/packages/frame/src/ui/tool-frame.ts +595 -0
  162. package/packages/frame/src/ui/working.ts +25 -0
  163. package/packages/frame/src/view/state.ts +97 -0
  164. package/packages/frame/src/view/transcript.ts +175 -0
  165. package/packages/frame/src/view/view.ts +162 -0
  166. package/packages/memory/CONTRIBUTING.md +7 -0
  167. package/packages/memory/LICENSE +21 -0
  168. package/packages/memory/README.md +44 -0
  169. package/packages/memory/SECURITY.md +20 -0
  170. package/packages/memory/package.json +55 -0
  171. package/packages/memory/skills/review-memory/SKILL.md +48 -0
  172. package/packages/memory/src/index.ts +163 -0
  173. package/packages/memory/src/prompt.ts +25 -0
  174. package/packages/memory/src/review.ts +150 -0
  175. package/packages/memory/src/secrets.ts +22 -0
  176. package/packages/memory/src/store.ts +173 -0
  177. package/packages/modes/CHANGELOG.md +104 -0
  178. package/packages/modes/CONTRIBUTING.md +7 -0
  179. package/packages/modes/LICENSE +21 -0
  180. package/packages/modes/README.md +174 -0
  181. package/packages/modes/SECURITY.md +17 -0
  182. package/packages/modes/package.json +55 -0
  183. package/packages/modes/skills/review-permissions/SKILL.md +54 -0
  184. package/packages/modes/src/bash.ts +218 -0
  185. package/packages/modes/src/deny-off.ts +62 -0
  186. package/packages/modes/src/git-safety.ts +72 -0
  187. package/packages/modes/src/index.ts +338 -0
  188. package/packages/modes/src/interview.ts +206 -0
  189. package/packages/modes/src/judge-gate.ts +113 -0
  190. package/packages/modes/src/modes.ts +121 -0
  191. package/packages/modes/src/review/apply.mjs +156 -0
  192. package/packages/modes/src/review/collect.mjs +208 -0
  193. package/packages/modes/src/review/tools.ts +71 -0
  194. package/packages/modes/src/sandbox.ts +37 -0
  195. package/packages/router/CHANGELOG.md +8 -0
  196. package/packages/router/LICENSE +21 -0
  197. package/packages/router/README.md +90 -0
  198. package/packages/router/package.json +51 -0
  199. package/packages/router/src/config.ts +65 -0
  200. package/packages/router/src/index.ts +172 -0
  201. package/packages/router/src/judge.ts +51 -0
  202. package/packages/router/src/route.ts +67 -0
  203. package/packages/web/CHANGELOG.md +36 -0
  204. package/packages/web/LICENSE +21 -0
  205. package/packages/web/README.md +87 -0
  206. package/packages/web/SECURITY.md +13 -0
  207. package/packages/web/package.json +61 -0
  208. package/packages/web/src/config.ts +109 -0
  209. package/packages/web/src/dnsfilter.ts +97 -0
  210. package/packages/web/src/extract.ts +65 -0
  211. package/packages/web/src/index.ts +217 -0
  212. package/packages/web/src/net.ts +109 -0
  213. package/packages/web/src/reader.ts +73 -0
  214. package/packages/web/src/sanitize.ts +50 -0
  215. package/packages/web/src/search.ts +76 -0
  216. package/packages/web/src/secrets.ts +22 -0
  217. package/packages/web/src/validate.ts +186 -0
  218. package/src/index.ts +156 -0
  219. package/src/settings.ts +78 -0
@@ -0,0 +1,205 @@
1
+ // The agent's checklist: the `todo` tool, a panel above the editor and `/todos`.
2
+ import { CUT, entryFrame, type FeatureScope } from "@adeildo/pi-kit";
3
+ import type { ExtensionContext, Theme } from "@earendil-works/pi-coding-agent";
4
+ import { type Component, Text, type TUI, truncateToWidth } from "@earendil-works/pi-tui";
5
+ import { Type } from "typebox";
6
+
7
+ import {
8
+ changedTodos,
9
+ doneCount,
10
+ hasOpenTodos,
11
+ NO_TODOS,
12
+ type Todo,
13
+ TODO_ENTRY,
14
+ type TodoChange,
15
+ type TodoList,
16
+ todosOnBranch,
17
+ type TodoStatus,
18
+ todoSummary,
19
+ todoText,
20
+ withTodoReminder,
21
+ } from "../data/todos.ts";
22
+ import type { IconSet } from "../render/glyphs.ts";
23
+
24
+ const WIDGET = "pi-frame:todos";
25
+ const MOST_ROWS = 6;
26
+
27
+ export function registerTodos(scope: FeatureScope, set: () => IconSet): void {
28
+ let list = NO_TODOS;
29
+ let ctx: ExtensionContext | undefined;
30
+ let tui: TUI | undefined;
31
+
32
+ const adopt = (next: TodoList) => {
33
+ list = next;
34
+ tui?.requestRender();
35
+ };
36
+ const save = (next: TodoList) => {
37
+ if (next === list) return;
38
+ scope.appendEntry<TodoList>(TODO_ENTRY, next);
39
+ adopt(next);
40
+ };
41
+
42
+ scope.registerTool({
43
+ name: "todo",
44
+ label: "Todo",
45
+ description:
46
+ "Your checklist for work with several steps, which the user sees above the editor. Every call answers with the whole list. No arguments reads it.",
47
+ promptSnippet: "Keep a checklist of multi-step work",
48
+ promptGuidelines: [
49
+ "Use `todo` for work of 3 or more steps, or when given several tasks. Skip it for one quick step or a question.",
50
+ "Use `todo` in one call per step: {plan:[...], start:1} to begin, then {done:[1], start:2}. One item is active at a time.",
51
+ "Mark a `todo` item done only when it is finished and checked. If tests fail or it's partial, leave it active and add what blocks it.",
52
+ ],
53
+ parameters: Type.Object({
54
+ plan: Type.Optional(Type.Array(Type.String(), { description: "Replace the whole list" })),
55
+ add: Type.Optional(Type.Array(Type.String(), { description: "Add to the end" })),
56
+ drop: Type.Optional(Type.Array(Type.Integer(), { description: "Remove these ids" })),
57
+ done: Type.Optional(Type.Array(Type.Integer(), { description: "Mark these ids finished" })),
58
+ start: Type.Optional(Type.Integer({ description: "Work on this id now" })),
59
+ }),
60
+ async execute(_id, params) {
61
+ const reading = Object.values(params).every((value) => value === undefined);
62
+ if (!reading) save(changedTodos(list, params as TodoChange));
63
+ return {
64
+ content: [{ type: "text", text: todoText(list) }],
65
+ details: { summary: todoSummary(list) },
66
+ };
67
+ },
68
+ renderResult(result, options, theme, context) {
69
+ const block = result.content[0];
70
+ const text = block?.type === "text" ? block.text : "";
71
+ const summary = (result.details as { summary?: unknown } | undefined)?.summary;
72
+ const shown = options.expanded || context.isError || typeof summary !== "string" ? text : summary;
73
+ return new Text(theme.fg(context.isError ? "error" : "toolOutput", shown), 0, 0);
74
+ },
75
+ });
76
+
77
+ scope.registerCommand("todos", {
78
+ description: "Show the agent's todo list, or `/todos clear` to empty it",
79
+ getArgumentCompletions: (prefix) => {
80
+ const typed = prefix.trim().toLowerCase();
81
+ return "clear".startsWith(typed) && typed !== "clear" ? [{ value: "clear", label: "clear" }] : null;
82
+ },
83
+ handler: async (args, command) => {
84
+ const asked = args.trim().toLowerCase();
85
+ if (asked === "clear") {
86
+ if (list.items.length === 0) return;
87
+ save(NO_TODOS);
88
+ // Its last answer still shows the old list.
89
+ scope.sendMessage(
90
+ { customType: TODO_ENTRY, content: "The user emptied your todo list.", display: false },
91
+ { deliverAs: command.isIdle() ? "nextTurn" : "steer" },
92
+ );
93
+ command.ui.notify("Todo list emptied.", "info");
94
+ } else if (asked === "") {
95
+ command.ui.notify(todoText(list), "info");
96
+ } else {
97
+ command.ui.notify(`Unknown argument "${asked}". Use /todos or /todos clear.`, "error");
98
+ }
99
+ },
100
+ });
101
+
102
+ // A new session or another branch has its own list.
103
+ scope.onSessionStart((started) => {
104
+ ctx = started;
105
+ list = todosOnBranch(started.sessionManager.getBranch());
106
+ if (started.mode !== "tui") return;
107
+ started.ui.setWidget(
108
+ WIDGET,
109
+ (widgetTui, theme) => {
110
+ tui = widgetTui;
111
+ return {
112
+ render: (width) =>
113
+ todoPanel(list, width, {
114
+ theme: ctx?.ui.theme ?? theme,
115
+ set: set(),
116
+ rows: panelRows(widgetTui.terminal.rows),
117
+ all: ctx?.ui.getToolsExpanded() === true,
118
+ }),
119
+ invalidate: () => {},
120
+ } satisfies Component;
121
+ },
122
+ { placement: "aboveEditor" },
123
+ );
124
+ });
125
+ scope.on("session_tree", (_event, tree) => adopt(todosOnBranch(tree.sessionManager.getBranch())));
126
+ scope.onShutdown(() => {
127
+ if (ctx?.mode === "tui") ctx.ui.setWidget(WIDGET, undefined);
128
+ ctx = undefined;
129
+ tui = undefined;
130
+ });
131
+
132
+ // Only your next prompt starts this: a retry mustn't take the list away. The next task starts clean.
133
+ scope.on("before_agent_start", () => {
134
+ if (list.items.length > 0 && !hasOpenTodos(list)) save(NO_TODOS);
135
+ });
136
+
137
+ scope.on("context", (event) => {
138
+ const messages = withTodoReminder(
139
+ event.messages as ({ role: string; toolName?: string; isError?: boolean } & (typeof event.messages)[number])[],
140
+ list,
141
+ (text) =>
142
+ ({
143
+ role: "custom",
144
+ customType: TODO_ENTRY,
145
+ content: text,
146
+ display: false,
147
+ timestamp: 0,
148
+ }) as never,
149
+ );
150
+ return messages === undefined ? undefined : { messages };
151
+ });
152
+ }
153
+
154
+ function panelRows(terminalRows: number): number {
155
+ return Math.max(2, Math.min(MOST_ROWS, Math.floor(terminalRows / 4)));
156
+ }
157
+
158
+ const STATUS_MARKS: Record<"plain" | "ascii", Record<TodoStatus, string>> = {
159
+ plain: { open: "○", active: "▸", done: "✓" },
160
+ ascii: { open: "-", active: ">", done: "x" },
161
+ };
162
+
163
+ /** What's still to do comes first, starting with the active item, then the latest finished. */
164
+ function shownItems(list: TodoList, rows: number): Set<Todo> {
165
+ const active = list.items.filter((item) => item.status === "active");
166
+ const open = list.items.filter((item) => item.status === "open");
167
+ const done = list.items.filter((item) => item.status === "done");
168
+ const kept = [...active, ...open].slice(0, rows);
169
+ return new Set([...kept, ...done.slice(Math.max(0, done.length - (rows - kept.length)))]);
170
+ }
171
+
172
+ export interface TodoPanel {
173
+ theme: Theme;
174
+ set: IconSet;
175
+ rows: number;
176
+ all: boolean;
177
+ }
178
+
179
+ /** Empty draws nothing. The count is always over the whole list, whatever is cut from the rows. */
180
+ export function todoPanel(list: TodoList, width: number, panel: TodoPanel): string[] {
181
+ if (list.items.length === 0) return [];
182
+ const { theme } = panel;
183
+ const marks = STATUS_MARKS[panel.set === "ascii" ? "ascii" : "plain"];
184
+ const shown = panel.all ? new Set(list.items) : shownItems(list, panel.rows);
185
+ const room = Math.max(1, width - 6);
186
+ const rows = list.items
187
+ .filter((item) => shown.has(item))
188
+ .map((item) => {
189
+ const text = truncateToWidth(item.text, room, CUT);
190
+ if (item.status === "done") return theme.fg("dim", `${marks.done} ${text}`);
191
+ if (item.status === "active")
192
+ return theme.fg("accent", `${marks.active} ${theme.bold(text)}`);
193
+ return `${theme.fg("muted", marks.open)} ${theme.fg("text", text)}`;
194
+ });
195
+ const hiddenDone = list.items.filter((item) => item.status === "done" && !shown.has(item)).length;
196
+ const hiddenOpen = list.items.length - shown.size - hiddenDone;
197
+ const hidden = [hiddenDone > 0 && `+${hiddenDone} done`, hiddenOpen > 0 && `+${hiddenOpen} more`]
198
+ .filter(Boolean)
199
+ .join(", ");
200
+ return entryFrame(rows, width, theme, {
201
+ top: theme.fg("dim", `todo ${doneCount(list)}/${list.items.length}`),
202
+ ...(hidden === "" ? {} : { bottom: theme.fg("dim", hidden) }),
203
+ color: "borderMuted",
204
+ });
205
+ }