@plainconceptsplatform/agent-harness 3.9.0 → 3.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +551 -551
- package/cli/commands/join.js +259 -259
- package/cli/commands/migrate.js +310 -310
- package/cli/commands/shared.js +27 -27
- package/cli/commands/single.js +79 -79
- package/cli/commands/update.js +121 -121
- package/cli/commands/wizard.js +134 -134
- package/cli/fragments/archive/az.md +97 -97
- package/cli/fragments/archive/gh.md +96 -96
- package/cli/fragments/archive/gl.md +96 -96
- package/cli/fragments/archive/none.md +75 -75
- package/cli/fragments/guardrails/codegraph.md +5 -5
- package/cli/fragments/guardrails/humanizer.md +4 -4
- package/cli/fragments/guardrails/memory.md +4 -4
- package/cli/fragments/guardrails/rtk.md +3 -3
- package/cli/fragments/guardrails/simple-english.md +4 -4
- package/cli/fragments/ops-backlog/az.md +28 -28
- package/cli/fragments/ops-backlog/gh.md +28 -28
- package/cli/fragments/ops-backlog/jira.md +28 -28
- package/cli/fragments/ops-review/az.md +62 -62
- package/cli/fragments/ops-review/gh.md +51 -51
- package/cli/fragments/ops-review/gl.md +55 -55
- package/cli/fragments/ops-ship/az.md +81 -81
- package/cli/fragments/ops-ship/gh.md +67 -67
- package/cli/fragments/ops-ship/gl.md +84 -84
- package/cli/index.js +116 -116
- package/cli/presets/agents-content.json +34 -34
- package/cli/presets/browser.json +10 -10
- package/cli/presets/clean.json +21 -21
- package/cli/presets/models.json +68 -68
- package/cli/presets/optimization.json +32 -32
- package/cli/presets/platforms.json +76 -76
- package/cli/presets/source.json +23 -23
- package/cli/steps/browser/index.js +52 -48
- package/cli/steps/clean/index.js +120 -120
- package/cli/steps/copy/agents.js +176 -176
- package/cli/steps/copy/commands.js +79 -79
- package/cli/steps/copy/fullstack-engineer.js +81 -81
- package/cli/steps/copy/index.js +88 -88
- package/cli/steps/copy/opencode-json.js +359 -324
- package/cli/steps/copy/skills.js +316 -316
- package/cli/steps/metadata/index.js +115 -115
- package/cli/steps/models/format.js +88 -88
- package/cli/steps/models/index.js +64 -64
- package/cli/steps/models/write.js +38 -38
- package/cli/steps/openspec/index.js +136 -136
- package/cli/steps/optimization/codegraph.js +141 -141
- package/cli/steps/optimization/detect.js +66 -66
- package/cli/steps/optimization/humanizer.js +17 -17
- package/cli/steps/optimization/index.js +158 -158
- package/cli/steps/optimization/memory.js +91 -91
- package/cli/steps/optimization/patch-guardrails.js +111 -111
- package/cli/steps/optimization/simple-english.js +17 -17
- package/cli/steps/optimization/skills-lock.js +30 -30
- package/cli/steps/platform/index.js +109 -109
- package/cli/steps/source/index.js +123 -123
- package/cli/utils/agent-color.js +111 -111
- package/cli/utils/copy.js +134 -134
- package/cli/utils/exec-spinner.js +47 -47
- package/cli/utils/exec.js +134 -134
- package/cli/utils/legacy-check.js +30 -30
- package/cli/utils/models-cache.js +58 -58
- package/cli/utils/models-pricing.js +42 -42
- package/cli/utils/paths.js +82 -82
- package/cli/utils/process.js +3 -3
- package/cli/utils/terminal.js +6 -6
- package/cli/utils/update-manifest.js +75 -75
- package/harness/.opencode/_gitignore +12 -12
- package/harness/.opencode/commands/init.md +5 -5
- package/harness/.opencode/commands/make-architecture.md +5 -5
- package/harness/.opencode/commands/make-design.md +5 -5
- package/harness/.opencode/commands/make-engineer.md +5 -5
- package/harness/.opencode/commands/make-guardrails.md +5 -5
- package/harness/.opencode/commands/make-user-model.md +5 -5
- package/harness/.opencode/commands/ops-backlog.md +10 -10
- package/harness/.opencode/commands/ops-review.md +10 -10
- package/harness/.opencode/commands/ops-ship.md +9 -9
- package/harness/.opencode/commands/plan-apply.md +9 -9
- package/harness/.opencode/commands/plan-archive.md +7 -7
- package/harness/.opencode/commands/plan-explore.md +11 -11
- package/harness/.opencode/commands/plan-goal.md +5 -5
- package/harness/.opencode/commands/plan-propose.md +11 -11
- package/harness/.opencode/commands/plan-quick.md +7 -7
- package/harness/.opencode/commands/plan-story.md +11 -11
- package/harness/.opencode/commands/repo-audit.md +7 -7
- package/harness/.opencode/commands/repo-help.md +5 -5
- package/harness/.opencode/commands/repo-initialize.md +5 -5
- package/harness/.opencode/commands/repo-onboard.md +5 -5
- package/harness/.opencode/commands/repo-verify.md +5 -5
- package/harness/.opencode/plugins/pc-commit-coauthor.js +41 -41
- package/harness/.opencode/plugins/pc-subagent-monitor.js +184 -184
- package/harness/.opencode/plugins/pc-system-reminders.js +424 -424
- package/harness/.opencode/scripts/check-diff.mjs +305 -305
- package/harness/.opencode/scripts/code-rules.mjs +288 -288
- package/harness/.opencode/scripts/platform-contract.mjs +366 -366
- package/harness/AGENTS.md +55 -55
- package/harness/ARCHITECTURE.md +13 -13
- package/harness/DESIGN.md +13 -13
- package/harness/opencode.jsonc +37 -36
- package/harness/openspec/config.yaml +20 -20
- package/harness/skills-lock.json +17 -17
- package/package.json +14 -12
- package/skills/README.md +18 -18
- package/skills/agent-harness-cli/SKILL.md +86 -86
- package/skills/browser-automation/SKILL.md +100 -72
- package/skills/pc-guardrails-generic/SKILL.md +53 -53
- package/skills/pc-guardrails-project/SKILL.md +8 -8
- package/skills/pc-make-architecture/SKILL.md +33 -33
- package/skills/pc-make-architecture/structure-template.md +64 -64
- package/skills/pc-make-design/SKILL.md +45 -45
- package/skills/pc-make-engineer/SKILL.md +59 -59
- package/skills/pc-make-engineer/signal-mapping.md +53 -53
- package/skills/pc-make-engineer/template.md +36 -36
- package/skills/pc-make-guardrails/SKILL.md +44 -44
- package/skills/pc-make-guardrails/category-reference.md +112 -112
- package/skills/pc-make-merge-risk-assess/SKILL.md +70 -70
- package/skills/pc-make-merge-risk-assess/category-reference.md +114 -114
- package/skills/pc-make-user-model/SKILL.md +56 -56
- package/skills/pc-ops-ship/SKILL.md +22 -22
- package/skills/pc-plan-apply/SKILL.md +90 -90
- package/skills/pc-plan-apply/simple-mode.md +21 -21
- package/skills/pc-plan-archive/SKILL.md +66 -66
- package/skills/pc-plan-explore/SKILL.md +21 -21
- package/skills/pc-plan-goal/SKILL.md +91 -91
- package/skills/pc-plan-goal/branching.md +39 -39
- package/skills/pc-plan-goal/failure-policy.md +30 -30
- package/skills/pc-plan-goal/output-mode.md +10 -10
- package/skills/pc-plan-goal/output.md +71 -71
- package/skills/pc-plan-propose/SKILL.md +127 -127
- package/skills/pc-plan-propose/task-annotation.md +39 -39
- package/skills/pc-plan-quick/SKILL.md +46 -46
- package/skills/pc-plan-story/SKILL.md +93 -93
- package/skills/pc-repo-audit/SKILL.md +44 -44
- package/skills/pc-repo-help/SKILL.md +87 -87
- package/skills/pc-repo-initialize/SKILL.md +119 -119
- package/skills/pc-repo-onboard/SKILL.md +32 -32
- package/skills/pc-repo-verify/SKILL.md +150 -150
- package/skills/pc-userstory-az/SKILL.md +71 -71
- package/skills/pc-userstory-browser/SKILL.md +73 -64
- package/skills/pc-userstory-gh/SKILL.md +63 -63
- package/skills/pc-userstory-jira/SKILL.md +74 -74
package/cli/utils/paths.js
CHANGED
|
@@ -1,82 +1,82 @@
|
|
|
1
|
-
import os from 'node:os'
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Every harness path that lands in a consumer repo, in one place.
|
|
6
|
-
*
|
|
7
|
-
* These filenames are a contract with every repo the harness has been
|
|
8
|
-
* installed into: the CLI writes them, and the opencode plugins shipped in
|
|
9
|
-
* harness/.opencode/plugins/ read them back at runtime. Changing a name
|
|
10
|
-
* here means changing it in that payload too, or the plugins go blind.
|
|
11
|
-
*
|
|
12
|
-
* They are deliberately named for the harness rather than for the CLI, so a
|
|
13
|
-
* future rename of the package does not become a rename of the on-disk state.
|
|
14
|
-
*/
|
|
15
|
-
export const OPENCODE_DIR = '.opencode'
|
|
16
|
-
|
|
17
|
-
/** Project config written by the metadata step. */
|
|
18
|
-
export const CONFIG_FILE = 'harness.json'
|
|
19
|
-
|
|
20
|
-
/** Per-developer model override, gitignored, never committed. */
|
|
21
|
-
export const USER_CONFIG_FILE = 'harness.user.json'
|
|
22
|
-
|
|
23
|
-
/** Hashes of every managed file, so `update` can detect local edits. */
|
|
24
|
-
export const MANIFEST_FILE = 'harness-managed.json'
|
|
25
|
-
|
|
26
|
-
/** Live subagent wave state, owned by the pc-subagent-monitor plugin. */
|
|
27
|
-
export const RUN_STATE_FILE = 'harness-run.json'
|
|
28
|
-
|
|
29
|
-
/** Names `.opencode/.gitignore` must cover. Mirrored in content/.opencode/_gitignore. */
|
|
30
|
-
export const IGNORED_ENTRIES = [
|
|
31
|
-
'node_modules',
|
|
32
|
-
RUN_STATE_FILE,
|
|
33
|
-
USER_CONFIG_FILE,
|
|
34
|
-
MANIFEST_FILE,
|
|
35
|
-
'source-roots.json',
|
|
36
|
-
'*-engineer.*.md',
|
|
37
|
-
// Regenerated from fullstack-engineer.md by pc-subagent-tiers every startup.
|
|
38
|
-
'agents/build.md',
|
|
39
|
-
'agents/plan.md',
|
|
40
|
-
'agents/planner.md',
|
|
41
|
-
]
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Files the harness shipped and has since retired. `update` deletes them, because a skill or
|
|
45
|
-
* command left behind keeps being offered to agents long after the procedure it describes is
|
|
46
|
-
* gone. pc-ops-evidence wrote a capturePlan for a CI workflow that no longer exists; the
|
|
47
|
-
* verification plan from pc-repo-verify is what the evidence workflow replays now.
|
|
48
|
-
*/
|
|
49
|
-
export const RETIRED_PATHS = [
|
|
50
|
-
'.agents/skills/pc-ops-evidence',
|
|
51
|
-
'.agents/skills/pc-make-evidence-scaffold',
|
|
52
|
-
'.opencode/commands/ops-evidence.md',
|
|
53
|
-
'.opencode/commands/make-evidence-scaffold.md',
|
|
54
|
-
'.opencode/scripts/platform-manifest.mjs',
|
|
55
|
-
]
|
|
56
|
-
|
|
57
|
-
export function configPath(cwd = process.cwd()) {
|
|
58
|
-
return path.join(cwd, OPENCODE_DIR, CONFIG_FILE)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function userConfigPath(cwd = process.cwd()) {
|
|
62
|
-
return path.join(cwd, OPENCODE_DIR, USER_CONFIG_FILE)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function manifestPath(cwd = process.cwd()) {
|
|
66
|
-
return path.join(cwd, OPENCODE_DIR, MANIFEST_FILE)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/** Cross-run models cache, keyed to the CLI rather than to any one repo. */
|
|
70
|
-
export function modelsCacheDir() {
|
|
71
|
-
return path.join(os.homedir(), '.config', 'agent-harness')
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Filenames written by opencode-onboard v1.x. Only used to detect a v1 repo
|
|
76
|
-
* and refuse to half-patch it: nothing reads their contents.
|
|
77
|
-
*/
|
|
78
|
-
export const LEGACY_CONFIG_FILES = [
|
|
79
|
-
'opencode-onboard.json',
|
|
80
|
-
'opencode-onboard.user.json',
|
|
81
|
-
'opencode-onboard-managed.json',
|
|
82
|
-
]
|
|
1
|
+
import os from 'node:os'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Every harness path that lands in a consumer repo, in one place.
|
|
6
|
+
*
|
|
7
|
+
* These filenames are a contract with every repo the harness has been
|
|
8
|
+
* installed into: the CLI writes them, and the opencode plugins shipped in
|
|
9
|
+
* harness/.opencode/plugins/ read them back at runtime. Changing a name
|
|
10
|
+
* here means changing it in that payload too, or the plugins go blind.
|
|
11
|
+
*
|
|
12
|
+
* They are deliberately named for the harness rather than for the CLI, so a
|
|
13
|
+
* future rename of the package does not become a rename of the on-disk state.
|
|
14
|
+
*/
|
|
15
|
+
export const OPENCODE_DIR = '.opencode'
|
|
16
|
+
|
|
17
|
+
/** Project config written by the metadata step. */
|
|
18
|
+
export const CONFIG_FILE = 'harness.json'
|
|
19
|
+
|
|
20
|
+
/** Per-developer model override, gitignored, never committed. */
|
|
21
|
+
export const USER_CONFIG_FILE = 'harness.user.json'
|
|
22
|
+
|
|
23
|
+
/** Hashes of every managed file, so `update` can detect local edits. */
|
|
24
|
+
export const MANIFEST_FILE = 'harness-managed.json'
|
|
25
|
+
|
|
26
|
+
/** Live subagent wave state, owned by the pc-subagent-monitor plugin. */
|
|
27
|
+
export const RUN_STATE_FILE = 'harness-run.json'
|
|
28
|
+
|
|
29
|
+
/** Names `.opencode/.gitignore` must cover. Mirrored in content/.opencode/_gitignore. */
|
|
30
|
+
export const IGNORED_ENTRIES = [
|
|
31
|
+
'node_modules',
|
|
32
|
+
RUN_STATE_FILE,
|
|
33
|
+
USER_CONFIG_FILE,
|
|
34
|
+
MANIFEST_FILE,
|
|
35
|
+
'source-roots.json',
|
|
36
|
+
'*-engineer.*.md',
|
|
37
|
+
// Regenerated from fullstack-engineer.md by pc-subagent-tiers every startup.
|
|
38
|
+
'agents/build.md',
|
|
39
|
+
'agents/plan.md',
|
|
40
|
+
'agents/planner.md',
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Files the harness shipped and has since retired. `update` deletes them, because a skill or
|
|
45
|
+
* command left behind keeps being offered to agents long after the procedure it describes is
|
|
46
|
+
* gone. pc-ops-evidence wrote a capturePlan for a CI workflow that no longer exists; the
|
|
47
|
+
* verification plan from pc-repo-verify is what the evidence workflow replays now.
|
|
48
|
+
*/
|
|
49
|
+
export const RETIRED_PATHS = [
|
|
50
|
+
'.agents/skills/pc-ops-evidence',
|
|
51
|
+
'.agents/skills/pc-make-evidence-scaffold',
|
|
52
|
+
'.opencode/commands/ops-evidence.md',
|
|
53
|
+
'.opencode/commands/make-evidence-scaffold.md',
|
|
54
|
+
'.opencode/scripts/platform-manifest.mjs',
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
export function configPath(cwd = process.cwd()) {
|
|
58
|
+
return path.join(cwd, OPENCODE_DIR, CONFIG_FILE)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function userConfigPath(cwd = process.cwd()) {
|
|
62
|
+
return path.join(cwd, OPENCODE_DIR, USER_CONFIG_FILE)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function manifestPath(cwd = process.cwd()) {
|
|
66
|
+
return path.join(cwd, OPENCODE_DIR, MANIFEST_FILE)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Cross-run models cache, keyed to the CLI rather than to any one repo. */
|
|
70
|
+
export function modelsCacheDir() {
|
|
71
|
+
return path.join(os.homedir(), '.config', 'agent-harness')
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Filenames written by opencode-onboard v1.x. Only used to detect a v1 repo
|
|
76
|
+
* and refuse to half-patch it: nothing reads their contents.
|
|
77
|
+
*/
|
|
78
|
+
export const LEGACY_CONFIG_FILES = [
|
|
79
|
+
'opencode-onboard.json',
|
|
80
|
+
'opencode-onboard.user.json',
|
|
81
|
+
'opencode-onboard-managed.json',
|
|
82
|
+
]
|
package/cli/utils/process.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export function exit(code = 0) {
|
|
2
|
-
process.exit(code)
|
|
3
|
-
}
|
|
1
|
+
export function exit(code = 0) {
|
|
2
|
+
process.exit(code)
|
|
3
|
+
}
|
package/cli/utils/terminal.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export const MARKERS = {
|
|
2
|
-
EMPTY: " ",
|
|
3
|
-
OK_PREFIX: "✓ ",
|
|
4
|
-
WARN_PREFIX: "⚠ ",
|
|
5
|
-
ERROR_PREFIX: "✗ ",
|
|
6
|
-
};
|
|
1
|
+
export const MARKERS = {
|
|
2
|
+
EMPTY: " ",
|
|
3
|
+
OK_PREFIX: "✓ ",
|
|
4
|
+
WARN_PREFIX: "⚠ ",
|
|
5
|
+
ERROR_PREFIX: "✗ ",
|
|
6
|
+
};
|
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
import crypto from 'node:crypto'
|
|
2
|
-
import fse from 'fs-extra'
|
|
3
|
-
import path from 'node:path'
|
|
4
|
-
import { MANIFEST_FILE, OPENCODE_DIR } from './paths.js'
|
|
5
|
-
|
|
6
|
-
const MANIFEST_RELATIVE_PATH = path.join(OPENCODE_DIR, MANIFEST_FILE)
|
|
7
|
-
|
|
8
|
-
function normalizeRelativePath(relativePath) {
|
|
9
|
-
return relativePath.split(path.sep).join('/')
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function hashContent(content) {
|
|
13
|
-
return crypto.createHash('sha256').update(content).digest('hex')
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export async function hashFile(filePath) {
|
|
17
|
-
return hashContent(await fse.readFile(filePath))
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// A file counts as untouched when it differs from what we shipped only in ways
|
|
21
|
-
// the harness itself caused. Two of those, and both made the raw-bytes
|
|
22
|
-
// comparison call an untouched file modified — permanently, because the flag is
|
|
23
|
-
// re-derived on every update:
|
|
24
|
-
//
|
|
25
|
-
// 1. Marker pairs. The patchers rewrite them after the copy, so a file with
|
|
26
|
-
// any PC-* marker never matches its own source again.
|
|
27
|
-
// 2. Line endings. A file that reaches a consumer's tree through git arrives
|
|
28
|
-
// CRLF on Windows while the shipped source is LF.
|
|
29
|
-
//
|
|
30
|
-
// This is the general form of the bug that left five repos on a stale
|
|
31
|
-
// browser-automation skill through repeated updates.
|
|
32
|
-
const MARKER_PAIR = /(<!-- PC-[A-Z0-9-]+-START -->)[\s\S]*?(<!-- PC-[A-Z0-9-]+-END -->)/g
|
|
33
|
-
|
|
34
|
-
function comparableContent(buffer) {
|
|
35
|
-
return buffer.toString('utf-8').replace(/\r\n/g, '\n').replace(MARKER_PAIR, '$1$2')
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export async function hashComparableFile(filePath) {
|
|
39
|
-
return hashContent(comparableContent(await fse.readFile(filePath)))
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export async function readUpdateManifest(cwd = process.cwd()) {
|
|
43
|
-
const manifestPath = path.join(cwd, MANIFEST_RELATIVE_PATH)
|
|
44
|
-
const manifest = await fse.readJson(manifestPath).catch(() => ({ version: 1, files: {} }))
|
|
45
|
-
if (!manifest.files || typeof manifest.files !== 'object') manifest.files = {}
|
|
46
|
-
return manifest
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export async function writeUpdateManifest(manifest, cwd = process.cwd()) {
|
|
50
|
-
const manifestPath = path.join(cwd, MANIFEST_RELATIVE_PATH)
|
|
51
|
-
await fse.ensureDir(path.dirname(manifestPath))
|
|
52
|
-
await fse.writeJson(manifestPath, manifest, { spaces: 2 })
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export async function canUpdateManagedFile(relativePath, cwd, manifest) {
|
|
56
|
-
const normalizedPath = normalizeRelativePath(relativePath)
|
|
57
|
-
const destinationPath = path.join(cwd, relativePath)
|
|
58
|
-
if (!await fse.pathExists(destinationPath)) return true
|
|
59
|
-
const previousHash = manifest.files?.[normalizedPath]
|
|
60
|
-
if (!previousHash) return false
|
|
61
|
-
// Raw is accepted too: manifests written before this comparison existed hold
|
|
62
|
-
// raw source hashes, and re-recording them all would need an update to run
|
|
63
|
-
// first, which is the thing being unblocked.
|
|
64
|
-
return previousHash === await hashComparableFile(destinationPath)
|
|
65
|
-
|| previousHash === await hashFile(destinationPath)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export async function recordManagedFile(manifest, relativePath, sourcePath) {
|
|
69
|
-
const files = manifest.files
|
|
70
|
-
files[normalizeRelativePath(relativePath)] = await hashComparableFile(sourcePath)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function manifestPath() {
|
|
74
|
-
return MANIFEST_RELATIVE_PATH
|
|
75
|
-
}
|
|
1
|
+
import crypto from 'node:crypto'
|
|
2
|
+
import fse from 'fs-extra'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { MANIFEST_FILE, OPENCODE_DIR } from './paths.js'
|
|
5
|
+
|
|
6
|
+
const MANIFEST_RELATIVE_PATH = path.join(OPENCODE_DIR, MANIFEST_FILE)
|
|
7
|
+
|
|
8
|
+
function normalizeRelativePath(relativePath) {
|
|
9
|
+
return relativePath.split(path.sep).join('/')
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function hashContent(content) {
|
|
13
|
+
return crypto.createHash('sha256').update(content).digest('hex')
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function hashFile(filePath) {
|
|
17
|
+
return hashContent(await fse.readFile(filePath))
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// A file counts as untouched when it differs from what we shipped only in ways
|
|
21
|
+
// the harness itself caused. Two of those, and both made the raw-bytes
|
|
22
|
+
// comparison call an untouched file modified — permanently, because the flag is
|
|
23
|
+
// re-derived on every update:
|
|
24
|
+
//
|
|
25
|
+
// 1. Marker pairs. The patchers rewrite them after the copy, so a file with
|
|
26
|
+
// any PC-* marker never matches its own source again.
|
|
27
|
+
// 2. Line endings. A file that reaches a consumer's tree through git arrives
|
|
28
|
+
// CRLF on Windows while the shipped source is LF.
|
|
29
|
+
//
|
|
30
|
+
// This is the general form of the bug that left five repos on a stale
|
|
31
|
+
// browser-automation skill through repeated updates.
|
|
32
|
+
const MARKER_PAIR = /(<!-- PC-[A-Z0-9-]+-START -->)[\s\S]*?(<!-- PC-[A-Z0-9-]+-END -->)/g
|
|
33
|
+
|
|
34
|
+
function comparableContent(buffer) {
|
|
35
|
+
return buffer.toString('utf-8').replace(/\r\n/g, '\n').replace(MARKER_PAIR, '$1$2')
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export async function hashComparableFile(filePath) {
|
|
39
|
+
return hashContent(comparableContent(await fse.readFile(filePath)))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function readUpdateManifest(cwd = process.cwd()) {
|
|
43
|
+
const manifestPath = path.join(cwd, MANIFEST_RELATIVE_PATH)
|
|
44
|
+
const manifest = await fse.readJson(manifestPath).catch(() => ({ version: 1, files: {} }))
|
|
45
|
+
if (!manifest.files || typeof manifest.files !== 'object') manifest.files = {}
|
|
46
|
+
return manifest
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function writeUpdateManifest(manifest, cwd = process.cwd()) {
|
|
50
|
+
const manifestPath = path.join(cwd, MANIFEST_RELATIVE_PATH)
|
|
51
|
+
await fse.ensureDir(path.dirname(manifestPath))
|
|
52
|
+
await fse.writeJson(manifestPath, manifest, { spaces: 2 })
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function canUpdateManagedFile(relativePath, cwd, manifest) {
|
|
56
|
+
const normalizedPath = normalizeRelativePath(relativePath)
|
|
57
|
+
const destinationPath = path.join(cwd, relativePath)
|
|
58
|
+
if (!await fse.pathExists(destinationPath)) return true
|
|
59
|
+
const previousHash = manifest.files?.[normalizedPath]
|
|
60
|
+
if (!previousHash) return false
|
|
61
|
+
// Raw is accepted too: manifests written before this comparison existed hold
|
|
62
|
+
// raw source hashes, and re-recording them all would need an update to run
|
|
63
|
+
// first, which is the thing being unblocked.
|
|
64
|
+
return previousHash === await hashComparableFile(destinationPath)
|
|
65
|
+
|| previousHash === await hashFile(destinationPath)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function recordManagedFile(manifest, relativePath, sourcePath) {
|
|
69
|
+
const files = manifest.files
|
|
70
|
+
files[normalizeRelativePath(relativePath)] = await hashComparableFile(sourcePath)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function manifestPath() {
|
|
74
|
+
return MANIFEST_RELATIVE_PATH
|
|
75
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
node_modules
|
|
2
|
-
harness-run.json
|
|
3
|
-
harness.user.json
|
|
4
|
-
harness-managed.json
|
|
5
|
-
harness-models.json
|
|
6
|
-
source-roots.json
|
|
7
|
-
tmp/
|
|
8
|
-
*-engineer.*.md
|
|
9
|
-
agents/build.md
|
|
10
|
-
agents/plan.md
|
|
11
|
-
agents/planner.md
|
|
12
|
-
agents/planner-sub.md
|
|
1
|
+
node_modules
|
|
2
|
+
harness-run.json
|
|
3
|
+
harness.user.json
|
|
4
|
+
harness-managed.json
|
|
5
|
+
harness-models.json
|
|
6
|
+
source-roots.json
|
|
7
|
+
tmp/
|
|
8
|
+
*-engineer.*.md
|
|
9
|
+
agents/build.md
|
|
10
|
+
agents/plan.md
|
|
11
|
+
agents/planner.md
|
|
12
|
+
agents/planner-sub.md
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Initialize the project. Presents a single form with all setup questions, then executes selected steps.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-repo-initialize` skill.
|
|
1
|
+
---
|
|
2
|
+
description: Initialize the project. Presents a single form with all setup questions, then executes selected steps.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-repo-initialize` skill.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Generate or update ARCHITECTURE.md by analyzing the codebase structure. Safe to run at any time.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-make-architecture` skill.
|
|
1
|
+
---
|
|
2
|
+
description: Generate or update ARCHITECTURE.md by analyzing the codebase structure. Safe to run at any time.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-make-architecture` skill.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Generate or update DESIGN.md by analyzing the codebase design system. Safe to run at any time.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-make-design` skill.
|
|
1
|
+
---
|
|
2
|
+
description: Generate or update DESIGN.md by analyzing the codebase design system. Safe to run at any time.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-make-design` skill.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Create a custom engineer agent via persona-driven interactive design
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-make-engineer` skill.
|
|
1
|
+
---
|
|
2
|
+
description: Create a custom engineer agent via persona-driven interactive design
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-make-engineer` skill.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Generate or update a pc-guardrails-project skill from ARCHITECTURE.md and relevant project files.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-make-guardrails` skill.
|
|
1
|
+
---
|
|
2
|
+
description: Generate or update a pc-guardrails-project skill from ARCHITECTURE.md and relevant project files.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-make-guardrails` skill.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Set the model for a tier (plan, build, or fast). Team-wide or user-local override.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-make-user-model` skill.
|
|
1
|
+
---
|
|
2
|
+
description: Set the model for a tier (plan, build, or fast). Team-wide or user-local override.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-make-user-model` skill.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Create an issue in the backlog platform (GitHub, Azure DevOps, Jira) from a description.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Backlog platform is set in `.opencode/harness.json` → `platform.backlog`. The platform-specific content below is injected by the CLI during onboarding.
|
|
6
|
-
|
|
7
|
-
Input: `$ARGUMENTS` (the issue title/description)
|
|
8
|
-
|
|
9
|
-
<!-- PC-PLATFORM-BACKLOG-START -->
|
|
10
|
-
<!-- PC-PLATFORM-BACKLOG-END -->
|
|
1
|
+
---
|
|
2
|
+
description: Create an issue in the backlog platform (GitHub, Azure DevOps, Jira) from a description.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Backlog platform is set in `.opencode/harness.json` → `platform.backlog`. The platform-specific content below is injected by the CLI during onboarding.
|
|
6
|
+
|
|
7
|
+
Input: `$ARGUMENTS` (the issue title/description)
|
|
8
|
+
|
|
9
|
+
<!-- PC-PLATFORM-BACKLOG-START -->
|
|
10
|
+
<!-- PC-PLATFORM-BACKLOG-END -->
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Read and triage PR review feedback. Reports what needs fixing, does not implement fixes.
|
|
3
|
-
agent: planner
|
|
4
|
-
subagent: false
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
Repo platform is set in `.opencode/harness.json` → `platform.repo`. The platform-specific content below is injected by the CLI during onboarding.
|
|
8
|
-
|
|
9
|
-
<!-- PC-PLATFORM-REVIEW-START -->
|
|
10
|
-
<!-- PC-PLATFORM-REVIEW-END -->
|
|
1
|
+
---
|
|
2
|
+
description: Read and triage PR review feedback. Reports what needs fixing, does not implement fixes.
|
|
3
|
+
agent: planner
|
|
4
|
+
subagent: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Repo platform is set in `.opencode/harness.json` → `platform.repo`. The platform-specific content below is injected by the CLI during onboarding.
|
|
8
|
+
|
|
9
|
+
<!-- PC-PLATFORM-REVIEW-START -->
|
|
10
|
+
<!-- PC-PLATFORM-REVIEW-END -->
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Create a pull request for the current feature branch with screenshots if UI changed.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-ops-ship` skill and execute it.
|
|
6
|
-
|
|
7
|
-
Input:
|
|
8
|
-
|
|
9
|
-
$ARGUMENTS
|
|
1
|
+
---
|
|
2
|
+
description: Create a pull request for the current feature branch with screenshots if UI changed.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-ops-ship` skill and execute it.
|
|
6
|
+
|
|
7
|
+
Input:
|
|
8
|
+
|
|
9
|
+
$ARGUMENTS
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Implement tasks from a plan: works with OpenSpec proposals and in-conversation plans."
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-plan-apply` skill and execute it in **interactive mode** with `start_from: branch`.
|
|
6
|
-
|
|
7
|
-
Input:
|
|
8
|
-
|
|
9
|
-
$ARGUMENTS
|
|
1
|
+
---
|
|
2
|
+
description: "Implement tasks from a plan: works with OpenSpec proposals and in-conversation plans."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-plan-apply` skill and execute it in **interactive mode** with `start_from: branch`.
|
|
6
|
+
|
|
7
|
+
Input:
|
|
8
|
+
|
|
9
|
+
$ARGUMENTS
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Archive the oldest merged unarchived OpenSpec change and update documentation.
|
|
3
|
-
agent: planner
|
|
4
|
-
subagent: false
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
Load the `pc-plan-archive` skill and execute it in **interactive mode**. No input required.
|
|
1
|
+
---
|
|
2
|
+
description: Archive the oldest merged unarchived OpenSpec change and update documentation.
|
|
3
|
+
agent: planner
|
|
4
|
+
subagent: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Load the `pc-plan-archive` skill and execute it in **interactive mode**. No input required.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Think through an idea, investigate a problem, or clarify requirements before creating a change.
|
|
3
|
-
agent: planner
|
|
4
|
-
subagent: false
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
Load the `pc-plan-explore` skill and execute it in **interactive mode**.
|
|
8
|
-
|
|
9
|
-
Input:
|
|
10
|
-
|
|
11
|
-
$ARGUMENTS
|
|
1
|
+
---
|
|
2
|
+
description: Think through an idea, investigate a problem, or clarify requirements before creating a change.
|
|
3
|
+
agent: planner
|
|
4
|
+
subagent: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Load the `pc-plan-explore` skill and execute it in **interactive mode**.
|
|
8
|
+
|
|
9
|
+
Input:
|
|
10
|
+
|
|
11
|
+
$ARGUMENTS
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Autonomous pipeline: explore, propose, apply, archive, then merge/PR/push. For loop-engineering."
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-plan-goal` skill.
|
|
1
|
+
---
|
|
2
|
+
description: "Autonomous pipeline: explore, propose, apply, archive, then merge/PR/push. For loop-engineering."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-plan-goal` skill.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Parse a work item or idea and propose a change plan with enriched task assignments.
|
|
3
|
-
agent: planner
|
|
4
|
-
subagent: false
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
Load the `pc-plan-propose` skill and execute it in **interactive mode**.
|
|
8
|
-
|
|
9
|
-
Input:
|
|
10
|
-
|
|
11
|
-
$ARGUMENTS
|
|
1
|
+
---
|
|
2
|
+
description: Parse a work item or idea and propose a change plan with enriched task assignments.
|
|
3
|
+
agent: planner
|
|
4
|
+
subagent: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Load the `pc-plan-propose` skill and execute it in **interactive mode**.
|
|
8
|
+
|
|
9
|
+
Input:
|
|
10
|
+
|
|
11
|
+
$ARGUMENTS
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Quick plan: analyze the codebase and create a task checklist using the Todo pane. No files, no OpenSpec."
|
|
3
|
-
agent: planner
|
|
4
|
-
subagent: false
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
Load the `pc-plan-quick` skill.
|
|
1
|
+
---
|
|
2
|
+
description: "Quick plan: analyze the codebase and create a task checklist using the Todo pane. No files, no OpenSpec."
|
|
3
|
+
agent: planner
|
|
4
|
+
subagent: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Load the `pc-plan-quick` skill.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Write a detailed, repo-aware user story from a feature idea or need.
|
|
3
|
-
agent: planner
|
|
4
|
-
subagent: false
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
Load the `pc-plan-story` skill.
|
|
8
|
-
|
|
9
|
-
Input:
|
|
10
|
-
|
|
11
|
-
$ARGUMENTS
|
|
1
|
+
---
|
|
2
|
+
description: Write a detailed, repo-aware user story from a feature idea or need.
|
|
3
|
+
agent: planner
|
|
4
|
+
subagent: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Load the `pc-plan-story` skill.
|
|
8
|
+
|
|
9
|
+
Input:
|
|
10
|
+
|
|
11
|
+
$ARGUMENTS
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Audit every configured source root against the fullstack engineer's guardrails and abilities. Read-only.
|
|
3
|
-
agent: planner
|
|
4
|
-
subagent: false
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
Load the `pc-repo-audit` skill.
|
|
1
|
+
---
|
|
2
|
+
description: Audit every configured source root against the fullstack engineer's guardrails and abilities. Read-only.
|
|
3
|
+
agent: planner
|
|
4
|
+
subagent: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Load the `pc-repo-audit` skill.
|