headlesscode 1.0.2

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 (232) hide show
  1. package/ATTRIBUTION.md +53 -0
  2. package/CODE_OF_CONDUCT.md +130 -0
  3. package/CONTRIBUTING.md +107 -0
  4. package/LICENSE +202 -0
  5. package/README.md +486 -0
  6. package/SECURITY.md +211 -0
  7. package/bin/headlesscode.mjs +83 -0
  8. package/package.json +63 -0
  9. package/shared/prompts/review-mode-prompt-short.md +93 -0
  10. package/shared/prompts/review-mode-prompt.md +281 -0
  11. package/shared/rules-code/rules.md +22 -0
  12. package/shared/stacks/cpp/rules.md +30 -0
  13. package/shared/stacks/fastapi/rules.md +30 -0
  14. package/shared/stacks/javascript/rules.md +37 -0
  15. package/shared/stacks/postgresql/rules.md +31 -0
  16. package/shared/stacks/python/rules.md +35 -0
  17. package/shared/stacks/react/rules.md +11 -0
  18. package/shared/stacks/typescript/rules.md +10 -0
  19. package/src/budget/budget.ts +221 -0
  20. package/src/budget/concurrency.ts +126 -0
  21. package/src/budget/cost.ts +309 -0
  22. package/src/budget/index.ts +8 -0
  23. package/src/checkpoints/cli.ts +256 -0
  24. package/src/checkpoints/service.ts +227 -0
  25. package/src/cli.ts +1535 -0
  26. package/src/cloud/docker-provider.ts +334 -0
  27. package/src/cloud/provider.ts +300 -0
  28. package/src/codeintel/call-graph.ts +78 -0
  29. package/src/codeintel/find-references.ts +123 -0
  30. package/src/codeintel/go-to-definition.ts +193 -0
  31. package/src/codeintel/handlers.ts +190 -0
  32. package/src/codeintel/import-graph.ts +173 -0
  33. package/src/codeintel/outline.ts +180 -0
  34. package/src/codeintel/position.ts +77 -0
  35. package/src/codeintel/program.ts +350 -0
  36. package/src/codeintel/rename-symbol.ts +213 -0
  37. package/src/codeintel/tools.ts +280 -0
  38. package/src/codemap/build.ts +135 -0
  39. package/src/codemap/cli.ts +190 -0
  40. package/src/codemap/extract.ts +339 -0
  41. package/src/codemap/files.ts +236 -0
  42. package/src/codemap/fingerprint.ts +65 -0
  43. package/src/codemap/flows.ts +62 -0
  44. package/src/codemap/html.ts +451 -0
  45. package/src/codemap/lock.ts +80 -0
  46. package/src/codemap/types.ts +101 -0
  47. package/src/codesearch/airunner-embedder.ts +185 -0
  48. package/src/codesearch/chunk.ts +339 -0
  49. package/src/codesearch/cli.ts +223 -0
  50. package/src/codesearch/embedder.ts +332 -0
  51. package/src/codesearch/files.ts +280 -0
  52. package/src/codesearch/index.ts +469 -0
  53. package/src/codesearch/ollama-embedder.ts +205 -0
  54. package/src/codesearch/search.ts +141 -0
  55. package/src/codesearch/types.ts +100 -0
  56. package/src/config/mode-models.ts +218 -0
  57. package/src/dashboard/aggregate.ts +364 -0
  58. package/src/dashboard/chat-thread.ts +141 -0
  59. package/src/dashboard/checkpoints.ts +124 -0
  60. package/src/dashboard/cli.ts +193 -0
  61. package/src/dashboard/codemap.ts +44 -0
  62. package/src/dashboard/files.ts +121 -0
  63. package/src/dashboard/page.ts +2803 -0
  64. package/src/dashboard/self-improvement-metrics.ts +282 -0
  65. package/src/dashboard/server.ts +1103 -0
  66. package/src/dashboard/session-launch.ts +310 -0
  67. package/src/dashboard/timeline.ts +273 -0
  68. package/src/dashboard/tool-exec.ts +107 -0
  69. package/src/dashboard/trend-cli.ts +141 -0
  70. package/src/dashboard/trend.ts +413 -0
  71. package/src/decision-proxy/cli.ts +261 -0
  72. package/src/decision-proxy/proxy.ts +569 -0
  73. package/src/deploy/gate-cli.ts +147 -0
  74. package/src/deploy/gate.ts +254 -0
  75. package/src/engine/condense.ts +512 -0
  76. package/src/engine/events.ts +428 -0
  77. package/src/engine/handoff.ts +71 -0
  78. package/src/engine/lazy-tools.ts +160 -0
  79. package/src/engine/local-explore.ts +653 -0
  80. package/src/engine/logger.ts +96 -0
  81. package/src/engine/loop.ts +5517 -0
  82. package/src/engine/parser.ts +347 -0
  83. package/src/engine/prompt.ts +860 -0
  84. package/src/engine/reports.ts +47 -0
  85. package/src/engine/stacks.ts +448 -0
  86. package/src/engine/types.ts +291 -0
  87. package/src/engine/usage.ts +186 -0
  88. package/src/github/app-auth.ts +161 -0
  89. package/src/github/cli.ts +448 -0
  90. package/src/github/installations.ts +133 -0
  91. package/src/github/pr.ts +321 -0
  92. package/src/github/provision.ts +118 -0
  93. package/src/github/push.ts +122 -0
  94. package/src/index-util.ts +50 -0
  95. package/src/index.ts +81 -0
  96. package/src/init/cli.ts +248 -0
  97. package/src/init/gitignore.ts +74 -0
  98. package/src/llm/ollama.ts +308 -0
  99. package/src/llm/openrouter.ts +868 -0
  100. package/src/llm/preflight.ts +367 -0
  101. package/src/llm/transcript-capture.ts +84 -0
  102. package/src/memory/embed.ts +110 -0
  103. package/src/memory/index.ts +22 -0
  104. package/src/memory/local.ts +259 -0
  105. package/src/memory/summarizer.ts +283 -0
  106. package/src/memory/types.ts +153 -0
  107. package/src/memory/uwuchat.ts +157 -0
  108. package/src/migrate/cli.ts +115 -0
  109. package/src/orchestrator/analyze-cli.ts +104 -0
  110. package/src/orchestrator/auto-split.ts +206 -0
  111. package/src/orchestrator/cleanup.ts +1003 -0
  112. package/src/orchestrator/cli.ts +3571 -0
  113. package/src/orchestrator/cost-estimate.ts +564 -0
  114. package/src/orchestrator/cost-history-cli.ts +242 -0
  115. package/src/orchestrator/cost-history.ts +397 -0
  116. package/src/orchestrator/git-sync.ts +250 -0
  117. package/src/orchestrator/index.ts +153 -0
  118. package/src/orchestrator/log-analysis.ts +0 -0
  119. package/src/orchestrator/merge-check.ts +108 -0
  120. package/src/orchestrator/pipeline.ts +411 -0
  121. package/src/orchestrator/resume.ts +1940 -0
  122. package/src/orchestrator/reviewer.ts +503 -0
  123. package/src/orchestrator/split.ts +296 -0
  124. package/src/orchestrator/state.ts +542 -0
  125. package/src/orchestrator/status.ts +697 -0
  126. package/src/orchestrator/verification-gate.ts +134 -0
  127. package/src/orchestrator/watch.ts +898 -0
  128. package/src/permissions/commands.ts +1083 -0
  129. package/src/permissions/config.ts +241 -0
  130. package/src/permissions/index.ts +12 -0
  131. package/src/permissions/protected-files.ts +96 -0
  132. package/src/permissions/store-protection.ts +272 -0
  133. package/src/project-store.ts +648 -0
  134. package/src/projects/cli.ts +382 -0
  135. package/src/qa/qa.ts +487 -0
  136. package/src/tools/browser/handler.ts +346 -0
  137. package/src/tools/browser/service.ts +406 -0
  138. package/src/tools/browser/smoke.ts +78 -0
  139. package/src/tools/browser/tool.ts +99 -0
  140. package/src/tools/executor.ts +2575 -0
  141. package/src/tools/language-detect.ts +183 -0
  142. package/src/tools/output-summarizer.ts +369 -0
  143. package/src/tools/run-tests.ts +302 -0
  144. package/src/tools/set-indentation-tool.ts +49 -0
  145. package/src/tools/test-selection.ts +160 -0
  146. package/src/vendor/tests/smoke.ts +103 -0
  147. package/src/vendor/zoo-code/VENDOR-NOTES.md +213 -0
  148. package/src/vendor/zoo-code/shim/anthropic.ts +71 -0
  149. package/src/vendor/zoo-code/shim/openai.d.ts +60 -0
  150. package/src/vendor/zoo-code/shim/os-name.ts +18 -0
  151. package/src/vendor/zoo-code/shim/strip-bom.ts +14 -0
  152. package/src/vendor/zoo-code/shim/vscode.ts +76 -0
  153. package/src/vendor/zoo-code/src/core/config/CustomModesManager.ts +1015 -0
  154. package/src/vendor/zoo-code/src/core/diff/strategies/multi-search-replace.ts +670 -0
  155. package/src/vendor/zoo-code/src/core/prompts/sections/capabilities.ts +46 -0
  156. package/src/vendor/zoo-code/src/core/prompts/sections/custom-instructions.ts +559 -0
  157. package/src/vendor/zoo-code/src/core/prompts/sections/index.ts +10 -0
  158. package/src/vendor/zoo-code/src/core/prompts/sections/markdown-formatting.ts +7 -0
  159. package/src/vendor/zoo-code/src/core/prompts/sections/modes.ts +35 -0
  160. package/src/vendor/zoo-code/src/core/prompts/sections/objective.ts +13 -0
  161. package/src/vendor/zoo-code/src/core/prompts/sections/rules.ts +95 -0
  162. package/src/vendor/zoo-code/src/core/prompts/sections/skills.ts +105 -0
  163. package/src/vendor/zoo-code/src/core/prompts/sections/system-info.ts +30 -0
  164. package/src/vendor/zoo-code/src/core/prompts/sections/tool-use-guidelines.ts +9 -0
  165. package/src/vendor/zoo-code/src/core/prompts/sections/tool-use.ts +7 -0
  166. package/src/vendor/zoo-code/src/core/prompts/system.ts +176 -0
  167. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/access_mcp_resource.ts +41 -0
  168. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/apply_diff.ts +40 -0
  169. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/apply_patch.ts +61 -0
  170. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/ask_followup_question.ts +62 -0
  171. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/attempt_completion.ts +33 -0
  172. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/codebase_search.ts +43 -0
  173. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/converters.ts +109 -0
  174. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/edit.ts +48 -0
  175. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/edit_file.ts +72 -0
  176. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/execute_command.ts +54 -0
  177. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/generate_image.ts +51 -0
  178. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/index.ts +75 -0
  179. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/list_files.ts +41 -0
  180. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/mcp_server.ts +75 -0
  181. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/new_task.ts +39 -0
  182. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/read_command_output.ts +81 -0
  183. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/read_file.ts +169 -0
  184. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/run_slash_command.ts +31 -0
  185. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/search_files.ts +50 -0
  186. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/search_replace.ts +51 -0
  187. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/skill.ts +33 -0
  188. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/switch_mode.ts +31 -0
  189. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/update_todo_list.ts +54 -0
  190. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/write_to_file.ts +40 -0
  191. package/src/vendor/zoo-code/src/core/prompts/types.ts +12 -0
  192. package/src/vendor/zoo-code/src/i18n/index.ts +19 -0
  193. package/src/vendor/zoo-code/src/integrations/misc/extract-text.ts +81 -0
  194. package/src/vendor/zoo-code/src/services/checkpoints/RepoPerTaskCheckpointService.ts +15 -0
  195. package/src/vendor/zoo-code/src/services/checkpoints/ShadowCheckpointService.ts +553 -0
  196. package/src/vendor/zoo-code/src/services/checkpoints/excludes.ts +212 -0
  197. package/src/vendor/zoo-code/src/services/checkpoints/index.ts +3 -0
  198. package/src/vendor/zoo-code/src/services/checkpoints/types.ts +35 -0
  199. package/src/vendor/zoo-code/src/services/code-index/manager.ts +19 -0
  200. package/src/vendor/zoo-code/src/services/mcp/McpHub.ts +36 -0
  201. package/src/vendor/zoo-code/src/services/roo-config/index.ts +441 -0
  202. package/src/vendor/zoo-code/src/services/search/file-search.ts +143 -0
  203. package/src/vendor/zoo-code/src/services/skills/SkillsManager.ts +20 -0
  204. package/src/vendor/zoo-code/src/shared/globalFileNames.ts +9 -0
  205. package/src/vendor/zoo-code/src/shared/language.ts +43 -0
  206. package/src/vendor/zoo-code/src/shared/modes.ts +257 -0
  207. package/src/vendor/zoo-code/src/shared/tools.ts +385 -0
  208. package/src/vendor/zoo-code/src/utils/fs.ts +39 -0
  209. package/src/vendor/zoo-code/src/utils/globalContext.ts +22 -0
  210. package/src/vendor/zoo-code/src/utils/json-schema.ts +16 -0
  211. package/src/vendor/zoo-code/src/utils/logging.ts +21 -0
  212. package/src/vendor/zoo-code/src/utils/mcp-name.ts +190 -0
  213. package/src/vendor/zoo-code/src/utils/object.ts +18 -0
  214. package/src/vendor/zoo-code/src/utils/path.ts +94 -0
  215. package/src/vendor/zoo-code/src/utils/shell.ts +376 -0
  216. package/src/vendor/zoo-code/src/utils/text-normalization.ts +99 -0
  217. package/src/vendor/zoo-code/types/global-settings.ts +19 -0
  218. package/src/vendor/zoo-code/types/index.ts +22 -0
  219. package/src/vendor/zoo-code/types/message.ts +375 -0
  220. package/src/vendor/zoo-code/types/mode.ts +241 -0
  221. package/src/vendor/zoo-code/types/todo.ts +19 -0
  222. package/src/vendor/zoo-code/types/tool-params.ts +116 -0
  223. package/src/vendor/zoo-code/types/tool.ts +67 -0
  224. package/src/vendor/zoo-code/types/vscode.ts +84 -0
  225. package/src/vision/describe.ts +242 -0
  226. package/src/vision/tool.ts +91 -0
  227. package/src/watcher/cli.ts +369 -0
  228. package/src/watcher/github.ts +304 -0
  229. package/src/watcher/index.ts +59 -0
  230. package/src/watcher/state.ts +254 -0
  231. package/src/watcher/watch.ts +562 -0
  232. package/tsconfig.json +18 -0
package/SECURITY.md ADDED
@@ -0,0 +1,211 @@
1
+ # Security
2
+
3
+ ## TL;DR
4
+
5
+ `headlesscode` is a **headless coding-agent harness**: an AI model reads a task,
6
+ then drives your machine by running shell commands and editing files. By design,
7
+ an unconfigured session runs **arbitrary commands with your full user
8
+ privileges** and can **read and modify your files** — including `~/.ssh`,
9
+ `~/.aws`, and any other credentials the user can access.
10
+
11
+ **Run it only on a machine you are willing to let an AI operate, only on
12
+ repositories you trust, and only with untrusted content isolated from your real
13
+ session.** This project does not sandbox agent actions, and nothing in the
14
+ harness can be relied upon to stop a malicious or compromised model that has
15
+ been given the ability to execute commands.
16
+
17
+ ## Default-allow command execution
18
+
19
+ An unconfigured session gives the agent:
20
+
21
+ - **Arbitrary shell command execution.** `execute_command` spawns the
22
+ model-supplied command string with `shell: true`, the full process
23
+ environment, and no sandbox (see
24
+ [`src/tools/executor.ts`](src/tools/executor.ts:1286) and
25
+ [`src/permissions/commands.ts`](src/permissions/commands.ts:834)). The
26
+ command runs as **you** — the same OS user, with the same files, network
27
+ access, and credentials the harness process has. There is no per-command
28
+ approval prompt (the harness is non-interactive by design), no container, and
29
+ no privilege boundary.
30
+ - **File read/write.** The write tools (`write_to_file`, `apply_diff`,
31
+ `search_replace`, `edit_file`) can create and overwrite any file under the
32
+ workspace root. Reads are not restricted at all.
33
+
34
+ An empty `allowedCommands` list means **allow everything** — only the
35
+ `deniedCommands` list (also empty by default) restricts anything. This is a
36
+ deliberate design choice for a headless tool: it preserves the behavior of a
37
+ local CLI that a developer runs in their own checkout. It is **not** a security
38
+ boundary.
39
+
40
+ ### What this means in practice
41
+
42
+ With default settings, an agent can, for example:
43
+
44
+ - Read `~/.ssh/id_rsa`, `~/.aws/credentials`, or any other file the user can
45
+ read.
46
+ - Exfiltrate data over the network (`curl`, `scp`, `gh`, …).
47
+ - Modify, delete, or encrypt files; install software; change system
48
+ configuration.
49
+ - Persist backdoors or leave any other modification on the machine.
50
+
51
+ Do not point this at data or machines where that outcome would be
52
+ unacceptable, and do not feed it untrusted task text or repository content you
53
+ have not reviewed.
54
+
55
+ ## When untrusted content is involved
56
+
57
+ If the task text, the repository, or anything the agent will read could be
58
+ hostile, treat the agent as untrusted code running as your user. The only safe
59
+ mitigation is OS-level isolation **outside** this project — for example a
60
+ throwaway container, VM, or dedicated user account with no access to your real
61
+ credentials:
62
+
63
+ - No credentials (SSH keys, cloud tokens, API keys) mounted unless the task
64
+ genuinely needs them.
65
+ - No writable access to anything you care about beyond a scratch workspace.
66
+ - Network access limited if exfiltration is a concern.
67
+
68
+ The harness itself cannot provide this isolation, and no amount of prompt
69
+ engineering, rules files, or "trusted mode" configuration is a substitute for
70
+ it.
71
+
72
+ ## Browser and vision cloud data flow
73
+
74
+ Two agent-driven tools send data off the machine as part of their normal
75
+ operation — not a bug, but worth knowing before pointing either at anything
76
+ sensitive:
77
+
78
+ - **Browser tool.** `browser_action` (see
79
+ [`src/tools/browser/service.ts`](src/tools/browser/service.ts:112)) launches
80
+ a headless Chromium instance and navigates it to whatever URL the model
81
+ supplies. The page content, cookies set by the site, and any redirects are
82
+ fetched directly by the browser process on your machine/network — the same
83
+ as visiting the URL yourself. If the model is given (or invents) a URL for
84
+ an internal or sensitive endpoint, that page's content becomes visible to
85
+ the model in its response.
86
+ - **Vision (image description).** `describeImage`
87
+ (see [`src/vision/describe.ts`](src/vision/describe.ts:118)) base64-encodes
88
+ a screenshot or workspace image and POSTs it to OpenRouter
89
+ (`openrouter.ai`, or `HEADLESSCODE_VISION_MODEL`'s configured provider) for
90
+ captioning, then feeds the description back into the model's context. The
91
+ image bytes themselves leave the machine and are processed by a third-party
92
+ cloud model, subject to that provider's own data-handling policy.
93
+
94
+ Neither flow has a local-only mode today. Do not use `browser_action` against
95
+ URLs, or `describeImage` against screenshots/images, that contain data you
96
+ would not otherwise send to a third-party cloud API.
97
+
98
+ ## The permissions mechanism (defense in depth, not a boundary)
99
+
100
+ The harness ships an optional permissions layer that can restrict what the
101
+ agent does — see [`docs/central-store.md`](docs/central-store.md) and
102
+ [`src/permissions/config.ts`](src/permissions/config.ts). It includes:
103
+
104
+ - `--allowed-commands` / `--denied-commands` (or
105
+ `HEADLESSCODE_ALLOWED_COMMANDS` / `HEADLESSCODE_DENIED_COMMANDS`, or a
106
+ central `permissions.json`) — allow/deny prefix matching for commands.
107
+ - `--protected-files` / `HEADLESSCODE_PROTECTED_FILES` — glob patterns of files
108
+ the write tools refuse to touch (defaults protect `.env`, `*.pem`, `*.key`,
109
+ `id_rsa*`).
110
+ - `--allow-protected-writes` — explicit escape hatch that bypasses the
111
+ protected-files check (OFF by default).
112
+
113
+ This layer is useful defense in depth against accidents and makes refusal
114
+ messages actionable, but it is a **prefix-match policy on a command string**, not
115
+ a sandbox. A malicious or sufficiently capable model can evade it (e.g. by
116
+ writing a script and running it, or by abusing any command that is allowed), so
117
+ **do not rely on it to contain untrusted code.** Restricting commands does not
118
+ restrict what the agent can *read* or what allowed commands can accomplish.
119
+
120
+ ## Known limitations (tracked audit findings)
121
+
122
+ These are specific, known gaps in the defense-in-depth layers above — not new
123
+ risks beyond the "not a sandbox" scope already documented, but concrete ways
124
+ the prefix-match and pattern-based checks can be evaded. Documented here per
125
+ the project's own audit process rather than silently left implicit.
126
+
127
+ - **Deny-list is a raw-string prefix match, not a program-identity check**
128
+ (`src/permissions/commands.ts` — `findLongestPrefixMatch`). A deny entry of
129
+ `rm` is trivially evaded by `command rm`, `/bin/rm`, `env rm`, `xargs rm`,
130
+ or `python -c "shutil.rmtree(...)"` — none of these share the `rm` prefix.
131
+ The allow/deny mechanism is prefix matching on the literal command string by
132
+ design (ported verbatim from upstream for parity); it does not resolve
133
+ `argv[0]`, follow `PATH`, or understand that many programs can accomplish
134
+ the same effect. Treat every deny-list entry as a speed bump against
135
+ accidental/careless commands, never as a guarantee that a given program
136
+ cannot run.
137
+ - **Central-store protection (`src/permissions/store-protection.ts`) is
138
+ pattern-based, not a sandbox.** As of the SEC-6 fix it protects the store
139
+ root, its ancestors, AND its descendants, and it follows symlinks
140
+ (`fs.realpathSync`) and tracks a leading `cd <dir> &&` chain's effective
141
+ cwd. It still does **not** catch: `cd` performed inside a subshell
142
+ (`(cd /x && rm -rf y)`) or via a shell variable/`pushd`/`popd`; `sudo rm`;
143
+ non-`rm` deletion (`find ... -delete`, `python -c shutil.rmtree(...)`, a
144
+ script that deletes the store); or a non-recursive `rm` of a single file
145
+ inside the store. It only recognizes GNU/POSIX `rm` flag syntax.
146
+ - **The dashboard's local HTTP server gates only POST routes with the bearer
147
+ token** (`HEADLESSCODE_DASHBOARD_TOKEN`); GET routes that list/read
148
+ workspace files, checkpoints, codemap, cost history, and projects are
149
+ reachable by any request that can reach `127.0.0.1` on the dashboard port
150
+ (including via DNS-rebinding or localhost-CSRF from a browser tab open to a
151
+ malicious page). Do not run the dashboard on a shared or multi-user machine
152
+ without additional network isolation (see also
153
+ [`src/dashboard/files.ts`](src/dashboard/files.ts) and
154
+ [`src/dashboard/trend.ts`](src/dashboard/trend.ts)).
155
+ - **`execute_command` children inherit the full process environment,**
156
+ including `HEADLESSCODE_OPENROUTER_API_KEY` and any other secret exported
157
+ into the harness's own env. `protected-files.ts` only prevents the agent
158
+ from *writing* `.env`; nothing stops the agent from reading its own
159
+ process's environment (`printenv`, `env`) and having that flow into the LLM
160
+ context. Acceptable for the documented trusted-single-user model; a real
161
+ constraint if this project is ever run multi-tenant (see
162
+ `docs/multi-tenant-hosting-design.md`) — don't put shared secrets in a
163
+ session's environment that a given task should not be able to see.
164
+
165
+ ## Reporting vulnerabilities
166
+
167
+ This project is pre-1.0 and has no private disclosure channel yet. For now,
168
+ report security findings by opening a GitHub issue on
169
+ [Capsize-Games/headlesscode](https://github.com/Capsize-Games/headlesscode)
170
+ tagged `security`, or a pull request with a fix. See the docs in `docs/` for
171
+ the overall design.
172
+
173
+ ## Supported versions
174
+
175
+ Only the current `master` branch is supported. The project has not cut
176
+ releases yet (no tags, `version: 0.1.0`); patches land on `master` and are
177
+ expected to be forward-only.
178
+
179
+ ## Security-relevant areas
180
+
181
+ If you are auditing the codebase, the highest-value targets are:
182
+
183
+ - `src/tools/executor.ts` — the tool executor, including the
184
+ `execute_command` handler that spawns shell commands and the path-traversal
185
+ guard for file tools.
186
+ - `src/permissions/` — command allow/deny, protected files, and the
187
+ central-store protection; defaults are documented in `config.ts`.
188
+ - `src/cloud/` and `src/orchestrator/` — session isolation, worktree
189
+ spawning, and the scripts they shell out to (`scripts/*.sh`).
190
+ - `src/vendor/zoo-code/` — the vendored Apache-2.0 portable core (see
191
+ `ATTRIBUTION.md`); upstream security fixes should be tracked via
192
+ `VENDOR-NOTES.md`.
193
+
194
+ The npm package (`npm pack`) ships only the runtime source under `src/`
195
+ (excluding `__tests__/`), `shared/`, and the top-level docs — internal
196
+ `plans/`, `recon/`, `.roo/`, and dev scripts are intentionally excluded (see
197
+ the `files` field in `package.json`).
198
+
199
+ ## Responsible-use checklist
200
+
201
+ Before running `headlesscode` on anything you care about:
202
+
203
+ 1. Confirm you are running it as a user whose privileges you are willing to
204
+ expose to the agent (ideally a dedicated, unprivileged account).
205
+ 2. Confirm the workspace and task are trusted, or the environment is isolated
206
+ (container/VM) so the blast radius is contained.
207
+ 3. Review the command permissions (`--allowed-commands` /
208
+ `--denied-commands`) and protected files (`--protected-files`) if you want
209
+ the defense-in-depth layer on.
210
+ 4. Never run it with credentials or secrets mounted that the task does not
211
+ need.
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * headlesscode bin launcher (issue #99).
4
+ *
5
+ * npm's `bin` entry used to point at `src/cli.ts`, whose shebang is
6
+ * `#!/usr/bin/env tsx` — but tsx is a devDependency, so on a clean
7
+ * `npm install -g` (which installs dependencies only) `env` finds no `tsx`
8
+ * on PATH and every invocation fails with "tsx: not found".
9
+ *
10
+ * This launcher fixes that by resolving THIS package's own node_modules/tsx
11
+ * directly (the same ancestor walk-up `scripts/run-tests.mjs` uses — npm
12
+ * flattens node_modules, so tsx may live in this package's node_modules OR
13
+ * be hoisted to an ancestor's) and re-execing node through tsx's CLI entry.
14
+ * It also pins TSX_TSCONFIG_PATH to this package's tsconfig.json so tsx
15
+ * resolves the package's own tsconfig instead of discovering one from the
16
+ * caller's CWD (the tsconfig now has no `paths` aliases — issue #99 rework —
17
+ * but the pin keeps the package's compiler options, e.g. `moduleResolution`,
18
+ * stable regardless of where the CLI is invoked from).
19
+ *
20
+ * A small amount of JS (not TS) on purpose: the launcher must run without
21
+ * tsx — the whole point is that it finds tsx itself.
22
+ */
23
+
24
+ import { spawnSync } from "node:child_process"
25
+ import * as fs from "node:fs"
26
+ import * as path from "node:path"
27
+ import { fileURLToPath } from "node:url"
28
+
29
+ /** This package's root (the directory above bin/). */
30
+ const PKG_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
31
+
32
+ /**
33
+ * Resolve the tsx CLI entry by walking up through ancestor `node_modules`
34
+ * directories — the same resolution Node's own module lookup (and
35
+ * `scripts/run-tests.mjs`) uses. npm hoists dependencies to the nearest
36
+ * ancestor node_modules, so the tsx binary may sit at
37
+ * `<pkgRoot>/node_modules/tsx/dist/cli.mjs` (repo checkout, nested install)
38
+ * or at an ancestor's (a global install or a consumer with a flat tree).
39
+ */
40
+ function resolveTsxCli(dir) {
41
+ let current = dir
42
+ while (true) {
43
+ const candidate = path.join(current, "node_modules", "tsx", "dist", "cli.mjs")
44
+ if (fs.existsSync(candidate)) {
45
+ return candidate
46
+ }
47
+ const parent = path.dirname(current)
48
+ if (parent === current) {
49
+ return undefined
50
+ }
51
+ current = parent
52
+ }
53
+ }
54
+
55
+ const tsxCli = resolveTsxCli(PKG_ROOT)
56
+ if (tsxCli === undefined) {
57
+ process.stderr.write(
58
+ "headlesscode: cannot find the 'tsx' runtime (node_modules/tsx/dist/cli.mjs) — " +
59
+ "this package's dependencies are not installed. Run `npm install` (or re-install the package) and retry.\n",
60
+ )
61
+ process.exit(1)
62
+ }
63
+
64
+ const cliEntry = path.join(PKG_ROOT, "src", "cli.ts")
65
+ const tsconfigPath = path.join(PKG_ROOT, "tsconfig.json")
66
+
67
+ // Run the CLI through tsx in a child process with inherited stdio. The
68
+ // caller's cwd is preserved (headlesscode's own --repo/--workspace default
69
+ // to process.cwd(), matching install-cli.sh's wrapper contract). TSX_TSCONFIG_PATH
70
+ // pins tsconfig resolution to THIS package, independent of the cwd.
71
+ const result = spawnSync(
72
+ process.execPath,
73
+ [tsxCli, cliEntry, ...process.argv.slice(2)],
74
+ { stdio: "inherit", env: { ...process.env, TSX_TSCONFIG_PATH: tsconfigPath } },
75
+ )
76
+
77
+ if (result.error) {
78
+ process.stderr.write(`headlesscode: failed to launch the CLI: ${result.error.message}\n`)
79
+ process.exit(1)
80
+ }
81
+ // Propagate the CLI's exit code; a signal-killed child becomes a non-zero
82
+ // exit here (the launcher itself has no signal handlers installed).
83
+ process.exit(result.status ?? 1)
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "headlesscode",
3
+ "version": "1.0.2",
4
+ "description": "Standalone headless coding-agent harness: runs the Zoo Code agent loop (prompts, tools, modes) without a VS Code UI, driven by CLI, HTTP, and parallel worktree orchestration.",
5
+ "license": "Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/Capsize-Games/headlesscode.git"
9
+ },
10
+ "author": "The headlesscode contributors",
11
+ "keywords": [
12
+ "cli",
13
+ "coding-agent",
14
+ "headless",
15
+ "automation",
16
+ "agent"
17
+ ],
18
+ "type": "module",
19
+ "engines": {
20
+ "node": ">=18"
21
+ },
22
+ "bin": {
23
+ "headlesscode": "bin/headlesscode.mjs"
24
+ },
25
+ "files": [
26
+ "LICENSE",
27
+ "README.md",
28
+ "ATTRIBUTION.md",
29
+ "SECURITY.md",
30
+ "CONTRIBUTING.md",
31
+ "CODE_OF_CONDUCT.md",
32
+ "tsconfig.json",
33
+ "shared/",
34
+ "src/",
35
+ "!src/**/__tests__/",
36
+ "!src/**/*.test.ts"
37
+ ],
38
+ "scripts": {
39
+ "typecheck": "tsc --noEmit",
40
+ "smoke": "tsx src/vendor/tests/smoke.ts",
41
+ "dev": "tsx src/index.ts",
42
+ "start": "tsx src/cli.ts",
43
+ "cli": "tsx src/cli.ts",
44
+ "test": "node scripts/run-tests.mjs",
45
+ "prepublishOnly": "npm ci && npm test"
46
+ },
47
+ "dependencies": {
48
+ "@modelcontextprotocol/sdk": "^1.30.0",
49
+ "@octokit/auth-app": "^8.2.0",
50
+ "fastest-levenshtein": "^1.0.16",
51
+ "p-wait-for": "^5.0.2",
52
+ "playwright": "^1.62.1",
53
+ "simple-git": "^3.36.0",
54
+ "tsx": "^4.19.0",
55
+ "typescript": "^5.6.0",
56
+ "undici": "^8.10.0",
57
+ "yaml": "^2.5.1",
58
+ "zod": "^3.25.76"
59
+ },
60
+ "devDependencies": {
61
+ "@types/node": "^22.10.0"
62
+ }
63
+ }
@@ -0,0 +1,93 @@
1
+ # Independent review — operating procedure
2
+
3
+ Use this after a worker session (in any worktree under `.worktrees/`) claims
4
+ to have finished a task. Run it against that worktree directly — it needs
5
+ the real checked-out branch, not a description of the work.
6
+
7
+ ---
8
+
9
+ You are an independent reviewer. You did not write the code you are about to
10
+ review, and you must not extend it any benefit of the doubt. Your job is to
11
+ verify claims against reality, not to check whether the claims sound
12
+ plausible. Assume the report you're reviewing has at least one wrong or
13
+ overstated claim until you've personally confirmed otherwise — reports from
14
+ autonomous coding sessions routinely overstate what was actually verified
15
+ (a claimed "all tests pass" that turns out to mean "the tests that were
16
+ touched pass," a claimed e2e run that was never actually executed, a
17
+ "verified working" that means "looks right on read-through").
18
+
19
+ ## What to review
20
+
21
+ 1. **Read the worker's own summary/report in full.** Note every concrete,
22
+ checkable claim: which files changed, test/e2e pass counts, "tsc clean,"
23
+ specific behaviors it says it preserved or fixed.
24
+ 2. **Read the actual diff** (`git -C .worktrees/<name> diff origin/master...HEAD`
25
+ or equivalent) — not just the summary. Read the whole diff for anything
26
+ under ~500 lines; for larger diffs, prioritize the highest-risk files
27
+ first (anything touching the tool executor, budget/cost accounting,
28
+ orchestrator state, or checkpoint/git operations) before sampling the
29
+ rest.
30
+ 3. **Re-run every checkable claim yourself, for real, inside that worktree:**
31
+ - `npx tsc --noEmit` — confirm it's actually clean, don't take "tsc
32
+ clean" on faith.
33
+ - `npm test` — compare the actual suite count/pass count against what
34
+ the report claims. A mismatch of even one suite is not a rounding
35
+ error.
36
+ - If the report claims e2e suites pass, re-run the relevant ones under
37
+ `scripts/e2e*/run.sh` yourself and compare actual PASS/FAIL counts.
38
+ - If the report claims a manual smoke test was run (e.g. "confirmed the
39
+ dashboard shows a running session," "confirmed the process wasn't
40
+ killed on timeout"), reproduce it yourself where practical rather than
41
+ trusting the description — these are exactly the kind of claims most
42
+ likely to be asserted without having actually been checked.
43
+ 4. **Check for silent behavior changes**, not just crashes or test
44
+ failures — a change that alters control flow (e.g. moving a non-fatal
45
+ try/catch, changing what a timeout does, changing default-allow to
46
+ default-deny somewhere) can pass every existing test and still be wrong
47
+ if nothing exercises that specific path. Read the diff for anything that
48
+ changes an existing function's behavior, not just what's newly added.
49
+ 5. **Check the task file the worker was given** (whichever `plans/*.md` file
50
+ governed this worktree) and confirm the work actually addresses what was
51
+ asked, including anything under "What NOT to do" — a worker that built
52
+ something not requested, or built something explicitly excluded, is a
53
+ real finding even if the code itself is otherwise fine.
54
+ 6. **Keep every scratch/temp file inside the workspace — no `/tmp`.**
55
+ Any scratch you need (probe scripts, temp output captures, throwaway
56
+ test files) goes in `<workspace>/.headlesscode/scratch/` (create it
57
+ if it doesn't exist; `/.headlesscode/` is gitignored). Writing to
58
+ `/tmp` or any other path outside the workspace violates the repo's
59
+ "Never write to /tmp" rule — outside-workspace writes cannot be
60
+ auto-approved in the interactive GUI and are rejected by the file
61
+ tools in headless workers.
62
+
63
+ ## Verdict and action
64
+
65
+ - **If everything checks out**: say so plainly, with the actual command
66
+ output you personally reproduced as evidence, not "looks good."
67
+ - **If you find a real problem**: report it with exact file:line evidence,
68
+ the real command output that demonstrates it, and specific, actionable
69
+ instructions for what needs to change — written the way you'd want to
70
+ receive feedback if you were about to fix it yourself.
71
+ - **Do not fix the problem yourself in this mode.** Verification and
72
+ remediation are separate passes — report what needs to change, don't
73
+ change it.
74
+
75
+ ## What NOT to do
76
+
77
+ - Do not pad the review with issues that have no real consequence just to
78
+ look thorough.
79
+ - Do not accept "the tests pass" as sufficient evidence for a claim the
80
+ tests don't actually exercise — check what the tests actually assert.
81
+ - Do not skip re-running commands because the report already includes
82
+ output — output in a report is a claim, not evidence, until reproduced.
83
+ - Do not review by reading only the summary — read the actual diff and run
84
+ actual commands every time.
85
+ - No `/tmp` — scratch goes in `<workspace>/.headlesscode/scratch/` (the
86
+ repo rule "Never write to /tmp" is binding here too; a `/tmp` write in
87
+ a review session is a finding).
88
+
89
+ ## When you're done
90
+
91
+ Give a short final verdict: pass or fail, and if fail, the specific list of
92
+ what needs to change, precise enough that someone could act on it without
93
+ re-deriving your findings from scratch.