surgent 0.7.0-alpha.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 (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +407 -0
  3. package/bin/surgent.js +211 -0
  4. package/dist/optimizers/LICENSE +21 -0
  5. package/dist/optimizers/index.js +1984 -0
  6. package/dist/optimizers/index.js.map +7 -0
  7. package/dist/optimizers/package.json +31 -0
  8. package/package.json +45 -0
  9. package/src/agent/built-in/documenter.md +58 -0
  10. package/src/agent/built-in/general.md +107 -0
  11. package/src/agent/built-in/planner.md +73 -0
  12. package/src/agent/built-in/scout.md +97 -0
  13. package/src/agent/command.ts +140 -0
  14. package/src/agent/helpers.ts +95 -0
  15. package/src/agent/index.ts +9 -0
  16. package/src/agent/storage.ts +287 -0
  17. package/src/agent/types.ts +28 -0
  18. package/src/checkpoint/git.ts +173 -0
  19. package/src/checkpoint/index.ts +117 -0
  20. package/src/checkpoint/snapshot.ts +28 -0
  21. package/src/checkpoint/stage.ts +59 -0
  22. package/src/checkpoint/store.ts +108 -0
  23. package/src/cleanup/checkpoint.ts +31 -0
  24. package/src/cleanup/helpers.ts +24 -0
  25. package/src/cleanup/index.ts +21 -0
  26. package/src/cleanup/permission.ts +74 -0
  27. package/src/cleanup/subsession.ts +46 -0
  28. package/src/commands/helpers.ts +217 -0
  29. package/src/commands/index.ts +79 -0
  30. package/src/commands/render.ts +95 -0
  31. package/src/commands/types.ts +11 -0
  32. package/src/mcp-client/call-tool.ts +143 -0
  33. package/src/mcp-client/client.ts +90 -0
  34. package/src/mcp-client/command.ts +257 -0
  35. package/src/mcp-client/helpers.ts +153 -0
  36. package/src/mcp-client/index.ts +21 -0
  37. package/src/mcp-client/list-tools.ts +84 -0
  38. package/src/mcp-client/storage.ts +190 -0
  39. package/src/mcp-client/types.ts +34 -0
  40. package/src/mcp-client/validation.ts +115 -0
  41. package/src/optimizers/compactor/bash.ts +159 -0
  42. package/src/optimizers/compactor/grep.ts +141 -0
  43. package/src/optimizers/compactor/index.ts +132 -0
  44. package/src/optimizers/deduplicator/helpers.ts +75 -0
  45. package/src/optimizers/deduplicator/index.ts +23 -0
  46. package/src/optimizers/deduplicator/resources.ts +77 -0
  47. package/src/optimizers/deduplicator/state.ts +119 -0
  48. package/src/optimizers/deduplicator/types.ts +14 -0
  49. package/src/optimizers/entries.ts +104 -0
  50. package/src/optimizers/index.ts +17 -0
  51. package/src/optimizers/inspector/helpers.ts +60 -0
  52. package/src/optimizers/inspector/index.ts +89 -0
  53. package/src/optimizers/inspector/inspect.ts +88 -0
  54. package/src/optimizers/inspector/types.ts +7 -0
  55. package/src/optimizers/languages/go.ts +79 -0
  56. package/src/optimizers/languages/grammar.ts +200 -0
  57. package/src/optimizers/languages/index.ts +75 -0
  58. package/src/optimizers/languages/java.ts +64 -0
  59. package/src/optimizers/languages/python.ts +63 -0
  60. package/src/optimizers/languages/rust.ts +71 -0
  61. package/src/optimizers/languages/symbols.ts +95 -0
  62. package/src/optimizers/languages/tree-sitter-languages.d.ts +23 -0
  63. package/src/optimizers/languages/types.ts +134 -0
  64. package/src/optimizers/languages/typescript.ts +116 -0
  65. package/src/optimizers/mapper/files.ts +94 -0
  66. package/src/optimizers/mapper/index.ts +133 -0
  67. package/src/optimizers/mapper/types.ts +6 -0
  68. package/src/optimizers/pruner/cleanup.ts +121 -0
  69. package/src/optimizers/pruner/context.ts +46 -0
  70. package/src/optimizers/pruner/index.ts +45 -0
  71. package/src/optimizers/pruner/session.ts +34 -0
  72. package/src/optimizers/pruner/types.ts +18 -0
  73. package/src/permission/bash.ts +124 -0
  74. package/src/permission/command.ts +111 -0
  75. package/src/permission/components/prompt.ts +255 -0
  76. package/src/permission/components/rules-list.ts +342 -0
  77. package/src/permission/constants.ts +48 -0
  78. package/src/permission/helpers.ts +156 -0
  79. package/src/permission/index.ts +134 -0
  80. package/src/permission/pattern.ts +51 -0
  81. package/src/permission/piignore.ts +148 -0
  82. package/src/permission/precedence.ts +54 -0
  83. package/src/permission/resolution.ts +116 -0
  84. package/src/permission/storage.ts +142 -0
  85. package/src/permission/types.ts +57 -0
  86. package/src/questionnaire/component.ts +357 -0
  87. package/src/questionnaire/helpers.ts +220 -0
  88. package/src/questionnaire/index.ts +67 -0
  89. package/src/questionnaire/schemas.ts +50 -0
  90. package/src/questionnaire/types.ts +47 -0
  91. package/src/redactor/index.ts +34 -0
  92. package/src/redactor/patterns.ts +234 -0
  93. package/src/redactor/secrets.ts +113 -0
  94. package/src/subagent/helpers.ts +93 -0
  95. package/src/subagent/index.ts +81 -0
  96. package/src/subagent/storage.ts +100 -0
  97. package/src/subagent/subsession.ts +266 -0
  98. package/src/subagent/types.ts +83 -0
  99. package/src/subagent/validation.ts +100 -0
  100. package/src/ui/components/action-select-list.ts +165 -0
  101. package/src/ui/components/bash-mode.ts +281 -0
  102. package/src/ui/components/extended-select-list.ts +166 -0
  103. package/src/ui/components/form-field.ts +184 -0
  104. package/src/ui/components/form.ts +179 -0
  105. package/src/ui/components/frame.ts +60 -0
  106. package/src/ui/components/input-mode-indicator.ts +64 -0
  107. package/src/ui/components/keybound.ts +150 -0
  108. package/src/ui/components/lines.ts +27 -0
  109. package/src/ui/components/placeholder-input.ts +59 -0
  110. package/src/ui/components/scoped-input.ts +78 -0
  111. package/src/ui/components/scrollable-view.ts +155 -0
  112. package/src/ui/index.ts +40 -0
  113. package/src/utils.ts +206 -0
  114. package/src/web-tools/index.ts +15 -0
  115. package/src/web-tools/providers/brave.ts +55 -0
  116. package/src/web-tools/providers/firecrawl.ts +66 -0
  117. package/src/web-tools/providers/index.ts +50 -0
  118. package/src/web-tools/providers/jina.ts +48 -0
  119. package/src/web-tools/providers/native.ts +57 -0
  120. package/src/web-tools/providers/tavily.ts +56 -0
  121. package/src/web-tools/settings.ts +15 -0
  122. package/src/web-tools/web-fetch/helpers.ts +66 -0
  123. package/src/web-tools/web-fetch/index.ts +91 -0
  124. package/src/web-tools/web-fetch/parser.ts +51 -0
  125. package/src/web-tools/web-fetch/storage.ts +65 -0
  126. package/src/web-tools/web-fetch/types.ts +8 -0
  127. package/src/web-tools/web-login/helpers.ts +79 -0
  128. package/src/web-tools/web-login/index.ts +100 -0
  129. package/src/web-tools/web-login/types.ts +4 -0
  130. package/src/web-tools/web-search/helpers.ts +36 -0
  131. package/src/web-tools/web-search/index.ts +98 -0
  132. package/src/web-tools/web-search/types.ts +15 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 surgent
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,407 @@
1
+ # surgent
2
+
3
+ **A terminal coding agent that keeps context focused, delegates specialized work, and puts you in control of every change.**
4
+
5
+ surgent works inside an existing repository. Give it an engineering task and it can inspect the codebase, make a plan, edit files, run commands and tests, research the web, and report the result without forcing you to manage the agent's internal machinery.
6
+
7
+ It is designed for software engineers who want an agent that feels at home in a terminal: direct enough for quick fixes, structured enough for multi-step work, and careful enough for real repositories.
8
+
9
+ ## Why surgent
10
+
11
+ - **More useful context.** surgent navigates code structurally and reduces repetitive tool output so the model can spend more of its context on the task.
12
+ - **Repository-grounded work.** Project instructions, source files, command output, and session history stay connected to the work at hand.
13
+ - **Specialists when they help.** Built-in agents cover implementation, planning, codebase research, and documentation. The main agent can delegate focused work instead of filling one conversation with every detail.
14
+ - **Plans that do not crowd the coding session.** Explore and refine a plan in a separate session, then hand the finished plan back for implementation.
15
+ - **Explicit safety controls.** Review actions as they happen, save reusable permission rules, block sensitive paths, or switch modes when you need more or less autonomy.
16
+ - **Recoverable edits.** In Git repositories, surgent checkpoints edits made through its file tools and can restore the corresponding code state when you rewind or fork a session.
17
+ - **Model freedom.** Use models from Google, Anthropic, OpenAI, OpenRouter, Bedrock, and many other supported providers.
18
+ - **Extensible tooling.** Connect local or remote MCP servers and give the agent access to web search and URL fetching.
19
+
20
+ ## What you can do
21
+
22
+ surgent is useful anywhere the task is easier to describe than to execute manually:
23
+
24
+ ```text
25
+ Find the race condition behind the flaky queue tests, fix the root cause,
26
+ and run the smallest test set that proves the behavior.
27
+ ```
28
+
29
+ ```text
30
+ Trace how authentication state reaches the API client. Explain the current
31
+ design and identify places where an expired token can still be used.
32
+ ```
33
+
34
+ ```text
35
+ Add CSV export to the reporting command. Follow existing CLI conventions,
36
+ update tests, and document the new flag.
37
+ ```
38
+
39
+ ```text
40
+ Review this branch for correctness regressions. Do not modify files.
41
+ ```
42
+
43
+ ## Requirements
44
+
45
+ - Node.js 22.19 or newer
46
+
47
+ ## Install
48
+
49
+ Install surgent globally from npm:
50
+
51
+ ```bash
52
+ npm install -g surgent
53
+ ```
54
+
55
+ Confirm the command is available:
56
+
57
+ ```bash
58
+ surgent --version
59
+ ```
60
+
61
+ **Starting surgent**
62
+
63
+ From the repository you want to work on, run:
64
+
65
+ ```bash
66
+ cd /path/to/your-project
67
+ surgent
68
+ ```
69
+
70
+ **Update or remove**
71
+
72
+ ```bash
73
+ npm install -g surgent@latest # update
74
+ npm uninstall -g surgent # remove
75
+ ```
76
+
77
+ ## Optimizers for Pi
78
+
79
+ `@surgent/optimizers` is a Pi extension package that keeps code navigation and tool output focused, while being cache friendly. This extension is already built into surgent.
80
+
81
+ - `code_map` and `inspect` use Tree-sitter to navigate symbols and declarations in TypeScript/JavaScript, Python, Go, Java, and Rust.
82
+ - It compacts noisy Bash and grep output.
83
+ - It deduplicates previously read resource content, removes superseded `read` or `inspect` results
84
+ - It prunes empty `ls` or `find` results from context.
85
+
86
+ To use the optimizers with Pi instead of surgent, install the standalone package:
87
+
88
+ > **Important:** Install either surgent or `@surgent/optimizers` on a machine or configuration, not both. Surgent already includes the optimizers; installing both registers duplicate tools and hooks.
89
+
90
+ ```bash
91
+ pi install npm:@surgent/optimizers
92
+ ```
93
+
94
+ Verify the package is installed:
95
+
96
+ ```bash
97
+ pi list
98
+ ```
99
+
100
+ Start Pi in a repository, then ask the agent to use `code_map` to locate symbols and `inspect` to read a selected declaration.
101
+
102
+ ## Connect a model
103
+
104
+ surgent defaults to the Google provider. The quickest setup is a Gemini API key:
105
+
106
+ ```bash
107
+ export GEMINI_API_KEY="your-api-key"
108
+ surgent --provider google
109
+ ```
110
+
111
+ Other common choices work the same way:
112
+
113
+ | Provider | Environment variable | Start command |
114
+ | ---------- | -------------------- | ------------------------------- |
115
+ | Anthropic | `ANTHROPIC_API_KEY` | `surgent --provider anthropic` |
116
+ | OpenAI | `OPENAI_API_KEY` | `surgent --provider openai` |
117
+ | OpenRouter | `OPENROUTER_API_KEY` | `surgent --provider openrouter` |
118
+
119
+ List models available to your current installation:
120
+
121
+ ```bash
122
+ surgent --list-models
123
+ ```
124
+
125
+ Select a model directly with a provider-qualified model ID:
126
+
127
+ ```bash
128
+ surgent --model <provider>/<model-id>
129
+ ```
130
+
131
+ Provider keys are secrets. Keep them in your shell environment or a secret manager, never in the repository.
132
+
133
+ ## Quick start
134
+
135
+ For a new repository, initialize concise project instructions first:
136
+
137
+ ```text
138
+ /init
139
+ ```
140
+
141
+ `/init` inspects the repository and creates or updates `AGENTS.md` with verified commands, architecture notes, conventions, and project-specific guidance. Future sessions automatically benefit from those instructions.
142
+
143
+ Then describe the outcome you want:
144
+
145
+ ```text
146
+ Add input validation to the user creation endpoint. Match the existing error
147
+ format, add focused tests, and run them.
148
+ ```
149
+
150
+ surgent will inspect the relevant code, ask for permission where required, make the changes, validate them, and summarize the result.
151
+
152
+ ## Everyday workflows
153
+
154
+ ### Start with a task
155
+
156
+ Open the interactive TUI with an initial request:
157
+
158
+ ```bash
159
+ surgent "Find and fix the failing type check in the billing module"
160
+ ```
161
+
162
+ Name a longer-running session so it is easy to find later:
163
+
164
+ ```bash
165
+ surgent --name "Refactor billing retries"
166
+ ```
167
+
168
+ ### Plan before editing
169
+
170
+ Use a separate planning session for work that spans components or has unclear tradeoffs:
171
+
172
+ ```text
173
+ /plan Replace the in-memory job scheduler with a durable queue
174
+ ```
175
+
176
+ You can review the plan, send feedback, save it for later, or forward the final version into the main session for implementation.
177
+
178
+ Run `/plan` with no arguments to list saved plans. Resume one by selecting it or passing its plan ID:
179
+
180
+ ```text
181
+ /plan <plan-id>
182
+ ```
183
+
184
+ ### Run a one-shot task
185
+
186
+ Use print mode in scripts or for short, non-interactive work:
187
+
188
+ ```bash
189
+ surgent -p "Summarize the public API exposed by src/client"
190
+ ```
191
+
192
+ ### Perform a read-only review
193
+
194
+ Limit the active tools to read-only operations:
195
+
196
+ ```bash
197
+ surgent --tools read,grep,find,ls -p \
198
+ "Review src/auth for correctness and security regressions"
199
+ ```
200
+
201
+ ### Include files in the first message
202
+
203
+ Prefix a path with `@` to attach text, images, or other relevant files:
204
+
205
+ ```bash
206
+ surgent @spec.md @architecture.png "Implement the first milestone"
207
+ ```
208
+
209
+ ### Resume previous work
210
+
211
+ Continue the most recent session:
212
+
213
+ ```bash
214
+ surgent --continue
215
+ ```
216
+
217
+ Choose from saved sessions:
218
+
219
+ ```bash
220
+ surgent --resume
221
+ ```
222
+
223
+ Sessions can also be forked, exported to HTML, or started without persistence. Run `surgent --help` for the complete set of session options.
224
+
225
+ ### Run shell commands from the TUI
226
+
227
+ Start input with `!` to run a shell command and include its result in the conversation:
228
+
229
+ ```text
230
+ !npm test
231
+ ```
232
+
233
+ Start with `!!` to run a command without adding its result to model context:
234
+
235
+ ```text
236
+ !!git status
237
+ ```
238
+
239
+ Use `Ctrl+Alt+B` to cycle persistently between prompt input, context-included shell input, and regular shell input.
240
+
241
+ ## Interactive commands
242
+
243
+ | Command | Purpose |
244
+ | ----------------------- | ------------------------------------------------------------- |
245
+ | `/init` | Create or update repository-specific `AGENTS.md` instructions |
246
+ | `/plan [request]` | Start, refine, save, or resume an isolated planning session |
247
+ | `/agent` | Select, create, edit, or remove agent profiles |
248
+ | `/permissions` | View and manage file, shell, web, and MCP permission rules |
249
+ | `/mcp` | Add, edit, enable, disable, or remove MCP servers |
250
+ | `/web-login [provider]` | Configure credentials for web search and fetch providers |
251
+
252
+ The bundled agent profiles cover these common roles:
253
+
254
+ | Agent | Best for |
255
+ | ------------ | ------------------------------------------------------------------- |
256
+ | `general` | Implementation, debugging, tests, and command-heavy repository work |
257
+ | `planner` | Repository-grounded plans for complex changes |
258
+ | `scout` | Read-only codebase research and execution tracing |
259
+ | `documenter` | User-facing Markdown and project documentation |
260
+
261
+ Use `/agent` to start a new session with a specialist or create a project-specific or global profile. Profiles can constrain tools, files, shell commands, MCP servers, models, and thinking levels.
262
+
263
+ ## Command-line essentials
264
+
265
+ | Option | Purpose |
266
+ | ------------------------- | --------------------------------------------- |
267
+ | `-p`, `--print` | Process a prompt non-interactively and exit |
268
+ | `-c`, `--continue` | Continue the previous session |
269
+ | `-r`, `--resume` | Select a saved session |
270
+ | `--name <name>` | Give a session a memorable name |
271
+ | `--provider <name>` | Select a model provider |
272
+ | `--model <pattern>` | Select a model or provider-qualified model ID |
273
+ | `--thinking <level>` | Set the model thinking level |
274
+ | `--tools <names>` | Enable only the listed tools |
275
+ | `--exclude-tools <names>` | Disable selected tools |
276
+ | `--no-session` | Run without saving session history |
277
+ | `--offline` | Disable startup network operations |
278
+ | `--export <file>` | Export a session as HTML |
279
+
280
+ Run `surgent --help` for all options, supported credential environment variables, and examples.
281
+
282
+ ## Permissions and safety
283
+
284
+ surgent has three permission modes. Press `Alt+M` to cycle between them:
285
+
286
+ | Mode | Behavior |
287
+ | ---------- | ------------------------------------------------------------------ |
288
+ | Assistant | Prompts when an action is not already covered by a permission rule |
289
+ | YOLO | Runs actions allowed by the active agent without prompting |
290
+ | Restricted | Limits actions to explicitly allowed access |
291
+
292
+ Use `/permissions` to manage reusable rules for:
293
+
294
+ - File reads and writes
295
+ - Shell commands
296
+ - Web requests
297
+ - MCP tool calls
298
+
299
+ Rules can apply to the current session, the current project, all projects, or permanently. More specific rules take precedence.
300
+
301
+ ### Keep paths out of agent reach
302
+
303
+ Add sensitive or irrelevant paths to `.piignore`:
304
+
305
+ ```gitignore
306
+ .env*
307
+ secrets/**
308
+ production-data/**
309
+ ```
310
+
311
+ Negated patterns can re-include a safe example:
312
+
313
+ ```gitignore
314
+ secrets/**
315
+ !secrets/example.env
316
+ ```
317
+
318
+ On the first run in a repository, surgent uses an existing `.gitignore` as the starting point for `.piignore`. Ignored paths are blocked from file access even in YOLO mode.
319
+
320
+ surgent also keeps its project-local `.pi` working data out of Git through the repository's local exclude file. Checkpoints complement Git; they are not a replacement for commits, branches, or backups.
321
+
322
+ ## MCP and web access
323
+
324
+ ### Connect MCP servers
325
+
326
+ Run `/mcp` and choose **Add MCP server**. surgent supports:
327
+
328
+ - Local servers launched over standard input/output
329
+ - Remote servers reached over HTTP
330
+ - Project-scoped or global configurations
331
+
332
+ New servers are disabled until you enable them. In the MCP list, press `Tab` to enable or disable a server; surgent checks the connection before enabling it.
333
+
334
+ ### Configure web providers
335
+
336
+ surgent can search the web and fetch public URLs when a task needs current documentation or external context. Run `/web-login` to configure optional provider credentials for Tavily, Brave Search, Firecrawl, or Jina.
337
+
338
+ Web and MCP actions pass through the same permission system as file and shell operations.
339
+
340
+ ## Tips for better results
341
+
342
+ - Describe the outcome, constraints, and validation you expect. A task such as "fix login" leaves more ambiguity than "reject expired refresh tokens, preserve the existing error shape, and run the auth tests."
343
+ - Let surgent inspect before prescribing a patch. Existing abstractions and tests often point to a smaller solution.
344
+ - Use `/plan` when a change spans several systems or needs a design decision.
345
+ - Use a read-only tool set for audits and reviews.
346
+ - Put stable repository facts in `AGENTS.md`; keep one-off task details in the prompt.
347
+ - Commit or stash valuable work before enabling YOLO mode or requesting broad changes.
348
+
349
+ ## Troubleshooting
350
+
351
+ ### `surgent: command not found`
352
+
353
+ Confirm npm's global binary directory is on your `PATH`, then open a new shell.
354
+
355
+ ### No models are available
356
+
357
+ Check that the provider's environment variable is set in the same shell, then inspect matching models:
358
+
359
+ ```bash
360
+ surgent --list-models <search>
361
+ ```
362
+
363
+ You can also check whether a configured provider is ready:
364
+
365
+ ```bash
366
+ surgent auth check --provider <provider>
367
+ ```
368
+
369
+ ### A file cannot be read or edited
370
+
371
+ Check `.piignore`, the active agent's file limits, the current permission mode, and saved rules under `/permissions`. Path blocks in `.piignore` remain active in every mode.
372
+
373
+ ### An MCP server has no tools
374
+
375
+ Open `/mcp`, verify the command or URL, and enable the server with `Tab`. A server must pass its connection check before surgent makes its tools available.
376
+
377
+ ## Development
378
+
379
+ For source development, install dependencies and link the local command:
380
+
381
+ ```bash
382
+ pnpm install
383
+ npm link
384
+ ```
385
+
386
+ `pnpm build` builds only the distributable optimizer package in `dist/optimizers`. npm runs this build automatically through `prepack` when packaging surgent.
387
+
388
+ To publish the standalone optimizer artifact after building it:
389
+
390
+ ```bash
391
+ npm publish ./dist/optimizers --access public
392
+ ```
393
+
394
+ ## Reference
395
+
396
+ surgent is built on [Pi](https://github.com/earendil-works/pi), created by [Mario Zechner](https://github.com/badlogic) and developed by its maintainers and contributors. Pi provides the agent runtime, TUI, model integration, extension system, and SDK that make surgent possible.
397
+
398
+ Refer to the upstream repository for Pi installation, configuration, providers, extension APIs, SDK usage, and other runtime documentation.
399
+
400
+ - [Pi repository](https://github.com/earendil-works/pi)
401
+ - [Pi coding agent](https://github.com/earendil-works/pi/tree/main/packages/coding-agent)
402
+ - [Pi documentation](https://github.com/earendil-works/pi/tree/main/packages/coding-agent/docs)
403
+ - [Pi contributors](https://github.com/earendil-works/pi/graphs/contributors)
404
+
405
+ ## License
406
+
407
+ surgent is available under the [MIT License](LICENSE).
package/bin/surgent.js ADDED
@@ -0,0 +1,211 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { main } from "@earendil-works/pi-coding-agent";
4
+ import { spawn } from "node:child_process";
5
+ import { existsSync } from "node:fs";
6
+ import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
7
+ import { homedir } from "node:os";
8
+ import { dirname, resolve } from "node:path";
9
+ import { fileURLToPath } from "node:url";
10
+
11
+ process.title = "surgent";
12
+ const args = process.argv.slice(2);
13
+
14
+ const PACKAGE_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "..");
15
+ const AGENT_ENTRY_URL = import.meta.resolve("@earendil-works/pi-coding-agent");
16
+ const LOCAL_PI_SUBDIRS = ["agents", "plans"];
17
+ const BUILT_IN_META = {
18
+ documenter: {
19
+ tools: ["code_map", "inspect", "read", "find", "grep", "ls", "edit", "write", "questionnaire"],
20
+ "files.write": ["**/*.md"],
21
+ },
22
+ planner: {
23
+ tools: ["read", "grep", "find", "ls", "web_fetch", "web_search", "questionnaire"],
24
+ },
25
+ scout: {
26
+ tools: ["ls", "find", "grep", "code_map", "inspect", "read", "web_fetch", "web_search"],
27
+ },
28
+ };
29
+
30
+ function isMissingFileError(error) {
31
+ return Boolean(error) && typeof error === "object" && "code" in error && error.code === "ENOENT";
32
+ }
33
+
34
+ async function initBuiltInMeta() {
35
+ const settingsPath = resolve(homedir(), ".pi", "agent", "settings.json");
36
+ let settings;
37
+
38
+ try {
39
+ settings = JSON.parse(await readFile(settingsPath, "utf8"));
40
+ } catch (error) {
41
+ if (!isMissingFileError(error)) throw error;
42
+ settings = {};
43
+ }
44
+
45
+ const meta = { ...settings.agent?.meta };
46
+ let changed = false;
47
+ for (const [name, builtInMeta] of Object.entries(BUILT_IN_META)) {
48
+ if (Object.hasOwn(meta, name)) continue;
49
+ meta[name] = builtInMeta;
50
+ changed = true;
51
+ }
52
+ if (!changed) return;
53
+
54
+ settings.agent = { ...settings.agent, meta };
55
+ await mkdir(dirname(settingsPath), { recursive: true });
56
+ await writeFile(settingsPath, `${JSON.stringify(settings, null, 2)}\n`);
57
+ }
58
+
59
+ async function getGitExcludePath(cwd) {
60
+ try {
61
+ const excludePath = (
62
+ await new Promise((resolveOutput, rejectOutput) => {
63
+ let stdout = "";
64
+ const childProcess = spawn(
65
+ process.platform === "win32" ? "git.cmd" : "git",
66
+ ["rev-parse", "--git-path", "info/exclude"],
67
+ { cwd, env: process.env, stdio: ["ignore", "pipe", "ignore"] },
68
+ );
69
+
70
+ childProcess.stdout.on("data", (chunk) => {
71
+ stdout += chunk.toString();
72
+ });
73
+
74
+ childProcess.on("error", (error) => {
75
+ rejectOutput(error);
76
+ });
77
+
78
+ childProcess.on("close", (exitCode) => {
79
+ if (exitCode === 0) {
80
+ resolveOutput(stdout);
81
+ return;
82
+ }
83
+ rejectOutput(new Error("Git exclude path resolution failed."));
84
+ });
85
+ })
86
+ ).trim();
87
+
88
+ if (excludePath) {
89
+ return resolve(cwd, excludePath);
90
+ }
91
+ } catch {}
92
+ }
93
+
94
+ async function ensurePiExcluded(cwd) {
95
+ const excludePath = await getGitExcludePath(cwd);
96
+ if (!excludePath) return;
97
+
98
+ let excludeContents = "";
99
+ try {
100
+ excludeContents = await readFile(excludePath, "utf8");
101
+ } catch (error) {
102
+ if (!isMissingFileError(error)) return;
103
+ }
104
+
105
+ const existingPatterns = excludeContents.split(/\r?\n/).map((line) => line.trim());
106
+ if (existingPatterns.includes(".pi")) return;
107
+
108
+ const separator = excludeContents.length > 0 && !excludeContents.endsWith("\n") ? "\n" : "";
109
+ await writeFile(excludePath, `${excludeContents}${separator}.pi\n`);
110
+ }
111
+
112
+ async function syncPiIgnore(cwd) {
113
+ const piIgnorePath = resolve(cwd, ".piignore");
114
+ try {
115
+ await readFile(piIgnorePath, "utf8");
116
+ return;
117
+ } catch (error) {
118
+ if (!isMissingFileError(error)) return;
119
+ }
120
+
121
+ if (existsSync(resolve(cwd, ".pi"))) return;
122
+ const gitIgnorePath = resolve(cwd, ".gitignore");
123
+ let gitIgnoreContents = "";
124
+
125
+ try {
126
+ gitIgnoreContents = await readFile(gitIgnorePath, "utf8");
127
+ } catch (error) {
128
+ return;
129
+ }
130
+
131
+ await writeFile(piIgnorePath, gitIgnoreContents);
132
+ }
133
+
134
+ function isJsonModeActive(args) {
135
+ for (let i = 0; i < args.length - 1; i++) {
136
+ const arg = args[i];
137
+ if (arg === "--mode" && args[i + 1] === "json") {
138
+ return true;
139
+ }
140
+ }
141
+ return false;
142
+ }
143
+
144
+ function rewriteHelpLine(line) {
145
+ if (/^pi\b/.test(line)) {
146
+ return line.replace(/^pi\b/, "surgent");
147
+ }
148
+ if (/^(\s+)pi\b/.test(line)) {
149
+ return line.replace(/^(\s+)pi\b/, "$1surgent");
150
+ }
151
+ if (/^Alias:\s+pi\b/.test(line)) {
152
+ return line.replace(/^Alias:\s+pi\b/, "Alias: surgent");
153
+ }
154
+ return line.replace(/(["'`])pi(?=[\s-])/g, "$1surgent");
155
+ }
156
+
157
+ function rewriteHelpText(text) {
158
+ return text.split("\n").map(rewriteHelpLine).join("\n");
159
+ }
160
+
161
+ async function runRewrittenHelp(args) {
162
+ const cliPath = fileURLToPath(new URL("./cli.js", AGENT_ENTRY_URL));
163
+
164
+ await new Promise((resolve, reject) => {
165
+ const child = spawn(process.execPath, [cliPath, ...args], {
166
+ stdio: ["inherit", "pipe", "pipe"],
167
+ env: process.env,
168
+ });
169
+
170
+ let stdout = "";
171
+ let stderr = "";
172
+
173
+ child.stdout.on("data", (chunk) => {
174
+ stdout += chunk.toString();
175
+ });
176
+
177
+ child.stderr.on("data", (chunk) => {
178
+ stderr += chunk.toString();
179
+ });
180
+
181
+ child.on("error", reject);
182
+ child.on("close", (code) => {
183
+ if (stdout) process.stdout.write(rewriteHelpText(stdout));
184
+ if (stderr) process.stderr.write(rewriteHelpText(stderr));
185
+ process.exitCode = code ?? 0;
186
+ resolve();
187
+ });
188
+ });
189
+ }
190
+
191
+ await initBuiltInMeta();
192
+
193
+ if (args.includes("--help") || args.includes("-h")) {
194
+ await runRewrittenHelp(args);
195
+ } else {
196
+ const cwd = process.cwd();
197
+ if (!isJsonModeActive(args)) {
198
+ await ensurePiExcluded(cwd);
199
+ await syncPiIgnore(cwd);
200
+ }
201
+ for (const localPiSubdir of LOCAL_PI_SUBDIRS) {
202
+ await mkdir(resolve(cwd, ".pi", localPiSubdir), { recursive: true });
203
+ }
204
+
205
+ const srcDir = resolve(PACKAGE_DIR, "src");
206
+ const entries = await readdir(srcDir, { withFileTypes: true });
207
+ const extensionArgs = entries
208
+ .filter((entry) => entry.isDirectory())
209
+ .flatMap((entry) => ["--extension", resolve(srcDir, entry.name)]);
210
+ await main([...extensionArgs, ...args]);
211
+ }
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 surgent
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.