@plainconceptsplatform/agent-harness 2.3.0 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/README.md +23 -12
  2. package/{src → cli}/commands/join.js +3 -4
  3. package/{src → cli}/commands/migrate.js +1 -1
  4. package/{src → cli}/commands/wizard.js +1 -1
  5. package/{src → cli}/index.js +1 -1
  6. package/{src → cli}/presets/agents-content.json +4 -4
  7. package/cli/presets/browser.json +10 -0
  8. package/{src → cli}/presets/clean.json +21 -21
  9. package/{src → cli}/presets/optimization.json +37 -37
  10. package/{src → cli}/presets/platforms.json +76 -76
  11. package/{src → cli}/presets/quota.json +16 -16
  12. package/{src → cli}/presets/source.json +23 -23
  13. package/cli/steps/browser/index.js +48 -0
  14. package/{src → cli}/steps/clean/index.js +120 -120
  15. package/{src → cli}/steps/copy/agents.js +119 -119
  16. package/{src → cli}/steps/copy/commands.js +95 -95
  17. package/{src → cli}/steps/copy/fullstack-engineer.js +89 -88
  18. package/{src → cli}/steps/copy/index.js +1 -1
  19. package/{src → cli}/steps/copy/opencode-json.js +196 -161
  20. package/{src → cli}/steps/copy/skills.js +2 -2
  21. package/{src → cli}/steps/models/format.js +88 -88
  22. package/{src → cli}/steps/models/index.js +64 -64
  23. package/{src → cli}/steps/openspec/index.js +136 -136
  24. package/{src → cli}/steps/optimization/codegraph.js +127 -127
  25. package/{src → cli}/steps/optimization/detect.js +66 -66
  26. package/{src → cli}/steps/optimization/humanizer.js +17 -17
  27. package/{src → cli}/steps/optimization/index.js +163 -163
  28. package/{src → cli}/steps/optimization/memory.js +88 -88
  29. package/{src → cli}/steps/optimization/patch-guardrails.js +109 -109
  30. package/{src → cli}/steps/optimization/quota.js +119 -119
  31. package/{src → cli}/steps/optimization/simple-english.js +17 -17
  32. package/{src → cli}/steps/optimization/skills-lock.js +30 -30
  33. package/{src → cli}/steps/platform/index.js +109 -109
  34. package/{src → cli}/steps/source/index.js +123 -123
  35. package/{src → cli}/utils/agent-color.js +111 -83
  36. package/{src → cli}/utils/exec-spinner.js +47 -47
  37. package/{src → cli}/utils/exec.js +134 -134
  38. package/{src → cli}/utils/models-pricing.js +42 -42
  39. package/{src → cli}/utils/paths.js +1 -1
  40. package/{src → cli}/utils/process.js +3 -3
  41. package/{src → cli}/utils/terminal.js +6 -6
  42. package/harness/.agents/skills/browser-automation/SKILL.md +72 -0
  43. package/{src/content → harness}/.agents/skills/pc-make-engineer/SKILL.md +219 -219
  44. package/{src/content → harness}/.agents/skills/pc-make-engineer/template.md +80 -80
  45. package/{src/content → harness}/.agents/skills/pc-plan-apply/simple-mode.md +1 -1
  46. package/{src/content → harness}/.agents/skills/pc-plan-archive/SKILL.md +3 -0
  47. package/{src/content → harness}/.agents/skills/pc-plan-explore/SKILL.md +3 -0
  48. package/{src/content → harness}/.agents/skills/pc-plan-goal/SKILL.md +11 -20
  49. package/{src/content → harness}/.agents/skills/pc-plan-goal/branching.md +1 -1
  50. package/{src/content → harness}/.agents/skills/pc-plan-goal/output.md +5 -8
  51. package/{src/content → harness}/.agents/skills/pc-plan-story/SKILL.md +3 -0
  52. package/{src/content → harness}/.agents/skills/pc-userstory-browser/SKILL.md +136 -132
  53. package/{src/content → harness}/.opencode/package.json +9 -10
  54. package/{src/content → harness}/.opencode/plugins/pc-subagent-tiers.js +368 -337
  55. package/{src/content → harness}/ARCHITECTURE.md +16 -16
  56. package/{src/content → harness}/DESIGN.md +16 -16
  57. package/{src/content → harness}/opencode.jsonc +47 -41
  58. package/{src/content → harness}/openspec/config.yaml +20 -20
  59. package/{src/content → harness}/skills-lock.json +17 -17
  60. package/package.json +7 -7
  61. package/src/content/.agents/skills/browser-automation/SKILL.md +0 -66
  62. package/src/presets/browser.json +0 -22
  63. package/src/steps/browser/index.js +0 -91
  64. /package/{src → cli}/commands/shared.js +0 -0
  65. /package/{src → cli}/commands/single.js +0 -0
  66. /package/{src → cli}/commands/update.js +0 -0
  67. /package/{src → cli}/fragments/archive/az.md +0 -0
  68. /package/{src → cli}/fragments/archive/gh.md +0 -0
  69. /package/{src → cli}/fragments/archive/gl.md +0 -0
  70. /package/{src → cli}/fragments/archive/none.md +0 -0
  71. /package/{src → cli}/fragments/guardrails/codegraph.md +0 -0
  72. /package/{src → cli}/fragments/guardrails/humanizer.md +0 -0
  73. /package/{src → cli}/fragments/guardrails/memory.md +0 -0
  74. /package/{src → cli}/fragments/guardrails/rtk.md +0 -0
  75. /package/{src → cli}/fragments/guardrails/simple-english.md +0 -0
  76. /package/{src → cli}/fragments/ops-backlog/az.md +0 -0
  77. /package/{src → cli}/fragments/ops-backlog/gh.md +0 -0
  78. /package/{src → cli}/fragments/ops-backlog/jira.md +0 -0
  79. /package/{src → cli}/fragments/ops-evidence/az.md +0 -0
  80. /package/{src → cli}/fragments/ops-evidence/gh.md +0 -0
  81. /package/{src → cli}/fragments/ops-evidence/jira.md +0 -0
  82. /package/{src → cli}/fragments/ops-review/az.md +0 -0
  83. /package/{src → cli}/fragments/ops-review/gh.md +0 -0
  84. /package/{src → cli}/fragments/ops-review/gl.md +0 -0
  85. /package/{src → cli}/fragments/ops-ship/az.md +0 -0
  86. /package/{src → cli}/fragments/ops-ship/gh.md +0 -0
  87. /package/{src → cli}/fragments/ops-ship/gl.md +0 -0
  88. /package/{src → cli}/presets/models.json +0 -0
  89. /package/{src → cli}/presets/openspec.json +0 -0
  90. /package/{src → cli}/steps/metadata/index.js +0 -0
  91. /package/{src → cli}/steps/models/write.js +0 -0
  92. /package/{src → cli}/utils/copy.js +0 -0
  93. /package/{src → cli}/utils/legacy-check.js +0 -0
  94. /package/{src → cli}/utils/models-cache.js +0 -0
  95. /package/{src → cli}/utils/update-manifest.js +0 -0
  96. /package/{src/content → harness}/.agents/skills/pc-guardrails-generic/SKILL.md +0 -0
  97. /package/{src/content → harness}/.agents/skills/pc-guardrails-project/SKILL.md +0 -0
  98. /package/{src/content → harness}/.agents/skills/pc-make-architecture/SKILL.md +0 -0
  99. /package/{src/content → harness}/.agents/skills/pc-make-architecture/structure-template.md +0 -0
  100. /package/{src/content → harness}/.agents/skills/pc-make-design/SKILL.md +0 -0
  101. /package/{src/content → harness}/.agents/skills/pc-make-engineer/signal-mapping.md +0 -0
  102. /package/{src/content → harness}/.agents/skills/pc-make-evidence-scaffold/SKILL.md +0 -0
  103. /package/{src/content → harness}/.agents/skills/pc-make-evidence-scaffold/evidence-contract.md +0 -0
  104. /package/{src/content → harness}/.agents/skills/pc-make-guardrails/SKILL.md +0 -0
  105. /package/{src/content → harness}/.agents/skills/pc-make-guardrails/category-reference.md +0 -0
  106. /package/{src/content → harness}/.agents/skills/pc-make-merge-risk-assess/SKILL.md +0 -0
  107. /package/{src/content → harness}/.agents/skills/pc-make-merge-risk-assess/category-reference.md +0 -0
  108. /package/{src/content → harness}/.agents/skills/pc-make-user-model/SKILL.md +0 -0
  109. /package/{src/content → harness}/.agents/skills/pc-ops-evidence/SKILL.md +0 -0
  110. /package/{src/content → harness}/.agents/skills/pc-ops-ship/SKILL.md +0 -0
  111. /package/{src/content → harness}/.agents/skills/pc-plan-apply/SKILL.md +0 -0
  112. /package/{src/content → harness}/.agents/skills/pc-plan-goal/failure-policy.md +0 -0
  113. /package/{src/content → harness}/.agents/skills/pc-plan-goal/output-mode.md +0 -0
  114. /package/{src/content → harness}/.agents/skills/pc-plan-propose/SKILL.md +0 -0
  115. /package/{src/content → harness}/.agents/skills/pc-plan-propose/task-annotation.md +0 -0
  116. /package/{src/content → harness}/.agents/skills/pc-plan-quick/SKILL.md +0 -0
  117. /package/{src/content → harness}/.agents/skills/pc-repo-audit/SKILL.md +0 -0
  118. /package/{src/content → harness}/.agents/skills/pc-repo-help/SKILL.md +0 -0
  119. /package/{src/content → harness}/.agents/skills/pc-repo-initialize/SKILL.md +0 -0
  120. /package/{src/content → harness}/.agents/skills/pc-repo-onboard/SKILL.md +0 -0
  121. /package/{src/content → harness}/.agents/skills/pc-repo-verify/SKILL.md +0 -0
  122. /package/{src/content → harness}/.agents/skills/pc-userstory-az/SKILL.md +0 -0
  123. /package/{src/content → harness}/.agents/skills/pc-userstory-gh/SKILL.md +0 -0
  124. /package/{src/content → harness}/.agents/skills/pc-userstory-jira/SKILL.md +0 -0
  125. /package/{src/content → harness}/.opencode/_gitignore +0 -0
  126. /package/{src/content → harness}/.opencode/commands/init.md +0 -0
  127. /package/{src/content → harness}/.opencode/commands/make-architecture.md +0 -0
  128. /package/{src/content → harness}/.opencode/commands/make-design.md +0 -0
  129. /package/{src/content → harness}/.opencode/commands/make-engineer.md +0 -0
  130. /package/{src/content → harness}/.opencode/commands/make-evidence-scaffold.md +0 -0
  131. /package/{src/content → harness}/.opencode/commands/make-guardrails.md +0 -0
  132. /package/{src/content → harness}/.opencode/commands/make-user-model.md +0 -0
  133. /package/{src/content → harness}/.opencode/commands/ops-backlog.md +0 -0
  134. /package/{src/content → harness}/.opencode/commands/ops-evidence.md +0 -0
  135. /package/{src/content → harness}/.opencode/commands/ops-review.md +0 -0
  136. /package/{src/content → harness}/.opencode/commands/ops-ship.md +0 -0
  137. /package/{src/content → harness}/.opencode/commands/plan-apply.md +0 -0
  138. /package/{src/content → harness}/.opencode/commands/plan-archive.md +0 -0
  139. /package/{src/content → harness}/.opencode/commands/plan-explore.md +0 -0
  140. /package/{src/content → harness}/.opencode/commands/plan-goal.md +0 -0
  141. /package/{src/content → harness}/.opencode/commands/plan-propose.md +0 -0
  142. /package/{src/content → harness}/.opencode/commands/plan-quick.md +0 -0
  143. /package/{src/content → harness}/.opencode/commands/plan-story.md +0 -0
  144. /package/{src/content → harness}/.opencode/commands/repo-audit.md +0 -0
  145. /package/{src/content → harness}/.opencode/commands/repo-help.md +0 -0
  146. /package/{src/content → harness}/.opencode/commands/repo-initialize.md +0 -0
  147. /package/{src/content → harness}/.opencode/commands/repo-onboard.md +0 -0
  148. /package/{src/content → harness}/.opencode/commands/repo-verify.md +0 -0
  149. /package/{src/content → harness}/.opencode/plugins/pc-subagent-monitor.js +0 -0
  150. /package/{src/content → harness}/.opencode/plugins/pc-system-reminders.js +0 -0
  151. /package/{src/content → harness}/.opencode/tui/pc-subagents.tsx +0 -0
  152. /package/{src/content → harness}/.opencode/tui.json +0 -0
  153. /package/{src/content → harness}/AGENTS.md +0 -0
  154. /package/{src/content → harness}/openspec/changes/archive/.gitkeep +0 -0
  155. /package/{src/content → harness}/openspec/specs/.gitkeep +0 -0
@@ -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: 'AminBlg/SimpleEnglish',
6
- sourceType: 'github',
7
- skillPath: 'skills/simple-english/SKILL.md',
8
- }
9
-
10
- export async function installSimpleEnglish(options = {}) {
11
- if (!options.skipHeader) header('Installing Simple English')
12
-
13
- info('Adding Simple English to skills-lock.json for batch install')
14
- await addSkillToLock('simple-english', SKILL_ENTRY)
15
- success('Simple English 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: 'AminBlg/SimpleEnglish',
6
+ sourceType: 'github',
7
+ skillPath: 'skills/simple-english/SKILL.md',
8
+ }
9
+
10
+ export async function installSimpleEnglish(options = {}) {
11
+ if (!options.skipHeader) header('Installing Simple English')
12
+
13
+ info('Adding Simple English to skills-lock.json for batch install')
14
+ await addSkillToLock('simple-english', SKILL_ENTRY)
15
+ success('Simple English queued for installation')
16
+ return { optedIn: true, installed: true }
17
+ }
@@ -1,30 +1,30 @@
1
- import fse from 'fs-extra'
2
- import path from 'path'
3
- import { info, warn } from '../../utils/exec.js'
4
-
5
- export async function addSkillToLock(skillName, entry) {
6
- if (!entry) {
7
- warn(`No entry provided for skills-lock.json: ${skillName}`)
8
- return false
9
- }
10
-
11
- const destLock = path.join(process.cwd(), 'skills-lock.json')
12
-
13
- let lock = { version: 1, skills: {} }
14
- if (await fse.pathExists(destLock)) {
15
- try {
16
- lock = await fse.readJson(destLock)
17
- if (!lock.skills) lock.skills = {}
18
- } catch {
19
- warn('Could not parse existing skills-lock.json, creating fresh')
20
- }
21
- }
22
-
23
- if (!lock.skills[skillName]) {
24
- lock.skills[skillName] = entry
25
- await fse.writeJson(destLock, lock, { spaces: 2 })
26
- info(`Added ${skillName} to skills-lock.json`)
27
- }
28
-
29
- return true
30
- }
1
+ import fse from 'fs-extra'
2
+ import path from 'path'
3
+ import { info, warn } from '../../utils/exec.js'
4
+
5
+ export async function addSkillToLock(skillName, entry) {
6
+ if (!entry) {
7
+ warn(`No entry provided for skills-lock.json: ${skillName}`)
8
+ return false
9
+ }
10
+
11
+ const destLock = path.join(process.cwd(), 'skills-lock.json')
12
+
13
+ let lock = { version: 1, skills: {} }
14
+ if (await fse.pathExists(destLock)) {
15
+ try {
16
+ lock = await fse.readJson(destLock)
17
+ if (!lock.skills) lock.skills = {}
18
+ } catch {
19
+ warn('Could not parse existing skills-lock.json, creating fresh')
20
+ }
21
+ }
22
+
23
+ if (!lock.skills[skillName]) {
24
+ lock.skills[skillName] = entry
25
+ await fse.writeJson(destLock, lock, { spaces: 2 })
26
+ info(`Added ${skillName} to skills-lock.json`)
27
+ }
28
+
29
+ return true
30
+ }
@@ -1,109 +1,109 @@
1
- import { select } 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, success, warn } from '../../utils/exec.js'
7
-
8
- const __dirname = path.dirname(fileURLToPath(import.meta.url))
9
- const PLATFORMS_PRESET_PATH = path.resolve(__dirname, '../../presets/platforms.json')
10
- const platformsPreset = await fse.readJson(PLATFORMS_PRESET_PATH)
11
-
12
-
13
- export async function checkPlatform(platform) {
14
- const preset = platformsPreset.find(p => p.value === platform) || platformsPreset[0]
15
- if (!preset.cli) {
16
- header(`Step 4, Checking ${preset.name} CLI`)
17
- info('No platform integration selected, skipping CLI checks.')
18
- success(`Platform: ${preset.name}`)
19
- return
20
- }
21
- await checkPlatformCli(preset)
22
- }
23
-
24
- export async function choosePlatform() {
25
- header('Step 3, Version control platform')
26
-
27
- const backlogChoices = platformsPreset.filter(p => !p.repoOnly)
28
- const backlogPlatform = await select({
29
- message: 'Where is your backlog (work items / issues)?',
30
- choices: backlogChoices.map(p => ({ name: p.name, value: p.value })),
31
- })
32
-
33
- const backlogPreset = platformsPreset.find(p => p.value === backlogPlatform)
34
- success(`Backlog platform: ${backlogPreset?.name || backlogPlatform}`)
35
-
36
- let repoPlatform = backlogPlatform
37
- if (backlogPlatform !== 'none') {
38
- // Exclude backlog-only platforms (e.g. Jira) from repo choices
39
- const repoChoices = platformsPreset.filter(p => !p.backlogOnly)
40
- repoPlatform = await select({
41
- message: 'Where is your code repository (PRs / code reviews)?',
42
- choices: repoChoices.map(p => ({ name: p.name, value: p.value })),
43
- default: backlogPreset.backlogOnly ? 'github' : backlogPlatform,
44
- })
45
- const repoPreset = platformsPreset.find(p => p.value === repoPlatform)
46
- success(`Repo platform: ${repoPreset?.name || repoPlatform}`)
47
- }
48
-
49
- // Check CLIs for both platforms (deduped)
50
- const platformsToCheck = [...new Set([backlogPlatform, repoPlatform])].filter(p => p !== 'none')
51
- for (const p of platformsToCheck) {
52
- const preset = platformsPreset.find(x => x.value === p)
53
- if (preset?.cli) await checkPlatformCli(preset)
54
- }
55
-
56
- return { backlogPlatform, repoPlatform }
57
- }
58
-
59
- async function checkPlatformCli(platformPreset) {
60
- const { cli } = platformPreset
61
- header(`Step 4, Checking ${platformPreset.name} CLI`)
62
-
63
- const hasCli = await commandExists(cli.command)
64
- if (!hasCli) {
65
- warn(`${cli.displayName} not found.`)
66
- info(`Install from: ${cli.installUrl}`)
67
- if (cli.authCheck?.commands?.length) {
68
- console.log()
69
- info('After installing, authenticate with:')
70
- code(cli.authCheck.commands)
71
- }
72
- return
73
- }
74
- success(`${cli.displayName} available`)
75
-
76
- if (cli.authCheck) await runAuthCheck(cli)
77
- if (cli.extensionCheck) await runExtensionCheck(cli)
78
- }
79
-
80
- async function runAuthCheck(cli) {
81
- try {
82
- const result = await execa(cli.command, cli.authCheck.args, { reject: false })
83
- if (result.exitCode === 0) {
84
- success(`${cli.displayName} authenticated`)
85
- } else {
86
- warn(cli.authCheck.notAuthenticatedMessage)
87
- code(cli.authCheck.commands)
88
- }
89
- } catch {
90
- warn(`Could not check ${cli.command} auth status.`)
91
- }
92
- }
93
-
94
- async function runExtensionCheck(cli) {
95
- try {
96
- const result = await execa(cli.command, cli.extensionCheck.args, { reject: false })
97
- const hasExtension = result.stdout && result.stdout.includes(cli.extensionCheck.expectedOutput)
98
-
99
- if (hasExtension) {
100
- success(`${cli.extensionCheck.expectedOutput} extension installed`)
101
- } else {
102
- warn(cli.extensionCheck.missingMessage)
103
- code(cli.extensionCheck.commands)
104
- }
105
- } catch {
106
- warn(cli.extensionCheck.errorMessage)
107
- code(cli.extensionCheck.commands)
108
- }
109
- }
1
+ import { select } 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, success, warn } from '../../utils/exec.js'
7
+
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
9
+ const PLATFORMS_PRESET_PATH = path.resolve(__dirname, '../../presets/platforms.json')
10
+ const platformsPreset = await fse.readJson(PLATFORMS_PRESET_PATH)
11
+
12
+
13
+ export async function checkPlatform(platform) {
14
+ const preset = platformsPreset.find(p => p.value === platform) || platformsPreset[0]
15
+ if (!preset.cli) {
16
+ header(`Step 4, Checking ${preset.name} CLI`)
17
+ info('No platform integration selected, skipping CLI checks.')
18
+ success(`Platform: ${preset.name}`)
19
+ return
20
+ }
21
+ await checkPlatformCli(preset)
22
+ }
23
+
24
+ export async function choosePlatform() {
25
+ header('Step 3, Version control platform')
26
+
27
+ const backlogChoices = platformsPreset.filter(p => !p.repoOnly)
28
+ const backlogPlatform = await select({
29
+ message: 'Where is your backlog (work items / issues)?',
30
+ choices: backlogChoices.map(p => ({ name: p.name, value: p.value })),
31
+ })
32
+
33
+ const backlogPreset = platformsPreset.find(p => p.value === backlogPlatform)
34
+ success(`Backlog platform: ${backlogPreset?.name || backlogPlatform}`)
35
+
36
+ let repoPlatform = backlogPlatform
37
+ if (backlogPlatform !== 'none') {
38
+ // Exclude backlog-only platforms (e.g. Jira) from repo choices
39
+ const repoChoices = platformsPreset.filter(p => !p.backlogOnly)
40
+ repoPlatform = await select({
41
+ message: 'Where is your code repository (PRs / code reviews)?',
42
+ choices: repoChoices.map(p => ({ name: p.name, value: p.value })),
43
+ default: backlogPreset.backlogOnly ? 'github' : backlogPlatform,
44
+ })
45
+ const repoPreset = platformsPreset.find(p => p.value === repoPlatform)
46
+ success(`Repo platform: ${repoPreset?.name || repoPlatform}`)
47
+ }
48
+
49
+ // Check CLIs for both platforms (deduped)
50
+ const platformsToCheck = [...new Set([backlogPlatform, repoPlatform])].filter(p => p !== 'none')
51
+ for (const p of platformsToCheck) {
52
+ const preset = platformsPreset.find(x => x.value === p)
53
+ if (preset?.cli) await checkPlatformCli(preset)
54
+ }
55
+
56
+ return { backlogPlatform, repoPlatform }
57
+ }
58
+
59
+ async function checkPlatformCli(platformPreset) {
60
+ const { cli } = platformPreset
61
+ header(`Step 4, Checking ${platformPreset.name} CLI`)
62
+
63
+ const hasCli = await commandExists(cli.command)
64
+ if (!hasCli) {
65
+ warn(`${cli.displayName} not found.`)
66
+ info(`Install from: ${cli.installUrl}`)
67
+ if (cli.authCheck?.commands?.length) {
68
+ console.log()
69
+ info('After installing, authenticate with:')
70
+ code(cli.authCheck.commands)
71
+ }
72
+ return
73
+ }
74
+ success(`${cli.displayName} available`)
75
+
76
+ if (cli.authCheck) await runAuthCheck(cli)
77
+ if (cli.extensionCheck) await runExtensionCheck(cli)
78
+ }
79
+
80
+ async function runAuthCheck(cli) {
81
+ try {
82
+ const result = await execa(cli.command, cli.authCheck.args, { reject: false })
83
+ if (result.exitCode === 0) {
84
+ success(`${cli.displayName} authenticated`)
85
+ } else {
86
+ warn(cli.authCheck.notAuthenticatedMessage)
87
+ code(cli.authCheck.commands)
88
+ }
89
+ } catch {
90
+ warn(`Could not check ${cli.command} auth status.`)
91
+ }
92
+ }
93
+
94
+ async function runExtensionCheck(cli) {
95
+ try {
96
+ const result = await execa(cli.command, cli.extensionCheck.args, { reject: false })
97
+ const hasExtension = result.stdout && result.stdout.includes(cli.extensionCheck.expectedOutput)
98
+
99
+ if (hasExtension) {
100
+ success(`${cli.extensionCheck.expectedOutput} extension installed`)
101
+ } else {
102
+ warn(cli.extensionCheck.missingMessage)
103
+ code(cli.extensionCheck.commands)
104
+ }
105
+ } catch {
106
+ warn(cli.extensionCheck.errorMessage)
107
+ code(cli.extensionCheck.commands)
108
+ }
109
+ }
@@ -1,123 +1,123 @@
1
- import { checkbox, select } from '@inquirer/prompts'
2
- import fse from 'fs-extra'
3
- import path from 'path'
4
- import { fileURLToPath } from 'url'
5
- import { header, info, success, warn } from '../../utils/exec.js'
6
-
7
- const __dirname = path.dirname(fileURLToPath(import.meta.url))
8
- const SOURCE_PRESET_PATH = path.resolve(__dirname, '../../presets/source.json')
9
- const sourcePreset = await fse.readJson(SOURCE_PRESET_PATH)
10
-
11
- async function listChildFolders(cwd) {
12
- const entries = await fse.readdir(cwd)
13
- const dirs = []
14
-
15
- for (const name of entries) {
16
- if (name.startsWith('.')) continue
17
- const abs = path.join(cwd, name)
18
- try {
19
- const stat = await fse.stat(abs)
20
- if (!stat.isDirectory()) continue
21
- dirs.push({ name, abs })
22
- } catch {
23
- // ignore invalid entries
24
- }
25
- }
26
-
27
- dirs.sort((a, b) => a.name.localeCompare(b.name))
28
- return dirs
29
- }
30
-
31
- async function listParentFolders(cwd) {
32
- const parent = path.resolve(cwd, '..')
33
- const entries = await fse.readdir(parent)
34
- const dirs = []
35
-
36
- for (const name of entries) {
37
- if (name.startsWith('.')) continue
38
- const abs = path.join(parent, name)
39
- try {
40
- const stat = await fse.stat(abs)
41
- if (!stat.isDirectory()) continue
42
- if (path.resolve(abs) === path.resolve(cwd)) continue
43
- dirs.push({ name, abs })
44
- } catch {
45
- // ignore invalid entries
46
- }
47
- }
48
-
49
- dirs.sort((a, b) => a.name.localeCompare(b.name))
50
- return dirs
51
- }
52
-
53
- export async function chooseSourceScope() {
54
- header('Step 1, Source code scope')
55
-
56
- const cwd = process.cwd()
57
- info('Choose where agents should read source code from during init analysis.')
58
-
59
- const mode = await select({
60
- message: sourcePreset.message,
61
- default: sourcePreset.default,
62
- choices: sourcePreset.choices,
63
- })
64
-
65
- if (mode === 'current') {
66
- success(`Source scope: ${cwd}`)
67
- return { sourceMode: 'current', sourceRoots: [cwd] }
68
- }
69
-
70
- if (mode === 'children') {
71
- const childFolders = await listChildFolders(cwd)
72
- if (childFolders.length === 0) {
73
- warn('No child folders found in current directory. Falling back to current folder.')
74
- success(`Source scope: ${cwd}`)
75
- return { sourceMode: 'current', sourceRoots: [cwd] }
76
- }
77
-
78
- const selected = await checkbox({
79
- message: sourcePreset.childrenSelectionMessage,
80
- choices: childFolders.map(d => ({
81
- name: `./${d.name}`,
82
- value: d.abs,
83
- checked: true,
84
- })),
85
- required: true,
86
- })
87
-
88
- if (!selected || selected.length === 0) {
89
- warn('No folders selected. Falling back to current folder.')
90
- success(`Source scope: ${cwd}`)
91
- return { sourceMode: 'current', sourceRoots: [cwd] }
92
- }
93
-
94
- success(`Source scope: ${selected.map(p => path.basename(p)).join(', ')}`)
95
- return { sourceMode: 'children-selected', sourceRoots: selected }
96
- }
97
-
98
- const parentFolders = await listParentFolders(cwd)
99
- if (parentFolders.length === 0) {
100
- warn('No sibling folders found in parent directory. Falling back to current folder.')
101
- success(`Source scope: ${cwd}`)
102
- return { sourceMode: 'current', sourceRoots: [cwd] }
103
- }
104
-
105
- const selected = await checkbox({
106
- message: sourcePreset.parentSelectionMessage,
107
- choices: parentFolders.map(d => ({
108
- name: `../${d.name}`,
109
- value: d.abs,
110
- checked: true,
111
- })),
112
- required: true,
113
- })
114
-
115
- if (!selected || selected.length === 0) {
116
- warn('No folders selected. Falling back to current folder.')
117
- success(`Source scope: ${cwd}`)
118
- return { sourceMode: 'current', sourceRoots: [cwd] }
119
- }
120
-
121
- success(`Source scope: ${selected.map(p => path.basename(p)).join(', ')}`)
122
- return { sourceMode: 'parent-selected', sourceRoots: selected }
123
- }
1
+ import { checkbox, select } from '@inquirer/prompts'
2
+ import fse from 'fs-extra'
3
+ import path from 'path'
4
+ import { fileURLToPath } from 'url'
5
+ import { header, info, success, warn } from '../../utils/exec.js'
6
+
7
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
8
+ const SOURCE_PRESET_PATH = path.resolve(__dirname, '../../presets/source.json')
9
+ const sourcePreset = await fse.readJson(SOURCE_PRESET_PATH)
10
+
11
+ async function listChildFolders(cwd) {
12
+ const entries = await fse.readdir(cwd)
13
+ const dirs = []
14
+
15
+ for (const name of entries) {
16
+ if (name.startsWith('.')) continue
17
+ const abs = path.join(cwd, name)
18
+ try {
19
+ const stat = await fse.stat(abs)
20
+ if (!stat.isDirectory()) continue
21
+ dirs.push({ name, abs })
22
+ } catch {
23
+ // ignore invalid entries
24
+ }
25
+ }
26
+
27
+ dirs.sort((a, b) => a.name.localeCompare(b.name))
28
+ return dirs
29
+ }
30
+
31
+ async function listParentFolders(cwd) {
32
+ const parent = path.resolve(cwd, '..')
33
+ const entries = await fse.readdir(parent)
34
+ const dirs = []
35
+
36
+ for (const name of entries) {
37
+ if (name.startsWith('.')) continue
38
+ const abs = path.join(parent, name)
39
+ try {
40
+ const stat = await fse.stat(abs)
41
+ if (!stat.isDirectory()) continue
42
+ if (path.resolve(abs) === path.resolve(cwd)) continue
43
+ dirs.push({ name, abs })
44
+ } catch {
45
+ // ignore invalid entries
46
+ }
47
+ }
48
+
49
+ dirs.sort((a, b) => a.name.localeCompare(b.name))
50
+ return dirs
51
+ }
52
+
53
+ export async function chooseSourceScope() {
54
+ header('Step 1, Source code scope')
55
+
56
+ const cwd = process.cwd()
57
+ info('Choose where agents should read source code from during init analysis.')
58
+
59
+ const mode = await select({
60
+ message: sourcePreset.message,
61
+ default: sourcePreset.default,
62
+ choices: sourcePreset.choices,
63
+ })
64
+
65
+ if (mode === 'current') {
66
+ success(`Source scope: ${cwd}`)
67
+ return { sourceMode: 'current', sourceRoots: [cwd] }
68
+ }
69
+
70
+ if (mode === 'children') {
71
+ const childFolders = await listChildFolders(cwd)
72
+ if (childFolders.length === 0) {
73
+ warn('No child folders found in current directory. Falling back to current folder.')
74
+ success(`Source scope: ${cwd}`)
75
+ return { sourceMode: 'current', sourceRoots: [cwd] }
76
+ }
77
+
78
+ const selected = await checkbox({
79
+ message: sourcePreset.childrenSelectionMessage,
80
+ choices: childFolders.map(d => ({
81
+ name: `./${d.name}`,
82
+ value: d.abs,
83
+ checked: true,
84
+ })),
85
+ required: true,
86
+ })
87
+
88
+ if (!selected || selected.length === 0) {
89
+ warn('No folders selected. Falling back to current folder.')
90
+ success(`Source scope: ${cwd}`)
91
+ return { sourceMode: 'current', sourceRoots: [cwd] }
92
+ }
93
+
94
+ success(`Source scope: ${selected.map(p => path.basename(p)).join(', ')}`)
95
+ return { sourceMode: 'children-selected', sourceRoots: selected }
96
+ }
97
+
98
+ const parentFolders = await listParentFolders(cwd)
99
+ if (parentFolders.length === 0) {
100
+ warn('No sibling folders found in parent directory. Falling back to current folder.')
101
+ success(`Source scope: ${cwd}`)
102
+ return { sourceMode: 'current', sourceRoots: [cwd] }
103
+ }
104
+
105
+ const selected = await checkbox({
106
+ message: sourcePreset.parentSelectionMessage,
107
+ choices: parentFolders.map(d => ({
108
+ name: `../${d.name}`,
109
+ value: d.abs,
110
+ checked: true,
111
+ })),
112
+ required: true,
113
+ })
114
+
115
+ if (!selected || selected.length === 0) {
116
+ warn('No folders selected. Falling back to current folder.')
117
+ success(`Source scope: ${cwd}`)
118
+ return { sourceMode: 'current', sourceRoots: [cwd] }
119
+ }
120
+
121
+ success(`Source scope: ${selected.map(p => path.basename(p)).join(', ')}`)
122
+ return { sourceMode: 'parent-selected', sourceRoots: selected }
123
+ }