@pi-in-go/pigpen-acp 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 (134) hide show
  1. package/CREDITS.md +23 -0
  2. package/LICENSE +22 -0
  3. package/README.md +110 -0
  4. package/extensions/acp/cmd/pig-acp/e2e_llm_test.go +168 -0
  5. package/extensions/acp/cmd/pig-acp/e2e_test.go +541 -0
  6. package/extensions/acp/cmd/pig-acp/go.mod +6 -0
  7. package/extensions/acp/cmd/pig-acp/internal/acp/agent.go +784 -0
  8. package/extensions/acp/cmd/pig-acp/internal/acp/agent_builtin_test.go +536 -0
  9. package/extensions/acp/cmd/pig-acp/internal/acp/agent_commands_test.go +199 -0
  10. package/extensions/acp/cmd/pig-acp/internal/acp/agent_config_test.go +530 -0
  11. package/extensions/acp/cmd/pig-acp/internal/acp/agent_helpers_test.go +215 -0
  12. package/extensions/acp/cmd/pig-acp/internal/acp/agent_load_test.go +333 -0
  13. package/extensions/acp/cmd/pig-acp/internal/acp/agent_prompt.go +289 -0
  14. package/extensions/acp/cmd/pig-acp/internal/acp/agent_session_test.go +429 -0
  15. package/extensions/acp/cmd/pig-acp/internal/acp/auth.go +61 -0
  16. package/extensions/acp/cmd/pig-acp/internal/acp/bench_test.go +47 -0
  17. package/extensions/acp/cmd/pig-acp/internal/acp/helpers_test.go +421 -0
  18. package/extensions/acp/cmd/pig-acp/internal/acp/main_test.go +28 -0
  19. package/extensions/acp/cmd/pig-acp/internal/acp/mutation_extra_test.go +142 -0
  20. package/extensions/acp/cmd/pig-acp/internal/acp/paths.go +77 -0
  21. package/extensions/acp/cmd/pig-acp/internal/acp/pisessions.go +317 -0
  22. package/extensions/acp/cmd/pig-acp/internal/acp/protocol.go +188 -0
  23. package/extensions/acp/cmd/pig-acp/internal/acp/server.go +218 -0
  24. package/extensions/acp/cmd/pig-acp/internal/acp/server_test.go +386 -0
  25. package/extensions/acp/cmd/pig-acp/internal/acp/session.go +1068 -0
  26. package/extensions/acp/cmd/pig-acp/internal/acp/session_diff_test.go +183 -0
  27. package/extensions/acp/cmd/pig-acp/internal/acp/session_events_test.go +443 -0
  28. package/extensions/acp/cmd/pig-acp/internal/acp/session_extra_test.go +547 -0
  29. package/extensions/acp/cmd/pig-acp/internal/acp/session_usage_test.go +198 -0
  30. package/extensions/acp/cmd/pig-acp/internal/acp/settings.go +79 -0
  31. package/extensions/acp/cmd/pig-acp/internal/acp/slash.go +278 -0
  32. package/extensions/acp/cmd/pig-acp/internal/acp/slash_test.go +128 -0
  33. package/extensions/acp/cmd/pig-acp/internal/acp/startup.go +156 -0
  34. package/extensions/acp/cmd/pig-acp/internal/acp/store.go +118 -0
  35. package/extensions/acp/cmd/pig-acp/internal/acp/store_paths_test.go +466 -0
  36. package/extensions/acp/cmd/pig-acp/internal/acp/translate.go +352 -0
  37. package/extensions/acp/cmd/pig-acp/internal/acp/translate_test.go +105 -0
  38. package/extensions/acp/cmd/pig-acp/internal/acp/twin_test.go +28 -0
  39. package/extensions/acp/cmd/pig-acp/internal/acp/types.go +202 -0
  40. package/extensions/acp/cmd/pig-acp/internal/jsonrpc/bench_test.go +24 -0
  41. package/extensions/acp/cmd/pig-acp/internal/jsonrpc/jsonrpc.go +302 -0
  42. package/extensions/acp/cmd/pig-acp/internal/jsonrpc/jsonrpc_test.go +320 -0
  43. package/extensions/acp/cmd/pig-acp/internal/jsonrpc/twin_test.go +28 -0
  44. package/extensions/acp/cmd/pig-acp/internal/pirpc/kill_unix.go +19 -0
  45. package/extensions/acp/cmd/pig-acp/internal/pirpc/kill_windows.go +11 -0
  46. package/extensions/acp/cmd/pig-acp/internal/pirpc/process.go +530 -0
  47. package/extensions/acp/cmd/pig-acp/internal/pirpc/process_test.go +355 -0
  48. package/extensions/acp/cmd/pig-acp/internal/pirpc/twin_test.go +28 -0
  49. package/extensions/acp/cmd/pig-acp/main.go +177 -0
  50. package/extensions/acp/cmd/pig-acp/main_test.go +213 -0
  51. package/extensions/acp/cmd/pig-acp/sigpipe_unix.go +10 -0
  52. package/extensions/acp/cmd/pig-acp/sigpipe_windows.go +5 -0
  53. package/extensions/acp/cmd/pig-acp/testdata/ask/extension.go +28 -0
  54. package/extensions/acp/cmd/pig-acp/testdata/ask/go.mod +7 -0
  55. package/extensions/acp/cmd/pig-acp/testdata/ask/go.sum +2 -0
  56. package/extensions/acp/cmd/pig-acp/testdata/gate/extension.go +37 -0
  57. package/extensions/acp/cmd/pig-acp/testdata/gate/go.mod +7 -0
  58. package/extensions/acp/cmd/pig-acp/testdata/gate/go.sum +2 -0
  59. package/extensions/acp/cmd/pig-acp/twin_test.go +28 -0
  60. package/extensions/acp/extension.go +63 -0
  61. package/extensions/acp/extension_test.go +111 -0
  62. package/extensions/acp/fakehost_test.go +548 -0
  63. package/extensions/acp/go.mod +6 -0
  64. package/extensions/acp/go.sum +2 -0
  65. package/package.json +41 -0
  66. package/port/PORT.md +147 -0
  67. package/port/interop/package-lock.json +89 -0
  68. package/port/interop/package.json +13 -0
  69. package/port/interop/run.mjs +229 -0
  70. package/port/mutate.mjs +110 -0
  71. package/port/mutation-results.txt +107 -0
  72. package/port/mutations.json +748 -0
  73. package/port/oracle/pi-acp/LICENSE +21 -0
  74. package/port/oracle/pi-acp/README.md +209 -0
  75. package/port/oracle/pi-acp/package.json +65 -0
  76. package/port/oracle/pi-acp/src/acp/agent.ts +1661 -0
  77. package/port/oracle/pi-acp/src/acp/auth-required.ts +37 -0
  78. package/port/oracle/pi-acp/src/acp/auth.ts +59 -0
  79. package/port/oracle/pi-acp/src/acp/paths.ts +15 -0
  80. package/port/oracle/pi-acp/src/acp/pi-commands.ts +59 -0
  81. package/port/oracle/pi-acp/src/acp/pi-sessions.ts +333 -0
  82. package/port/oracle/pi-acp/src/acp/pi-settings.ts +75 -0
  83. package/port/oracle/pi-acp/src/acp/session-store.ts +68 -0
  84. package/port/oracle/pi-acp/src/acp/session.ts +1078 -0
  85. package/port/oracle/pi-acp/src/acp/slash-commands.ts +197 -0
  86. package/port/oracle/pi-acp/src/acp/translate/bash.ts +100 -0
  87. package/port/oracle/pi-acp/src/acp/translate/pi-messages.ts +17 -0
  88. package/port/oracle/pi-acp/src/acp/translate/pi-tools.ts +51 -0
  89. package/port/oracle/pi-acp/src/acp/translate/prompt.ts +71 -0
  90. package/port/oracle/pi-acp/src/index.ts +82 -0
  91. package/port/oracle/pi-acp/src/pi-rpc/command.ts +16 -0
  92. package/port/oracle/pi-acp/src/pi-rpc/process.ts +432 -0
  93. package/port/oracle/pi-acp/test/component/agent-steering-followup-modes.test.ts +143 -0
  94. package/port/oracle/pi-acp/test/component/session-diff.test.ts +214 -0
  95. package/port/oracle/pi-acp/test/component/session-events.test.ts +1102 -0
  96. package/port/oracle/pi-acp/test/component/session-list-and-load.test.ts +129 -0
  97. package/port/oracle/pi-acp/test/component/session-list-custom-session-dir.test.ts +52 -0
  98. package/port/oracle/pi-acp/test/component/session-list-scoped.test.ts +76 -0
  99. package/port/oracle/pi-acp/test/component/session-load-toolresult.test.ts +68 -0
  100. package/port/oracle/pi-acp/test/component/session-queue-cancel.test.ts +43 -0
  101. package/port/oracle/pi-acp/test/component/session-slash-commands.test.ts +37 -0
  102. package/port/oracle/pi-acp/test/component/session-thinking-modes.test.ts +22 -0
  103. package/port/oracle/pi-acp/test/component/session-title-long-session.test.ts +56 -0
  104. package/port/oracle/pi-acp/test/component/session-updatedAt-message-only.test.ts +57 -0
  105. package/port/oracle/pi-acp/test/helpers/fakes.ts +87 -0
  106. package/port/oracle/pi-acp/test/unit/auth-methods-terminal-auth-meta.test.ts +22 -0
  107. package/port/oracle/pi-acp/test/unit/builtin-commands.test.ts +60 -0
  108. package/port/oracle/pi-acp/test/unit/context-usage.test.ts +204 -0
  109. package/port/oracle/pi-acp/test/unit/merge-commands.test.ts +19 -0
  110. package/port/oracle/pi-acp/test/unit/model-thinking-levels.test.ts +268 -0
  111. package/port/oracle/pi-acp/test/unit/new-session-auth-required-when-no-models.test.ts +51 -0
  112. package/port/oracle/pi-acp/test/unit/new-session-pi-not-found.test.ts +26 -0
  113. package/port/oracle/pi-acp/test/unit/new-session-runtime-startup-errors.test.ts +148 -0
  114. package/port/oracle/pi-acp/test/unit/pi-command.test.ts +44 -0
  115. package/port/oracle/pi-acp/test/unit/pi-commands.test.ts +32 -0
  116. package/port/oracle/pi-acp/test/unit/pi-enable-embed-context-flag.test.ts +35 -0
  117. package/port/oracle/pi-acp/test/unit/pi-messages.test.ts +29 -0
  118. package/port/oracle/pi-acp/test/unit/pi-rpc-request-timeout.test.ts +137 -0
  119. package/port/oracle/pi-acp/test/unit/pi-rpc-session-path.test.ts +93 -0
  120. package/port/oracle/pi-acp/test/unit/pi-tools.test.ts +40 -0
  121. package/port/oracle/pi-acp/test/unit/prompt-to-pi-message.test.ts +74 -0
  122. package/port/oracle/pi-acp/test/unit/session-config-options.test.ts +217 -0
  123. package/port/oracle/pi-acp/test/unit/session-delete.test.ts +170 -0
  124. package/port/oracle/pi-acp/test/unit/session-restore.test.ts +239 -0
  125. package/port/oracle/pi-acp/test/unit/slash-commands.test.ts +36 -0
  126. package/port/oracle/pi-acp/test/unit/startup-info-env.test.ts +84 -0
  127. package/port/oracle/pi-acp/test/unit/startup-info-load-session.test.ts +53 -0
  128. package/port/oracle/pi-acp/test/unit/startup-info-project-packages.test.ts +74 -0
  129. package/port/oracle/pi-acp/test/unit/stdout-destroyed-does-not-crash.test.ts +32 -0
  130. package/port/oracle/pi-acp/test/unit/thinking-level-rpc.test.ts +43 -0
  131. package/port/schema/LICENSE +191 -0
  132. package/port/schema/schema.json +8015 -0
  133. package/port/upstream-tests.json +201 -0
  134. package/provenance.json +28 -0
@@ -0,0 +1,748 @@
1
+ [
2
+ {
3
+ "name": "embedded-context-default-on",
4
+ "module": "cmd",
5
+ "file": "internal/acp/agent.go",
6
+ "find": "envFlag(\"PIG_ACP_ENABLE_EMBEDDED_CONTEXT\", \"PI_ACP_ENABLE_EMBEDDED_CONTEXT\") == \"true\"",
7
+ "replace": "envFlag(\"PIG_ACP_ENABLE_EMBEDDED_CONTEXT\", \"PI_ACP_ENABLE_EMBEDDED_CONTEXT\") != \"true\"",
8
+ "why": "no-op case on the red stub: embeddedContext defaults to false"
9
+ },
10
+ {
11
+ "name": "embedded-context-false-string-enables",
12
+ "module": "cmd",
13
+ "file": "internal/acp/agent.go",
14
+ "find": "envFlag(\"PIG_ACP_ENABLE_EMBEDDED_CONTEXT\", \"PI_ACP_ENABLE_EMBEDDED_CONTEXT\") == \"true\"",
15
+ "replace": "envFlag(\"PIG_ACP_ENABLE_EMBEDDED_CONTEXT\", \"PI_ACP_ENABLE_EMBEDDED_CONTEXT\") != \"\"",
16
+ "why": "no-op case on the red stub: 'false' keeps embeddedContext off"
17
+ },
18
+ {
19
+ "name": "protocol-version-2",
20
+ "module": "cmd",
21
+ "file": "internal/acp/agent.go",
22
+ "find": "ProtocolVersion: ProtocolVersion,",
23
+ "replace": "ProtocolVersion: 2,"
24
+ },
25
+ {
26
+ "name": "load-session-not-advertised",
27
+ "module": "cmd",
28
+ "file": "internal/acp/agent.go",
29
+ "find": "LoadSession: true,",
30
+ "replace": "LoadSession: false,"
31
+ },
32
+ {
33
+ "name": "audio-advertised",
34
+ "module": "cmd",
35
+ "file": "internal/acp/agent.go",
36
+ "find": "Image: true, Audio: false,",
37
+ "replace": "Image: true, Audio: true,"
38
+ },
39
+ {
40
+ "name": "mcp-http-advertised",
41
+ "module": "cmd",
42
+ "file": "internal/acp/agent.go",
43
+ "find": "McpCapabilities{HTTP: false, SSE: false}",
44
+ "replace": "McpCapabilities{HTTP: true, SSE: false}"
45
+ },
46
+ {
47
+ "name": "relative-cwd-accepted-new",
48
+ "module": "cmd",
49
+ "file": "internal/acp/agent.go",
50
+ "find": "if !filepath.IsAbs(req.Cwd) {\n\t\treturn NewSessionResponse{}",
51
+ "replace": "if false {\n\t\treturn NewSessionResponse{}"
52
+ },
53
+ {
54
+ "name": "relative-cwd-accepted-load",
55
+ "module": "cmd",
56
+ "file": "internal/acp/agent.go",
57
+ "find": "if !filepath.IsAbs(req.Cwd) {\n\t\treturn LoadSessionResponse{}",
58
+ "replace": "if false {\n\t\treturn LoadSessionResponse{}"
59
+ },
60
+ {
61
+ "name": "new-session-keeps-old-children",
62
+ "module": "cmd",
63
+ "file": "internal/acp/agent.go",
64
+ "find": "\ta.sessions.CloseAllExcept(sess.ID())\n\n\tvar startup any",
65
+ "replace": "\tvar startup any"
66
+ },
67
+ {
68
+ "name": "zero-models-not-auth-required",
69
+ "module": "cmd",
70
+ "file": "internal/acp/agent.go",
71
+ "find": "len(raw) == 0 {\n\t\ta.cleanupFailedNewSession",
72
+ "replace": "len(raw) == -1 {\n\t\ta.cleanupFailedNewSession"
73
+ },
74
+ {
75
+ "name": "state-auth-error-ignored",
76
+ "module": "cmd",
77
+ "file": "internal/acp/agent.go",
78
+ "find": "stateErr != nil && MaybeAuthRequiredError(stateErr) != nil",
79
+ "replace": "false",
80
+ "equivalent": "the same credentials error is caught again by the configuration branch below it (both are upstream code); the mutant changes no observable result"
81
+ },
82
+ {
83
+ "name": "quiet-startup-ignored",
84
+ "module": "cmd",
85
+ "file": "internal/acp/agent.go",
86
+ "find": "if !GetQuietStartup(req.Cwd) {",
87
+ "replace": "if true {"
88
+ },
89
+ {
90
+ "name": "startup-sent-before-response",
91
+ "module": "cmd",
92
+ "file": "internal/acp/agent.go",
93
+ "find": "a.defer_(sess.SendStartupInfoIfPending)",
94
+ "replace": "sess.SendStartupInfoIfPending()"
95
+ },
96
+ {
97
+ "name": "cancel-restores-stale-session",
98
+ "module": "cmd",
99
+ "file": "internal/acp/agent.go",
100
+ "find": "s := a.sessions.MaybeGet(sessionID)\n\tif s == nil {\n\t\treturn nil\n\t}",
101
+ "replace": "s, err := a.restoreSession(sessionID, \"\", nil)\n\tif err != nil {\n\t\treturn err\n\t}",
102
+ "why": "no-op case on the red stub: cancel of an unknown session does nothing"
103
+ },
104
+ {
105
+ "name": "delete-unknown-is-error",
106
+ "module": "cmd",
107
+ "file": "internal/acp/agent.go",
108
+ "find": "if stored == nil && ps == nil {\n\t\treturn map[string]any{}, nil\n\t}",
109
+ "replace": "if stored == nil && ps == nil {\n\t\treturn nil, ErrInvalidParams(nil, \"unknown\")\n\t}",
110
+ "why": "no-op case on the red stub: session/delete of an unknown id succeeds"
111
+ },
112
+ {
113
+ "name": "delete-keeps-file",
114
+ "module": "cmd",
115
+ "file": "internal/acp/agent.go",
116
+ "find": "_ = os.Remove(file) // best effort\n\t}\n\ta.store.Delete(req.SessionID)",
117
+ "replace": "_ = file\n\t}\n\ta.store.Delete(req.SessionID)"
118
+ },
119
+ {
120
+ "name": "delete-keeps-map-entry",
121
+ "module": "cmd",
122
+ "file": "internal/acp/agent.go",
123
+ "find": "\ta.store.Delete(req.SessionID)\n\treturn map[string]any{}, nil",
124
+ "replace": "\treturn map[string]any{}, nil"
125
+ },
126
+ {
127
+ "name": "list-page-size",
128
+ "module": "cmd",
129
+ "file": "internal/acp/agent.go",
130
+ "find": "listPageSize = 50",
131
+ "replace": "listPageSize = 51"
132
+ },
133
+ {
134
+ "name": "list-ignores-last-cwd",
135
+ "module": "cmd",
136
+ "file": "internal/acp/agent.go",
137
+ "find": "cwd := a.getLastCwd()",
138
+ "replace": "cwd := \"\""
139
+ },
140
+ {
141
+ "name": "list-explicit-cwd-ignored",
142
+ "module": "cmd",
143
+ "file": "internal/acp/agent.go",
144
+ "find": "if req.Cwd != nil {\n\t\tcwd = *req.Cwd\n\t}",
145
+ "replace": ""
146
+ },
147
+ {
148
+ "name": "list-cursor-ignored",
149
+ "module": "cmd",
150
+ "file": "internal/acp/agent.go",
151
+ "find": "if n, ok := parseIntPrefix(*req.Cursor); ok && n > 0 {",
152
+ "replace": "if n, ok := parseIntPrefix(*req.Cursor); ok && n > 1000000 {"
153
+ },
154
+ {
155
+ "name": "model-lookup-without-provider-skipped",
156
+ "module": "cmd",
157
+ "file": "internal/acp/agent.go",
158
+ "find": "if provider == \"\" || modelID == \"\" {",
159
+ "replace": "if false {"
160
+ },
161
+ {
162
+ "name": "model-change-no-usage-refresh",
163
+ "module": "cmd",
164
+ "file": "internal/acp/agent.go",
165
+ "find": "if modelChanged {\n\t\tsess.PublishContextUsage()",
166
+ "replace": "if modelChanged && false {\n\t\tsess.PublishContextUsage()"
167
+ },
168
+ {
169
+ "name": "thinking-change-refreshes-usage",
170
+ "module": "cmd",
171
+ "file": "internal/acp/agent.go",
172
+ "find": "if modelChanged {\n\t\tsess.PublishContextUsage()",
173
+ "replace": "if modelChanged || true {\n\t\tsess.PublishContextUsage()",
174
+ "why": "no-op case on the red stub: a thinking-level change publishes no usage update"
175
+ },
176
+ {
177
+ "name": "empty-mode-accepted",
178
+ "module": "cmd",
179
+ "file": "internal/acp/agent.go",
180
+ "find": "if !ok || mode == \"\" {",
181
+ "replace": "if !ok {"
182
+ },
183
+ {
184
+ "name": "unknown-config-option-accepted",
185
+ "module": "cmd",
186
+ "file": "internal/acp/agent.go",
187
+ "find": "default:\n\t\treturn SetSessionConfigOptionResponse{}, ErrInvalidParams(nil, \"Unknown config option: \"+req.ConfigID)",
188
+ "replace": "default:"
189
+ },
190
+ {
191
+ "name": "load-does-not-close-live-copy",
192
+ "module": "cmd",
193
+ "file": "internal/acp/agent.go",
194
+ "find": "\ta.sessions.Close(req.SessionID)\n\ta.setLastCwd(req.Cwd)",
195
+ "replace": "\ta.setLastCwd(req.Cwd)"
196
+ },
197
+ {
198
+ "name": "load-failure-keeps-child",
199
+ "module": "cmd",
200
+ "file": "internal/acp/agent.go",
201
+ "find": "\t\ta.sessions.Close(sess.ID())\n\t\treturn LoadSessionResponse{}, err",
202
+ "replace": "\t\treturn LoadSessionResponse{}, err"
203
+ },
204
+ {
205
+ "name": "load-does-not-refresh-map",
206
+ "module": "cmd",
207
+ "file": "internal/acp/agent.go",
208
+ "find": "\ta.store.Upsert(StoredSession{SessionID: req.SessionID, Cwd: req.Cwd, SessionFile: stored.sessionFile})\n\n\tdata, err",
209
+ "replace": "\n\tdata, err"
210
+ },
211
+ {
212
+ "name": "restore-uses-no-session-file",
213
+ "module": "cmd",
214
+ "file": "internal/acp/agent.go",
215
+ "find": "SpawnParams{Cwd: cwd, SessionPath: stored.sessionFile, PiCommand: a.pigCommand()}",
216
+ "replace": "SpawnParams{Cwd: cwd, PiCommand: a.pigCommand()}"
217
+ },
218
+ {
219
+ "name": "tool-history-not-replayed-as-error",
220
+ "module": "cmd",
221
+ "file": "internal/acp/agent.go",
222
+ "find": "status := \"completed\"\n\t\tif isError {\n\t\t\tstatus = \"failed\"\n\t\t}\n\t\tif IsBashTool(toolName)",
223
+ "replace": "status := \"completed\"\n\t\tif IsBashTool(toolName)"
224
+ },
225
+ {
226
+ "name": "slash-with-image-handled-locally",
227
+ "module": "cmd",
228
+ "file": "internal/acp/agent_prompt.go",
229
+ "find": "if len(images) == 0 && strings.HasPrefix",
230
+ "replace": "if strings.HasPrefix"
231
+ },
232
+ {
233
+ "name": "autocompact-toggle-not-inverted",
234
+ "module": "cmd",
235
+ "file": "internal/acp/agent_prompt.go",
236
+ "find": "enabled = !truthy(state[\"autoCompactionEnabled\"])",
237
+ "replace": "enabled = truthy(state[\"autoCompactionEnabled\"])"
238
+ },
239
+ {
240
+ "name": "steering-any-mode-accepted",
241
+ "module": "cmd",
242
+ "file": "internal/acp/agent_prompt.go",
243
+ "find": "if mode != \"all\" && mode != \"one-at-a-time\" {",
244
+ "replace": "if false {"
245
+ },
246
+ {
247
+ "name": "name-empty-accepted",
248
+ "module": "cmd",
249
+ "file": "internal/acp/agent_prompt.go",
250
+ "find": "if name == \"\" {",
251
+ "replace": "if false {"
252
+ },
253
+ {
254
+ "name": "export-empty-session-exported",
255
+ "module": "cmd",
256
+ "file": "internal/acp/agent_prompt.go",
257
+ "find": "if file == \"\" || count == 0 || !exists {",
258
+ "replace": "if file == \"\" || count < 0 || !exists {"
259
+ },
260
+ {
261
+ "name": "error-turn-reported-as-error",
262
+ "module": "cmd",
263
+ "file": "internal/acp/agent_prompt.go",
264
+ "find": "if reason == StopError {",
265
+ "replace": "if false {"
266
+ },
267
+ {
268
+ "name": "cancelled-error-turn-is-end-turn",
269
+ "module": "cmd",
270
+ "file": "internal/acp/agent_prompt.go",
271
+ "find": "if sess.WasCancelRequested() {\n\t\t\treason = StopCancelled",
272
+ "replace": "if false {\n\t\t\treason = StopCancelled"
273
+ },
274
+ {
275
+ "name": "changelog-not-truncated",
276
+ "module": "cmd",
277
+ "file": "internal/acp/agent.go",
278
+ "find": "maxChangelogChars = 20000",
279
+ "replace": "maxChangelogChars = 20001"
280
+ },
281
+ {
282
+ "name": "idle-notice-not-flushed-before-response",
283
+ "module": "cmd",
284
+ "file": "internal/acp/session.go",
285
+ "find": "\t\ts.emit(queueInfo(0, false))\n\t\ts.flushEmits()",
286
+ "replace": "\t\ts.emit(queueInfo(0, false))"
287
+ },
288
+ {
289
+ "name": "cancel-flag-leaks-into-next-turn",
290
+ "module": "cmd",
291
+ "file": "internal/acp/session.go",
292
+ "find": "\ts.cancelRequested = false\n\ts.inAgentLoop = false\n\ts.pending = t",
293
+ "replace": "\ts.inAgentLoop = false\n\ts.pending = t"
294
+ },
295
+ {
296
+ "name": "cancelled-turn-reports-end-turn",
297
+ "module": "cmd",
298
+ "file": "internal/acp/session.go",
299
+ "find": "if s.cancelRequested {\n\t\treason = StopCancelled",
300
+ "replace": "if false {\n\t\treason = StopCancelled"
301
+ },
302
+ {
303
+ "name": "prompt-auth-error-swallowed",
304
+ "module": "cmd",
305
+ "file": "internal/acp/session.go",
306
+ "find": "if authErr := MaybeAuthRequiredError(err); authErr != nil {",
307
+ "replace": "if authErr := MaybeAuthRequiredError(err); false && authErr != nil {"
308
+ },
309
+ {
310
+ "name": "prompt-error-after-cancel-is-error",
311
+ "module": "cmd",
312
+ "file": "internal/acp/session.go",
313
+ "find": "} else if cancelled {",
314
+ "replace": "} else if cancelled && false {"
315
+ },
316
+ {
317
+ "name": "queue-not-cleared-on-cancel",
318
+ "module": "cmd",
319
+ "file": "internal/acp/session.go",
320
+ "find": "queued := s.queue\n\ts.queue = nil",
321
+ "replace": "queued := []*queuedTurn{}"
322
+ },
323
+ {
324
+ "name": "startup-info-sent-twice",
325
+ "module": "cmd",
326
+ "file": "internal/acp/session.go",
327
+ "find": "\ts.startupSent = true\n\ttext := *s.startupInfo",
328
+ "replace": "\ttext := *s.startupInfo"
329
+ },
330
+ {
331
+ "name": "tool-status-downgraded",
332
+ "module": "cmd",
333
+ "file": "internal/acp/session.go",
334
+ "find": "\tstatus := \"pending\"\n\tif has {\n\t\tstatus = existing\n\t}",
335
+ "replace": "\tstatus := \"pending\"\n\t_ = existing"
336
+ },
337
+ {
338
+ "name": "select-index-leading-zero-accepted",
339
+ "module": "cmd",
340
+ "file": "internal/acp/session.go",
341
+ "find": "if err != nil || n < 0 || strconv.Itoa(n) != raw {",
342
+ "replace": "if err != nil || n < 0 {"
343
+ },
344
+ {
345
+ "name": "select-out-of-range-index-panics",
346
+ "module": "cmd",
347
+ "file": "internal/acp/session.go",
348
+ "find": "ok && idx < len(options)",
349
+ "replace": "ok"
350
+ },
351
+ {
352
+ "name": "confirm-no-is-yes",
353
+ "module": "cmd",
354
+ "file": "internal/acp/session.go",
355
+ "find": "\"confirmed\": resp.Outcome.OptionID == \"yes\"",
356
+ "replace": "\"confirmed\": resp.Outcome.OptionID != \"yes\""
357
+ },
358
+ {
359
+ "name": "confirm-cancel-is-no",
360
+ "module": "cmd",
361
+ "file": "internal/acp/session.go",
362
+ "find": "if resp.Outcome.Outcome == \"cancelled\" {\n\t\ts.sendUI(map[string]any{\"id\": id, \"cancelled\": true})\n\t\treturn\n\t}\n\ts.sendUI(map[string]any{\"id\": id, \"confirmed\"",
363
+ "replace": "if false {\n\t\treturn\n\t}\n\ts.sendUI(map[string]any{\"id\": id, \"confirmed\""
364
+ },
365
+ {
366
+ "name": "permission-error-not-cancelled",
367
+ "module": "cmd",
368
+ "file": "internal/acp/session.go",
369
+ "find": "if err != nil {\n\t\ts.sendUI(map[string]any{\"id\": id, \"cancelled\": true})\n\t\treturn PermissionResponse{}, false",
370
+ "replace": "if err != nil {\n\t\treturn PermissionResponse{}, false"
371
+ },
372
+ {
373
+ "name": "input-dialog-answered-with-value",
374
+ "module": "cmd",
375
+ "file": "internal/acp/session.go",
376
+ "find": "s.emit(textChunk(\"agent_message_chunk\", fmt.Sprintf(\"Pi %s UI request is not supported in ACP yet; cancelling it.\", method)))\n\t\tcancel()",
377
+ "replace": "s.emit(textChunk(\"agent_message_chunk\", fmt.Sprintf(\"Pi %s UI request is not supported in ACP yet; cancelling it.\", method)))\n\t\ts.ackQ.do(func() { s.sendUI(map[string]any{\"id\": id, \"value\": \"\"}) })"
378
+ },
379
+ {
380
+ "name": "notify-level-default",
381
+ "module": "cmd",
382
+ "file": "internal/acp/session.go",
383
+ "find": "level := \"info\"",
384
+ "replace": "level := \"warning\""
385
+ },
386
+ {
387
+ "name": "usage-empty-window-accepted",
388
+ "module": "cmd",
389
+ "file": "internal/acp/session.go",
390
+ "find": "!ok2 || size <= 0",
391
+ "replace": "!ok2"
392
+ },
393
+ {
394
+ "name": "usage-negative-tokens-accepted",
395
+ "module": "cmd",
396
+ "file": "internal/acp/session.go",
397
+ "find": "!ok1 || used < 0",
398
+ "replace": "!ok1"
399
+ },
400
+ {
401
+ "name": "usage-null-tokens-accepted",
402
+ "module": "cmd",
403
+ "file": "internal/acp/session.go",
404
+ "find": "f, ok := asNumber(v)\n\tif !ok ||",
405
+ "replace": "f, ok := asNumber(v)\n\tif ok &&"
406
+ },
407
+ {
408
+ "name": "retry-subsecond-rounds-to-zero",
409
+ "module": "cmd",
410
+ "file": "internal/acp/session.go",
411
+ "find": "if delayMs > 0 && secs == 0 {",
412
+ "replace": "if false {"
413
+ },
414
+ {
415
+ "name": "edit-duplicate-match-gets-a-line",
416
+ "module": "cmd",
417
+ "file": "internal/acp/session.go",
418
+ "find": "if strings.Contains(text[first+len(needle):], needle) {",
419
+ "replace": "if false {"
420
+ },
421
+ {
422
+ "name": "write-new-file-not-a-diff",
423
+ "module": "cmd",
424
+ "file": "internal/acp/session.go",
425
+ "find": "if snap.oldText == nil || newText != *snap.oldText {",
426
+ "replace": "if snap.oldText != nil && newText != *snap.oldText {"
427
+ },
428
+ {
429
+ "name": "failed-tool-gets-a-diff",
430
+ "module": "cmd",
431
+ "file": "internal/acp/session.go",
432
+ "find": "if !isError && hasSnap {",
433
+ "replace": "if hasSnap {"
434
+ },
435
+ {
436
+ "name": "manager-double-dispose",
437
+ "module": "cmd",
438
+ "file": "internal/acp/session.go",
439
+ "find": "\tif ok {\n\t\ts.proc.Dispose()\n\t}",
440
+ "replace": "\tif ok || !ok {\n\t\ts.proc.Dispose()\n\t}"
441
+ },
442
+ {
443
+ "name": "manager-does-not-record-file",
444
+ "module": "cmd",
445
+ "file": "internal/acp/session.go",
446
+ "find": "m.store.Upsert(StoredSession{SessionID: id, Cwd: p.Cwd, SessionFile: file})",
447
+ "replace": "_ = file"
448
+ },
449
+ {
450
+ "name": "unknown-session-id-not-invalid-params",
451
+ "module": "cmd",
452
+ "file": "internal/acp/session.go",
453
+ "find": "return nil, ErrInvalidParams(nil, \"Unknown sessionId: \"+id)",
454
+ "replace": "return nil, ErrInternal(nil, \"Unknown sessionId: \"+id)"
455
+ },
456
+ {
457
+ "name": "base64-length-padding",
458
+ "module": "cmd",
459
+ "file": "internal/acp/translate.go",
460
+ "find": "pad = 2",
461
+ "replace": "pad = 1"
462
+ },
463
+ {
464
+ "name": "bash-exit-code-error-default",
465
+ "module": "cmd",
466
+ "file": "internal/acp/translate.go",
467
+ "find": "if isError {\n\t\treturn 1\n\t}\n\treturn 0",
468
+ "replace": "return 0"
469
+ },
470
+ {
471
+ "name": "bash-delta-always-full",
472
+ "module": "cmd",
473
+ "file": "internal/acp/translate.go",
474
+ "find": "if strings.HasPrefix(next, previous) {\n\t\treturn next[len(previous):]\n\t}",
475
+ "replace": ""
476
+ },
477
+ {
478
+ "name": "tool-diff-preferred-over-content",
479
+ "module": "cmd",
480
+ "file": "internal/acp/translate.go",
481
+ "find": "if diff, ok := details[\"diff\"].(string); ok && jsTrim(diff) != \"\" {",
482
+ "replace": "if diff, ok := details[\"diff\"].(string); ok && false {"
483
+ },
484
+ {
485
+ "name": "image-marker-dropped",
486
+ "module": "cmd",
487
+ "file": "internal/acp/translate.go",
488
+ "find": "images = append(images, Image{\"type\": \"image\", \"mimeType\": b[\"mimeType\"], \"data\": b[\"data\"]})",
489
+ "replace": ""
490
+ },
491
+ {
492
+ "name": "slash-first-arg-wins-dedupe",
493
+ "module": "cmd",
494
+ "file": "internal/acp/slash.go",
495
+ "find": "if seen[c.Name] {\n\t\t\tcontinue\n\t\t}\n\t\tseen[c.Name] = true\n\t\tout = append(out, AvailableCommand{Name: c.Name, Description: c.Description})",
496
+ "replace": "seen[c.Name] = true\n\t\tout = append(out, AvailableCommand{Name: c.Name, Description: c.Description})"
497
+ },
498
+ {
499
+ "name": "extension-commands-advertised",
500
+ "module": "cmd",
501
+ "file": "internal/acp/slash.go",
502
+ "find": "!opts.IncludeExtensionCommands && src == \"extension\"",
503
+ "replace": "false && src == \"extension\""
504
+ },
505
+ {
506
+ "name": "store-wrong-version",
507
+ "module": "cmd",
508
+ "file": "internal/acp/store.go",
509
+ "find": "f.Version != 1",
510
+ "replace": "f.Version != 2"
511
+ },
512
+ {
513
+ "name": "sessions-oldest-first",
514
+ "module": "cmd",
515
+ "file": "internal/acp/pisessions.go",
516
+ "find": "return key(items[i].UpdatedAt) > key(items[j].UpdatedAt)",
517
+ "replace": "return key(items[i].UpdatedAt) < key(items[j].UpdatedAt)"
518
+ },
519
+ {
520
+ "name": "shared-dirs-any-value",
521
+ "module": "cmd",
522
+ "file": "internal/acp/paths.go",
523
+ "find": "os.Getenv(\"PIG_USE_PI_DIRS\") == \"1\"",
524
+ "replace": "os.Getenv(\"PIG_USE_PI_DIRS\") != \"\""
525
+ },
526
+ {
527
+ "name": "quiet-start-legacy-ignored",
528
+ "module": "cmd",
529
+ "file": "internal/acp/settings.go",
530
+ "find": "if b, ok := m[\"quietStart\"].(bool); ok {",
531
+ "replace": "if b, ok := m[\"quietStartX\"].(bool); ok {"
532
+ },
533
+ {
534
+ "name": "auth-403-not-detected",
535
+ "module": "cmd",
536
+ "file": "internal/acp/auth.go",
537
+ "find": "\"forbidden\", \"401\", \"403\"}",
538
+ "replace": "\"forbidden\", \"401\"}"
539
+ },
540
+ {
541
+ "name": "unknown-method-succeeds",
542
+ "module": "cmd",
543
+ "file": "internal/acp/server.go",
544
+ "find": "return nil, ErrMethodNotFound(req.Method)",
545
+ "replace": "return map[string]any{}, nil"
546
+ },
547
+ {
548
+ "name": "initialize-without-version-accepted",
549
+ "module": "cmd",
550
+ "file": "internal/acp/server.go",
551
+ "find": "need(p.ProtocolVersion != nil, \"protocolVersion is required\")",
552
+ "replace": "need(true, \"\")"
553
+ },
554
+ {
555
+ "name": "cancel-as-request-unanswered-null",
556
+ "module": "cmd",
557
+ "file": "internal/acp/server.go",
558
+ "find": "if err := a.Cancel(*p.SessionID); err != nil {\n\t\t\treturn nil, err\n\t\t}",
559
+ "replace": ""
560
+ },
561
+ {
562
+ "name": "deferred-work-not-after-response",
563
+ "module": "cmd",
564
+ "file": "internal/acp/server.go",
565
+ "find": "a := base.Scoped(req.AfterResponse)",
566
+ "replace": "a := base.Scoped(func(fn func()) { fn() })"
567
+ },
568
+ {
569
+ "name": "internal-error-code",
570
+ "module": "cmd",
571
+ "file": "internal/jsonrpc/jsonrpc.go",
572
+ "find": "Code: -32603, Message: \"Internal error\"",
573
+ "replace": "Code: -32602, Message: \"Internal error\""
574
+ },
575
+ {
576
+ "name": "notification-answered",
577
+ "module": "cmd",
578
+ "file": "internal/jsonrpc/jsonrpc.go",
579
+ "find": "\tif notification {\n\t\treturn\n\t}\n\tresp :=",
580
+ "replace": "\tresp :="
581
+ },
582
+ {
583
+ "name": "after-response-hook-dropped",
584
+ "module": "cmd",
585
+ "file": "internal/jsonrpc/jsonrpc.go",
586
+ "find": "\tfor _, fn := range req.after {\n\t\tfn()\n\t}",
587
+ "replace": ""
588
+ },
589
+ {
590
+ "name": "bad-line-stops-reading",
591
+ "module": "cmd",
592
+ "file": "internal/jsonrpc/jsonrpc.go",
593
+ "find": "if json.Unmarshal(line, &m) == nil {\n\t\t\t\tc.dispatch(m)\n\t\t\t}",
594
+ "replace": "if json.Unmarshal(line, &m) != nil {\n\t\t\t\tc.closeDone()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tc.dispatch(m)"
595
+ },
596
+ {
597
+ "name": "failed-write-does-not-end-connection",
598
+ "module": "cmd",
599
+ "file": "internal/jsonrpc/jsonrpc.go",
600
+ "find": "\t\t\tc.queue = nil\n\t\t\tc.mu.Unlock()\n\t\t\tc.closeDone()",
601
+ "replace": "\t\t\tc.queue = nil\n\t\t\tc.mu.Unlock()"
602
+ },
603
+ {
604
+ "name": "rpc-failure-is-success",
605
+ "module": "cmd",
606
+ "file": "internal/pirpc/process.go",
607
+ "find": "if !res.Success {\n\t\treturn res, fmt.Errorf(\"pi %v failed",
608
+ "replace": "if false {\n\t\treturn res, fmt.Errorf(\"pi %v failed"
609
+ },
610
+ {
611
+ "name": "thinking-levels-any-accepted",
612
+ "module": "cmd",
613
+ "file": "internal/pirpc/process.go",
614
+ "find": "if !ok || s == \"\" {",
615
+ "replace": "if !ok {"
616
+ },
617
+ {
618
+ "name": "late-response-broadcast-as-event",
619
+ "module": "cmd",
620
+ "file": "internal/pirpc/process.go",
621
+ "find": "if c == nil {\n\t\t\treturn\n\t\t}\n\t\tvar w wireResponse",
622
+ "replace": "if c == nil {\n\t\t\tfor _, h := range p.handlers {\n\t\t\t\th(msg)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tvar w wireResponse"
623
+ },
624
+ {
625
+ "name": "windows-default-launcher",
626
+ "module": "cmd",
627
+ "file": "internal/pirpc/process.go",
628
+ "find": "if goos == \"windows\" {\n\t\treturn \"pig.cmd\"\n\t}",
629
+ "replace": "if goos == \"windows\" {\n\t\treturn \"pig\"\n\t}"
630
+ },
631
+ {
632
+ "name": "shell-for-exe",
633
+ "module": "cmd",
634
+ "file": "internal/pirpc/process.go",
635
+ "find": "strings.HasSuffix(l, \".cmd\") || strings.HasSuffix(l, \".bat\")",
636
+ "replace": "strings.HasSuffix(l, \".cmd\") || strings.HasSuffix(l, \".exe\")"
637
+ },
638
+ {
639
+ "name": "session-flag-dropped",
640
+ "module": "cmd",
641
+ "file": "internal/pirpc/process.go",
642
+ "find": "args = append(args, \"--session\", sessionPath)",
643
+ "replace": "_ = sessionPath"
644
+ },
645
+ {
646
+ "name": "unknown-flag-exits-1",
647
+ "module": "cmd",
648
+ "file": "main.go",
649
+ "find": "fmt.Fprintf(errw, \"pig-acp: %s\\n\\n%s\", msg, usage)\n\t\treturn 2",
650
+ "replace": "fmt.Fprintf(errw, \"pig-acp: %s\\n\\n%s\", msg, usage)\n\t\treturn 1"
651
+ },
652
+ {
653
+ "name": "env-precedence-swapped",
654
+ "module": "cmd",
655
+ "file": "main.go",
656
+ "find": "[]string{\"PIG_ACP_PIG_COMMAND\", \"PI_ACP_PI_COMMAND\"}",
657
+ "replace": "[]string{\"PI_ACP_PI_COMMAND\", \"PIG_ACP_PIG_COMMAND\"}"
658
+ },
659
+ {
660
+ "name": "terminal-login-exit-code-lost",
661
+ "module": "cmd",
662
+ "file": "main.go",
663
+ "find": "\t\t\tif code := exitErr.ExitCode(); code >= 0 {\n\t\t\t\treturn code\n\t\t\t}",
664
+ "replace": "\t\t\tif code := exitErr.ExitCode(); code >= 0 {\n\t\t\t\treturn 1\n\t\t\t}"
665
+ },
666
+ {
667
+ "name": "piglet-flag-dropped",
668
+ "module": "cmd",
669
+ "file": "main.go",
670
+ "find": "extra = append([]string{\"--piglet\", piglet}, extra...)",
671
+ "replace": "_ = piglet"
672
+ },
673
+ {
674
+ "name": "version-lacks-protocol",
675
+ "module": "cmd",
676
+ "file": "main.go",
677
+ "find": "fmt.Fprintf(out, \"pig-acp %s (ACP protocol version %d)\\n\", version, acp.ProtocolVersion)",
678
+ "replace": "fmt.Fprintf(out, \"pig-acp %s\\n\", version)"
679
+ },
680
+ {
681
+ "name": "acp-usage-warning-level",
682
+ "module": "ext",
683
+ "file": "extension.go",
684
+ "find": "ctx.Notify(\"Usage: /acp [zed]\", \"warning\")",
685
+ "replace": "ctx.Notify(\"Usage: /acp [zed]\", \"info\")"
686
+ },
687
+ {
688
+ "name": "acp-zed-arg-shows-limits",
689
+ "module": "ext",
690
+ "file": "extension.go",
691
+ "find": "ctx.Notify(zedSnippet(), \"info\")\n\t\tdefault:",
692
+ "replace": "ctx.Notify(zedSnippet()+\"\\n\\n\"+limits(), \"info\")\n\t\tdefault:"
693
+ },
694
+ {
695
+ "name": "acp-limits-dropped",
696
+ "module": "ext",
697
+ "file": "extension.go",
698
+ "find": "ctx.Notify(zedSnippet()+\"\\n\\n\"+limits(), \"info\")\n\t\tcase \"zed\":",
699
+ "replace": "ctx.Notify(zedSnippet(), \"info\")\n\t\tcase \"zed\":"
700
+ },
701
+ {
702
+ "name": "acp-names-wrong-executable",
703
+ "module": "ext",
704
+ "file": "extension.go",
705
+ "find": "\"args\": []string{\"--pig\", Executable()}",
706
+ "replace": "\"args\": []string{\"--pig\", \"pig\"}"
707
+ },
708
+ {
709
+ "name": "review-harness-binary-ignored",
710
+ "module": "ext",
711
+ "file": "extension.go",
712
+ "find": "\tif host := os.Getenv(\"PIG_HARNESS_BINARY\"); host != \"\" {\n\t\treturn host\n\t}\n",
713
+ "replace": "",
714
+ "why": "review: installed as a Package, /acp must name the agent, not the extension cell runner"
715
+ },
716
+ {
717
+ "name": "review-login-drops-piglet",
718
+ "module": "cmd",
719
+ "file": "main.go",
720
+ "find": "\tif piglet != \"\" {\n\t\tlogin = append(login, \"--piglet\", piglet)\n\t}\n",
721
+ "replace": "",
722
+ "why": "review: the terminal auth method must start the agent the sessions use"
723
+ },
724
+ {
725
+ "name": "review-shared-map-under-pi",
726
+ "module": "cmd",
727
+ "file": "internal/acp/paths.go",
728
+ "find": "\tif x := os.Getenv(\"XDG_CONFIG_HOME\"); x != \"\" {\n\t\treturn filepath.Join(expandTilde(x), \"pig\")\n\t}",
729
+ "replace": "\tif sharedPiDirs() {\n\t\treturn filepath.Join(userHome(), \".pi\")\n\t}\n\tif x := os.Getenv(\"XDG_CONFIG_HOME\"); x != \"\" {\n\t\treturn filepath.Join(expandTilde(x), \"pig\")\n\t}",
730
+ "why": "review: PiG state stays under PiG config root in shared mode"
731
+ },
732
+ {
733
+ "name": "review-session-dir-env-no-tilde",
734
+ "module": "cmd",
735
+ "file": "internal/acp/pisessions.go",
736
+ "find": "\tif d := os.Getenv(env); d != \"\" {\n\t\treturn expandTilde(d)\n\t}",
737
+ "replace": "\tif d := os.Getenv(env); d != \"\" {\n\t\treturn d\n\t}",
738
+ "why": "review: pig expands ~ in the session directory variable"
739
+ },
740
+ {
741
+ "name": "review-shared-session-dir-env-ignored",
742
+ "module": "cmd",
743
+ "file": "internal/acp/pisessions.go",
744
+ "find": "\t\tenv = \"PI_CODING_AGENT_SESSION_DIR\"",
745
+ "replace": "\t\tenv = \"PIG_CODING_AGENT_SESSION_DIR\"",
746
+ "why": "review: shared mode reads PI_CODING_AGENT_SESSION_DIR"
747
+ }
748
+ ]