pi-mono-all 1.0.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 (161) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/LICENCE.md +7 -0
  3. package/node_modules/pi-common/package.json +22 -0
  4. package/node_modules/pi-common/src/auth-config.ts +290 -0
  5. package/node_modules/pi-common/src/auth.ts +63 -0
  6. package/node_modules/pi-common/src/cache.ts +60 -0
  7. package/node_modules/pi-common/src/errors.ts +47 -0
  8. package/node_modules/pi-common/src/http-client.ts +118 -0
  9. package/node_modules/pi-common/src/index.ts +7 -0
  10. package/node_modules/pi-common/src/rate-limiter.ts +32 -0
  11. package/node_modules/pi-common/src/tool-result.ts +27 -0
  12. package/node_modules/pi-mono-ask-user-question/CHANGELOG.md +185 -0
  13. package/node_modules/pi-mono-ask-user-question/README.md +226 -0
  14. package/node_modules/pi-mono-ask-user-question/index.ts +923 -0
  15. package/node_modules/pi-mono-ask-user-question/package.json +29 -0
  16. package/node_modules/pi-mono-auto-fix/CHANGELOG.md +59 -0
  17. package/node_modules/pi-mono-auto-fix/README.md +77 -0
  18. package/node_modules/pi-mono-auto-fix/index.ts +488 -0
  19. package/node_modules/pi-mono-auto-fix/package.json +23 -0
  20. package/node_modules/pi-mono-btw/CHANGELOG.md +180 -0
  21. package/node_modules/pi-mono-btw/README.md +24 -0
  22. package/node_modules/pi-mono-btw/index.ts +499 -0
  23. package/node_modules/pi-mono-btw/package.json +29 -0
  24. package/node_modules/pi-mono-clear/CHANGELOG.md +180 -0
  25. package/node_modules/pi-mono-clear/README.md +40 -0
  26. package/node_modules/pi-mono-clear/index.ts +45 -0
  27. package/node_modules/pi-mono-clear/package.json +29 -0
  28. package/node_modules/pi-mono-context/CHANGELOG.md +12 -0
  29. package/node_modules/pi-mono-context/README.md +74 -0
  30. package/node_modules/pi-mono-context/index.ts +641 -0
  31. package/node_modules/pi-mono-context/package.json +29 -0
  32. package/node_modules/pi-mono-context-guard/CHANGELOG.md +195 -0
  33. package/node_modules/pi-mono-context-guard/README.md +81 -0
  34. package/node_modules/pi-mono-context-guard/index.ts +212 -0
  35. package/node_modules/pi-mono-context-guard/package.json +23 -0
  36. package/node_modules/pi-mono-figma/CHANGELOG.md +59 -0
  37. package/node_modules/pi-mono-figma/README.md +236 -0
  38. package/node_modules/pi-mono-figma/__tests__/code-connect.test.ts +32 -0
  39. package/node_modules/pi-mono-figma/__tests__/figma-assets.test.ts +38 -0
  40. package/node_modules/pi-mono-figma/__tests__/figma-component-hints.test.ts +23 -0
  41. package/node_modules/pi-mono-figma/__tests__/figma-implementation-layout.test.ts +47 -0
  42. package/node_modules/pi-mono-figma/__tests__/figma-search.test.ts +51 -0
  43. package/node_modules/pi-mono-figma/__tests__/figma-summarizer.test.ts +65 -0
  44. package/node_modules/pi-mono-figma/__tests__/fixtures/complex-auto-layout.json +115 -0
  45. package/node_modules/pi-mono-figma/__tests__/fixtures/component-instance.json +50 -0
  46. package/node_modules/pi-mono-figma/__tests__/fixtures/hidden-and-vectors.json +28 -0
  47. package/node_modules/pi-mono-figma/__tests__/fixtures/variables-and-styles.json +40 -0
  48. package/node_modules/pi-mono-figma/docs/live-selection-bridge.md +16 -0
  49. package/node_modules/pi-mono-figma/index.ts +6 -0
  50. package/node_modules/pi-mono-figma/package.json +33 -0
  51. package/node_modules/pi-mono-figma/skills/figma/SKILL.md +143 -0
  52. package/node_modules/pi-mono-figma/src/code-connect.ts +110 -0
  53. package/node_modules/pi-mono-figma/src/figma-assets.ts +146 -0
  54. package/node_modules/pi-mono-figma/src/figma-cache.ts +6 -0
  55. package/node_modules/pi-mono-figma/src/figma-client.ts +471 -0
  56. package/node_modules/pi-mono-figma/src/figma-component-hints.ts +87 -0
  57. package/node_modules/pi-mono-figma/src/figma-implementation.ts +264 -0
  58. package/node_modules/pi-mono-figma/src/figma-schemas.ts +139 -0
  59. package/node_modules/pi-mono-figma/src/figma-search.ts +195 -0
  60. package/node_modules/pi-mono-figma/src/figma-summarizer.ts +673 -0
  61. package/node_modules/pi-mono-figma/src/figma-tokens.ts +57 -0
  62. package/node_modules/pi-mono-figma/src/figma-tools.ts +352 -0
  63. package/node_modules/pi-mono-linear/CHANGELOG.md +44 -0
  64. package/node_modules/pi-mono-linear/README.md +159 -0
  65. package/node_modules/pi-mono-linear/index.ts +6 -0
  66. package/node_modules/pi-mono-linear/package.json +30 -0
  67. package/node_modules/pi-mono-linear/skills/linear/SKILL.md +107 -0
  68. package/node_modules/pi-mono-linear/src/linear-client.ts +339 -0
  69. package/node_modules/pi-mono-linear/src/linear-queries.ts +101 -0
  70. package/node_modules/pi-mono-linear/src/linear-schemas.ts +90 -0
  71. package/node_modules/pi-mono-linear/src/linear-tools.ts +362 -0
  72. package/node_modules/pi-mono-loop/CHANGELOG.md +163 -0
  73. package/node_modules/pi-mono-loop/README.md +54 -0
  74. package/node_modules/pi-mono-loop/index.ts +291 -0
  75. package/node_modules/pi-mono-loop/package.json +26 -0
  76. package/node_modules/pi-mono-multi-edit/CHANGELOG.md +232 -0
  77. package/node_modules/pi-mono-multi-edit/README.md +244 -0
  78. package/node_modules/pi-mono-multi-edit/__tests__/classic.test.ts +277 -0
  79. package/node_modules/pi-mono-multi-edit/__tests__/diff.test.ts +77 -0
  80. package/node_modules/pi-mono-multi-edit/__tests__/patch.test.ts +287 -0
  81. package/node_modules/pi-mono-multi-edit/benchmark-edits.ts +966 -0
  82. package/node_modules/pi-mono-multi-edit/classic.ts +435 -0
  83. package/node_modules/pi-mono-multi-edit/diff.ts +143 -0
  84. package/node_modules/pi-mono-multi-edit/index.ts +266 -0
  85. package/node_modules/pi-mono-multi-edit/package.json +37 -0
  86. package/node_modules/pi-mono-multi-edit/patch.ts +463 -0
  87. package/node_modules/pi-mono-multi-edit/types.ts +53 -0
  88. package/node_modules/pi-mono-multi-edit/workspace.ts +85 -0
  89. package/node_modules/pi-mono-review/CHANGELOG.md +190 -0
  90. package/node_modules/pi-mono-review/README.md +30 -0
  91. package/node_modules/pi-mono-review/common.ts +930 -0
  92. package/node_modules/pi-mono-review/index.ts +8 -0
  93. package/node_modules/pi-mono-review/package.json +29 -0
  94. package/node_modules/pi-mono-review/review-tui.ts +194 -0
  95. package/node_modules/pi-mono-review/review.ts +119 -0
  96. package/node_modules/pi-mono-review/reviewer.ts +339 -0
  97. package/node_modules/pi-mono-sentinel/CHANGELOG.md +158 -0
  98. package/node_modules/pi-mono-sentinel/README.md +87 -0
  99. package/node_modules/pi-mono-sentinel/__tests__/output-scanner.test.ts +109 -0
  100. package/node_modules/pi-mono-sentinel/__tests__/permissions.test.ts +202 -0
  101. package/node_modules/pi-mono-sentinel/__tests__/whitelist.test.ts +59 -0
  102. package/node_modules/pi-mono-sentinel/guards/execution-tracker.ts +281 -0
  103. package/node_modules/pi-mono-sentinel/guards/output-scanner.ts +232 -0
  104. package/node_modules/pi-mono-sentinel/guards/permission-gate.ts +170 -0
  105. package/node_modules/pi-mono-sentinel/index.ts +43 -0
  106. package/node_modules/pi-mono-sentinel/package.json +26 -0
  107. package/node_modules/pi-mono-sentinel/patterns/permissions.ts +175 -0
  108. package/node_modules/pi-mono-sentinel/patterns/read-targets.ts +104 -0
  109. package/node_modules/pi-mono-sentinel/patterns/secrets.ts +143 -0
  110. package/node_modules/pi-mono-sentinel/session.ts +95 -0
  111. package/node_modules/pi-mono-sentinel/specs/2026/04/sentinel/001-permission-gate.md +145 -0
  112. package/node_modules/pi-mono-sentinel/types.ts +39 -0
  113. package/node_modules/pi-mono-sentinel/whitelist.ts +86 -0
  114. package/node_modules/pi-mono-simplify/CHANGELOG.md +163 -0
  115. package/node_modules/pi-mono-simplify/README.md +56 -0
  116. package/node_modules/pi-mono-simplify/index.ts +78 -0
  117. package/node_modules/pi-mono-simplify/package.json +29 -0
  118. package/node_modules/pi-mono-status-line/CHANGELOG.md +180 -0
  119. package/node_modules/pi-mono-status-line/README.md +96 -0
  120. package/node_modules/pi-mono-status-line/basic.ts +89 -0
  121. package/node_modules/pi-mono-status-line/expert.ts +689 -0
  122. package/node_modules/pi-mono-status-line/index.ts +54 -0
  123. package/node_modules/pi-mono-status-line/package.json +29 -0
  124. package/node_modules/pi-mono-team-mode/CHANGELOG.md +278 -0
  125. package/node_modules/pi-mono-team-mode/README.md +246 -0
  126. package/node_modules/pi-mono-team-mode/__tests__/agent-manager-transient.test.ts +75 -0
  127. package/node_modules/pi-mono-team-mode/__tests__/delegation-manager.test.ts +118 -0
  128. package/node_modules/pi-mono-team-mode/__tests__/formatters.test.ts +104 -0
  129. package/node_modules/pi-mono-team-mode/__tests__/model-config.test.ts +272 -0
  130. package/node_modules/pi-mono-team-mode/__tests__/notification-box.test.ts +34 -0
  131. package/node_modules/pi-mono-team-mode/__tests__/parallel-utils.test.ts +32 -0
  132. package/node_modules/pi-mono-team-mode/__tests__/pi-stream-parser.test.ts +64 -0
  133. package/node_modules/pi-mono-team-mode/__tests__/prompts.test.ts +106 -0
  134. package/node_modules/pi-mono-team-mode/__tests__/store.test.ts +164 -0
  135. package/node_modules/pi-mono-team-mode/__tests__/tasks.test.ts +267 -0
  136. package/node_modules/pi-mono-team-mode/__tests__/teammate-specs.test.ts +114 -0
  137. package/node_modules/pi-mono-team-mode/__tests__/widget.test.ts +41 -0
  138. package/node_modules/pi-mono-team-mode/__tests__/worktree.test.ts +78 -0
  139. package/node_modules/pi-mono-team-mode/core/chain-utils.ts +90 -0
  140. package/node_modules/pi-mono-team-mode/core/fs-utils.ts +44 -0
  141. package/node_modules/pi-mono-team-mode/core/model-config.ts +432 -0
  142. package/node_modules/pi-mono-team-mode/core/parallel-utils.ts +48 -0
  143. package/node_modules/pi-mono-team-mode/core/prompts.ts +158 -0
  144. package/node_modules/pi-mono-team-mode/core/store.ts +156 -0
  145. package/node_modules/pi-mono-team-mode/core/tasks.ts +99 -0
  146. package/node_modules/pi-mono-team-mode/core/teammate-specs.ts +124 -0
  147. package/node_modules/pi-mono-team-mode/core/types.ts +160 -0
  148. package/node_modules/pi-mono-team-mode/index.ts +825 -0
  149. package/node_modules/pi-mono-team-mode/managers/agent-manager.ts +654 -0
  150. package/node_modules/pi-mono-team-mode/managers/delegation-manager.ts +211 -0
  151. package/node_modules/pi-mono-team-mode/managers/task-manager.ts +238 -0
  152. package/node_modules/pi-mono-team-mode/managers/team-manager.ts +59 -0
  153. package/node_modules/pi-mono-team-mode/package.json +33 -0
  154. package/node_modules/pi-mono-team-mode/runtime/pi-stream-parser.ts +194 -0
  155. package/node_modules/pi-mono-team-mode/runtime/subprocess.ts +183 -0
  156. package/node_modules/pi-mono-team-mode/runtime/transient-session.ts +196 -0
  157. package/node_modules/pi-mono-team-mode/runtime/worktree.ts +90 -0
  158. package/node_modules/pi-mono-team-mode/ui/formatters.ts +149 -0
  159. package/node_modules/pi-mono-team-mode/ui/notification-box.ts +55 -0
  160. package/node_modules/pi-mono-team-mode/ui/widget.ts +94 -0
  161. package/package.json +76 -0
@@ -0,0 +1,362 @@
1
+ import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
2
+ import { registerAuthConfigurator, runWithAuthRetry, type AuthConfiguratorOptions } from "pi-common/auth-config";
3
+ import { jsonToolResult } from "pi-common/tool-result";
4
+ import { LinearClient, type UploadedFileResult } from "./linear-client.js";
5
+ import {
6
+ EmptyParams,
7
+ LinearCommentsParams,
8
+ LinearCreateCommentParams,
9
+ LinearCreateIssueParams,
10
+ LinearDocumentsParams,
11
+ LinearGetDocumentParams,
12
+ LinearGetIssueParams,
13
+ LinearGetProjectParams,
14
+ LinearGetStatusParams,
15
+ LinearGetTeamParams,
16
+ LinearGetUserParams,
17
+ LinearListIssuesParams,
18
+ LinearListMyIssuesParams,
19
+ LinearSearchIssuesParams,
20
+ LinearUpdateIssueParams,
21
+ LinearUploadFileParams,
22
+ LinearUploadFileToIssueCommentParams,
23
+ OptionalTeamParams,
24
+ } from "./linear-schemas.js";
25
+
26
+ const LINEAR_AUTH: AuthConfiguratorOptions = {
27
+ service: "linear",
28
+ displayName: "Linear",
29
+ envName: "LINEAR_API_KEY",
30
+ authPath: ["linear", "key"],
31
+ commandName: "linear-auth",
32
+ toolName: "linear_configure_auth",
33
+ tokenUrl: "https://linear.app/settings/account/security",
34
+ scopeInstructions: [
35
+ "Read access is enough for lookup/list/get tools.",
36
+ "Write access is required for creating issues, updating issues, creating comments, and uploading files.",
37
+ "Admin access is not required.",
38
+ ],
39
+ };
40
+
41
+ function withLinearAuth<T>(ctx: ExtensionContext, operation: () => Promise<T>): Promise<T> {
42
+ return runWithAuthRetry(ctx, LINEAR_AUTH, operation);
43
+ }
44
+
45
+ function buildFileCommentBody(upload: UploadedFileResult, commentBody?: string, altText?: string): string {
46
+ const markdown = upload.contentType.startsWith("image/")
47
+ ? `![${escapeMarkdownAltText(altText?.trim() || upload.filename)}](${upload.assetUrl})`
48
+ : `[${upload.filename}](${upload.assetUrl})`;
49
+ if (!commentBody?.trim()) return markdown;
50
+ if (commentBody.includes("{markdown}") || commentBody.includes("{url}")) {
51
+ return commentBody.replaceAll("{markdown}", markdown).replaceAll("{url}", upload.assetUrl);
52
+ }
53
+ return `${commentBody.trim()}\n\n${markdown}`;
54
+ }
55
+
56
+ function escapeMarkdownAltText(value: string): string {
57
+ return value.replaceAll("[", "\\[").replaceAll("]", "\\]");
58
+ }
59
+
60
+ export function registerLinearTools(pi: ExtensionAPI): void {
61
+ const client = new LinearClient();
62
+ registerAuthConfigurator(pi, LINEAR_AUTH);
63
+
64
+ pi.registerTool({
65
+ name: "linear_whoami",
66
+ label: "Linear Whoami",
67
+ description: "Get the authenticated Linear user.",
68
+ parameters: EmptyParams,
69
+ async execute(_id, params, _signal, _onUpdate, ctx) {
70
+ return jsonToolResult(await withLinearAuth(ctx, () => client.whoami()), { maxChars: params.maxResponseChars });
71
+ },
72
+ });
73
+
74
+ pi.registerTool({
75
+ name: "linear_workspace_metadata",
76
+ label: "Linear Workspace Metadata",
77
+ description: "Get teams, projects, workflow states, labels, and users in one Linear call.",
78
+ promptSnippet: "Fetch Linear workspace teams, projects, states, labels, and users.",
79
+ promptGuidelines: [
80
+ "Use linear_configure_auth only when Linear auth is missing, invalid, expired, or the user asks to update the key; never ask the user to paste API keys in chat.",
81
+ "Use linear_workspace_metadata first when Linear team, project, state, label, or user IDs are unknown.",
82
+ "Use linear_search_issues for Linear keyword lookup.",
83
+ "Use linear_get_issue before updating or commenting on a Linear issue.",
84
+ ],
85
+ parameters: EmptyParams,
86
+ async execute(_id, params, _signal, _onUpdate, ctx) {
87
+ return jsonToolResult(await withLinearAuth(ctx, () => client.workspaceMetadata()), { maxChars: params.maxResponseChars });
88
+ },
89
+ });
90
+
91
+ pi.registerTool({
92
+ name: "linear_list_teams",
93
+ label: "Linear List Teams",
94
+ description: "List Linear teams.",
95
+ parameters: EmptyParams,
96
+ async execute(_id, params, _signal, _onUpdate, ctx) {
97
+ return jsonToolResult(await withLinearAuth(ctx, () => client.listTeams()), { maxChars: params.maxResponseChars });
98
+ },
99
+ });
100
+
101
+ pi.registerTool({
102
+ name: "linear_get_team",
103
+ label: "Linear Get Team",
104
+ description: "Get a Linear team by ID.",
105
+ parameters: LinearGetTeamParams,
106
+ async execute(_id, params, _signal, _onUpdate, ctx) {
107
+ return jsonToolResult(await withLinearAuth(ctx, () => client.getTeam(params.teamId)), { maxChars: params.maxResponseChars });
108
+ },
109
+ });
110
+
111
+ pi.registerTool({
112
+ name: "linear_list_issues",
113
+ label: "Linear List Issues",
114
+ description: "List Linear issues with optional team, assignee, status, and limit filters.",
115
+ parameters: LinearListIssuesParams,
116
+ async execute(_id, params, _signal, _onUpdate, ctx) {
117
+ const result = await withLinearAuth(ctx, () => client.listIssues({
118
+ teamId: params.teamId,
119
+ assigneeId: params.assigneeId,
120
+ statusName: params.statusName,
121
+ limit: params.limit,
122
+ }));
123
+ return jsonToolResult(result, { maxChars: params.maxResponseChars });
124
+ },
125
+ });
126
+
127
+ pi.registerTool({
128
+ name: "linear_get_issue",
129
+ label: "Linear Get Issue",
130
+ description: "Get full Linear issue details by UUID or identifier like ENG-123.",
131
+ parameters: LinearGetIssueParams,
132
+ async execute(_id, params, _signal, _onUpdate, ctx) {
133
+ return jsonToolResult(await withLinearAuth(ctx, () => client.getIssue(params.issueId)), { maxChars: params.maxResponseChars });
134
+ },
135
+ });
136
+
137
+ pi.registerTool({
138
+ name: "linear_search_issues",
139
+ label: "Linear Search Issues",
140
+ description: "Search Linear issues by keyword.",
141
+ parameters: LinearSearchIssuesParams,
142
+ async execute(_id, params, _signal, _onUpdate, ctx) {
143
+ return jsonToolResult(await withLinearAuth(ctx, () => client.searchIssues(params.query, params.limit)), { maxChars: params.maxResponseChars });
144
+ },
145
+ });
146
+
147
+ pi.registerTool({
148
+ name: "linear_list_my_issues",
149
+ label: "Linear My Issues",
150
+ description: "List open Linear issues assigned to the authenticated user.",
151
+ parameters: LinearListMyIssuesParams,
152
+ async execute(_id, params, _signal, _onUpdate, ctx) {
153
+ return jsonToolResult(await withLinearAuth(ctx, () => client.listMyIssues(params.limit)), { maxChars: params.maxResponseChars });
154
+ },
155
+ });
156
+
157
+ pi.registerTool({
158
+ name: "linear_create_issue",
159
+ label: "Linear Create Issue",
160
+ description: "Create a Linear issue. Use linear_workspace_metadata first if team/state/user/project IDs are unknown.",
161
+ parameters: LinearCreateIssueParams,
162
+ async execute(_id, params, _signal, _onUpdate, ctx) {
163
+ const result = await withLinearAuth(ctx, () => client.createIssue({
164
+ teamId: params.teamId,
165
+ title: params.title,
166
+ description: params.description,
167
+ priority: params.priority,
168
+ assigneeId: params.assigneeId,
169
+ labelIds: params.labelIds,
170
+ projectId: params.projectId,
171
+ stateId: params.stateId,
172
+ }));
173
+ return jsonToolResult(result, { maxChars: params.maxResponseChars });
174
+ },
175
+ });
176
+
177
+ pi.registerTool({
178
+ name: "linear_update_issue",
179
+ label: "Linear Update Issue",
180
+ description: "Update a Linear issue title, description, priority, state, or assignee. Call linear_get_issue first.",
181
+ parameters: LinearUpdateIssueParams,
182
+ async execute(_id, params, _signal, _onUpdate, ctx) {
183
+ const result = await withLinearAuth(ctx, () => client.updateIssue(params.issueId, {
184
+ title: params.title,
185
+ description: params.description,
186
+ priority: params.priority,
187
+ stateId: params.stateId,
188
+ assigneeId: params.assigneeId,
189
+ }));
190
+ return jsonToolResult(result, { maxChars: params.maxResponseChars });
191
+ },
192
+ });
193
+
194
+ pi.registerTool({
195
+ name: "linear_list_projects",
196
+ label: "Linear List Projects",
197
+ description: "List Linear projects, optionally for a team.",
198
+ parameters: OptionalTeamParams,
199
+ async execute(_id, params, _signal, _onUpdate, ctx) {
200
+ return jsonToolResult(await withLinearAuth(ctx, () => client.listProjects(params.teamId)), { maxChars: params.maxResponseChars });
201
+ },
202
+ });
203
+
204
+ pi.registerTool({
205
+ name: "linear_get_project",
206
+ label: "Linear Get Project",
207
+ description: "Get a Linear project by ID.",
208
+ parameters: LinearGetProjectParams,
209
+ async execute(_id, params, _signal, _onUpdate, ctx) {
210
+ return jsonToolResult(await withLinearAuth(ctx, () => client.getProject(params.projectId)), { maxChars: params.maxResponseChars });
211
+ },
212
+ });
213
+
214
+ pi.registerTool({
215
+ name: "linear_list_issue_statuses",
216
+ label: "Linear List Issue Statuses",
217
+ description: "List Linear workflow states, optionally for a team.",
218
+ parameters: OptionalTeamParams,
219
+ async execute(_id, params, _signal, _onUpdate, ctx) {
220
+ return jsonToolResult(await withLinearAuth(ctx, () => client.listIssueStatuses(params.teamId)), { maxChars: params.maxResponseChars });
221
+ },
222
+ });
223
+
224
+ pi.registerTool({
225
+ name: "linear_get_issue_status",
226
+ label: "Linear Get Issue Status",
227
+ description: "Get a Linear workflow state by ID.",
228
+ parameters: LinearGetStatusParams,
229
+ async execute(_id, params, _signal, _onUpdate, ctx) {
230
+ return jsonToolResult(await withLinearAuth(ctx, () => client.getIssueStatus(params.stateId)), { maxChars: params.maxResponseChars });
231
+ },
232
+ });
233
+
234
+ pi.registerTool({
235
+ name: "linear_list_labels",
236
+ label: "Linear List Labels",
237
+ description: "List Linear labels, optionally for a team.",
238
+ parameters: OptionalTeamParams,
239
+ async execute(_id, params, _signal, _onUpdate, ctx) {
240
+ return jsonToolResult(await withLinearAuth(ctx, () => client.listLabels(params.teamId)), { maxChars: params.maxResponseChars });
241
+ },
242
+ });
243
+
244
+ pi.registerTool({
245
+ name: "linear_list_users",
246
+ label: "Linear List Users",
247
+ description: "List Linear users.",
248
+ parameters: EmptyParams,
249
+ async execute(_id, params, _signal, _onUpdate, ctx) {
250
+ return jsonToolResult(await withLinearAuth(ctx, () => client.listUsers()), { maxChars: params.maxResponseChars });
251
+ },
252
+ });
253
+
254
+ pi.registerTool({
255
+ name: "linear_get_user",
256
+ label: "Linear Get User",
257
+ description: "Get a Linear user by ID.",
258
+ parameters: LinearGetUserParams,
259
+ async execute(_id, params, _signal, _onUpdate, ctx) {
260
+ return jsonToolResult(await withLinearAuth(ctx, () => client.getUser(params.userId)), { maxChars: params.maxResponseChars });
261
+ },
262
+ });
263
+
264
+ pi.registerTool({
265
+ name: "linear_list_comments",
266
+ label: "Linear List Comments",
267
+ description: "List comments for a Linear issue.",
268
+ parameters: LinearCommentsParams,
269
+ async execute(_id, params, _signal, _onUpdate, ctx) {
270
+ return jsonToolResult(await withLinearAuth(ctx, () => client.listComments(params.issueId)), { maxChars: params.maxResponseChars });
271
+ },
272
+ });
273
+
274
+ pi.registerTool({
275
+ name: "linear_create_comment",
276
+ label: "Linear Create Comment",
277
+ description: "Create a comment on a Linear issue. Call linear_get_issue first.",
278
+ parameters: LinearCreateCommentParams,
279
+ async execute(_id, params, _signal, _onUpdate, ctx) {
280
+ return jsonToolResult(await withLinearAuth(ctx, () => client.createComment(params.issueId, params.body)), { maxChars: params.maxResponseChars });
281
+ },
282
+ });
283
+
284
+ pi.registerTool({
285
+ name: "linear_upload_file",
286
+ label: "Linear Upload File",
287
+ description: "Upload a local file to Linear and return a Linear asset URL. Supports images, videos, and generic files.",
288
+ promptGuidelines: [
289
+ "Use this when you need a Linear-hosted URL for a local image, video, or file.",
290
+ "Tool results include the asset URL and sanitized metadata, not file bytes, signed upload URLs, or upload headers.",
291
+ "Use linear_get_issue before inserting the returned URL into an issue or comment.",
292
+ ],
293
+ parameters: LinearUploadFileParams,
294
+ async execute(_id, params, _signal, _onUpdate, ctx) {
295
+ const result = await withLinearAuth(ctx, () => client.uploadFile({
296
+ filePath: params.filePath,
297
+ filename: params.filename,
298
+ contentType: params.contentType,
299
+ maxBytes: params.maxBytes,
300
+ makePublic: params.makePublic,
301
+ }));
302
+ return jsonToolResult(result, { maxChars: params.maxResponseChars });
303
+ },
304
+ });
305
+
306
+ pi.registerTool({
307
+ name: "linear_upload_file_to_issue_comment",
308
+ label: "Linear Upload File to Issue Comment",
309
+ description: "Upload a local file to Linear and create a Markdown comment on an issue. Call linear_get_issue first.",
310
+ promptGuidelines: [
311
+ "Use this after linear_get_issue has verified the target issue.",
312
+ "Images are inserted as Markdown images; videos and other files are inserted as links.",
313
+ "Use commentBody with {url} or {markdown} placeholders for custom wording, or omit it to post only the file Markdown.",
314
+ ],
315
+ parameters: LinearUploadFileToIssueCommentParams,
316
+ async execute(_id, params, _signal, _onUpdate, ctx) {
317
+ const result = await withLinearAuth(ctx, async () => {
318
+ const upload = await client.uploadFile({
319
+ filePath: params.filePath,
320
+ filename: params.filename,
321
+ contentType: params.contentType,
322
+ maxBytes: params.maxBytes,
323
+ makePublic: params.makePublic,
324
+ });
325
+ const body = buildFileCommentBody(upload, params.commentBody, params.altText);
326
+ const comment = await client.createComment(params.issueId, body);
327
+ return { upload, comment };
328
+ });
329
+ return jsonToolResult(result, { maxChars: params.maxResponseChars });
330
+ },
331
+ });
332
+
333
+ pi.registerTool({
334
+ name: "linear_list_cycles",
335
+ label: "Linear List Cycles",
336
+ description: "List Linear cycles, optionally for a team.",
337
+ parameters: OptionalTeamParams,
338
+ async execute(_id, params, _signal, _onUpdate, ctx) {
339
+ return jsonToolResult(await withLinearAuth(ctx, () => client.listCycles(params.teamId)), { maxChars: params.maxResponseChars });
340
+ },
341
+ });
342
+
343
+ pi.registerTool({
344
+ name: "linear_list_documents",
345
+ label: "Linear List Documents",
346
+ description: "List Linear documents, optionally for a project.",
347
+ parameters: LinearDocumentsParams,
348
+ async execute(_id, params, _signal, _onUpdate, ctx) {
349
+ return jsonToolResult(await withLinearAuth(ctx, () => client.listDocuments(params.projectId)), { maxChars: params.maxResponseChars });
350
+ },
351
+ });
352
+
353
+ pi.registerTool({
354
+ name: "linear_get_document",
355
+ label: "Linear Get Document",
356
+ description: "Get a Linear document by ID.",
357
+ parameters: LinearGetDocumentParams,
358
+ async execute(_id, params, _signal, _onUpdate, ctx) {
359
+ return jsonToolResult(await withLinearAuth(ctx, () => client.getDocument(params.documentId)), { maxChars: params.maxResponseChars });
360
+ },
361
+ });
362
+ }
@@ -0,0 +1,163 @@
1
+ # pi-mono-loop
2
+
3
+ ## 1.7.2
4
+
5
+ ### Patch Changes
6
+
7
+ ### Fixed: ask-user-question
8
+
9
+ - Remove unused `StringEnum` import from `@mariozechner/pi-ai`.
10
+
11
+
12
+ ## 1.7.1
13
+
14
+ ### Patch Changes
15
+
16
+ ### Fixed: team-mode
17
+
18
+ - Widget no longer mislabels blocked or approval-pending teams as "running smoothly" — blockers and pending approvals are now detected via team summaries.
19
+ - Preserve in-flight work on re-emitted `session_start` events instead of tearing the runtime down and SIGTERM-ing live teammates.
20
+ - Auto-relaunch leaders for `running` teams after a session reset; surface failures as both a team signal and a UI notification.
21
+ - `createTeam` now defaults `repoRoots` to `[process.cwd()]` when the caller passes an empty array.
22
+ - Archive `process.json` into `history/` before a new task reuses the same role slot, so the prior task's final state is no longer silently clobbered.
23
+
24
+ ### Enhanced: team-mode
25
+
26
+ - Durable intent queue for subprocess handoff: `team_spawn_teammate` calls made from a teammate subprocess are written to disk and executed by the main session's `LeaderRuntime` instead of spawning orphaned grand-children.
27
+ - New tool `team_task_create_batch` lets the leader emit the full initial task DAG in one call, removing per-task LLM round-trips during bootstrap.
28
+ - `team_create` / `launchLeader` accept an `awaitBootstrap` option so the user sees the task graph before the tool returns; leader launch retries up to 3 times on transient failures.
29
+ - Persist per-turn debug artifacts (prompt, invocation, stderr, raw event stream) for both leader and teammate subprocesses, exposed via `TeammateSummary.debugArtifacts`.
30
+ - Track `exitCode`, `exitSignal`, `terminationReason`, `stderrTail`, `toolExecutions`, `model` and `modelProvider` on every `TeammateProcess` record.
31
+ - Provider detection now consults pi's `settings.json` and `auth.json` in addition to env vars; default model IDs aligned with the provider/model scheme.
32
+ - `collectPiOutput` supports `AbortSignal` cancellation.
33
+
34
+ ### Tests
35
+
36
+ - New `intent-queue` and `model-config` suites; expanded coverage across `leader-runtime`, `team-manager`, `team-query-tool` and `formatters`.
37
+
38
+
39
+ ## 1.7.0
40
+
41
+ ### Minor Changes
42
+
43
+ ### Enhanced: status-line
44
+
45
+ - Improved progress rendering and colors in expert mode
46
+
47
+ ### Enhanced: team-mode
48
+
49
+ - **LLM-driven leader** — replaced the hardcoded `research → synthesis → implementation → verification` state machine with a pi subprocess coordinator that authors the task graph via tool calls
50
+ - **New tool `team_task_create`** so the leader can author tasks at runtime
51
+ - **New tool `team_handoff`** for explicit teammate → teammate context handoffs (replaces regex-scraping of `Handoffs:` output sections)
52
+ - **File-based teammate specs** — drop `.claude/teammates/<role>.md` frontmatter files (`name`, `description`, `needsWorktree`, `hasMemory`, `modelTier`) to extend or override the seven built-in roles
53
+ - **Event-driven leader wakes** — mailbox messages addressed to the leader (or broadcast) trigger a debounced (~200ms) cycle instead of waiting for the 20s polling tick
54
+ - **Templates accept any string** — `fullstack` / `research` / `refactor` remain as built-ins, but unknown template keys are accepted and no-op gracefully
55
+ - **Provider config per team** — per-team model overrides via `/team models`
56
+ - Reduced leader overhead and parent-session token churn
57
+ - `spawnTeammate` now always appends the full runtime-built context (signals, mailbox, dependencies, team memory) so teammates get the richer snapshot even when the caller's `context` argument is brief
58
+
59
+ ### Breaking changes: team-mode
60
+
61
+ - Removed `LeaderPhase` enum and `currentPhase` field from `TeamRecord` / `TeamSummary`
62
+ - Removed `parseExplicitHandoffs` export and the legacy `Handoffs:` output parser — peer handoffs must go through the `team_handoff` tool
63
+ - Removed the deterministic auto-spawn loop (`ensureBootstrapTasks`) — all task authoring and teammate spawning is now the LLM leader's responsibility
64
+ - Removed `StringEnum` gate on `team_create`'s `template` parameter (now plain string)
65
+
66
+ ### Fixed: review
67
+
68
+ - Annotate diff lines so the model picks correct line numbers
69
+ - Fix slice chunk around lines for comments in the reviewer TUI
70
+
71
+ ### Documentation
72
+
73
+ - Updated root README and sentinel extension README
74
+ - Documented the new file-based teammate spec format and event-driven leader wake in the team-mode README
75
+
76
+ ## 1.6.0
77
+
78
+ ### Minor Changes
79
+
80
+ ### New Extension: sentinel
81
+
82
+ Replaced the `grep` extension with a new security-focused `sentinel` extension for monitoring and guarding sensitive operations.
83
+
84
+ ### Enhanced: team-mode
85
+
86
+ - Added comprehensive test suite with integration tests
87
+ - New mock helpers for subprocess testing
88
+ - Improved signal manager with better error handling
89
+ - Leader runtime refactoring for stability
90
+ - Team query tool with dedicated tests
91
+
92
+ ### Enhanced: status-line
93
+
94
+ - Added basic and expert mode displays
95
+ - Improved index.ts with better state management
96
+
97
+ ### Enhanced: clear
98
+
99
+ - Updated keyboard shortcut to `Ctrl+Shift+L`
100
+ - Better busy-state handling for shortcuts
101
+ - Added warning/cancel handling and error notifications
102
+
103
+ ### Enhanced: context-guard
104
+
105
+ - Improved read deduplication across sessions
106
+ - Added `context-guard:file-modified` event for cache eviction
107
+
108
+ ### Documentation
109
+
110
+ - Added dedicated README for `clear` extension
111
+ - Added dedicated README for `context-guard` extension
112
+ - Updated main README with improved extension descriptions
113
+
114
+ ## 1.5.0
115
+
116
+ ### Minor Changes
117
+
118
+ - ### `multi-edit` — diverge from upstream fork
119
+
120
+ The extension was originally derived from [mitsuhiko/agent-stuff](https://github.com/mitsuhiko/agent-stuff)'s `pi-extensions/multi-edit.ts`. This release rewrites the largest unmodified subsystems so the implementation is structurally distinct from upstream while keeping the public contract intact.
121
+
122
+ - **Modularized layout** — the 953-line `index.ts` is split into purpose-scoped modules: `types.ts`, `workspace.ts`, `classic.ts`, `patch.ts`, `diff.ts`, and a slim `index.ts` (~180 lines of registration + dispatch wiring).
123
+ - **New patch engine** — `patch.ts` is now a recursive-descent parser over a `LineCursor` class with `indexOf`-based hunk anchoring. Hunks are stored as `{ oldBlock, newBlock }` raw strings (previously `{ oldLines[], newLines[] }` arrays), letting the applier splice content directly instead of reconstructing line arrays per apply.
124
+ - **Two-pass diff renderer** — `diff.ts` now walks `diffLines` parts into a typed `Entry[]` stream and makes all gutter / context-collapse decisions in a second pass, replacing the prior single-loop state-flag design.
125
+ - **Polished classic edits** — extracted `groupEditsByPath`, `sortGroupByPosition`, `applyGroupToContent`, and `rollbackSnapshots` helpers; formalized the quote-fallback as an ordered `MATCH_PASSES` array so new normalizers (dashes, NBSP, etc.) can be added by appending one entry.
126
+ - **First contract test suite** — 34 tests under `__tests__/` cover classic edits (positional reordering, redundant-pair skip, quote fallback, atomic rollback, read-only preflight), patch operations (Add/Delete/Update round-trips, move-rejection, multi-op batches), and diff rendering (line-number gutter, context collapse, add/remove-only cases). Runs via `npm test` (`tsx --test`).
127
+ - **Dropped Codex apply_patch edge cases** (documented in `README.md` → "Codex apply_patch compatibility"): `*** End of File` sentinel hunks, 4-pass fuzzy `seekSequence` matching, implicit first hunk without `@@`, whitespace-tolerant anchoring. Common paths (Add/Delete/Update-single-chunk, Update with multiple hunks, Add+Update+Delete batches) are fully tested and preserved.
128
+ - **README attribution** — new "Origins" section crediting `mitsuhiko/agent-stuff` as the original source.
129
+
130
+ ## 1.4.0
131
+
132
+ ### Minor Changes
133
+
134
+ - Add teammate progress heartbeats and widget refresh improvements to team mode.
135
+
136
+ ## 1.3.0
137
+
138
+ ### Minor Changes
139
+
140
+ - ### New Extensions
141
+
142
+ #### `loop`
143
+
144
+ New extension that runs a prompt or slash command on a recurring interval. Useful for periodic tasks, polling, and automated repeated actions within a pi session.
145
+
146
+ #### `simplify`
147
+
148
+ New extension that reviews changed code for reuse, quality, and efficiency, then automatically fixes any issues found. Integrates with `git diff` to scope the review to recent changes.
149
+
150
+ ***
151
+
152
+ ### Bug Fixes
153
+
154
+ #### `multi-edit`
155
+
156
+ - **Broader unicode normalization**: `findActualString` now handles the full range of Unicode single-quote variants (`‘’‚‛`) and double-quote variants (`“”„‟`) when falling back from exact match — fixes more curly-quote mismatch cases
157
+ - **Parallel write-access preflight**: `checkWriteAccess` calls are now issued concurrently via `Promise.all` instead of sequentially — faster batch preflight on large edit sets
158
+ - **Removed redundant `editOrder` array**: `Map` insertion order is now relied upon directly, simplifying the grouping loop
159
+
160
+ #### `team-mode`
161
+
162
+ - **Stall detection hardened**: introduced `STALL_BLOCKER_MARKER` / `STALL_BLOCKER_MESSAGE` constants so the marker used to detect and record abnormal process exits stays in sync — prevents duplicate stall reports
163
+ - **Leader cycle guard comment clarified**: `cycleRunning` guard comment now explicitly calls out the race between the poll interval and teammate-completion handlers
@@ -0,0 +1,54 @@
1
+ # loop extension
2
+
3
+ Runs a prompt or slash command on a recurring interval.
4
+
5
+ Adapted from the [`/loop` skill in claude-code](https://github.com/emanuelcasco/claude-code/blob/main/src/skills/bundled/loop.ts). The original relied on Claude Code's Kairos cron system; this version uses JS timers and `pi.sendUserMessage()` instead.
6
+
7
+ ## Usage
8
+
9
+ ```
10
+ /loop [interval] <prompt>
11
+ ```
12
+
13
+ Intervals use a number followed by a unit suffix: `s` (seconds), `m` (minutes), `h` (hours), `d` (days). If no interval is given, it defaults to `10m`.
14
+
15
+ ## Subcommands
16
+
17
+ | Command | Description |
18
+ |---|---|
19
+ | `/loop list` | Show all active loops with their IDs and fire counts |
20
+ | `/loop stop` | Cancel all active loops |
21
+ | `/loop stop <id>` | Cancel a specific loop by ID |
22
+
23
+ ## Examples
24
+
25
+ ```
26
+ /loop 5m /review
27
+ /loop 30m check the deploy
28
+ /loop 1h run the tests and report failures
29
+ /loop check the deploy # defaults to 10m
30
+ /loop check the deploy every 20m # trailing "every" clause
31
+ /loop list
32
+ /loop stop loop-1
33
+ /loop stop
34
+ ```
35
+
36
+ ## Interval parsing
37
+
38
+ Arguments are parsed using this priority order:
39
+
40
+ 1. **Leading token** — if the first word matches `\d+[smhd]` it is the interval (e.g. `5m /review`)
41
+ 2. **Trailing "every" clause** — if the input ends with `every <N><unit>`, that is the interval (e.g. `check the deploy every 20m`)
42
+ 3. **Default** — no interval found; uses `10m` and the full input is the prompt
43
+
44
+ ## Behaviour
45
+
46
+ - The prompt is **executed immediately** on the first invocation, then repeated at the given interval
47
+ - If the agent is busy when a timer fires, the next prompt is queued as a follow-up rather than interrupting the current turn
48
+ - Minimum interval is **10 seconds**
49
+ - Loops **auto-expire after 7 days**
50
+ - All timers are cleaned up on session shutdown
51
+
52
+ ## Files
53
+
54
+ - `index.ts` — extension entry point