@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.
- package/CREDITS.md +23 -0
- package/LICENSE +22 -0
- package/README.md +110 -0
- package/extensions/acp/cmd/pig-acp/e2e_llm_test.go +168 -0
- package/extensions/acp/cmd/pig-acp/e2e_test.go +541 -0
- package/extensions/acp/cmd/pig-acp/go.mod +6 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/agent.go +784 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/agent_builtin_test.go +536 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/agent_commands_test.go +199 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/agent_config_test.go +530 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/agent_helpers_test.go +215 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/agent_load_test.go +333 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/agent_prompt.go +289 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/agent_session_test.go +429 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/auth.go +61 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/bench_test.go +47 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/helpers_test.go +421 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/main_test.go +28 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/mutation_extra_test.go +142 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/paths.go +77 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/pisessions.go +317 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/protocol.go +188 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/server.go +218 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/server_test.go +386 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/session.go +1068 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/session_diff_test.go +183 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/session_events_test.go +443 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/session_extra_test.go +547 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/session_usage_test.go +198 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/settings.go +79 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/slash.go +278 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/slash_test.go +128 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/startup.go +156 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/store.go +118 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/store_paths_test.go +466 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/translate.go +352 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/translate_test.go +105 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/twin_test.go +28 -0
- package/extensions/acp/cmd/pig-acp/internal/acp/types.go +202 -0
- package/extensions/acp/cmd/pig-acp/internal/jsonrpc/bench_test.go +24 -0
- package/extensions/acp/cmd/pig-acp/internal/jsonrpc/jsonrpc.go +302 -0
- package/extensions/acp/cmd/pig-acp/internal/jsonrpc/jsonrpc_test.go +320 -0
- package/extensions/acp/cmd/pig-acp/internal/jsonrpc/twin_test.go +28 -0
- package/extensions/acp/cmd/pig-acp/internal/pirpc/kill_unix.go +19 -0
- package/extensions/acp/cmd/pig-acp/internal/pirpc/kill_windows.go +11 -0
- package/extensions/acp/cmd/pig-acp/internal/pirpc/process.go +530 -0
- package/extensions/acp/cmd/pig-acp/internal/pirpc/process_test.go +355 -0
- package/extensions/acp/cmd/pig-acp/internal/pirpc/twin_test.go +28 -0
- package/extensions/acp/cmd/pig-acp/main.go +177 -0
- package/extensions/acp/cmd/pig-acp/main_test.go +213 -0
- package/extensions/acp/cmd/pig-acp/sigpipe_unix.go +10 -0
- package/extensions/acp/cmd/pig-acp/sigpipe_windows.go +5 -0
- package/extensions/acp/cmd/pig-acp/testdata/ask/extension.go +28 -0
- package/extensions/acp/cmd/pig-acp/testdata/ask/go.mod +7 -0
- package/extensions/acp/cmd/pig-acp/testdata/ask/go.sum +2 -0
- package/extensions/acp/cmd/pig-acp/testdata/gate/extension.go +37 -0
- package/extensions/acp/cmd/pig-acp/testdata/gate/go.mod +7 -0
- package/extensions/acp/cmd/pig-acp/testdata/gate/go.sum +2 -0
- package/extensions/acp/cmd/pig-acp/twin_test.go +28 -0
- package/extensions/acp/extension.go +63 -0
- package/extensions/acp/extension_test.go +111 -0
- package/extensions/acp/fakehost_test.go +548 -0
- package/extensions/acp/go.mod +6 -0
- package/extensions/acp/go.sum +2 -0
- package/package.json +41 -0
- package/port/PORT.md +147 -0
- package/port/interop/package-lock.json +89 -0
- package/port/interop/package.json +13 -0
- package/port/interop/run.mjs +229 -0
- package/port/mutate.mjs +110 -0
- package/port/mutation-results.txt +107 -0
- package/port/mutations.json +748 -0
- package/port/oracle/pi-acp/LICENSE +21 -0
- package/port/oracle/pi-acp/README.md +209 -0
- package/port/oracle/pi-acp/package.json +65 -0
- package/port/oracle/pi-acp/src/acp/agent.ts +1661 -0
- package/port/oracle/pi-acp/src/acp/auth-required.ts +37 -0
- package/port/oracle/pi-acp/src/acp/auth.ts +59 -0
- package/port/oracle/pi-acp/src/acp/paths.ts +15 -0
- package/port/oracle/pi-acp/src/acp/pi-commands.ts +59 -0
- package/port/oracle/pi-acp/src/acp/pi-sessions.ts +333 -0
- package/port/oracle/pi-acp/src/acp/pi-settings.ts +75 -0
- package/port/oracle/pi-acp/src/acp/session-store.ts +68 -0
- package/port/oracle/pi-acp/src/acp/session.ts +1078 -0
- package/port/oracle/pi-acp/src/acp/slash-commands.ts +197 -0
- package/port/oracle/pi-acp/src/acp/translate/bash.ts +100 -0
- package/port/oracle/pi-acp/src/acp/translate/pi-messages.ts +17 -0
- package/port/oracle/pi-acp/src/acp/translate/pi-tools.ts +51 -0
- package/port/oracle/pi-acp/src/acp/translate/prompt.ts +71 -0
- package/port/oracle/pi-acp/src/index.ts +82 -0
- package/port/oracle/pi-acp/src/pi-rpc/command.ts +16 -0
- package/port/oracle/pi-acp/src/pi-rpc/process.ts +432 -0
- package/port/oracle/pi-acp/test/component/agent-steering-followup-modes.test.ts +143 -0
- package/port/oracle/pi-acp/test/component/session-diff.test.ts +214 -0
- package/port/oracle/pi-acp/test/component/session-events.test.ts +1102 -0
- package/port/oracle/pi-acp/test/component/session-list-and-load.test.ts +129 -0
- package/port/oracle/pi-acp/test/component/session-list-custom-session-dir.test.ts +52 -0
- package/port/oracle/pi-acp/test/component/session-list-scoped.test.ts +76 -0
- package/port/oracle/pi-acp/test/component/session-load-toolresult.test.ts +68 -0
- package/port/oracle/pi-acp/test/component/session-queue-cancel.test.ts +43 -0
- package/port/oracle/pi-acp/test/component/session-slash-commands.test.ts +37 -0
- package/port/oracle/pi-acp/test/component/session-thinking-modes.test.ts +22 -0
- package/port/oracle/pi-acp/test/component/session-title-long-session.test.ts +56 -0
- package/port/oracle/pi-acp/test/component/session-updatedAt-message-only.test.ts +57 -0
- package/port/oracle/pi-acp/test/helpers/fakes.ts +87 -0
- package/port/oracle/pi-acp/test/unit/auth-methods-terminal-auth-meta.test.ts +22 -0
- package/port/oracle/pi-acp/test/unit/builtin-commands.test.ts +60 -0
- package/port/oracle/pi-acp/test/unit/context-usage.test.ts +204 -0
- package/port/oracle/pi-acp/test/unit/merge-commands.test.ts +19 -0
- package/port/oracle/pi-acp/test/unit/model-thinking-levels.test.ts +268 -0
- package/port/oracle/pi-acp/test/unit/new-session-auth-required-when-no-models.test.ts +51 -0
- package/port/oracle/pi-acp/test/unit/new-session-pi-not-found.test.ts +26 -0
- package/port/oracle/pi-acp/test/unit/new-session-runtime-startup-errors.test.ts +148 -0
- package/port/oracle/pi-acp/test/unit/pi-command.test.ts +44 -0
- package/port/oracle/pi-acp/test/unit/pi-commands.test.ts +32 -0
- package/port/oracle/pi-acp/test/unit/pi-enable-embed-context-flag.test.ts +35 -0
- package/port/oracle/pi-acp/test/unit/pi-messages.test.ts +29 -0
- package/port/oracle/pi-acp/test/unit/pi-rpc-request-timeout.test.ts +137 -0
- package/port/oracle/pi-acp/test/unit/pi-rpc-session-path.test.ts +93 -0
- package/port/oracle/pi-acp/test/unit/pi-tools.test.ts +40 -0
- package/port/oracle/pi-acp/test/unit/prompt-to-pi-message.test.ts +74 -0
- package/port/oracle/pi-acp/test/unit/session-config-options.test.ts +217 -0
- package/port/oracle/pi-acp/test/unit/session-delete.test.ts +170 -0
- package/port/oracle/pi-acp/test/unit/session-restore.test.ts +239 -0
- package/port/oracle/pi-acp/test/unit/slash-commands.test.ts +36 -0
- package/port/oracle/pi-acp/test/unit/startup-info-env.test.ts +84 -0
- package/port/oracle/pi-acp/test/unit/startup-info-load-session.test.ts +53 -0
- package/port/oracle/pi-acp/test/unit/startup-info-project-packages.test.ts +74 -0
- package/port/oracle/pi-acp/test/unit/stdout-destroyed-does-not-crash.test.ts +32 -0
- package/port/oracle/pi-acp/test/unit/thinking-level-rpc.test.ts +43 -0
- package/port/schema/LICENSE +191 -0
- package/port/schema/schema.json +8015 -0
- package/port/upstream-tests.json +201 -0
- package/provenance.json +28 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import test from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { mkdirSync, writeFileSync } from 'node:fs'
|
|
4
|
+
import { mkdtempSync } from 'node:fs'
|
|
5
|
+
import { tmpdir } from 'node:os'
|
|
6
|
+
import { join } from 'node:path'
|
|
7
|
+
import { PiAcpSession } from '../../src/acp/session.js'
|
|
8
|
+
import { FakeAgentSideConnection, FakePiRpcProcess, asAgentConn } from '../helpers/fakes.js'
|
|
9
|
+
|
|
10
|
+
function createSession(cwd: string) {
|
|
11
|
+
const conn = new FakeAgentSideConnection()
|
|
12
|
+
const proc = new FakePiRpcProcess()
|
|
13
|
+
|
|
14
|
+
new PiAcpSession({
|
|
15
|
+
sessionId: 's1',
|
|
16
|
+
cwd,
|
|
17
|
+
mcpServers: [],
|
|
18
|
+
proc: proc as any,
|
|
19
|
+
conn: asAgentConn(conn),
|
|
20
|
+
fileCommands: []
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
return { conn, proc }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function completedToolUpdate(conn: FakeAgentSideConnection, toolCallId = 't1') {
|
|
27
|
+
return conn.updates.find(
|
|
28
|
+
u =>
|
|
29
|
+
(u.update as any).toolCallId === toolCallId &&
|
|
30
|
+
u.update.sessionUpdate === 'tool_call_update' &&
|
|
31
|
+
(u.update as any).status === 'completed'
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
test('PiAcpSession: emits ACP diff content for edit tool from actual before/after file contents', async () => {
|
|
36
|
+
const dir = mkdtempSync(join(tmpdir(), 'pi-acp-diff-'))
|
|
37
|
+
mkdirSync(dir, { recursive: true })
|
|
38
|
+
const filePath = join(dir, 'a.txt')
|
|
39
|
+
writeFileSync(filePath, 'before\n', 'utf8')
|
|
40
|
+
|
|
41
|
+
const { conn, proc } = createSession(dir)
|
|
42
|
+
|
|
43
|
+
proc.emit({ type: 'tool_execution_start', toolCallId: 't1', toolName: 'edit', args: { path: 'a.txt' } })
|
|
44
|
+
writeFileSync(filePath, 'after\n', 'utf8')
|
|
45
|
+
proc.emit({
|
|
46
|
+
type: 'tool_execution_end',
|
|
47
|
+
toolCallId: 't1',
|
|
48
|
+
isError: false,
|
|
49
|
+
result: { content: [{ type: 'text', text: 'ok' }] }
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
await new Promise(r => setTimeout(r, 0))
|
|
53
|
+
|
|
54
|
+
const end = completedToolUpdate(conn)
|
|
55
|
+
assert.ok(end, 'expected completed tool_call_update')
|
|
56
|
+
|
|
57
|
+
const content = (end.update as any).content as any[]
|
|
58
|
+
assert.ok(Array.isArray(content), 'expected content array')
|
|
59
|
+
const diff = content.find(c => c.type === 'diff')
|
|
60
|
+
assert.ok(diff, 'expected diff content item')
|
|
61
|
+
assert.equal(diff.path, 'a.txt')
|
|
62
|
+
assert.equal(diff.oldText, 'before\n')
|
|
63
|
+
assert.equal(diff.newText, 'after\n')
|
|
64
|
+
assert.equal((end.update as any).rawOutput, undefined, 'expected raw output to be suppressed when diff is emitted')
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
test('PiAcpSession: does not turn requested edit args into finalized ACP diffs at tool start', async () => {
|
|
68
|
+
const dir = mkdtempSync(join(tmpdir(), 'pi-acp-diff-'))
|
|
69
|
+
mkdirSync(dir, { recursive: true })
|
|
70
|
+
const filePath = join(dir, 'a.txt')
|
|
71
|
+
writeFileSync(filePath, 'before\n', 'utf8')
|
|
72
|
+
|
|
73
|
+
const { conn, proc } = createSession(dir)
|
|
74
|
+
|
|
75
|
+
proc.emit({
|
|
76
|
+
type: 'tool_execution_start',
|
|
77
|
+
toolCallId: 't1',
|
|
78
|
+
toolName: 'edit',
|
|
79
|
+
args: { path: 'a.txt', edits: [{ oldText: 'before', newText: 'after' }] }
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
await new Promise(r => setTimeout(r, 0))
|
|
83
|
+
|
|
84
|
+
const start = conn.updates.find(u => (u.update as any).toolCallId === 't1' && u.update.sessionUpdate === 'tool_call')
|
|
85
|
+
assert.ok(start, 'expected tool_call for edit start')
|
|
86
|
+
assert.equal((start.update as any).content, undefined, 'expected no start-time diff from requested edit args')
|
|
87
|
+
|
|
88
|
+
writeFileSync(filePath, 'after\n', 'utf8')
|
|
89
|
+
proc.emit({
|
|
90
|
+
type: 'tool_execution_end',
|
|
91
|
+
toolCallId: 't1',
|
|
92
|
+
isError: false,
|
|
93
|
+
result: { content: [{ type: 'text', text: 'ok' }] }
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
await new Promise(r => setTimeout(r, 0))
|
|
97
|
+
|
|
98
|
+
const end = completedToolUpdate(conn)
|
|
99
|
+
assert.ok(end, 'expected completed tool_call_update')
|
|
100
|
+
const diff = (end.update as any).content?.find((c: any) => c.type === 'diff')
|
|
101
|
+
assert.ok(diff, 'expected diff content item')
|
|
102
|
+
assert.equal(diff.oldText, 'before\n')
|
|
103
|
+
assert.equal(diff.newText, 'after\n')
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
test('PiAcpSession: edit diff uses realized fuzzy-match file contents instead of requested args', async () => {
|
|
107
|
+
const dir = mkdtempSync(join(tmpdir(), 'pi-acp-diff-'))
|
|
108
|
+
mkdirSync(dir, { recursive: true })
|
|
109
|
+
const filePath = join(dir, 'fuzzy.txt')
|
|
110
|
+
writeFileSync(filePath, 'FULLWIDTH: ABC123\n', 'utf8')
|
|
111
|
+
|
|
112
|
+
const { conn, proc } = createSession(dir)
|
|
113
|
+
|
|
114
|
+
proc.emit({
|
|
115
|
+
type: 'tool_execution_start',
|
|
116
|
+
toolCallId: 't1',
|
|
117
|
+
toolName: 'edit',
|
|
118
|
+
args: {
|
|
119
|
+
path: 'fuzzy.txt',
|
|
120
|
+
edits: [{ oldText: 'FULLWIDTH: ABC123', newText: 'FULLWIDTH: ascii replacement' }]
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
writeFileSync(filePath, 'FULLWIDTH: ascii replacement\n', 'utf8')
|
|
125
|
+
proc.emit({
|
|
126
|
+
type: 'tool_execution_end',
|
|
127
|
+
toolCallId: 't1',
|
|
128
|
+
isError: false,
|
|
129
|
+
result: { content: [{ type: 'text', text: 'Successfully replaced 1 block(s) in fuzzy.txt.' }] }
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
await new Promise(r => setTimeout(r, 0))
|
|
133
|
+
|
|
134
|
+
const end = completedToolUpdate(conn)
|
|
135
|
+
assert.ok(end, 'expected completed tool_call_update')
|
|
136
|
+
const diff = (end.update as any).content?.find((c: any) => c.type === 'diff')
|
|
137
|
+
assert.ok(diff, 'expected diff content item')
|
|
138
|
+
assert.equal(diff.oldText, 'FULLWIDTH: ABC123\n')
|
|
139
|
+
assert.equal(diff.newText, 'FULLWIDTH: ascii replacement\n')
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
test('PiAcpSession: emits write diff content from actual before/after file contents on completion', async () => {
|
|
143
|
+
const dir = mkdtempSync(join(tmpdir(), 'pi-acp-diff-'))
|
|
144
|
+
mkdirSync(dir, { recursive: true })
|
|
145
|
+
const filePath = join(dir, 'a.txt')
|
|
146
|
+
writeFileSync(filePath, 'before\n', 'utf8')
|
|
147
|
+
|
|
148
|
+
const { conn, proc } = createSession(dir)
|
|
149
|
+
|
|
150
|
+
proc.emit({
|
|
151
|
+
type: 'tool_execution_start',
|
|
152
|
+
toolCallId: 't1',
|
|
153
|
+
toolName: 'write',
|
|
154
|
+
args: { path: 'a.txt', content: 'after\n' }
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
await new Promise(r => setTimeout(r, 0))
|
|
158
|
+
|
|
159
|
+
const start = conn.updates.find(u => (u.update as any).toolCallId === 't1' && u.update.sessionUpdate === 'tool_call')
|
|
160
|
+
assert.ok(start, 'expected tool_call for write start')
|
|
161
|
+
assert.equal((start.update as any).content, undefined, 'expected no start-time diff for write')
|
|
162
|
+
|
|
163
|
+
writeFileSync(filePath, 'after\n', 'utf8')
|
|
164
|
+
proc.emit({
|
|
165
|
+
type: 'tool_execution_end',
|
|
166
|
+
toolCallId: 't1',
|
|
167
|
+
isError: false,
|
|
168
|
+
result: { content: [{ type: 'text', text: 'Successfully wrote 6 bytes to a.txt' }] }
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
await new Promise(r => setTimeout(r, 0))
|
|
172
|
+
|
|
173
|
+
const end = completedToolUpdate(conn)
|
|
174
|
+
assert.ok(end, 'expected completed tool_call_update')
|
|
175
|
+
const diff = (end.update as any).content?.find((c: any) => c.type === 'diff')
|
|
176
|
+
assert.ok(diff, 'expected diff content item')
|
|
177
|
+
assert.equal(diff.path, 'a.txt')
|
|
178
|
+
assert.equal(diff.oldText, 'before\n')
|
|
179
|
+
assert.equal(diff.newText, 'after\n')
|
|
180
|
+
assert.equal((end.update as any).rawOutput, undefined, 'expected raw output to be suppressed when diff is emitted')
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
test('PiAcpSession: emits write diff content for new files on completion', async () => {
|
|
184
|
+
const dir = mkdtempSync(join(tmpdir(), 'pi-acp-diff-'))
|
|
185
|
+
mkdirSync(dir, { recursive: true })
|
|
186
|
+
const filePath = join(dir, 'new.txt')
|
|
187
|
+
|
|
188
|
+
const { conn, proc } = createSession(dir)
|
|
189
|
+
|
|
190
|
+
proc.emit({
|
|
191
|
+
type: 'tool_execution_start',
|
|
192
|
+
toolCallId: 't1',
|
|
193
|
+
toolName: 'write',
|
|
194
|
+
args: { path: 'new.txt', content: 'created\n' }
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
writeFileSync(filePath, 'created\n', 'utf8')
|
|
198
|
+
proc.emit({
|
|
199
|
+
type: 'tool_execution_end',
|
|
200
|
+
toolCallId: 't1',
|
|
201
|
+
isError: false,
|
|
202
|
+
result: { content: [{ type: 'text', text: 'Successfully wrote 8 bytes to new.txt' }] }
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
await new Promise(r => setTimeout(r, 0))
|
|
206
|
+
|
|
207
|
+
const end = completedToolUpdate(conn)
|
|
208
|
+
assert.ok(end, 'expected completed tool_call_update')
|
|
209
|
+
const diff = (end.update as any).content?.find((c: any) => c.type === 'diff')
|
|
210
|
+
assert.ok(diff, 'expected diff content item')
|
|
211
|
+
assert.equal(diff.path, 'new.txt')
|
|
212
|
+
assert.equal(diff.oldText, null)
|
|
213
|
+
assert.equal(diff.newText, 'created\n')
|
|
214
|
+
})
|