@oneworks/cli 0.1.0-alpha.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 -0
- package/channel.js +7 -0
- package/cli.js +5 -0
- package/mem.js +7 -0
- package/package.json +59 -0
- package/postinstall.js +75 -0
- package/src/AGENTS.md +169 -0
- package/src/channel-cli.ts +19 -0
- package/src/cli-argv.ts +27 -0
- package/src/cli.ts +63 -0
- package/src/commands/@core/adapter-option.ts +85 -0
- package/src/commands/@core/extra-options.ts +12 -0
- package/src/commands/@core/plugin-install.ts +1 -0
- package/src/commands/@core/plugin-source.ts +1 -0
- package/src/commands/accounts.ts +204 -0
- package/src/commands/adapter/prepare-selection.ts +181 -0
- package/src/commands/adapter/prepare.ts +104 -0
- package/src/commands/adapter.ts +48 -0
- package/src/commands/agent/actions.ts +176 -0
- package/src/commands/agent/runtime-store-commands.ts +56 -0
- package/src/commands/agent/runtime-store-events.ts +23 -0
- package/src/commands/agent/runtime-store-session.ts +170 -0
- package/src/commands/agent/runtime-store-shared.ts +139 -0
- package/src/commands/agent/runtime-store.ts +4 -0
- package/src/commands/agent.ts +81 -0
- package/src/commands/benchmark.ts +198 -0
- package/src/commands/channel.ts +594 -0
- package/src/commands/clear.ts +140 -0
- package/src/commands/config/actions.ts +196 -0
- package/src/commands/config/display-state.ts +108 -0
- package/src/commands/config/index.ts +135 -0
- package/src/commands/config/interactive.ts +121 -0
- package/src/commands/config/read-state.ts +56 -0
- package/src/commands/config/section-state.ts +109 -0
- package/src/commands/config/shared.ts +195 -0
- package/src/commands/kill.ts +41 -0
- package/src/commands/list.ts +224 -0
- package/src/commands/memory/context.ts +76 -0
- package/src/commands/memory/entries.ts +131 -0
- package/src/commands/memory/shared.ts +89 -0
- package/src/commands/memory/store.ts +69 -0
- package/src/commands/memory/target.ts +54 -0
- package/src/commands/memory.ts +97 -0
- package/src/commands/plugin.ts +62 -0
- package/src/commands/report-targets.ts +149 -0
- package/src/commands/report.ts +232 -0
- package/src/commands/run/adapter-cli-version.ts +65 -0
- package/src/commands/run/command.ts +982 -0
- package/src/commands/run/input-bridge.ts +108 -0
- package/src/commands/run/input-control.ts +112 -0
- package/src/commands/run/input-decision.ts +88 -0
- package/src/commands/run/options.ts +104 -0
- package/src/commands/run/output.ts +179 -0
- package/src/commands/run/permission-decision.ts +19 -0
- package/src/commands/run/permission-recovery.ts +194 -0
- package/src/commands/run/permission-state.ts +177 -0
- package/src/commands/run/print-idle-timeout.ts +47 -0
- package/src/commands/run/protocol-envelope.ts +111 -0
- package/src/commands/run/protocol-stdio.ts +71 -0
- package/src/commands/run/protocol.ts +391 -0
- package/src/commands/run/runtime-command-bridge.ts +190 -0
- package/src/commands/run/runtime-event-sink.ts +560 -0
- package/src/commands/run/session-exit-controller.ts +45 -0
- package/src/commands/run/types.ts +65 -0
- package/src/commands/run.ts +62 -0
- package/src/commands/session-control.ts +133 -0
- package/src/commands/skills/add-command.ts +88 -0
- package/src/commands/skills/install-command.ts +105 -0
- package/src/commands/skills/install.ts +216 -0
- package/src/commands/skills/progress.ts +126 -0
- package/src/commands/skills/publish-command.ts +85 -0
- package/src/commands/skills/register.ts +17 -0
- package/src/commands/skills/remove-command.ts +102 -0
- package/src/commands/skills/shared.ts +117 -0
- package/src/commands/skills/sync.ts +571 -0
- package/src/commands/skills/types.ts +33 -0
- package/src/commands/skills.ts +1 -0
- package/src/commands/stop.ts +41 -0
- package/src/config.ts +1 -0
- package/src/default-skill-plugin.ts +29 -0
- package/src/env.ts +1 -0
- package/src/hooks/plugins/index.ts +66 -0
- package/src/mem-cli.ts +19 -0
- package/src/session-cache.ts +250 -0
- package/src/session-permission-cache.ts +40 -0
- package/src/utils.ts +25 -0
- package/src/workspace.ts +12 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import process from 'node:process'
|
|
2
|
+
|
|
3
|
+
export interface SkillsProgressReporter {
|
|
4
|
+
completeStep: (label: string) => void
|
|
5
|
+
fail: (label?: string) => void
|
|
6
|
+
failStep: (label: string) => void
|
|
7
|
+
finish: (summary?: string) => void
|
|
8
|
+
startStep: (label: string) => void
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const BAR_WIDTH = 20
|
|
12
|
+
const TICK_MS = 120
|
|
13
|
+
const SPINNER_FRAMES = ['-', '\\', '|', '/']
|
|
14
|
+
|
|
15
|
+
const formatElapsed = (startedAt: number) => {
|
|
16
|
+
const totalSeconds = Math.max(0, Math.floor((Date.now() - startedAt) / 1000))
|
|
17
|
+
const minutes = Math.floor(totalSeconds / 60)
|
|
18
|
+
const seconds = totalSeconds % 60
|
|
19
|
+
return `${minutes}:${seconds.toString().padStart(2, '0')}`
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const trimToWidth = (value: string, width: number) => (
|
|
23
|
+
value.length <= width ? value : `${value.slice(0, Math.max(0, width - 3))}...`
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
export const createSkillsProgress = (params: {
|
|
27
|
+
enabled?: boolean
|
|
28
|
+
} = {}): SkillsProgressReporter => {
|
|
29
|
+
const enabled = params.enabled !== false && process.env.VITEST_WORKER_ID == null
|
|
30
|
+
const startedAt = Date.now()
|
|
31
|
+
const tty = Boolean(process.stderr.isTTY)
|
|
32
|
+
let activeLabel: string | undefined
|
|
33
|
+
let completed = 0
|
|
34
|
+
let failed = false
|
|
35
|
+
let frame = 0
|
|
36
|
+
let interval: NodeJS.Timeout | undefined
|
|
37
|
+
let total = 0
|
|
38
|
+
let wrote = false
|
|
39
|
+
|
|
40
|
+
const buildLine = (label = activeLabel ?? 'Done') => {
|
|
41
|
+
const ratio = total === 0 ? 1 : completed / total
|
|
42
|
+
const filled = Math.max(0, Math.min(BAR_WIDTH, Math.round(ratio * BAR_WIDTH)))
|
|
43
|
+
const bar = `${'#'.repeat(filled)}${'.'.repeat(BAR_WIDTH - filled)}`
|
|
44
|
+
const spinner = activeLabel == null ? ' ' : SPINNER_FRAMES[frame % SPINNER_FRAMES.length]
|
|
45
|
+
return `[oneworks] ${spinner} [${bar}] ${completed}/${total} ${trimToWidth(label, 72)} ${formatElapsed(startedAt)}`
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const render = () => {
|
|
49
|
+
if (!enabled || total === 0) return
|
|
50
|
+
wrote = true
|
|
51
|
+
if (tty) {
|
|
52
|
+
process.stderr.write(`\r${buildLine()}\x1B[K`)
|
|
53
|
+
frame++
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (activeLabel != null) {
|
|
58
|
+
process.stderr.write(`${buildLine(activeLabel)}\n`)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const ensureTicker = () => {
|
|
63
|
+
if (!enabled || !tty || interval != null) return
|
|
64
|
+
interval = setInterval(render, TICK_MS)
|
|
65
|
+
interval.unref()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const stopTicker = () => {
|
|
69
|
+
if (interval == null) return
|
|
70
|
+
clearInterval(interval)
|
|
71
|
+
interval = undefined
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const finishLine = (summary?: string) => {
|
|
75
|
+
if (!enabled || !wrote) return
|
|
76
|
+
const label = summary ?? (failed ? 'Failed' : 'Done')
|
|
77
|
+
if (tty) {
|
|
78
|
+
process.stderr.write(`\r${buildLine(label)}\x1B[K\n`)
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
process.stderr.write(`[oneworks] ${label} (${formatElapsed(startedAt)})\n`)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
startStep(label) {
|
|
86
|
+
if (!enabled) return
|
|
87
|
+
total++
|
|
88
|
+
activeLabel = label
|
|
89
|
+
render()
|
|
90
|
+
ensureTicker()
|
|
91
|
+
},
|
|
92
|
+
completeStep(label) {
|
|
93
|
+
if (!enabled) return
|
|
94
|
+
completed = Math.min(total, completed + 1)
|
|
95
|
+
activeLabel = undefined
|
|
96
|
+
if (!tty) {
|
|
97
|
+
process.stderr.write(`[oneworks] done ${label} (${completed}/${total}, ${formatElapsed(startedAt)})\n`)
|
|
98
|
+
} else {
|
|
99
|
+
render()
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
failStep(label) {
|
|
103
|
+
if (!enabled) return
|
|
104
|
+
failed = true
|
|
105
|
+
activeLabel = undefined
|
|
106
|
+
if (!tty) {
|
|
107
|
+
process.stderr.write(`[oneworks] failed ${label} (${formatElapsed(startedAt)})\n`)
|
|
108
|
+
} else {
|
|
109
|
+
render()
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
fail(label) {
|
|
113
|
+
if (!enabled) return
|
|
114
|
+
failed = true
|
|
115
|
+
activeLabel = undefined
|
|
116
|
+
stopTicker()
|
|
117
|
+
finishLine(label ?? 'Failed')
|
|
118
|
+
},
|
|
119
|
+
finish(summary) {
|
|
120
|
+
if (!enabled) return
|
|
121
|
+
activeLabel = undefined
|
|
122
|
+
stopTicker()
|
|
123
|
+
finishLine(summary)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { Command } from 'commander'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
publishSkillsCli,
|
|
5
|
+
resolveConfiguredSkillRegistries,
|
|
6
|
+
resolveProjectSkillPublishSpec,
|
|
7
|
+
resolveSkillsRegistry
|
|
8
|
+
} from '@oneworks/utils'
|
|
9
|
+
|
|
10
|
+
import { resolveCliWorkspaceCwd } from '#~/workspace.js'
|
|
11
|
+
|
|
12
|
+
import { exitWithError, loadSkillsConfigState, printResult } from './shared'
|
|
13
|
+
import type { SkillsPublishOptions } from './types'
|
|
14
|
+
|
|
15
|
+
export const registerPublishSkillSubcommand = (skillsCommand: Command) => {
|
|
16
|
+
skillsCommand
|
|
17
|
+
.command('publish <skill>')
|
|
18
|
+
.description('Publish a local project skill, local path, or remote skill spec through the active skills CLI')
|
|
19
|
+
.option('--access <access>', 'Publish access level passed to the skills CLI')
|
|
20
|
+
.option('--group [name]', 'Publish to a specific group; pass bare --group to select interactively')
|
|
21
|
+
.option('--region <region>', 'Publish region passed to the skills CLI')
|
|
22
|
+
.option('--registry <registry>', 'Package registry used to install the managed skills CLI')
|
|
23
|
+
.option('-y, --yes', 'Skip confirmation prompts when the underlying skills CLI supports it', false)
|
|
24
|
+
.option('--json', 'Print JSON output', false)
|
|
25
|
+
.action(async (skill: string, opts: SkillsPublishOptions) => {
|
|
26
|
+
try {
|
|
27
|
+
const workspaceFolder = resolveCliWorkspaceCwd()
|
|
28
|
+
const state = await loadSkillsConfigState(workspaceFolder)
|
|
29
|
+
const resolved = await resolveProjectSkillPublishSpec({
|
|
30
|
+
selector: skill,
|
|
31
|
+
workspaceFolder
|
|
32
|
+
})
|
|
33
|
+
const publishSource = typeof resolved.publish?.source === 'string'
|
|
34
|
+
? resolved.publish.source
|
|
35
|
+
: resolved.publish?.registry
|
|
36
|
+
const boundRegistry = typeof publishSource === 'string'
|
|
37
|
+
? resolveConfiguredSkillRegistries(state.mergedConfig).find(entry => entry.source === publishSource)
|
|
38
|
+
: undefined
|
|
39
|
+
if (publishSource != null && boundRegistry == null && opts.registry == null) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`Configured publish source "${publishSource}" was not found in skillRegistries.`
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
const published = await publishSkillsCli({
|
|
45
|
+
access: opts.access ?? resolved.publish?.access ?? boundRegistry?.publish?.access,
|
|
46
|
+
cwd: workspaceFolder,
|
|
47
|
+
group: opts.group ?? resolved.publish?.group ?? boundRegistry?.publish?.group,
|
|
48
|
+
region: opts.region ?? resolved.publish?.region ?? boundRegistry?.publish?.region,
|
|
49
|
+
registry: opts.registry ?? boundRegistry?.registry ?? resolveSkillsRegistry(state.mergedConfig.skills),
|
|
50
|
+
skillSpec: resolved.skillSpec,
|
|
51
|
+
yes: opts.yes
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
if (opts.json) {
|
|
55
|
+
printResult({
|
|
56
|
+
action: 'publish',
|
|
57
|
+
boundSource: boundRegistry?.source,
|
|
58
|
+
output: published.output,
|
|
59
|
+
requested: resolved.requested,
|
|
60
|
+
skillSpec: resolved.skillSpec,
|
|
61
|
+
source: resolved.kind,
|
|
62
|
+
workspaceFolder
|
|
63
|
+
}, true)
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const output = published.output.trim()
|
|
68
|
+
if (output !== '') {
|
|
69
|
+
console.log(output)
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
printResult({
|
|
74
|
+
action: 'publish',
|
|
75
|
+
...(boundRegistry != null ? { boundSource: boundRegistry.source } : {}),
|
|
76
|
+
requested: resolved.requested,
|
|
77
|
+
skillSpec: resolved.skillSpec,
|
|
78
|
+
source: resolved.kind,
|
|
79
|
+
workspaceFolder
|
|
80
|
+
})
|
|
81
|
+
} catch (error) {
|
|
82
|
+
exitWithError(error, opts.json)
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Command } from 'commander'
|
|
2
|
+
|
|
3
|
+
import { registerAddSkillSubcommand } from './add-command'
|
|
4
|
+
import { registerInstallSkillSubcommands } from './install-command'
|
|
5
|
+
import { registerPublishSkillSubcommand } from './publish-command'
|
|
6
|
+
import { registerRemoveSkillSubcommand } from './remove-command'
|
|
7
|
+
|
|
8
|
+
export function registerSkillsCommand(program: Command) {
|
|
9
|
+
const skillsCommand = program
|
|
10
|
+
.command('skills')
|
|
11
|
+
.description('Install and manage project skills declared in workspace config')
|
|
12
|
+
|
|
13
|
+
registerAddSkillSubcommand(skillsCommand)
|
|
14
|
+
registerInstallSkillSubcommands(skillsCommand)
|
|
15
|
+
registerRemoveSkillSubcommand(skillsCommand)
|
|
16
|
+
registerPublishSkillSubcommand(skillsCommand)
|
|
17
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Option } from 'commander'
|
|
2
|
+
import type { Command } from 'commander'
|
|
3
|
+
|
|
4
|
+
import type { ConfigSource } from '@oneworks/config'
|
|
5
|
+
import { updateConfigFile } from '@oneworks/config'
|
|
6
|
+
import { normalizeProjectSkillInstall, removeProjectSkill, resolveConfiguredSkillInstalls } from '@oneworks/utils'
|
|
7
|
+
|
|
8
|
+
import { resolveCliWorkspaceCwd } from '#~/workspace.js'
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
buildGeneralSkillsUpdateValue,
|
|
12
|
+
exitWithError,
|
|
13
|
+
getRawSourceConfig,
|
|
14
|
+
loadSkillsConfigState,
|
|
15
|
+
matchesSkillSelector,
|
|
16
|
+
normalizeString,
|
|
17
|
+
printResult,
|
|
18
|
+
resolveInstalledSkillDirNames
|
|
19
|
+
} from './shared'
|
|
20
|
+
import { CONFIG_REMOVE_SOURCES } from './types'
|
|
21
|
+
import type { SkillsRemoveOptions } from './types'
|
|
22
|
+
|
|
23
|
+
export const registerRemoveSkillSubcommand = (skillsCommand: Command) => {
|
|
24
|
+
skillsCommand
|
|
25
|
+
.command('remove <skill>')
|
|
26
|
+
.description('Remove a configured project skill and delete the local installed directory')
|
|
27
|
+
.addOption(
|
|
28
|
+
new Option('--config-source <source>', 'Config source(s) to update').choices([...CONFIG_REMOVE_SOURCES]).default(
|
|
29
|
+
'all'
|
|
30
|
+
)
|
|
31
|
+
)
|
|
32
|
+
.option('--keep-files', 'Only update config and keep local installed files', false)
|
|
33
|
+
.option('--json', 'Print JSON output', false)
|
|
34
|
+
.action(async (skill: string, opts: SkillsRemoveOptions) => {
|
|
35
|
+
try {
|
|
36
|
+
const workspaceFolder = resolveCliWorkspaceCwd()
|
|
37
|
+
const state = await loadSkillsConfigState(workspaceFolder)
|
|
38
|
+
const selector = normalizeString(skill)
|
|
39
|
+
if (selector == null) {
|
|
40
|
+
throw new Error('Skill selector is required.')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const removedConfigSources: string[] = []
|
|
44
|
+
const removedDirNames = new Set<string>()
|
|
45
|
+
const sources: ConfigSource[] = opts.configSource === 'all'
|
|
46
|
+
? ['global', 'project', 'user']
|
|
47
|
+
: [opts.configSource ?? 'project']
|
|
48
|
+
|
|
49
|
+
for (const source of sources) {
|
|
50
|
+
const sourceConfig = getRawSourceConfig(state, source)
|
|
51
|
+
const configured = resolveConfiguredSkillInstalls(sourceConfig?.skills)
|
|
52
|
+
const remaining = configured.filter(item => !matchesSkillSelector(selector, item))
|
|
53
|
+
const matched = configured.filter(item => matchesSkillSelector(selector, item))
|
|
54
|
+
if (matched.length === 0) continue
|
|
55
|
+
|
|
56
|
+
for (const item of matched) {
|
|
57
|
+
const normalized = normalizeProjectSkillInstall(item)
|
|
58
|
+
if (normalized != null) {
|
|
59
|
+
removedDirNames.add(normalized.targetDirName)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
await updateConfigFile({
|
|
64
|
+
workspaceFolder,
|
|
65
|
+
source,
|
|
66
|
+
section: 'general',
|
|
67
|
+
value: buildGeneralSkillsUpdateValue(sourceConfig, remaining)
|
|
68
|
+
})
|
|
69
|
+
removedConfigSources.push(source)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const installedDirNames = await resolveInstalledSkillDirNames(workspaceFolder, selector)
|
|
73
|
+
for (const dirName of installedDirNames) {
|
|
74
|
+
removedDirNames.add(dirName)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const removedDirs = opts.keepFiles === true
|
|
78
|
+
? []
|
|
79
|
+
: await Promise.all(
|
|
80
|
+
Array.from(removedDirNames).map(dirName =>
|
|
81
|
+
removeProjectSkill({
|
|
82
|
+
dirName,
|
|
83
|
+
workspaceFolder
|
|
84
|
+
})
|
|
85
|
+
)
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
if (removedConfigSources.length === 0 && removedDirs.length === 0) {
|
|
89
|
+
throw new Error(`No configured or installed skill matched "${selector}".`)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
printResult({
|
|
93
|
+
action: 'remove',
|
|
94
|
+
removedConfigSources,
|
|
95
|
+
removedDirs: removedDirs.map(item => item.installDir),
|
|
96
|
+
workspaceFolder
|
|
97
|
+
}, opts.json)
|
|
98
|
+
} catch (error) {
|
|
99
|
+
exitWithError(error, opts.json)
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { access } from 'node:fs/promises'
|
|
2
|
+
import process from 'node:process'
|
|
3
|
+
|
|
4
|
+
import type { ConfigSource } from '@oneworks/config'
|
|
5
|
+
import { buildConfigJsonVariables, loadConfigState } from '@oneworks/config'
|
|
6
|
+
import type { Config, ConfiguredSkillInstallConfig } from '@oneworks/types'
|
|
7
|
+
import {
|
|
8
|
+
buildSkillsConfigValue,
|
|
9
|
+
isSameDeclaredSkill,
|
|
10
|
+
matchesDeclaredSkillSelector,
|
|
11
|
+
readProjectSkills,
|
|
12
|
+
toSkillSlug
|
|
13
|
+
} from '@oneworks/utils'
|
|
14
|
+
|
|
15
|
+
const normalizeString = (value: unknown) => (
|
|
16
|
+
typeof value === 'string' && value.trim() !== '' ? value.trim() : undefined
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
const pathExists = async (targetPath: string) => {
|
|
20
|
+
try {
|
|
21
|
+
await access(targetPath)
|
|
22
|
+
return true
|
|
23
|
+
} catch {
|
|
24
|
+
return false
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const printResult = (value: unknown, json = false) => {
|
|
29
|
+
if (json) {
|
|
30
|
+
console.log(JSON.stringify(
|
|
31
|
+
value != null && typeof value === 'object' && !Array.isArray(value)
|
|
32
|
+
? { ok: true, ...(value as Record<string, unknown>) }
|
|
33
|
+
: { ok: true, value },
|
|
34
|
+
null,
|
|
35
|
+
2
|
|
36
|
+
))
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (typeof value === 'string') {
|
|
41
|
+
console.log(value)
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
console.log(JSON.stringify(value, null, 2))
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const exitWithError = (error: unknown, json = false): never => {
|
|
49
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
50
|
+
if (json) {
|
|
51
|
+
console.error(JSON.stringify({ ok: false, error: message }, null, 2))
|
|
52
|
+
} else {
|
|
53
|
+
console.error(message)
|
|
54
|
+
}
|
|
55
|
+
process.exit(1)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export const loadSkillsConfigState = async (cwd: string) => (
|
|
59
|
+
await loadConfigState({
|
|
60
|
+
cwd,
|
|
61
|
+
jsonVariables: buildConfigJsonVariables(cwd, process.env)
|
|
62
|
+
})
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
export const getResolvedSourceConfig = (
|
|
66
|
+
state: Awaited<ReturnType<typeof loadSkillsConfigState>>,
|
|
67
|
+
source: ConfigSource
|
|
68
|
+
) => {
|
|
69
|
+
switch (source) {
|
|
70
|
+
case 'global':
|
|
71
|
+
return state.globalConfig
|
|
72
|
+
case 'project':
|
|
73
|
+
return state.projectSource?.resolvedConfig
|
|
74
|
+
case 'user':
|
|
75
|
+
return state.userConfig
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const getRawSourceConfig = (state: Awaited<ReturnType<typeof loadSkillsConfigState>>, source: ConfigSource) => {
|
|
80
|
+
switch (source) {
|
|
81
|
+
case 'global':
|
|
82
|
+
return state.globalSource?.rawConfig
|
|
83
|
+
case 'project':
|
|
84
|
+
return state.projectSource?.rawConfig
|
|
85
|
+
case 'user':
|
|
86
|
+
return state.userSource?.rawConfig
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export const buildGeneralSkillsUpdateValue = (
|
|
91
|
+
sourceConfig: Config | undefined,
|
|
92
|
+
nextSkills: Array<string | ConfiguredSkillInstallConfig>
|
|
93
|
+
) => {
|
|
94
|
+
const value: Record<string, unknown> = {
|
|
95
|
+
skills: buildSkillsConfigValue({
|
|
96
|
+
items: nextSkills,
|
|
97
|
+
current: sourceConfig?.skills
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
return value
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export const resolveInstalledSkillDirNames = async (workspaceFolder: string, selector: string) => {
|
|
104
|
+
const trimmedSelector = selector.trim()
|
|
105
|
+
const selectorSlug = toSkillSlug(trimmedSelector)
|
|
106
|
+
const skills = await readProjectSkills(workspaceFolder)
|
|
107
|
+
return skills
|
|
108
|
+
.filter(skill => (
|
|
109
|
+
skill.dirName === trimmedSelector ||
|
|
110
|
+
skill.name === trimmedSelector ||
|
|
111
|
+
skill.dirName === selectorSlug ||
|
|
112
|
+
toSkillSlug(skill.name) === selectorSlug
|
|
113
|
+
))
|
|
114
|
+
.map(skill => skill.dirName)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export { isSameDeclaredSkill, matchesDeclaredSkillSelector as matchesSkillSelector, normalizeString, pathExists }
|