@plainconceptsplatform/agent-harness 2.3.0 → 2.4.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/README.md +23 -12
- package/{src → cli}/commands/join.js +3 -4
- package/{src → cli}/commands/migrate.js +1 -1
- package/{src → cli}/commands/wizard.js +1 -1
- package/{src → cli}/index.js +1 -1
- package/{src → cli}/presets/agents-content.json +4 -4
- package/cli/presets/browser.json +10 -0
- package/{src → cli}/presets/clean.json +21 -21
- package/{src → cli}/presets/optimization.json +37 -37
- package/{src → cli}/presets/platforms.json +76 -76
- package/{src → cli}/presets/quota.json +16 -16
- package/{src → cli}/presets/source.json +23 -23
- package/cli/steps/browser/index.js +48 -0
- package/{src → cli}/steps/clean/index.js +120 -120
- package/{src → cli}/steps/copy/agents.js +119 -119
- package/{src → cli}/steps/copy/commands.js +95 -95
- package/{src → cli}/steps/copy/fullstack-engineer.js +89 -88
- package/{src → cli}/steps/copy/index.js +1 -1
- package/{src → cli}/steps/copy/opencode-json.js +196 -161
- package/{src → cli}/steps/copy/skills.js +2 -2
- package/{src → cli}/steps/models/format.js +88 -88
- package/{src → cli}/steps/models/index.js +64 -64
- package/{src → cli}/steps/openspec/index.js +136 -136
- package/{src → cli}/steps/optimization/codegraph.js +127 -127
- package/{src → cli}/steps/optimization/detect.js +66 -66
- package/{src → cli}/steps/optimization/humanizer.js +17 -17
- package/{src → cli}/steps/optimization/index.js +163 -163
- package/{src → cli}/steps/optimization/memory.js +88 -88
- package/{src → cli}/steps/optimization/patch-guardrails.js +109 -109
- package/{src → cli}/steps/optimization/quota.js +119 -119
- package/{src → cli}/steps/optimization/simple-english.js +17 -17
- package/{src → cli}/steps/optimization/skills-lock.js +30 -30
- package/{src → cli}/steps/platform/index.js +109 -109
- package/{src → cli}/steps/source/index.js +123 -123
- package/{src → cli}/utils/agent-color.js +111 -83
- package/{src → cli}/utils/exec-spinner.js +47 -47
- package/{src → cli}/utils/exec.js +134 -134
- package/{src → cli}/utils/models-pricing.js +42 -42
- package/{src → cli}/utils/paths.js +1 -1
- package/{src → cli}/utils/process.js +3 -3
- package/{src → cli}/utils/terminal.js +6 -6
- package/harness/.agents/skills/browser-automation/SKILL.md +72 -0
- package/{src/content → harness}/.agents/skills/pc-make-engineer/SKILL.md +219 -219
- package/{src/content → harness}/.agents/skills/pc-make-engineer/template.md +80 -80
- package/{src/content → harness}/.agents/skills/pc-plan-archive/SKILL.md +3 -0
- package/{src/content → harness}/.agents/skills/pc-plan-explore/SKILL.md +3 -0
- package/{src/content → harness}/.agents/skills/pc-plan-goal/SKILL.md +5 -16
- package/{src/content → harness}/.agents/skills/pc-plan-goal/branching.md +1 -1
- package/{src/content → harness}/.agents/skills/pc-plan-goal/output.md +5 -8
- package/{src/content → harness}/.agents/skills/pc-plan-story/SKILL.md +3 -0
- package/{src/content → harness}/.agents/skills/pc-userstory-browser/SKILL.md +136 -132
- package/{src/content → harness}/.opencode/package.json +9 -10
- package/{src/content → harness}/.opencode/plugins/pc-subagent-tiers.js +368 -337
- package/{src/content → harness}/ARCHITECTURE.md +16 -16
- package/{src/content → harness}/DESIGN.md +16 -16
- package/{src/content → harness}/opencode.jsonc +47 -41
- package/{src/content → harness}/openspec/config.yaml +20 -20
- package/{src/content → harness}/skills-lock.json +17 -17
- package/package.json +7 -7
- package/src/content/.agents/skills/browser-automation/SKILL.md +0 -66
- package/src/presets/browser.json +0 -22
- package/src/steps/browser/index.js +0 -91
- /package/{src → cli}/commands/shared.js +0 -0
- /package/{src → cli}/commands/single.js +0 -0
- /package/{src → cli}/commands/update.js +0 -0
- /package/{src → cli}/fragments/archive/az.md +0 -0
- /package/{src → cli}/fragments/archive/gh.md +0 -0
- /package/{src → cli}/fragments/archive/gl.md +0 -0
- /package/{src → cli}/fragments/archive/none.md +0 -0
- /package/{src → cli}/fragments/guardrails/codegraph.md +0 -0
- /package/{src → cli}/fragments/guardrails/humanizer.md +0 -0
- /package/{src → cli}/fragments/guardrails/memory.md +0 -0
- /package/{src → cli}/fragments/guardrails/rtk.md +0 -0
- /package/{src → cli}/fragments/guardrails/simple-english.md +0 -0
- /package/{src → cli}/fragments/ops-backlog/az.md +0 -0
- /package/{src → cli}/fragments/ops-backlog/gh.md +0 -0
- /package/{src → cli}/fragments/ops-backlog/jira.md +0 -0
- /package/{src → cli}/fragments/ops-evidence/az.md +0 -0
- /package/{src → cli}/fragments/ops-evidence/gh.md +0 -0
- /package/{src → cli}/fragments/ops-evidence/jira.md +0 -0
- /package/{src → cli}/fragments/ops-review/az.md +0 -0
- /package/{src → cli}/fragments/ops-review/gh.md +0 -0
- /package/{src → cli}/fragments/ops-review/gl.md +0 -0
- /package/{src → cli}/fragments/ops-ship/az.md +0 -0
- /package/{src → cli}/fragments/ops-ship/gh.md +0 -0
- /package/{src → cli}/fragments/ops-ship/gl.md +0 -0
- /package/{src → cli}/presets/models.json +0 -0
- /package/{src → cli}/presets/openspec.json +0 -0
- /package/{src → cli}/steps/metadata/index.js +0 -0
- /package/{src → cli}/steps/models/write.js +0 -0
- /package/{src → cli}/utils/copy.js +0 -0
- /package/{src → cli}/utils/legacy-check.js +0 -0
- /package/{src → cli}/utils/models-cache.js +0 -0
- /package/{src → cli}/utils/update-manifest.js +0 -0
- /package/{src/content → harness}/.agents/skills/pc-guardrails-generic/SKILL.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-guardrails-project/SKILL.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-make-architecture/SKILL.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-make-architecture/structure-template.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-make-design/SKILL.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-make-engineer/signal-mapping.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-make-evidence-scaffold/SKILL.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-make-evidence-scaffold/evidence-contract.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-make-guardrails/SKILL.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-make-guardrails/category-reference.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-make-merge-risk-assess/SKILL.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-make-merge-risk-assess/category-reference.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-make-user-model/SKILL.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-ops-evidence/SKILL.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-ops-ship/SKILL.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-plan-apply/SKILL.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-plan-apply/simple-mode.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-plan-goal/failure-policy.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-plan-goal/output-mode.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-plan-propose/SKILL.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-plan-propose/task-annotation.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-plan-quick/SKILL.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-repo-audit/SKILL.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-repo-help/SKILL.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-repo-initialize/SKILL.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-repo-onboard/SKILL.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-repo-verify/SKILL.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-userstory-az/SKILL.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-userstory-gh/SKILL.md +0 -0
- /package/{src/content → harness}/.agents/skills/pc-userstory-jira/SKILL.md +0 -0
- /package/{src/content → harness}/.opencode/_gitignore +0 -0
- /package/{src/content → harness}/.opencode/commands/init.md +0 -0
- /package/{src/content → harness}/.opencode/commands/make-architecture.md +0 -0
- /package/{src/content → harness}/.opencode/commands/make-design.md +0 -0
- /package/{src/content → harness}/.opencode/commands/make-engineer.md +0 -0
- /package/{src/content → harness}/.opencode/commands/make-evidence-scaffold.md +0 -0
- /package/{src/content → harness}/.opencode/commands/make-guardrails.md +0 -0
- /package/{src/content → harness}/.opencode/commands/make-user-model.md +0 -0
- /package/{src/content → harness}/.opencode/commands/ops-backlog.md +0 -0
- /package/{src/content → harness}/.opencode/commands/ops-evidence.md +0 -0
- /package/{src/content → harness}/.opencode/commands/ops-review.md +0 -0
- /package/{src/content → harness}/.opencode/commands/ops-ship.md +0 -0
- /package/{src/content → harness}/.opencode/commands/plan-apply.md +0 -0
- /package/{src/content → harness}/.opencode/commands/plan-archive.md +0 -0
- /package/{src/content → harness}/.opencode/commands/plan-explore.md +0 -0
- /package/{src/content → harness}/.opencode/commands/plan-goal.md +0 -0
- /package/{src/content → harness}/.opencode/commands/plan-propose.md +0 -0
- /package/{src/content → harness}/.opencode/commands/plan-quick.md +0 -0
- /package/{src/content → harness}/.opencode/commands/plan-story.md +0 -0
- /package/{src/content → harness}/.opencode/commands/repo-audit.md +0 -0
- /package/{src/content → harness}/.opencode/commands/repo-help.md +0 -0
- /package/{src/content → harness}/.opencode/commands/repo-initialize.md +0 -0
- /package/{src/content → harness}/.opencode/commands/repo-onboard.md +0 -0
- /package/{src/content → harness}/.opencode/commands/repo-verify.md +0 -0
- /package/{src/content → harness}/.opencode/plugins/pc-subagent-monitor.js +0 -0
- /package/{src/content → harness}/.opencode/plugins/pc-system-reminders.js +0 -0
- /package/{src/content → harness}/.opencode/tui/pc-subagents.tsx +0 -0
- /package/{src/content → harness}/.opencode/tui.json +0 -0
- /package/{src/content → harness}/AGENTS.md +0 -0
- /package/{src/content → harness}/openspec/changes/archive/.gitkeep +0 -0
- /package/{src/content → harness}/openspec/specs/.gitkeep +0 -0
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
import fse from 'fs-extra'
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
import { parse } from 'jsonc-parser'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Work out which optional tools a project actually has, rather than trusting
|
|
7
|
-
* the flags in harness.json.
|
|
8
|
-
*
|
|
9
|
-
* Those flags drift. Numa and Odissey both had codegraph and agentmemory MCP
|
|
10
|
-
* servers enabled in opencode.jsonc and the humanizer and simple-english skills
|
|
11
|
-
* installed, while harness.json recorded `codegraph: false`, `memory: false` and
|
|
12
|
-
* no humanizer key at all. patchGuardrails believed the config and emptied those
|
|
13
|
-
* marker sections, so agents lost the guidance for tools the project was running.
|
|
14
|
-
*
|
|
15
|
-
* Detection only ever turns a tool ON. A flag that is already true is left
|
|
16
|
-
* alone, because some of these install globally and cannot be seen from inside
|
|
17
|
-
* the repository at all.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
function mcpServers(cwd) {
|
|
21
|
-
const configPath = path.join(cwd, 'opencode.jsonc')
|
|
22
|
-
if (!fse.pathExistsSync(configPath)) return {}
|
|
23
|
-
const errors = []
|
|
24
|
-
const parsed = parse(fse.readFileSync(configPath, 'utf-8'), errors)
|
|
25
|
-
if (errors.length > 0 || typeof parsed !== 'object' || parsed === null) return {}
|
|
26
|
-
return parsed.mcp ?? {}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function hasSkill(cwd, name) {
|
|
30
|
-
return fse.pathExistsSync(path.join(cwd, '.agents', 'skills', name))
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** An MCP server counts as present unless it is explicitly disabled. */
|
|
34
|
-
function hasMcp(servers, name) {
|
|
35
|
-
const server = servers[name]
|
|
36
|
-
if (!server) return false
|
|
37
|
-
return server.enabled !== false
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function detectInstalledTools(cwd = process.cwd()) {
|
|
41
|
-
const servers = mcpServers(cwd)
|
|
42
|
-
return {
|
|
43
|
-
// rtk is a global CLI with nothing to find in the repo, so it is not
|
|
44
|
-
// detectable here and the saved flag stands on its own.
|
|
45
|
-
codegraph: hasMcp(servers, 'codegraph') || fse.pathExistsSync(path.join(cwd, '.codegraph')),
|
|
46
|
-
memory: hasMcp(servers, 'agentmemory'),
|
|
47
|
-
simpleEnglish: hasSkill(cwd, 'simple-english'),
|
|
48
|
-
humanizer: hasSkill(cwd, 'humanizer'),
|
|
49
|
-
quota: fse.pathExistsSync(path.join(cwd, '.opencode', 'opencode-quota')),
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Saved flags merged with what is on disk. Detection can only add, so a tool
|
|
55
|
-
* recorded as enabled stays enabled even when nothing local proves it.
|
|
56
|
-
*/
|
|
57
|
-
export function reconcileTools(saved = {}, cwd = process.cwd()) {
|
|
58
|
-
const detected = detectInstalledTools(cwd)
|
|
59
|
-
const merged = { ...saved }
|
|
60
|
-
for (const [key, present] of Object.entries(detected)) {
|
|
61
|
-
if (present) merged[key] = true
|
|
62
|
-
}
|
|
63
|
-
// simpleEnglish replaced caveman; honour the old key one last time.
|
|
64
|
-
if (saved.caveman) merged.simpleEnglish = true
|
|
65
|
-
return merged
|
|
66
|
-
}
|
|
1
|
+
import fse from 'fs-extra'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { parse } from 'jsonc-parser'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Work out which optional tools a project actually has, rather than trusting
|
|
7
|
+
* the flags in harness.json.
|
|
8
|
+
*
|
|
9
|
+
* Those flags drift. Numa and Odissey both had codegraph and agentmemory MCP
|
|
10
|
+
* servers enabled in opencode.jsonc and the humanizer and simple-english skills
|
|
11
|
+
* installed, while harness.json recorded `codegraph: false`, `memory: false` and
|
|
12
|
+
* no humanizer key at all. patchGuardrails believed the config and emptied those
|
|
13
|
+
* marker sections, so agents lost the guidance for tools the project was running.
|
|
14
|
+
*
|
|
15
|
+
* Detection only ever turns a tool ON. A flag that is already true is left
|
|
16
|
+
* alone, because some of these install globally and cannot be seen from inside
|
|
17
|
+
* the repository at all.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
function mcpServers(cwd) {
|
|
21
|
+
const configPath = path.join(cwd, 'opencode.jsonc')
|
|
22
|
+
if (!fse.pathExistsSync(configPath)) return {}
|
|
23
|
+
const errors = []
|
|
24
|
+
const parsed = parse(fse.readFileSync(configPath, 'utf-8'), errors)
|
|
25
|
+
if (errors.length > 0 || typeof parsed !== 'object' || parsed === null) return {}
|
|
26
|
+
return parsed.mcp ?? {}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function hasSkill(cwd, name) {
|
|
30
|
+
return fse.pathExistsSync(path.join(cwd, '.agents', 'skills', name))
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** An MCP server counts as present unless it is explicitly disabled. */
|
|
34
|
+
function hasMcp(servers, name) {
|
|
35
|
+
const server = servers[name]
|
|
36
|
+
if (!server) return false
|
|
37
|
+
return server.enabled !== false
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function detectInstalledTools(cwd = process.cwd()) {
|
|
41
|
+
const servers = mcpServers(cwd)
|
|
42
|
+
return {
|
|
43
|
+
// rtk is a global CLI with nothing to find in the repo, so it is not
|
|
44
|
+
// detectable here and the saved flag stands on its own.
|
|
45
|
+
codegraph: hasMcp(servers, 'codegraph') || fse.pathExistsSync(path.join(cwd, '.codegraph')),
|
|
46
|
+
memory: hasMcp(servers, 'agentmemory'),
|
|
47
|
+
simpleEnglish: hasSkill(cwd, 'simple-english'),
|
|
48
|
+
humanizer: hasSkill(cwd, 'humanizer'),
|
|
49
|
+
quota: fse.pathExistsSync(path.join(cwd, '.opencode', 'opencode-quota')),
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Saved flags merged with what is on disk. Detection can only add, so a tool
|
|
55
|
+
* recorded as enabled stays enabled even when nothing local proves it.
|
|
56
|
+
*/
|
|
57
|
+
export function reconcileTools(saved = {}, cwd = process.cwd()) {
|
|
58
|
+
const detected = detectInstalledTools(cwd)
|
|
59
|
+
const merged = { ...saved }
|
|
60
|
+
for (const [key, present] of Object.entries(detected)) {
|
|
61
|
+
if (present) merged[key] = true
|
|
62
|
+
}
|
|
63
|
+
// simpleEnglish replaced caveman; honour the old key one last time.
|
|
64
|
+
if (saved.caveman) merged.simpleEnglish = true
|
|
65
|
+
return merged
|
|
66
|
+
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { addSkillToLock } from './skills-lock.js'
|
|
2
|
-
import { header, success, info } from '../../utils/exec.js'
|
|
3
|
-
|
|
4
|
-
const SKILL_ENTRY = {
|
|
5
|
-
source: 'blader/humanizer',
|
|
6
|
-
sourceType: 'github',
|
|
7
|
-
skillPath: 'SKILL.md',
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export async function installHumanizer(options = {}) {
|
|
11
|
-
if (!options.skipHeader) header('Installing humanizer')
|
|
12
|
-
|
|
13
|
-
info('Adding humanizer to skills-lock.json for batch install')
|
|
14
|
-
await addSkillToLock('humanizer', SKILL_ENTRY)
|
|
15
|
-
success('humanizer queued for installation')
|
|
16
|
-
return { optedIn: true, installed: true }
|
|
17
|
-
}
|
|
1
|
+
import { addSkillToLock } from './skills-lock.js'
|
|
2
|
+
import { header, success, info } from '../../utils/exec.js'
|
|
3
|
+
|
|
4
|
+
const SKILL_ENTRY = {
|
|
5
|
+
source: 'blader/humanizer',
|
|
6
|
+
sourceType: 'github',
|
|
7
|
+
skillPath: 'SKILL.md',
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function installHumanizer(options = {}) {
|
|
11
|
+
if (!options.skipHeader) header('Installing humanizer')
|
|
12
|
+
|
|
13
|
+
info('Adding humanizer to skills-lock.json for batch install')
|
|
14
|
+
await addSkillToLock('humanizer', SKILL_ENTRY)
|
|
15
|
+
success('humanizer queued for installation')
|
|
16
|
+
return { optedIn: true, installed: true }
|
|
17
|
+
}
|
|
@@ -1,163 +1,163 @@
|
|
|
1
|
-
import { checkbox, confirm } from '@inquirer/prompts'
|
|
2
|
-
import { execa } from 'execa'
|
|
3
|
-
import fse from 'fs-extra'
|
|
4
|
-
import path from 'path'
|
|
5
|
-
import { fileURLToPath } from 'url'
|
|
6
|
-
import { code, commandExists, header, info, loading, success, warn } from '../../utils/exec.js'
|
|
7
|
-
import { installQuota } from './quota.js'
|
|
8
|
-
import { installSimpleEnglish } from './simple-english.js'
|
|
9
|
-
import { installCodegraph } from './codegraph.js'
|
|
10
|
-
import { installMemory } from './memory.js'
|
|
11
|
-
import { installHumanizer } from './humanizer.js'
|
|
12
|
-
import { patchGuardrails } from './patch-guardrails.js'
|
|
13
|
-
|
|
14
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
15
|
-
const OPTIMIZATION_PRESET_PATH = path.resolve(__dirname, '../../presets/optimization.json')
|
|
16
|
-
const optimizationPreset = await fse.readJson(OPTIMIZATION_PRESET_PATH)
|
|
17
|
-
|
|
18
|
-
export async function checkRtk(options = {}) {
|
|
19
|
-
if (!options.skipHeader) header('Checking rtk')
|
|
20
|
-
|
|
21
|
-
let shouldCheck = true
|
|
22
|
-
if (!options.skipPrompt) {
|
|
23
|
-
info('Recommended: install and verify rtk for safer agent CLI command execution.')
|
|
24
|
-
shouldCheck = await confirm({
|
|
25
|
-
message: 'Check rtk now?',
|
|
26
|
-
default: true,
|
|
27
|
-
})
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (!shouldCheck) {
|
|
31
|
-
warn('Skipped rtk check (you can install it later)')
|
|
32
|
-
return { optedIn: false, checked: false, available: false }
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
loading('checking rtk...')
|
|
36
|
-
|
|
37
|
-
const available = await commandExists('rtk')
|
|
38
|
-
|
|
39
|
-
if (available) {
|
|
40
|
-
success('rtk is available')
|
|
41
|
-
return { optedIn: true, checked: true, available: true }
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
warn('rtk not found on PATH.')
|
|
45
|
-
console.log()
|
|
46
|
-
info('rtk is required for agents to run CLI commands safely.')
|
|
47
|
-
info('Install it from: https://github.com/rtk-ai/rtk#pre-built-binaries')
|
|
48
|
-
console.log()
|
|
49
|
-
info('After installing, verify with:')
|
|
50
|
-
code(['rtk --version'])
|
|
51
|
-
return { optedIn: true, checked: true, available: false }
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export async function tokenOptimizationStep(options = {}) {
|
|
55
|
-
header('Step 8, Token optimization tools')
|
|
56
|
-
|
|
57
|
-
const defaultSelected = optimizationPreset.choices
|
|
58
|
-
.filter(choice => choice.checked)
|
|
59
|
-
.map(choice => choice.value)
|
|
60
|
-
let selected = defaultSelected
|
|
61
|
-
|
|
62
|
-
if (!options.skipPrompt && process.stdin.isTTY) {
|
|
63
|
-
info(optimizationPreset.info)
|
|
64
|
-
// Abort the prompt via signal instead of racing it: a raced prompt keeps
|
|
65
|
-
// stdin in raw mode after "losing" and rejects unhandled on a later Ctrl+C.
|
|
66
|
-
const controller = new AbortController()
|
|
67
|
-
const timer = setTimeout(() => controller.abort(), optimizationPreset.timeoutMs)
|
|
68
|
-
try {
|
|
69
|
-
selected = await checkbox(
|
|
70
|
-
{
|
|
71
|
-
message: optimizationPreset.message,
|
|
72
|
-
choices: optimizationPreset.choices,
|
|
73
|
-
},
|
|
74
|
-
{ signal: controller.signal },
|
|
75
|
-
)
|
|
76
|
-
} catch (err) {
|
|
77
|
-
if (err.name !== 'AbortPromptError') throw err
|
|
78
|
-
selected = defaultSelected
|
|
79
|
-
info('No response: continuing with the recommended defaults.')
|
|
80
|
-
} finally {
|
|
81
|
-
clearTimeout(timer)
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
loading('applying token optimization selections...')
|
|
86
|
-
|
|
87
|
-
const installScope = options.ctx?.installScope || 'local'
|
|
88
|
-
|
|
89
|
-
const has = value => selected.includes(value)
|
|
90
|
-
|
|
91
|
-
const rtk = has('rtk')
|
|
92
|
-
? await checkRtk({ skipHeader: true, skipPrompt: true })
|
|
93
|
-
: { optedIn: false, checked: false, available: false }
|
|
94
|
-
|
|
95
|
-
const quota = has('quota')
|
|
96
|
-
? await installQuota({ skipHeader: true, skipPrompt: true })
|
|
97
|
-
: { optedIn: false, installed: false }
|
|
98
|
-
|
|
99
|
-
const simpleEnglish = has('simpleEnglish')
|
|
100
|
-
? await installSimpleEnglish({
|
|
101
|
-
skipHeader: true,
|
|
102
|
-
skipPrompt: true,
|
|
103
|
-
installScope,
|
|
104
|
-
})
|
|
105
|
-
: { optedIn: false, installed: false }
|
|
106
|
-
|
|
107
|
-
const codegraph = has('codegraph')
|
|
108
|
-
? await installCodegraph({ skipHeader: true, installScope })
|
|
109
|
-
: { optedIn: false, installed: false }
|
|
110
|
-
|
|
111
|
-
const memory = has('memory')
|
|
112
|
-
? await installMemory({ skipHeader: true })
|
|
113
|
-
: { optedIn: false, installed: false }
|
|
114
|
-
|
|
115
|
-
const humanizer = has('humanizer')
|
|
116
|
-
? await installHumanizer({ skipHeader: true, installScope })
|
|
117
|
-
: { optedIn: false, installed: false }
|
|
118
|
-
|
|
119
|
-
// Run a single npx skills experimental_install to pick up all skills
|
|
120
|
-
// that were added to skills-lock.json by the individual installers above.
|
|
121
|
-
await syncSkillsLock()
|
|
122
|
-
|
|
123
|
-
// Patch guardrails skill with selected tool guidance sections
|
|
124
|
-
await patchGuardrails({
|
|
125
|
-
rtk: rtk.available,
|
|
126
|
-
codegraph: codegraph.optedIn,
|
|
127
|
-
memory: memory.optedIn,
|
|
128
|
-
simpleEnglish: simpleEnglish.installed,
|
|
129
|
-
humanizer: humanizer.optedIn,
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
if (selected.length === 0) warn('No token optimization tools selected')
|
|
133
|
-
else success('Token optimization step completed')
|
|
134
|
-
|
|
135
|
-
return { rtk, quota, simpleEnglish, codegraph, memory, humanizer }
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async function syncSkillsLock() {
|
|
139
|
-
const destLock = path.join(process.cwd(), 'skills-lock.json')
|
|
140
|
-
if (!await fse.pathExists(destLock)) {
|
|
141
|
-
info('No skills-lock.json found, skipping skills sync')
|
|
142
|
-
return
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
loading('syncing skills via npx skills experimental_install...')
|
|
146
|
-
try {
|
|
147
|
-
const result = await execa('npx', ['skills', 'experimental_install', '--yes'], {
|
|
148
|
-
cwd: process.cwd(),
|
|
149
|
-
reject: false,
|
|
150
|
-
stdio: 'pipe',
|
|
151
|
-
timeout: 600000,
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
if (result.exitCode === 0) {
|
|
155
|
-
success('Skills synced from skills-lock.json')
|
|
156
|
-
} else {
|
|
157
|
-
const errLine = result.stderr?.trim().split('\n').slice(-3).join('\n')
|
|
158
|
-
warn(`npx skills experimental_install exited with non-zero code${errLine ? `: ${errLine}` : ''}`)
|
|
159
|
-
}
|
|
160
|
-
} catch (err) {
|
|
161
|
-
warn(`npx skills experimental_install failed: ${err.message}`)
|
|
162
|
-
}
|
|
163
|
-
}
|
|
1
|
+
import { checkbox, confirm } from '@inquirer/prompts'
|
|
2
|
+
import { execa } from 'execa'
|
|
3
|
+
import fse from 'fs-extra'
|
|
4
|
+
import path from 'path'
|
|
5
|
+
import { fileURLToPath } from 'url'
|
|
6
|
+
import { code, commandExists, header, info, loading, success, warn } from '../../utils/exec.js'
|
|
7
|
+
import { installQuota } from './quota.js'
|
|
8
|
+
import { installSimpleEnglish } from './simple-english.js'
|
|
9
|
+
import { installCodegraph } from './codegraph.js'
|
|
10
|
+
import { installMemory } from './memory.js'
|
|
11
|
+
import { installHumanizer } from './humanizer.js'
|
|
12
|
+
import { patchGuardrails } from './patch-guardrails.js'
|
|
13
|
+
|
|
14
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
15
|
+
const OPTIMIZATION_PRESET_PATH = path.resolve(__dirname, '../../presets/optimization.json')
|
|
16
|
+
const optimizationPreset = await fse.readJson(OPTIMIZATION_PRESET_PATH)
|
|
17
|
+
|
|
18
|
+
export async function checkRtk(options = {}) {
|
|
19
|
+
if (!options.skipHeader) header('Checking rtk')
|
|
20
|
+
|
|
21
|
+
let shouldCheck = true
|
|
22
|
+
if (!options.skipPrompt) {
|
|
23
|
+
info('Recommended: install and verify rtk for safer agent CLI command execution.')
|
|
24
|
+
shouldCheck = await confirm({
|
|
25
|
+
message: 'Check rtk now?',
|
|
26
|
+
default: true,
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!shouldCheck) {
|
|
31
|
+
warn('Skipped rtk check (you can install it later)')
|
|
32
|
+
return { optedIn: false, checked: false, available: false }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
loading('checking rtk...')
|
|
36
|
+
|
|
37
|
+
const available = await commandExists('rtk')
|
|
38
|
+
|
|
39
|
+
if (available) {
|
|
40
|
+
success('rtk is available')
|
|
41
|
+
return { optedIn: true, checked: true, available: true }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
warn('rtk not found on PATH.')
|
|
45
|
+
console.log()
|
|
46
|
+
info('rtk is required for agents to run CLI commands safely.')
|
|
47
|
+
info('Install it from: https://github.com/rtk-ai/rtk#pre-built-binaries')
|
|
48
|
+
console.log()
|
|
49
|
+
info('After installing, verify with:')
|
|
50
|
+
code(['rtk --version'])
|
|
51
|
+
return { optedIn: true, checked: true, available: false }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function tokenOptimizationStep(options = {}) {
|
|
55
|
+
header('Step 8, Token optimization tools')
|
|
56
|
+
|
|
57
|
+
const defaultSelected = optimizationPreset.choices
|
|
58
|
+
.filter(choice => choice.checked)
|
|
59
|
+
.map(choice => choice.value)
|
|
60
|
+
let selected = defaultSelected
|
|
61
|
+
|
|
62
|
+
if (!options.skipPrompt && process.stdin.isTTY) {
|
|
63
|
+
info(optimizationPreset.info)
|
|
64
|
+
// Abort the prompt via signal instead of racing it: a raced prompt keeps
|
|
65
|
+
// stdin in raw mode after "losing" and rejects unhandled on a later Ctrl+C.
|
|
66
|
+
const controller = new AbortController()
|
|
67
|
+
const timer = setTimeout(() => controller.abort(), optimizationPreset.timeoutMs)
|
|
68
|
+
try {
|
|
69
|
+
selected = await checkbox(
|
|
70
|
+
{
|
|
71
|
+
message: optimizationPreset.message,
|
|
72
|
+
choices: optimizationPreset.choices,
|
|
73
|
+
},
|
|
74
|
+
{ signal: controller.signal },
|
|
75
|
+
)
|
|
76
|
+
} catch (err) {
|
|
77
|
+
if (err.name !== 'AbortPromptError') throw err
|
|
78
|
+
selected = defaultSelected
|
|
79
|
+
info('No response: continuing with the recommended defaults.')
|
|
80
|
+
} finally {
|
|
81
|
+
clearTimeout(timer)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
loading('applying token optimization selections...')
|
|
86
|
+
|
|
87
|
+
const installScope = options.ctx?.installScope || 'local'
|
|
88
|
+
|
|
89
|
+
const has = value => selected.includes(value)
|
|
90
|
+
|
|
91
|
+
const rtk = has('rtk')
|
|
92
|
+
? await checkRtk({ skipHeader: true, skipPrompt: true })
|
|
93
|
+
: { optedIn: false, checked: false, available: false }
|
|
94
|
+
|
|
95
|
+
const quota = has('quota')
|
|
96
|
+
? await installQuota({ skipHeader: true, skipPrompt: true })
|
|
97
|
+
: { optedIn: false, installed: false }
|
|
98
|
+
|
|
99
|
+
const simpleEnglish = has('simpleEnglish')
|
|
100
|
+
? await installSimpleEnglish({
|
|
101
|
+
skipHeader: true,
|
|
102
|
+
skipPrompt: true,
|
|
103
|
+
installScope,
|
|
104
|
+
})
|
|
105
|
+
: { optedIn: false, installed: false }
|
|
106
|
+
|
|
107
|
+
const codegraph = has('codegraph')
|
|
108
|
+
? await installCodegraph({ skipHeader: true, installScope })
|
|
109
|
+
: { optedIn: false, installed: false }
|
|
110
|
+
|
|
111
|
+
const memory = has('memory')
|
|
112
|
+
? await installMemory({ skipHeader: true })
|
|
113
|
+
: { optedIn: false, installed: false }
|
|
114
|
+
|
|
115
|
+
const humanizer = has('humanizer')
|
|
116
|
+
? await installHumanizer({ skipHeader: true, installScope })
|
|
117
|
+
: { optedIn: false, installed: false }
|
|
118
|
+
|
|
119
|
+
// Run a single npx skills experimental_install to pick up all skills
|
|
120
|
+
// that were added to skills-lock.json by the individual installers above.
|
|
121
|
+
await syncSkillsLock()
|
|
122
|
+
|
|
123
|
+
// Patch guardrails skill with selected tool guidance sections
|
|
124
|
+
await patchGuardrails({
|
|
125
|
+
rtk: rtk.available,
|
|
126
|
+
codegraph: codegraph.optedIn,
|
|
127
|
+
memory: memory.optedIn,
|
|
128
|
+
simpleEnglish: simpleEnglish.installed,
|
|
129
|
+
humanizer: humanizer.optedIn,
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
if (selected.length === 0) warn('No token optimization tools selected')
|
|
133
|
+
else success('Token optimization step completed')
|
|
134
|
+
|
|
135
|
+
return { rtk, quota, simpleEnglish, codegraph, memory, humanizer }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function syncSkillsLock() {
|
|
139
|
+
const destLock = path.join(process.cwd(), 'skills-lock.json')
|
|
140
|
+
if (!await fse.pathExists(destLock)) {
|
|
141
|
+
info('No skills-lock.json found, skipping skills sync')
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
loading('syncing skills via npx skills experimental_install...')
|
|
146
|
+
try {
|
|
147
|
+
const result = await execa('npx', ['skills', 'experimental_install', '--yes'], {
|
|
148
|
+
cwd: process.cwd(),
|
|
149
|
+
reject: false,
|
|
150
|
+
stdio: 'pipe',
|
|
151
|
+
timeout: 600000,
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
if (result.exitCode === 0) {
|
|
155
|
+
success('Skills synced from skills-lock.json')
|
|
156
|
+
} else {
|
|
157
|
+
const errLine = result.stderr?.trim().split('\n').slice(-3).join('\n')
|
|
158
|
+
warn(`npx skills experimental_install exited with non-zero code${errLine ? `: ${errLine}` : ''}`)
|
|
159
|
+
}
|
|
160
|
+
} catch (err) {
|
|
161
|
+
warn(`npx skills experimental_install failed: ${err.message}`)
|
|
162
|
+
}
|
|
163
|
+
}
|