@plainconceptsplatform/agent-harness 2.5.0 → 2.5.1
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/cli/utils/copy.js
CHANGED
|
@@ -15,6 +15,24 @@ const NEVER_OVERWRITE = [
|
|
|
15
15
|
|
|
16
16
|
const MARKER_COMMANDS = new Set(['.opencode/commands/ops-review.md', '.opencode/commands/ops-backlog.md'])
|
|
17
17
|
|
|
18
|
+
// Where a project may legitimately keep the doc instead of the repository root.
|
|
19
|
+
// Foundations puts both under ai/, and projects that follow it point their own
|
|
20
|
+
// AGENTS.md there.
|
|
21
|
+
const ROOT_DOCS = new Set(['ARCHITECTURE.md', 'DESIGN.md'])
|
|
22
|
+
const ALTERNATE_DOC_DIRS = ['ai', 'docs']
|
|
23
|
+
|
|
24
|
+
// Seeding the "NOT GENERATED YET, run /make-architecture" placeholder next to a
|
|
25
|
+
// real architecture document is worse than seeding nothing: pc-make-guardrails
|
|
26
|
+
// reads the root file as its primary source, and an agent that finds the
|
|
27
|
+
// placeholder there concludes the project has no architecture written down.
|
|
28
|
+
async function documentedElsewhere(destDir, fileName) {
|
|
29
|
+
if (!ROOT_DOCS.has(fileName)) return false
|
|
30
|
+
for (const directory of ALTERNATE_DOC_DIRS) {
|
|
31
|
+
if (await fse.pathExists(path.join(destDir, directory, fileName))) return true
|
|
32
|
+
}
|
|
33
|
+
return false
|
|
34
|
+
}
|
|
35
|
+
|
|
18
36
|
function isTemplateTest(relativePath) {
|
|
19
37
|
return relativePath.split(path.sep).join('/').startsWith('.opencode/plugins/') && relativePath.endsWith('.test.js')
|
|
20
38
|
}
|
|
@@ -50,6 +68,7 @@ export async function copyContent(contentDir, destDir, platform, ctx = {}) {
|
|
|
50
68
|
if (isTemplateTest(rel)) return false
|
|
51
69
|
if (ctx.hasDesign && rel === 'DESIGN.md') return false
|
|
52
70
|
if (ctx.hasArchitecture && rel === 'ARCHITECTURE.md') return false
|
|
71
|
+
if (await documentedElsewhere(destDir, rel)) return false
|
|
53
72
|
// User-owned config files are never overwritten, even with forceOverwrite.
|
|
54
73
|
// The update command calls writeModelsToConfigs separately to set the
|
|
55
74
|
// model field in opencode.jsonc without destroying user additions.
|
|
@@ -139,13 +139,30 @@ async function checkPush(command, root, defaultBranch) {
|
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
+
// `/tmp/gh-aw/` is the agent workflow runtime's own working directory, not agent scratch.
|
|
143
|
+
//
|
|
144
|
+
// GitHub Agentic Workflows stages everything a worker is given there before the agent starts:
|
|
145
|
+
// the issue context, the open-issue list, the pull request diff, the review comments. The worker
|
|
146
|
+
// prompts name those paths and tell the agent to read them. This check tests the whole command
|
|
147
|
+
// string, so it cannot tell "write to /tmp" from "read from /tmp" — and a command that read one
|
|
148
|
+
// of those files and wrote the result anywhere at all was denied.
|
|
149
|
+
//
|
|
150
|
+
// The effect was total and silent. Three refine runs in a row spent their whole turn arguing
|
|
151
|
+
// with this guardrail and emitted nothing: the agent tried
|
|
152
|
+
// `jq -r .body /tmp/gh-aw/agent/issue-context.json > .opencode/.tmp/body.md`, was refused, tried
|
|
153
|
+
// an absolute path, was refused again, and gave up. The advice it is handed names `$REPO_ROOT`,
|
|
154
|
+
// which is unset on a GitHub Actions runner, so following it exactly could not work either.
|
|
155
|
+
//
|
|
156
|
+
// Exempting this one directory is not a hole in the rule. The rule exists so the next step can
|
|
157
|
+
// still find what the agent wrote, and `/tmp/gh-aw/` is exactly where the next step looks.
|
|
142
158
|
function checkScratch(command) {
|
|
143
159
|
const writesSomewhere = /(>>?|\btee\b|\bcp\b|\bmv\b|\bmkdir\b|\btouch\b|\bdd\b)/.test(command)
|
|
144
|
-
|
|
160
|
+
// Everywhere else stays blocked: /tmp outside gh-aw, $TMPDIR, $TEMP, %TEMP%, mktemp.
|
|
161
|
+
const outsideRepo = /(\/tmp\/(?!gh-aw\/)|\$TMPDIR|\$TEMP\b|%TEMP%|\bmktemp\b)/.test(command)
|
|
145
162
|
if (writesSomewhere && outsideRepo) {
|
|
146
163
|
deny(
|
|
147
164
|
"Scratch files belong inside the repository, where the next step and the next agent can still find them.",
|
|
148
|
-
"Write under `$REPO_ROOT/.opencode/.tmp/`.",
|
|
165
|
+
"Write under `$REPO_ROOT/.opencode/.tmp/`, or the workflow runtime's own `/tmp/gh-aw/`.",
|
|
149
166
|
)
|
|
150
167
|
}
|
|
151
168
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plainconceptsplatform/agent-harness",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.1",
|
|
4
4
|
"description": "Installs the Plain Concepts Platform Harness into any codebase, and keeps it up to date. Wires OpenCode, OpenSpec, codegraph, and agentmemory into a multi-agent workflow that runs on native parallel subagents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"opencode",
|