@plainconceptsplatform/agent-harness 3.5.0 → 3.7.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 +471 -454
- 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 +48 -48
- package/cli/steps/clean/index.js +120 -120
- package/cli/steps/copy/agents.js +120 -120
- package/cli/steps/copy/commands.js +79 -79
- package/cli/steps/copy/fullstack-engineer.js +89 -89
- package/cli/steps/copy/index.js +88 -88
- package/cli/steps/copy/opencode-json.js +324 -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 +81 -81
- 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 +10 -10
- 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/package.json +5 -5
- package/harness/.opencode/plugins/pc-commit-coauthor.js +41 -0
- package/harness/.opencode/plugins/pc-subagent-monitor.js +184 -184
- package/harness/.opencode/plugins/pc-subagent-tiers.js +367 -367
- package/harness/.opencode/plugins/pc-system-reminders.js +404 -386
- package/harness/.opencode/scripts/check-diff.mjs +279 -252
- package/harness/.opencode/scripts/code-rules.mjs +288 -288
- package/harness/.opencode/scripts/platform-manifest.mjs +112 -0
- package/harness/AGENTS.md +49 -49
- package/harness/ARCHITECTURE.md +13 -13
- package/harness/DESIGN.md +13 -13
- package/harness/opencode.jsonc +36 -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 +72 -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 -32
- 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 +88 -88
- 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 +125 -125
- 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 +64 -64
- package/skills/pc-userstory-gh/SKILL.md +63 -63
- package/skills/pc-userstory-jira/SKILL.md +74 -74
package/cli/commands/shared.js
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import { execa } from 'execa'
|
|
2
|
-
import fse from 'fs-extra'
|
|
3
|
-
import { configPath } from '../utils/paths.js'
|
|
4
|
-
|
|
5
|
-
export async function readHarnessConfig() {
|
|
6
|
-
const cfgPath = configPath()
|
|
7
|
-
if (!await fse.pathExists(cfgPath)) return null
|
|
8
|
-
try {
|
|
9
|
-
return await fse.readJson(cfgPath)
|
|
10
|
-
} catch {
|
|
11
|
-
return null
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export async function ensureGitLongpaths(cwd = process.cwd()) {
|
|
16
|
-
// core.longpaths only matters on Windows; don't touch repo config elsewhere.
|
|
17
|
-
if (process.platform !== 'win32') return false
|
|
18
|
-
try {
|
|
19
|
-
const repoCheck = await execa('git', ['rev-parse', '--is-inside-work-tree'], { cwd, reject: false })
|
|
20
|
-
if (repoCheck.exitCode !== 0 || repoCheck.stdout.trim() !== 'true') return false
|
|
21
|
-
|
|
22
|
-
const configResult = await execa('git', ['config', 'core.longpaths', 'true'], { cwd, reject: false })
|
|
23
|
-
return configResult.exitCode === 0
|
|
24
|
-
} catch {
|
|
25
|
-
return false
|
|
26
|
-
}
|
|
27
|
-
}
|
|
1
|
+
import { execa } from 'execa'
|
|
2
|
+
import fse from 'fs-extra'
|
|
3
|
+
import { configPath } from '../utils/paths.js'
|
|
4
|
+
|
|
5
|
+
export async function readHarnessConfig() {
|
|
6
|
+
const cfgPath = configPath()
|
|
7
|
+
if (!await fse.pathExists(cfgPath)) return null
|
|
8
|
+
try {
|
|
9
|
+
return await fse.readJson(cfgPath)
|
|
10
|
+
} catch {
|
|
11
|
+
return null
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function ensureGitLongpaths(cwd = process.cwd()) {
|
|
16
|
+
// core.longpaths only matters on Windows; don't touch repo config elsewhere.
|
|
17
|
+
if (process.platform !== 'win32') return false
|
|
18
|
+
try {
|
|
19
|
+
const repoCheck = await execa('git', ['rev-parse', '--is-inside-work-tree'], { cwd, reject: false })
|
|
20
|
+
if (repoCheck.exitCode !== 0 || repoCheck.stdout.trim() !== 'true') return false
|
|
21
|
+
|
|
22
|
+
const configResult = await execa('git', ['config', 'core.longpaths', 'true'], { cwd, reject: false })
|
|
23
|
+
return configResult.exitCode === 0
|
|
24
|
+
} catch {
|
|
25
|
+
return false
|
|
26
|
+
}
|
|
27
|
+
}
|
package/cli/commands/single.js
CHANGED
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
import fse from 'fs-extra'
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
import { fileURLToPath } from 'url'
|
|
4
|
-
import { cleanAiFiles } from '../steps/clean/index.js'
|
|
5
|
-
import { copyContentStep } from '../steps/copy/index.js'
|
|
6
|
-
import { chooseModels } from '../steps/models/index.js'
|
|
7
|
-
import { initOpenspec } from '../steps/openspec/index.js'
|
|
8
|
-
import { tokenOptimizationStep } from '../steps/optimization/index.js'
|
|
9
|
-
import { choosePlatform } from '../steps/platform/index.js'
|
|
10
|
-
import { installBrowser } from '../steps/browser/index.js'
|
|
11
|
-
import { writeHarnessConfig } from '../steps/metadata/index.js'
|
|
12
|
-
import { readHarnessConfig } from './shared.js'
|
|
13
|
-
|
|
14
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
15
|
-
const platformsPreset = await fse.readJson(path.resolve(__dirname, '../presets/platforms.json'))
|
|
16
|
-
// platforms.json is the single source of truth for valid platform values.
|
|
17
|
-
// Hardcoding a subset here silently rewrote jira/gitlab/browser projects to github.
|
|
18
|
-
const VALID_PLATFORMS = new Set(platformsPreset.map(p => p.value))
|
|
19
|
-
|
|
20
|
-
export function resolvePlatform(value, fallback = 'github') {
|
|
21
|
-
return VALID_PLATFORMS.has(value) ? value : fallback
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export async function runSingleCommand(command) {
|
|
25
|
-
const saved = await readHarnessConfig()
|
|
26
|
-
const ctx = {
|
|
27
|
-
hasDesign: !!saved?.preexisting?.design,
|
|
28
|
-
hasArchitecture: !!saved?.preexisting?.architecture,
|
|
29
|
-
hasOpenspec: !!saved?.preexisting?.openspec,
|
|
30
|
-
sourceMode: saved?.source?.mode ?? 'current',
|
|
31
|
-
sourceRoots: Array.isArray(saved?.source?.roots) ? saved.source.roots : [],
|
|
32
|
-
maxConcurrentAgents: saved?.agents?.maxConcurrent ?? 3,
|
|
33
|
-
}
|
|
34
|
-
const backlogPlatform = saved?.platform?.backlog
|
|
35
|
-
const repoPlatform = saved?.platform?.repo
|
|
36
|
-
const resolvedBacklog = resolvePlatform(backlogPlatform)
|
|
37
|
-
const resolvedRepo = resolvePlatform(repoPlatform)
|
|
38
|
-
|
|
39
|
-
const handlers = {
|
|
40
|
-
clean: async () => {
|
|
41
|
-
await cleanAiFiles()
|
|
42
|
-
},
|
|
43
|
-
platform: async () => {
|
|
44
|
-
await choosePlatform()
|
|
45
|
-
},
|
|
46
|
-
copy: async () => {
|
|
47
|
-
await copyContentStep({ backlogPlatform: resolvedBacklog, repoPlatform: resolvedRepo }, ctx)
|
|
48
|
-
},
|
|
49
|
-
openspec: async () => {
|
|
50
|
-
await initOpenspec()
|
|
51
|
-
},
|
|
52
|
-
models: async () => {
|
|
53
|
-
await chooseModels()
|
|
54
|
-
},
|
|
55
|
-
optimization: async () => {
|
|
56
|
-
await tokenOptimizationStep({ ctx })
|
|
57
|
-
},
|
|
58
|
-
browser: async () => {
|
|
59
|
-
await installBrowser()
|
|
60
|
-
},
|
|
61
|
-
metadata: async () => {
|
|
62
|
-
await writeHarnessConfig({
|
|
63
|
-
...ctx,
|
|
64
|
-
backlogPlatform: resolvedBacklog,
|
|
65
|
-
repoPlatform: resolvedRepo,
|
|
66
|
-
maxConcurrentAgents: saved?.agents?.maxConcurrent ?? 3,
|
|
67
|
-
planModel: saved?.models?.plan ?? null,
|
|
68
|
-
buildModel: saved?.models?.build ?? null,
|
|
69
|
-
fastModel: saved?.models?.fast ?? null,
|
|
70
|
-
optionalTools: saved?.tools ?? null,
|
|
71
|
-
})
|
|
72
|
-
},
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const handler = handlers[command]
|
|
76
|
-
if (!handler) return false
|
|
77
|
-
await handler()
|
|
78
|
-
return true
|
|
79
|
-
}
|
|
1
|
+
import fse from 'fs-extra'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'url'
|
|
4
|
+
import { cleanAiFiles } from '../steps/clean/index.js'
|
|
5
|
+
import { copyContentStep } from '../steps/copy/index.js'
|
|
6
|
+
import { chooseModels } from '../steps/models/index.js'
|
|
7
|
+
import { initOpenspec } from '../steps/openspec/index.js'
|
|
8
|
+
import { tokenOptimizationStep } from '../steps/optimization/index.js'
|
|
9
|
+
import { choosePlatform } from '../steps/platform/index.js'
|
|
10
|
+
import { installBrowser } from '../steps/browser/index.js'
|
|
11
|
+
import { writeHarnessConfig } from '../steps/metadata/index.js'
|
|
12
|
+
import { readHarnessConfig } from './shared.js'
|
|
13
|
+
|
|
14
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
15
|
+
const platformsPreset = await fse.readJson(path.resolve(__dirname, '../presets/platforms.json'))
|
|
16
|
+
// platforms.json is the single source of truth for valid platform values.
|
|
17
|
+
// Hardcoding a subset here silently rewrote jira/gitlab/browser projects to github.
|
|
18
|
+
const VALID_PLATFORMS = new Set(platformsPreset.map(p => p.value))
|
|
19
|
+
|
|
20
|
+
export function resolvePlatform(value, fallback = 'github') {
|
|
21
|
+
return VALID_PLATFORMS.has(value) ? value : fallback
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function runSingleCommand(command) {
|
|
25
|
+
const saved = await readHarnessConfig()
|
|
26
|
+
const ctx = {
|
|
27
|
+
hasDesign: !!saved?.preexisting?.design,
|
|
28
|
+
hasArchitecture: !!saved?.preexisting?.architecture,
|
|
29
|
+
hasOpenspec: !!saved?.preexisting?.openspec,
|
|
30
|
+
sourceMode: saved?.source?.mode ?? 'current',
|
|
31
|
+
sourceRoots: Array.isArray(saved?.source?.roots) ? saved.source.roots : [],
|
|
32
|
+
maxConcurrentAgents: saved?.agents?.maxConcurrent ?? 3,
|
|
33
|
+
}
|
|
34
|
+
const backlogPlatform = saved?.platform?.backlog
|
|
35
|
+
const repoPlatform = saved?.platform?.repo
|
|
36
|
+
const resolvedBacklog = resolvePlatform(backlogPlatform)
|
|
37
|
+
const resolvedRepo = resolvePlatform(repoPlatform)
|
|
38
|
+
|
|
39
|
+
const handlers = {
|
|
40
|
+
clean: async () => {
|
|
41
|
+
await cleanAiFiles()
|
|
42
|
+
},
|
|
43
|
+
platform: async () => {
|
|
44
|
+
await choosePlatform()
|
|
45
|
+
},
|
|
46
|
+
copy: async () => {
|
|
47
|
+
await copyContentStep({ backlogPlatform: resolvedBacklog, repoPlatform: resolvedRepo }, ctx)
|
|
48
|
+
},
|
|
49
|
+
openspec: async () => {
|
|
50
|
+
await initOpenspec()
|
|
51
|
+
},
|
|
52
|
+
models: async () => {
|
|
53
|
+
await chooseModels()
|
|
54
|
+
},
|
|
55
|
+
optimization: async () => {
|
|
56
|
+
await tokenOptimizationStep({ ctx })
|
|
57
|
+
},
|
|
58
|
+
browser: async () => {
|
|
59
|
+
await installBrowser()
|
|
60
|
+
},
|
|
61
|
+
metadata: async () => {
|
|
62
|
+
await writeHarnessConfig({
|
|
63
|
+
...ctx,
|
|
64
|
+
backlogPlatform: resolvedBacklog,
|
|
65
|
+
repoPlatform: resolvedRepo,
|
|
66
|
+
maxConcurrentAgents: saved?.agents?.maxConcurrent ?? 3,
|
|
67
|
+
planModel: saved?.models?.plan ?? null,
|
|
68
|
+
buildModel: saved?.models?.build ?? null,
|
|
69
|
+
fastModel: saved?.models?.fast ?? null,
|
|
70
|
+
optionalTools: saved?.tools ?? null,
|
|
71
|
+
})
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const handler = handlers[command]
|
|
76
|
+
if (!handler) return false
|
|
77
|
+
await handler()
|
|
78
|
+
return true
|
|
79
|
+
}
|
package/cli/commands/update.js
CHANGED
|
@@ -1,121 +1,121 @@
|
|
|
1
|
-
import chalk from 'chalk'
|
|
2
|
-
import { execa } from 'execa'
|
|
3
|
-
import fse from 'fs-extra'
|
|
4
|
-
import path from 'node:path'
|
|
5
|
-
import { fileURLToPath } from 'url'
|
|
6
|
-
import { readHarnessConfig } from './shared.js'
|
|
7
|
-
import { copyContentStep } from '../steps/copy/index.js'
|
|
8
|
-
import { writeModelsToConfigs } from '../steps/models/write.js'
|
|
9
|
-
import { patchGuardrails } from '../steps/optimization/patch-guardrails.js'
|
|
10
|
-
import { reconcileTools } from '../steps/optimization/detect.js'
|
|
11
|
-
import { writeHarnessConfig } from '../steps/metadata/index.js'
|
|
12
|
-
import { info } from '../utils/exec.js'
|
|
13
|
-
import { exit } from '../utils/process.js'
|
|
14
|
-
|
|
15
|
-
const SIMPLE_ENGLISH_ENTRY = {
|
|
16
|
-
source: 'AminBlg/SimpleEnglish',
|
|
17
|
-
sourceType: 'github',
|
|
18
|
-
skillPath: 'skills/simple-english/SKILL.md',
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
22
|
-
const platformsPreset = await fse.readJson(path.resolve(__dirname, '../presets/platforms.json'))
|
|
23
|
-
const VALID_PLATFORMS = new Set(platformsPreset.map(p => p.value))
|
|
24
|
-
|
|
25
|
-
function resolvePlatform(value, fallback = 'github') {
|
|
26
|
-
return VALID_PLATFORMS.has(value) ? value : fallback
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export async function runUpdate() {
|
|
30
|
-
const saved = await readHarnessConfig()
|
|
31
|
-
if (!saved?.platform) {
|
|
32
|
-
console.log(chalk.red('No agent-harness config found. Run the wizard first.'))
|
|
33
|
-
exit(1)
|
|
34
|
-
return
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const backlogPlatform = resolvePlatform(saved.platform.backlog)
|
|
38
|
-
const repoPlatform = resolvePlatform(saved.platform.repo)
|
|
39
|
-
|
|
40
|
-
const ctx = {
|
|
41
|
-
hasDesign: !!saved.preexisting?.design,
|
|
42
|
-
hasArchitecture: !!saved.preexisting?.architecture,
|
|
43
|
-
hasOpenspec: !!saved.preexisting?.openspec,
|
|
44
|
-
sourceMode: saved.source?.mode ?? 'current',
|
|
45
|
-
sourceRoots: Array.isArray(saved.source?.roots) ? saved.source.roots : [],
|
|
46
|
-
maxConcurrentAgents: saved.agents?.maxConcurrent ?? 3,
|
|
47
|
-
installScope: 'local',
|
|
48
|
-
skipSkills: false,
|
|
49
|
-
updateMode: true,
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
console.log()
|
|
53
|
-
console.log(chalk.bold('Updating project from saved config'))
|
|
54
|
-
console.log(chalk.dim(` backlog: ${backlogPlatform} repo: ${repoPlatform} agents: ${ctx.maxConcurrentAgents}`))
|
|
55
|
-
console.log()
|
|
56
|
-
|
|
57
|
-
await copyContentStep({ backlogPlatform, repoPlatform }, ctx)
|
|
58
|
-
|
|
59
|
-
if (saved.models) {
|
|
60
|
-
await writeModelsToConfigs({ buildModel: saved.models.build, keepExisting: true })
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Reconcile against what is actually installed before patching guardrails.
|
|
64
|
-
// The saved flags drift: a project can be running the codegraph and
|
|
65
|
-
// agentmemory MCP servers with harness.json still recording them as false,
|
|
66
|
-
// and patchGuardrails would then empty those marker sections and strip the
|
|
67
|
-
// guidance for tools the project genuinely uses.
|
|
68
|
-
const tools = reconcileTools(saved.tools ?? {})
|
|
69
|
-
const gained = Object.keys(tools).filter(k => tools[k] && !saved.tools?.[k])
|
|
70
|
-
if (gained.length > 0) {
|
|
71
|
-
info(`Detected installed tools missing from harness.json: ${gained.join(', ')}`)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
await migrateCavemanSkill(tools)
|
|
75
|
-
await patchGuardrails({
|
|
76
|
-
rtk: !!tools.rtk,
|
|
77
|
-
simpleEnglish: !!(tools.simpleEnglish || tools.caveman),
|
|
78
|
-
codegraph: !!tools.codegraph,
|
|
79
|
-
memory: !!tools.memory,
|
|
80
|
-
humanizer: !!tools.humanizer,
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
await writeHarnessConfig({
|
|
84
|
-
...ctx,
|
|
85
|
-
backlogPlatform,
|
|
86
|
-
repoPlatform,
|
|
87
|
-
maxConcurrentAgents: ctx.maxConcurrentAgents,
|
|
88
|
-
planModel: saved.models?.plan ?? null,
|
|
89
|
-
buildModel: saved.models?.build ?? null,
|
|
90
|
-
fastModel: saved.models?.fast ?? null,
|
|
91
|
-
optionalTools: tools,
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
console.log()
|
|
95
|
-
console.log(chalk.bold.green('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'))
|
|
96
|
-
console.log(chalk.bold.green(' Update complete!'))
|
|
97
|
-
console.log(chalk.bold.green('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'))
|
|
98
|
-
console.log()
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
async function migrateCavemanSkill(tools) {
|
|
102
|
-
if (!tools.caveman || tools.simpleEnglish) return
|
|
103
|
-
|
|
104
|
-
const lockPath = path.join(process.cwd(), 'skills-lock.json')
|
|
105
|
-
const lock = await fse.readJson(lockPath).catch(() => ({ version: 1, skills: {} }))
|
|
106
|
-
lock.skills ??= {}
|
|
107
|
-
delete lock.skills.caveman
|
|
108
|
-
lock.skills['simple-english'] = SIMPLE_ENGLISH_ENTRY
|
|
109
|
-
await fse.writeJson(lockPath, lock, { spaces: 2 })
|
|
110
|
-
await fse.remove(path.join(process.cwd(), '.agents', 'skills', 'caveman'))
|
|
111
|
-
|
|
112
|
-
const result = await execa('npx', ['skills', 'experimental_install', '--yes'], {
|
|
113
|
-
cwd: process.cwd(),
|
|
114
|
-
reject: false,
|
|
115
|
-
stdio: 'pipe',
|
|
116
|
-
timeout: 600000,
|
|
117
|
-
})
|
|
118
|
-
if (result.exitCode !== 0) {
|
|
119
|
-
console.log(chalk.yellow('Simple English was added to skills-lock.json but could not be installed. Run npx skills experimental_install --yes.'))
|
|
120
|
-
}
|
|
121
|
-
}
|
|
1
|
+
import chalk from 'chalk'
|
|
2
|
+
import { execa } from 'execa'
|
|
3
|
+
import fse from 'fs-extra'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import { fileURLToPath } from 'url'
|
|
6
|
+
import { readHarnessConfig } from './shared.js'
|
|
7
|
+
import { copyContentStep } from '../steps/copy/index.js'
|
|
8
|
+
import { writeModelsToConfigs } from '../steps/models/write.js'
|
|
9
|
+
import { patchGuardrails } from '../steps/optimization/patch-guardrails.js'
|
|
10
|
+
import { reconcileTools } from '../steps/optimization/detect.js'
|
|
11
|
+
import { writeHarnessConfig } from '../steps/metadata/index.js'
|
|
12
|
+
import { info } from '../utils/exec.js'
|
|
13
|
+
import { exit } from '../utils/process.js'
|
|
14
|
+
|
|
15
|
+
const SIMPLE_ENGLISH_ENTRY = {
|
|
16
|
+
source: 'AminBlg/SimpleEnglish',
|
|
17
|
+
sourceType: 'github',
|
|
18
|
+
skillPath: 'skills/simple-english/SKILL.md',
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
22
|
+
const platformsPreset = await fse.readJson(path.resolve(__dirname, '../presets/platforms.json'))
|
|
23
|
+
const VALID_PLATFORMS = new Set(platformsPreset.map(p => p.value))
|
|
24
|
+
|
|
25
|
+
function resolvePlatform(value, fallback = 'github') {
|
|
26
|
+
return VALID_PLATFORMS.has(value) ? value : fallback
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function runUpdate() {
|
|
30
|
+
const saved = await readHarnessConfig()
|
|
31
|
+
if (!saved?.platform) {
|
|
32
|
+
console.log(chalk.red('No agent-harness config found. Run the wizard first.'))
|
|
33
|
+
exit(1)
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const backlogPlatform = resolvePlatform(saved.platform.backlog)
|
|
38
|
+
const repoPlatform = resolvePlatform(saved.platform.repo)
|
|
39
|
+
|
|
40
|
+
const ctx = {
|
|
41
|
+
hasDesign: !!saved.preexisting?.design,
|
|
42
|
+
hasArchitecture: !!saved.preexisting?.architecture,
|
|
43
|
+
hasOpenspec: !!saved.preexisting?.openspec,
|
|
44
|
+
sourceMode: saved.source?.mode ?? 'current',
|
|
45
|
+
sourceRoots: Array.isArray(saved.source?.roots) ? saved.source.roots : [],
|
|
46
|
+
maxConcurrentAgents: saved.agents?.maxConcurrent ?? 3,
|
|
47
|
+
installScope: 'local',
|
|
48
|
+
skipSkills: false,
|
|
49
|
+
updateMode: true,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
console.log()
|
|
53
|
+
console.log(chalk.bold('Updating project from saved config'))
|
|
54
|
+
console.log(chalk.dim(` backlog: ${backlogPlatform} repo: ${repoPlatform} agents: ${ctx.maxConcurrentAgents}`))
|
|
55
|
+
console.log()
|
|
56
|
+
|
|
57
|
+
await copyContentStep({ backlogPlatform, repoPlatform }, ctx)
|
|
58
|
+
|
|
59
|
+
if (saved.models) {
|
|
60
|
+
await writeModelsToConfigs({ buildModel: saved.models.build, keepExisting: true })
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Reconcile against what is actually installed before patching guardrails.
|
|
64
|
+
// The saved flags drift: a project can be running the codegraph and
|
|
65
|
+
// agentmemory MCP servers with harness.json still recording them as false,
|
|
66
|
+
// and patchGuardrails would then empty those marker sections and strip the
|
|
67
|
+
// guidance for tools the project genuinely uses.
|
|
68
|
+
const tools = reconcileTools(saved.tools ?? {})
|
|
69
|
+
const gained = Object.keys(tools).filter(k => tools[k] && !saved.tools?.[k])
|
|
70
|
+
if (gained.length > 0) {
|
|
71
|
+
info(`Detected installed tools missing from harness.json: ${gained.join(', ')}`)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
await migrateCavemanSkill(tools)
|
|
75
|
+
await patchGuardrails({
|
|
76
|
+
rtk: !!tools.rtk,
|
|
77
|
+
simpleEnglish: !!(tools.simpleEnglish || tools.caveman),
|
|
78
|
+
codegraph: !!tools.codegraph,
|
|
79
|
+
memory: !!tools.memory,
|
|
80
|
+
humanizer: !!tools.humanizer,
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
await writeHarnessConfig({
|
|
84
|
+
...ctx,
|
|
85
|
+
backlogPlatform,
|
|
86
|
+
repoPlatform,
|
|
87
|
+
maxConcurrentAgents: ctx.maxConcurrentAgents,
|
|
88
|
+
planModel: saved.models?.plan ?? null,
|
|
89
|
+
buildModel: saved.models?.build ?? null,
|
|
90
|
+
fastModel: saved.models?.fast ?? null,
|
|
91
|
+
optionalTools: tools,
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
console.log()
|
|
95
|
+
console.log(chalk.bold.green('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'))
|
|
96
|
+
console.log(chalk.bold.green(' Update complete!'))
|
|
97
|
+
console.log(chalk.bold.green('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'))
|
|
98
|
+
console.log()
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function migrateCavemanSkill(tools) {
|
|
102
|
+
if (!tools.caveman || tools.simpleEnglish) return
|
|
103
|
+
|
|
104
|
+
const lockPath = path.join(process.cwd(), 'skills-lock.json')
|
|
105
|
+
const lock = await fse.readJson(lockPath).catch(() => ({ version: 1, skills: {} }))
|
|
106
|
+
lock.skills ??= {}
|
|
107
|
+
delete lock.skills.caveman
|
|
108
|
+
lock.skills['simple-english'] = SIMPLE_ENGLISH_ENTRY
|
|
109
|
+
await fse.writeJson(lockPath, lock, { spaces: 2 })
|
|
110
|
+
await fse.remove(path.join(process.cwd(), '.agents', 'skills', 'caveman'))
|
|
111
|
+
|
|
112
|
+
const result = await execa('npx', ['skills', 'experimental_install', '--yes'], {
|
|
113
|
+
cwd: process.cwd(),
|
|
114
|
+
reject: false,
|
|
115
|
+
stdio: 'pipe',
|
|
116
|
+
timeout: 600000,
|
|
117
|
+
})
|
|
118
|
+
if (result.exitCode !== 0) {
|
|
119
|
+
console.log(chalk.yellow('Simple English was added to skills-lock.json but could not be installed. Run npx skills experimental_install --yes.'))
|
|
120
|
+
}
|
|
121
|
+
}
|