@technomoron/agent-run 0.99.24 → 0.99.25
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/CHANGES +10 -0
- package/README.md +56 -30
- package/dist/agent-run.js +13 -3213
- package/dist/checks.js +110 -0
- package/dist/cli.js +369 -0
- package/dist/commands.js +291 -0
- package/dist/config-tree.js +170 -0
- package/dist/constants.js +62 -0
- package/dist/defaults.js +408 -0
- package/dist/guards.js +163 -0
- package/dist/manifest.js +190 -0
- package/dist/model.js +2 -0
- package/dist/process.js +208 -0
- package/dist/project.js +316 -0
- package/dist/renderer.js +441 -0
- package/dist/templates.js +203 -0
- package/dist/tools.js +93 -0
- package/dist/utils.js +117 -0
- package/dist/walk-tree.js +24 -0
- package/examples/basic-config/README.md +3 -3
- package/examples/basic-config/agent-config/agent-run.defaults.jsonc +38 -0
- package/examples/basic-config/agent-config/global/tool-templates/AGENTS.md.njk +1 -1
- package/examples/basic-config/agent-config/starter/basic-project/agent-run.jsonc +1 -21
- package/package.json +1 -1
package/dist/defaults.js
ADDED
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultManifest = defaultManifest;
|
|
4
|
+
exports.stringifyRootDefaults = stringifyRootDefaults;
|
|
5
|
+
exports.defaultLocalTemplate = defaultLocalTemplate;
|
|
6
|
+
exports.defaultGlobalTemplates = defaultGlobalTemplates;
|
|
7
|
+
exports.defaultToolInstructionsTemplate = defaultToolInstructionsTemplate;
|
|
8
|
+
exports.defaultCodexConfigContent = defaultCodexConfigContent;
|
|
9
|
+
exports.defaultClaudeSettingsContent = defaultClaudeSettingsContent;
|
|
10
|
+
exports.legacyDefaultClaudeSettingsContent = legacyDefaultClaudeSettingsContent;
|
|
11
|
+
function defaultManifest(profile) {
|
|
12
|
+
return {
|
|
13
|
+
profile,
|
|
14
|
+
kind: 'code',
|
|
15
|
+
agent: {
|
|
16
|
+
base: 'global/agents/code.md.njk',
|
|
17
|
+
includes: ['{{ profile }}/local.md.njk']
|
|
18
|
+
},
|
|
19
|
+
skills: {
|
|
20
|
+
install: ['commit-workflow', 'github-release', 'release-package-check', 'code-review-organizer']
|
|
21
|
+
},
|
|
22
|
+
tools: {
|
|
23
|
+
codex: true,
|
|
24
|
+
claude: true
|
|
25
|
+
},
|
|
26
|
+
checks: ['agent-run check .', 'pnpm run cleanbuild'],
|
|
27
|
+
guardrails: {
|
|
28
|
+
blockGitWrite: true,
|
|
29
|
+
blockPublish: true,
|
|
30
|
+
blockGithubRelease: true,
|
|
31
|
+
forbidRepoAiFiles: true
|
|
32
|
+
},
|
|
33
|
+
paths: {
|
|
34
|
+
changesFile: '{{ projectRoot }}/CHANGES',
|
|
35
|
+
reviewDir: '{{ profileDir }}/reviews',
|
|
36
|
+
reviewFile: '{{ profileDir }}/reviews/REVIEW-{{ date }}.md',
|
|
37
|
+
memoriesDir: '{{ agentDir }}/memories'
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function defaultRootManifest() {
|
|
42
|
+
const { profile: _profile, ...manifest } = defaultManifest('default/profile');
|
|
43
|
+
return manifest;
|
|
44
|
+
}
|
|
45
|
+
function stringifyRootDefaults() {
|
|
46
|
+
return `${JSON.stringify(defaultRootManifest(), null, 2)}\n`;
|
|
47
|
+
}
|
|
48
|
+
function defaultLocalTemplate() {
|
|
49
|
+
return [
|
|
50
|
+
'# {{ profile }} local agent instructions',
|
|
51
|
+
'',
|
|
52
|
+
'Project root:',
|
|
53
|
+
'',
|
|
54
|
+
'```text',
|
|
55
|
+
'{{ projectRoot }}',
|
|
56
|
+
'```',
|
|
57
|
+
'',
|
|
58
|
+
'Agent directory:',
|
|
59
|
+
'',
|
|
60
|
+
'```text',
|
|
61
|
+
'{{ agentDir }}',
|
|
62
|
+
'```',
|
|
63
|
+
'',
|
|
64
|
+
'Profile source directory:',
|
|
65
|
+
'',
|
|
66
|
+
'```text',
|
|
67
|
+
'{{ profileDir }}',
|
|
68
|
+
'```',
|
|
69
|
+
'',
|
|
70
|
+
'Add project-specific rules here.',
|
|
71
|
+
''
|
|
72
|
+
].join('\n');
|
|
73
|
+
}
|
|
74
|
+
function defaultGlobalTemplates() {
|
|
75
|
+
return new Map([
|
|
76
|
+
['global/agents/code.md.njk', defaultCodeAgentTemplate()],
|
|
77
|
+
['global/agents/writing.md.njk', defaultWritingAgentTemplate()],
|
|
78
|
+
['global/snippets/git-rules.md.njk', defaultGitRulesSnippet()],
|
|
79
|
+
['global/snippets/no-ai-files.md.njk', defaultNoAiFilesSnippet()],
|
|
80
|
+
['global/snippets/verification.md.njk', defaultVerificationSnippet()],
|
|
81
|
+
['global/tool-templates/codex-config.toml.njk', defaultCodexConfigTemplate()],
|
|
82
|
+
['global/tool-templates/claude-settings.json.njk', defaultClaudeSettingsTemplate()],
|
|
83
|
+
['global/skills/commit-workflow/SKILL.md.njk', defaultCommitWorkflowSkill()],
|
|
84
|
+
['global/skills/github-release/SKILL.md.njk', defaultGithubReleaseSkill()],
|
|
85
|
+
['global/skills/release-package-check/SKILL.md.njk', defaultReleasePackageCheckSkill()],
|
|
86
|
+
['global/skills/code-review-organizer/SKILL.md.njk', defaultCodeReviewOrganizerSkill()]
|
|
87
|
+
]);
|
|
88
|
+
}
|
|
89
|
+
function defaultCodeAgentTemplate() {
|
|
90
|
+
return [
|
|
91
|
+
'# Code Agent',
|
|
92
|
+
'',
|
|
93
|
+
'Work in the project root shown by agent-run. Keep changes scoped to the user request.',
|
|
94
|
+
'',
|
|
95
|
+
'{% include "global/snippets/git-rules.md.njk" %}',
|
|
96
|
+
'',
|
|
97
|
+
'{% include "global/snippets/no-ai-files.md.njk" %}',
|
|
98
|
+
'',
|
|
99
|
+
'{% include "global/snippets/verification.md.njk" %}',
|
|
100
|
+
''
|
|
101
|
+
].join('\n');
|
|
102
|
+
}
|
|
103
|
+
function defaultWritingAgentTemplate() {
|
|
104
|
+
return [
|
|
105
|
+
'# Writing Agent',
|
|
106
|
+
'',
|
|
107
|
+
'Write clearly and preserve the existing voice, structure, and facts in the project.',
|
|
108
|
+
'',
|
|
109
|
+
'{% include "global/snippets/no-ai-files.md.njk" %}',
|
|
110
|
+
''
|
|
111
|
+
].join('\n');
|
|
112
|
+
}
|
|
113
|
+
function defaultGitRulesSnippet() {
|
|
114
|
+
return [
|
|
115
|
+
'## Git Rules',
|
|
116
|
+
'',
|
|
117
|
+
'Do not commit unless the user explicitly asks. Before committing, show changed files and the exact commit message.',
|
|
118
|
+
'Use human commit messages unless the user asks for conventional commits. Do not push unless explicitly asked.',
|
|
119
|
+
''
|
|
120
|
+
].join('\n');
|
|
121
|
+
}
|
|
122
|
+
function defaultNoAiFilesSnippet() {
|
|
123
|
+
return [
|
|
124
|
+
'## Agent File Storage',
|
|
125
|
+
'',
|
|
126
|
+
'Do not create AGENTS.md, CLAUDE.md, .agents, .claude, .codex, or other agent runtime files inside the project repository.',
|
|
127
|
+
'Generated agent-only files belong under {{ paths.liveDir }}.',
|
|
128
|
+
'Source config files belong under {{ profileDir }}.',
|
|
129
|
+
''
|
|
130
|
+
].join('\n');
|
|
131
|
+
}
|
|
132
|
+
function defaultVerificationSnippet() {
|
|
133
|
+
return [
|
|
134
|
+
'## Verification',
|
|
135
|
+
'',
|
|
136
|
+
'Run relevant checks before reporting completion. Configured checks:',
|
|
137
|
+
'',
|
|
138
|
+
'{% for check in checks %}',
|
|
139
|
+
'- `{{ check }}`',
|
|
140
|
+
'{% endfor %}',
|
|
141
|
+
''
|
|
142
|
+
].join('\n');
|
|
143
|
+
}
|
|
144
|
+
function defaultCommitWorkflowSkill() {
|
|
145
|
+
return [
|
|
146
|
+
'---',
|
|
147
|
+
'name: commit-workflow',
|
|
148
|
+
'description: Use for preparing or creating commits with explicit user approval.',
|
|
149
|
+
'---',
|
|
150
|
+
'',
|
|
151
|
+
'# Commit Workflow',
|
|
152
|
+
'',
|
|
153
|
+
'Never commit unless explicitly asked. Before committing, show changed files and the exact commit message.',
|
|
154
|
+
'Use human commit messages unless conventional commits are explicitly requested. Do not push.',
|
|
155
|
+
'Run configured checks before committing:',
|
|
156
|
+
'',
|
|
157
|
+
'{% for check in checks %}',
|
|
158
|
+
'- `{{ check }}`',
|
|
159
|
+
'{% endfor %}',
|
|
160
|
+
''
|
|
161
|
+
].join('\n');
|
|
162
|
+
}
|
|
163
|
+
function defaultGithubReleaseSkill() {
|
|
164
|
+
return [
|
|
165
|
+
'---',
|
|
166
|
+
'name: github-release',
|
|
167
|
+
'description: Use for releases, version bumps, tags, publishing, GitHub Releases, and CHANGES updates.',
|
|
168
|
+
'---',
|
|
169
|
+
'',
|
|
170
|
+
'# GitHub Release',
|
|
171
|
+
'',
|
|
172
|
+
'Use {{ paths.changesFile }} for change notes.',
|
|
173
|
+
'Require confirmation before writing CHANGES, bumping versions, committing, tagging, pushing, publishing, or creating a GitHub Release.',
|
|
174
|
+
'Follow `$commit-workflow` for release commits.',
|
|
175
|
+
''
|
|
176
|
+
].join('\n');
|
|
177
|
+
}
|
|
178
|
+
function defaultReleasePackageCheckSkill() {
|
|
179
|
+
return [
|
|
180
|
+
'---',
|
|
181
|
+
'name: release-package-check',
|
|
182
|
+
'description: Use before package releases and publish-ready changes to verify package metadata, release notes, lockfiles, workflows, git state, and agent-file hygiene.',
|
|
183
|
+
'---',
|
|
184
|
+
'',
|
|
185
|
+
'# Release Package Check',
|
|
186
|
+
'',
|
|
187
|
+
'Use this skill instead of an external `repo-check` command.',
|
|
188
|
+
'For package release or publish-ready work, verify the relevant package directory before finalizing:',
|
|
189
|
+
'',
|
|
190
|
+
'- The directory contains `package.json` and is inside a git repository.',
|
|
191
|
+
'- The repository path follows `<org>/<repo>`, and `package.json.name` is `@<org>/<package-dir-name>`.',
|
|
192
|
+
'- `package.json.version`, `package.json.license`, and `package.json.copyright` are present and non-empty.',
|
|
193
|
+
'- A package-local `LICENSE` file exists and contains the exact copyright string from `package.json.copyright`.',
|
|
194
|
+
'- A package-local `CHANGES` file exists.',
|
|
195
|
+
'- The first `Version ...` line in `CHANGES` matches `Version <package.json.version> (<YYYY-MM-DD>)`.',
|
|
196
|
+
'- The year in the top `CHANGES` version line appears in `package.json.copyright`.',
|
|
197
|
+
'- The git `origin` remote matches `<org>/<repo>`.',
|
|
198
|
+
'- The current branch has an upstream configured and is in sync with it after fetching.',
|
|
199
|
+
'- The repository does not contain agent files or directories such as `AGENTS.md`, `CLAUDE.md`, `codex.md`, `.claude`, or `.codex`.',
|
|
200
|
+
'- The repository root has a lockfile: `pnpm-lock.yaml`, `package-lock.json`, `yarn.lock`, `bun.lockb`, or `bun.lock`.',
|
|
201
|
+
'- Every GitHub Actions `uses:` reference is pinned to a full commit SHA.',
|
|
202
|
+
'- The pinned `actions/setup-node` release is v6-compatible and workflows use `node-version: 24`.',
|
|
203
|
+
'- GitHub workflows do not reference `node20` or `node22`.',
|
|
204
|
+
'- The git working tree is clean for files under the checked package directory.',
|
|
205
|
+
'- If files beyond `CHANGES` changed in the checked package directory, that package `CHANGES` file is also changed.',
|
|
206
|
+
'',
|
|
207
|
+
'Run the configured checks after this checklist:',
|
|
208
|
+
'',
|
|
209
|
+
'{% for check in checks %}',
|
|
210
|
+
'- `{{ check }}`',
|
|
211
|
+
'{% endfor %}',
|
|
212
|
+
''
|
|
213
|
+
].join('\n');
|
|
214
|
+
}
|
|
215
|
+
function defaultCodeReviewOrganizerSkill() {
|
|
216
|
+
return [
|
|
217
|
+
'---',
|
|
218
|
+
'name: code-review-organizer',
|
|
219
|
+
'description: Use for organizing code review findings, review files, and review follow-up state.',
|
|
220
|
+
'---',
|
|
221
|
+
'',
|
|
222
|
+
'# Code Review Organizer',
|
|
223
|
+
'',
|
|
224
|
+
'On review startup, move any files from {{ paths.liveDir }}/reviews into {{ paths.reviewDir }} so review history persists outside the ephemeral live directory.',
|
|
225
|
+
'Before doing any code review, read the generated AGENTS.md file and the current consolidated review file: {{ paths.reviewConsolidatedFile }}.',
|
|
226
|
+
'Save each active review to {{ paths.reviewDir }}/yyyy-mm-dd-[sequence].md, where the sequence increments for multiple reviews on the same date.',
|
|
227
|
+
'Whenever a saved review is created or changed, update {{ paths.reviewConsolidatedFile }} with the consolidated current review findings.',
|
|
228
|
+
'In {{ paths.reviewConsolidatedFile }}, include each active finding with its review date and source review filename.',
|
|
229
|
+
'When a finding is fixed, remove it from {{ paths.reviewConsolidatedFile }} and move it to {{ paths.reviewDir }}/DONE.md with the time it was fixed.',
|
|
230
|
+
'When a finding is intentionally not fixed, remove it from {{ paths.reviewConsolidatedFile }} and move it to {{ paths.reviewDir }}/DONE.md with the time it was marked intentional and a note that it was intentionally left as-is.',
|
|
231
|
+
'When a dated review file has no remaining active findings, delete it.',
|
|
232
|
+
'Also include active findings in the final user-facing reply.',
|
|
233
|
+
'Do not save review files inside the project repo.',
|
|
234
|
+
'Before the final reply for review work, verify that no REVIEW*.md files exist in {{ projectRoot }}, active dated review files exist only when they still contain active findings, and the consolidated REVIEW.md file was updated.',
|
|
235
|
+
''
|
|
236
|
+
].join('\n');
|
|
237
|
+
}
|
|
238
|
+
function defaultToolInstructionsTemplate(isClaude) {
|
|
239
|
+
return [
|
|
240
|
+
`# Generated ${isClaude ? 'Claude' : 'agent'} instructions for {{ profile }}`,
|
|
241
|
+
'',
|
|
242
|
+
'Do not edit this file directly. Profile source and optional overrides live under:',
|
|
243
|
+
'',
|
|
244
|
+
'```text',
|
|
245
|
+
'{{ profileDir }}',
|
|
246
|
+
'```',
|
|
247
|
+
'',
|
|
248
|
+
'{% for section in renderedAgentSections %}',
|
|
249
|
+
'{{ section }}',
|
|
250
|
+
'',
|
|
251
|
+
'{% endfor %}',
|
|
252
|
+
'## Absolute Paths',
|
|
253
|
+
'',
|
|
254
|
+
'Project root:',
|
|
255
|
+
'',
|
|
256
|
+
'```text',
|
|
257
|
+
'{{ projectRoot }}',
|
|
258
|
+
'```',
|
|
259
|
+
'',
|
|
260
|
+
'Agent directory:',
|
|
261
|
+
'',
|
|
262
|
+
'```text',
|
|
263
|
+
'{{ agentDir }}',
|
|
264
|
+
'```',
|
|
265
|
+
'',
|
|
266
|
+
'Profile source directory:',
|
|
267
|
+
'',
|
|
268
|
+
'```text',
|
|
269
|
+
'{{ profileDir }}',
|
|
270
|
+
'```',
|
|
271
|
+
'',
|
|
272
|
+
'Review directory:',
|
|
273
|
+
'',
|
|
274
|
+
'```text',
|
|
275
|
+
'{{ paths.reviewDir }}',
|
|
276
|
+
'```',
|
|
277
|
+
'',
|
|
278
|
+
"Today's review file:",
|
|
279
|
+
'',
|
|
280
|
+
'```text',
|
|
281
|
+
'{{ paths.reviewFile }}',
|
|
282
|
+
'```',
|
|
283
|
+
'',
|
|
284
|
+
'Consolidated review file:',
|
|
285
|
+
'',
|
|
286
|
+
'```text',
|
|
287
|
+
'{{ paths.reviewConsolidatedFile }}',
|
|
288
|
+
'```',
|
|
289
|
+
'',
|
|
290
|
+
'Memories directory:',
|
|
291
|
+
'',
|
|
292
|
+
'```text',
|
|
293
|
+
'{{ paths.memoriesDir }}',
|
|
294
|
+
'```',
|
|
295
|
+
'',
|
|
296
|
+
'Global memory directory:',
|
|
297
|
+
'',
|
|
298
|
+
'```text',
|
|
299
|
+
'{{ paths.globalMemoryDir }}',
|
|
300
|
+
'```',
|
|
301
|
+
'',
|
|
302
|
+
'Changes file:',
|
|
303
|
+
'',
|
|
304
|
+
'```text',
|
|
305
|
+
'{{ paths.changesFile }}',
|
|
306
|
+
'```',
|
|
307
|
+
'',
|
|
308
|
+
'## Available Skills',
|
|
309
|
+
'',
|
|
310
|
+
'{% for skill in skills %}',
|
|
311
|
+
'- `${{ skill.name }}`{% if skill.description %}: {{ skill.description }}{% endif %}',
|
|
312
|
+
'{% endfor %}',
|
|
313
|
+
'',
|
|
314
|
+
'## Tool Note',
|
|
315
|
+
'',
|
|
316
|
+
isClaude
|
|
317
|
+
? 'Claude receives {{ agentDir }}/CLAUDE.md through `--append-system-prompt-file` and loads generated skills as a local plugin.'
|
|
318
|
+
: 'Codex loads AGENTS.md, config.toml, and skills natively from {{ paths.codexHomeDir }}.',
|
|
319
|
+
'',
|
|
320
|
+
'## Mandatory Path Rule',
|
|
321
|
+
'',
|
|
322
|
+
'Do not create AGENTS.md, CLAUDE.md, .agents, .claude, .codex, or AI-related files inside the project repository.',
|
|
323
|
+
'Generated agent-only files must be stored under the agent directory shown above.',
|
|
324
|
+
'Source config files must be stored under the profile source directory shown above.',
|
|
325
|
+
''
|
|
326
|
+
].join('\n');
|
|
327
|
+
}
|
|
328
|
+
function defaultCodexConfigTemplate() {
|
|
329
|
+
return [
|
|
330
|
+
'# Generated by agent-run. Do not edit directly.',
|
|
331
|
+
'',
|
|
332
|
+
'project_doc_max_bytes = 65536',
|
|
333
|
+
'approval_policy = "on-request"',
|
|
334
|
+
'sandbox_mode = "workspace-write"',
|
|
335
|
+
'',
|
|
336
|
+
'[sandbox_workspace_write]',
|
|
337
|
+
'writable_roots = [',
|
|
338
|
+
' {{ projectRoot | dump }},',
|
|
339
|
+
' {{ paths.reviewDir | dump }},',
|
|
340
|
+
' {{ paths.memoriesDir | dump }}',
|
|
341
|
+
']',
|
|
342
|
+
'network_access = false',
|
|
343
|
+
''
|
|
344
|
+
].join('\n');
|
|
345
|
+
}
|
|
346
|
+
function defaultClaudeSettingsTemplate() {
|
|
347
|
+
const envBlock = [
|
|
348
|
+
' "env": {',
|
|
349
|
+
' "AGENT_DIR": {{ agentDir | dump }},',
|
|
350
|
+
' "AGENT_PROFILE_DIR": {{ profileDir | dump }},',
|
|
351
|
+
' "AGENT_RUN_PROJECT_ROOT": {{ projectRoot | dump }},',
|
|
352
|
+
' "AGENT_GLOBAL_MEMORY_DIR": {{ paths.globalMemoryDir | dump }}',
|
|
353
|
+
' }'
|
|
354
|
+
].join('\n');
|
|
355
|
+
return [
|
|
356
|
+
'{% if permissionsAllow.length %}{',
|
|
357
|
+
envBlock + ',',
|
|
358
|
+
' "permissions": {',
|
|
359
|
+
' "allow": {{ permissionsAllow | dump }}',
|
|
360
|
+
' }',
|
|
361
|
+
'}',
|
|
362
|
+
'{% else %}{',
|
|
363
|
+
envBlock,
|
|
364
|
+
'}',
|
|
365
|
+
'{% endif %}'
|
|
366
|
+
].join('\n');
|
|
367
|
+
}
|
|
368
|
+
function defaultCodexConfigContent(context) {
|
|
369
|
+
return [
|
|
370
|
+
'# Generated by agent-run. Do not edit directly.',
|
|
371
|
+
'',
|
|
372
|
+
'project_doc_max_bytes = 65536',
|
|
373
|
+
'approval_policy = "on-request"',
|
|
374
|
+
'sandbox_mode = "workspace-write"',
|
|
375
|
+
'',
|
|
376
|
+
'[sandbox_workspace_write]',
|
|
377
|
+
'writable_roots = [',
|
|
378
|
+
` ${JSON.stringify(context.projectRoot)},`,
|
|
379
|
+
` ${JSON.stringify(context.paths.reviewDir)},`,
|
|
380
|
+
` ${JSON.stringify(context.paths.memoriesDir)}`,
|
|
381
|
+
']',
|
|
382
|
+
'network_access = false',
|
|
383
|
+
''
|
|
384
|
+
].join('\n');
|
|
385
|
+
}
|
|
386
|
+
function defaultClaudeSettingsContent(context) {
|
|
387
|
+
const settings = {
|
|
388
|
+
env: {
|
|
389
|
+
AGENT_DIR: context.agentDir,
|
|
390
|
+
AGENT_PROFILE_DIR: context.profileDir,
|
|
391
|
+
AGENT_RUN_PROJECT_ROOT: context.projectRoot,
|
|
392
|
+
AGENT_GLOBAL_MEMORY_DIR: context.paths.globalMemoryDir
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
if (context.permissionsAllow.length > 0) {
|
|
396
|
+
settings.permissions = { allow: context.permissionsAllow };
|
|
397
|
+
}
|
|
398
|
+
return `${JSON.stringify(settings, null, 2)}\n`;
|
|
399
|
+
}
|
|
400
|
+
function legacyDefaultClaudeSettingsContent(context, agentDir) {
|
|
401
|
+
return `${JSON.stringify({
|
|
402
|
+
env: {
|
|
403
|
+
AGENT_DIR: agentDir,
|
|
404
|
+
AGENT_RUN_PROJECT_ROOT: context.projectRoot,
|
|
405
|
+
AGENT_GLOBAL_MEMORY_DIR: context.paths.globalMemoryDir
|
|
406
|
+
}
|
|
407
|
+
}, null, 2)}\n`;
|
|
408
|
+
}
|
package/dist/guards.js
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderGuardShims = renderGuardShims;
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const constants_1 = require("./constants");
|
|
6
|
+
function renderGuardShims(context) {
|
|
7
|
+
const names = [];
|
|
8
|
+
if (context.guardrails.blockGitWrite) {
|
|
9
|
+
names.push('git');
|
|
10
|
+
}
|
|
11
|
+
if (context.guardrails.blockPublish) {
|
|
12
|
+
names.push('npm', 'pnpm');
|
|
13
|
+
}
|
|
14
|
+
if (context.guardrails.blockGithubRelease) {
|
|
15
|
+
names.push('gh');
|
|
16
|
+
}
|
|
17
|
+
if (constants_1.IS_WINDOWS) {
|
|
18
|
+
return names.map((name) => ({
|
|
19
|
+
path: path.join(context.paths.binDir, `${name}.cmd`),
|
|
20
|
+
content: windowsShim(name)
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
return names.map((name) => ({
|
|
24
|
+
path: path.join(context.paths.binDir, name),
|
|
25
|
+
content: name === 'git'
|
|
26
|
+
? posixGitShim()
|
|
27
|
+
: name === 'gh'
|
|
28
|
+
? posixGhShim()
|
|
29
|
+
: posixPublishShim(name),
|
|
30
|
+
executable: true
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
function posixGitShim() {
|
|
34
|
+
return [
|
|
35
|
+
'#!/usr/bin/env bash',
|
|
36
|
+
'set -euo pipefail',
|
|
37
|
+
'for arg in "$@"; do',
|
|
38
|
+
' case "$arg" in',
|
|
39
|
+
' commit|tag|push)',
|
|
40
|
+
' if [ "${AGENT_RUN_ALLOW_GIT_WRITE:-}" != "1" ]; then',
|
|
41
|
+
' echo "agent-run: blocked git $arg. Review and run it manually, or set AGENT_RUN_ALLOW_GIT_WRITE=1 for this invocation." >&2',
|
|
42
|
+
' exit 42',
|
|
43
|
+
' fi',
|
|
44
|
+
' ;;',
|
|
45
|
+
' esac',
|
|
46
|
+
'done',
|
|
47
|
+
...posixRunRealCommand('git'),
|
|
48
|
+
''
|
|
49
|
+
].join('\n');
|
|
50
|
+
}
|
|
51
|
+
function posixPublishShim(tool) {
|
|
52
|
+
return [
|
|
53
|
+
'#!/usr/bin/env bash',
|
|
54
|
+
'set -euo pipefail',
|
|
55
|
+
'for arg in "$@"; do',
|
|
56
|
+
' if [ "$arg" = "publish" ] && [ "${AGENT_RUN_ALLOW_PUBLISH:-}" != "1" ]; then',
|
|
57
|
+
` echo "agent-run: blocked ${tool} publish. Review and run it manually, or set AGENT_RUN_ALLOW_PUBLISH=1 for this invocation." >&2`,
|
|
58
|
+
' exit 42',
|
|
59
|
+
' fi',
|
|
60
|
+
'done',
|
|
61
|
+
...posixRunRealCommand(tool),
|
|
62
|
+
''
|
|
63
|
+
].join('\n');
|
|
64
|
+
}
|
|
65
|
+
function posixGhShim() {
|
|
66
|
+
return [
|
|
67
|
+
'#!/usr/bin/env bash',
|
|
68
|
+
'set -euo pipefail',
|
|
69
|
+
'saw_release=0',
|
|
70
|
+
'for arg in "$@"; do',
|
|
71
|
+
' if [ "$arg" = "release" ]; then',
|
|
72
|
+
' saw_release=1',
|
|
73
|
+
' elif [ "$saw_release" = "1" ] && [ "$arg" = "create" ] && [ "${AGENT_RUN_ALLOW_GITHUB_RELEASE:-}" != "1" ]; then',
|
|
74
|
+
' echo "agent-run: blocked gh release create. Review and run it manually, or set AGENT_RUN_ALLOW_GITHUB_RELEASE=1 for this invocation." >&2',
|
|
75
|
+
' exit 42',
|
|
76
|
+
' fi',
|
|
77
|
+
'done',
|
|
78
|
+
...posixRunRealCommand('gh'),
|
|
79
|
+
''
|
|
80
|
+
].join('\n');
|
|
81
|
+
}
|
|
82
|
+
function posixRunRealCommand(tool) {
|
|
83
|
+
return [
|
|
84
|
+
'shim_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"',
|
|
85
|
+
'real_path="${AGENT_RUN_REAL_PATH:-}"',
|
|
86
|
+
'if [ -z "$real_path" ]; then',
|
|
87
|
+
' case "${PATH:-}" in',
|
|
88
|
+
' "$shim_dir") real_path="" ;;',
|
|
89
|
+
' "$shim_dir":*) real_path="${PATH#*:}" ;;',
|
|
90
|
+
' *) real_path="${PATH:-}" ;;',
|
|
91
|
+
' esac',
|
|
92
|
+
'fi',
|
|
93
|
+
`real_command="$(PATH="$real_path" command -v ${tool} || true)"`,
|
|
94
|
+
'if [ -z "$real_command" ]; then',
|
|
95
|
+
` echo "agent-run: cannot find the real ${tool} command outside the guard directory." >&2`,
|
|
96
|
+
' exit 127',
|
|
97
|
+
'fi',
|
|
98
|
+
`if [ "$real_command" = "$shim_dir/${tool}" ]; then`,
|
|
99
|
+
` echo "agent-run: refused recursive ${tool} guard resolution." >&2`,
|
|
100
|
+
' exit 127',
|
|
101
|
+
'fi',
|
|
102
|
+
'PATH="$real_path" exec "$real_command" "$@"'
|
|
103
|
+
];
|
|
104
|
+
}
|
|
105
|
+
function windowsShim(name) {
|
|
106
|
+
const executable = name === 'npm' || name === 'pnpm' ? `${name}.cmd` : `${name}.exe`;
|
|
107
|
+
const guard = name === 'git' ? windowsGitGuard() : name === 'gh' ? windowsGhGuard() : windowsPublishGuard(name);
|
|
108
|
+
return [
|
|
109
|
+
'@echo off',
|
|
110
|
+
...guard,
|
|
111
|
+
':run',
|
|
112
|
+
'if defined AGENT_RUN_REAL_PATH (',
|
|
113
|
+
' set "PATH=%AGENT_RUN_REAL_PATH%"',
|
|
114
|
+
') else (',
|
|
115
|
+
' for /f "tokens=1,* delims=;" %%A in ("%PATH%") do set "PATH=%%B"',
|
|
116
|
+
')',
|
|
117
|
+
`${executable} %*`,
|
|
118
|
+
''
|
|
119
|
+
].join('\n');
|
|
120
|
+
}
|
|
121
|
+
function windowsGitGuard() {
|
|
122
|
+
return [
|
|
123
|
+
':scan',
|
|
124
|
+
'if "%~1"=="" goto run',
|
|
125
|
+
'if /I "%~1"=="commit" goto block_git',
|
|
126
|
+
'if /I "%~1"=="tag" goto block_git',
|
|
127
|
+
'if /I "%~1"=="push" goto block_git',
|
|
128
|
+
'shift',
|
|
129
|
+
'goto scan',
|
|
130
|
+
':block_git',
|
|
131
|
+
'if "%AGENT_RUN_ALLOW_GIT_WRITE%"=="1" goto run',
|
|
132
|
+
'echo agent-run: blocked git write. Review and run it manually, or set AGENT_RUN_ALLOW_GIT_WRITE=1 for this invocation. 1>&2',
|
|
133
|
+
'exit /b 42'
|
|
134
|
+
];
|
|
135
|
+
}
|
|
136
|
+
function windowsGhGuard() {
|
|
137
|
+
return [
|
|
138
|
+
'set "SAW_RELEASE=0"',
|
|
139
|
+
':scan',
|
|
140
|
+
'if "%~1"=="" goto run',
|
|
141
|
+
'if /I "%~1"=="release" set "SAW_RELEASE=1"',
|
|
142
|
+
'if "%SAW_RELEASE%"=="1" if /I "%~1"=="create" goto block_release',
|
|
143
|
+
'shift',
|
|
144
|
+
'goto scan',
|
|
145
|
+
':block_release',
|
|
146
|
+
'if "%AGENT_RUN_ALLOW_GITHUB_RELEASE%"=="1" goto run',
|
|
147
|
+
'echo agent-run: blocked gh release create. Review and run it manually, or set AGENT_RUN_ALLOW_GITHUB_RELEASE=1 for this invocation. 1>&2',
|
|
148
|
+
'exit /b 42'
|
|
149
|
+
];
|
|
150
|
+
}
|
|
151
|
+
function windowsPublishGuard(name) {
|
|
152
|
+
return [
|
|
153
|
+
':scan',
|
|
154
|
+
'if "%~1"=="" goto run',
|
|
155
|
+
'if /I "%~1"=="publish" goto block_publish',
|
|
156
|
+
'shift',
|
|
157
|
+
'goto scan',
|
|
158
|
+
':block_publish',
|
|
159
|
+
'if "%AGENT_RUN_ALLOW_PUBLISH%"=="1" goto run',
|
|
160
|
+
`echo agent-run: blocked ${name} publish. Review and run it manually, or set AGENT_RUN_ALLOW_PUBLISH=1 for this invocation. 1>&2`,
|
|
161
|
+
'exit /b 42'
|
|
162
|
+
];
|
|
163
|
+
}
|