@osovv/vvcode 0.4.1 → 0.5.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 +78 -13
- package/dist/vvcode.js +295 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,14 +8,20 @@
|
|
|
8
8
|
bun add -g @osovv/vvcode
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
For local development from this repo:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
bun install
|
|
15
15
|
bun run cli -- --help
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
##
|
|
18
|
+
## Config layout
|
|
19
|
+
|
|
20
|
+
Global config path:
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
~/.config/vvcode/config.jsonc
|
|
24
|
+
```
|
|
19
25
|
|
|
20
26
|
Project config path:
|
|
21
27
|
|
|
@@ -23,30 +29,89 @@ Project config path:
|
|
|
23
29
|
.vvcode/config.jsonc
|
|
24
30
|
```
|
|
25
31
|
|
|
26
|
-
|
|
32
|
+
The current behavior is:
|
|
27
33
|
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
1. Global config is the source of shared presets and profiles.
|
|
35
|
+
2. Project config is optional for launch if a project root already exists.
|
|
36
|
+
3. `vvcode init` creates a minimal project config scaffold.
|
|
37
|
+
4. `vvcode preset add <name>` copies a preset from global config into the project config.
|
|
38
|
+
5. `vvcode preset remove <name>` removes a copied project preset and prunes unused copied profiles.
|
|
39
|
+
|
|
40
|
+
## Quick start
|
|
41
|
+
|
|
42
|
+
Initialize a project-local config:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
vvcode init
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
See which presets are available:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
vvcode preset list
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Copy a global preset into the current project:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
vvcode preset add openai
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Launch OpenCode with a preset:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
vvcode opencode --preset openai
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Or use the shorthand form:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
vvcode --preset openai
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Commands
|
|
73
|
+
|
|
74
|
+
Show help:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
vvcode help
|
|
78
|
+
vvcode --help
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Initialize project config:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
vvcode init
|
|
85
|
+
vvcode init --project-root /path/to/project
|
|
30
86
|
```
|
|
31
87
|
|
|
32
|
-
|
|
88
|
+
Launch OpenCode:
|
|
33
89
|
|
|
34
90
|
```bash
|
|
35
91
|
vvcode opencode --preset <name>
|
|
92
|
+
vvcode --preset <name>
|
|
36
93
|
```
|
|
37
94
|
|
|
38
95
|
Options:
|
|
39
96
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
97
|
+
1. `--preset`, `-p` for the preset name.
|
|
98
|
+
2. `--global-config`, `-c` to override the global config file path.
|
|
99
|
+
3. `--project-root`, `-r` to launch from a different project root.
|
|
43
100
|
|
|
44
|
-
|
|
101
|
+
Manage presets:
|
|
45
102
|
|
|
46
103
|
```bash
|
|
47
|
-
vvcode
|
|
104
|
+
vvcode preset list
|
|
105
|
+
vvcode preset add <preset-name>
|
|
106
|
+
vvcode preset remove <preset-name>
|
|
48
107
|
```
|
|
49
108
|
|
|
109
|
+
`preset list` prints one preset per line with its source label:
|
|
110
|
+
|
|
111
|
+
1. `global`
|
|
112
|
+
2. `project`
|
|
113
|
+
3. `project-overrides-global`
|
|
114
|
+
|
|
50
115
|
## Runtime artifacts
|
|
51
116
|
|
|
52
117
|
- `.vvcode/local/runtime/overlays/`
|
|
@@ -60,9 +125,9 @@ vvcode --preset <name>
|
|
|
60
125
|
## Packaging notes
|
|
61
126
|
|
|
62
127
|
- Package name: `@osovv/vvcode`
|
|
63
|
-
- CLI bin: `
|
|
128
|
+
- CLI bin: `vvcode`
|
|
64
129
|
- Published runtime entry: `dist/vvcode.js`
|
|
65
130
|
- Build command: `bun run build`
|
|
66
131
|
- Local dev command: `bun run cli -- --help`
|
|
67
|
-
- `prepack` builds `dist` automatically before publish
|
|
132
|
+
- `prepack` builds `dist` automatically before publish or pack
|
|
68
133
|
- Scoped publish target: `npm publish --access=public`
|
package/dist/vvcode.js
CHANGED
|
@@ -543,11 +543,11 @@ function _getBuiltinFlags(long, short, userNames, userAliases) {
|
|
|
543
543
|
|
|
544
544
|
// src/cli/vvcode.ts
|
|
545
545
|
import { homedir } from "os";
|
|
546
|
-
import { join as join3 } from "path";
|
|
546
|
+
import { join as join3, resolve } from "path";
|
|
547
547
|
// package.json
|
|
548
548
|
var package_default = {
|
|
549
549
|
name: "@osovv/vvcode",
|
|
550
|
-
version: "0.
|
|
550
|
+
version: "0.5.0",
|
|
551
551
|
description: "Packaged CLI for launching OpenCode with vvcode runtime semantics.",
|
|
552
552
|
license: "MIT",
|
|
553
553
|
homepage: "https://github.com/osovv/vvcode",
|
|
@@ -602,10 +602,6 @@ var package_default = {
|
|
|
602
602
|
]
|
|
603
603
|
};
|
|
604
604
|
|
|
605
|
-
// src/cli/pivv-opencode.ts
|
|
606
|
-
import { rm } from "fs/promises";
|
|
607
|
-
import { spawn } from "child_process";
|
|
608
|
-
|
|
609
605
|
// src/config/load-pivv-config.ts
|
|
610
606
|
class PivvConfigError extends Error {
|
|
611
607
|
code;
|
|
@@ -628,9 +624,6 @@ async function loadPivvConfig(globalConfigPath, projectRoot) {
|
|
|
628
624
|
for (const sourceCandidate of sourceCandidates) {
|
|
629
625
|
const sourcePath = sourceCandidate.path;
|
|
630
626
|
const sourceExists = await pathExists(sourcePath);
|
|
631
|
-
if (!sourceExists && sourceCandidate.sourceType === "project") {
|
|
632
|
-
throw new PivvConfigError("CONFIG_NOT_FOUND", `Project config not found at ${sourcePath}`);
|
|
633
|
-
}
|
|
634
627
|
if (!sourceExists) {
|
|
635
628
|
continue;
|
|
636
629
|
}
|
|
@@ -674,6 +667,37 @@ async function findProjectRoot(projectRoot) {
|
|
|
674
667
|
}
|
|
675
668
|
throw new PivvConfigError("CONFIG_NOT_FOUND", `Unable to resolve project root from ${projectRoot}`);
|
|
676
669
|
}
|
|
670
|
+
function resolveProjectConfigPath(projectRoot) {
|
|
671
|
+
return joinPath(resolvePath(projectRoot), PROJECT_CONFIG_PATH);
|
|
672
|
+
}
|
|
673
|
+
function createEmptyRawVvcodeConfig() {
|
|
674
|
+
return {
|
|
675
|
+
profiles: {},
|
|
676
|
+
presets: {},
|
|
677
|
+
memory: {},
|
|
678
|
+
overlay: {}
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
async function readOptionalRawVvcodeConfig(configPath) {
|
|
682
|
+
const normalizedPath = resolvePath(configPath);
|
|
683
|
+
if (!await pathExists(normalizedPath)) {
|
|
684
|
+
return null;
|
|
685
|
+
}
|
|
686
|
+
return readJsoncConfig(normalizedPath);
|
|
687
|
+
}
|
|
688
|
+
async function writeRawVvcodeConfig(configPath, config) {
|
|
689
|
+
const normalizedPath = resolvePath(configPath);
|
|
690
|
+
const fsPromises = await getFsPromises();
|
|
691
|
+
const stableConfig = {
|
|
692
|
+
profiles: isRecord(config.profiles) ? config.profiles : {},
|
|
693
|
+
presets: isRecord(config.presets) ? config.presets : {},
|
|
694
|
+
memory: isRecord(config.memory) ? config.memory : {},
|
|
695
|
+
overlay: isRecord(config.overlay) ? config.overlay : {}
|
|
696
|
+
};
|
|
697
|
+
await fsPromises.mkdir(getParentPath(normalizedPath), { recursive: true });
|
|
698
|
+
await fsPromises.writeFile(normalizedPath, `${JSON.stringify(stableConfig, null, 2)}
|
|
699
|
+
`, "utf-8");
|
|
700
|
+
}
|
|
677
701
|
function normalizeConfig(rawConfig, projectRoot, configSources) {
|
|
678
702
|
if (!isRecord(rawConfig)) {
|
|
679
703
|
throw new PivvConfigError("CONFIG_INVALID", "Config root must be an object");
|
|
@@ -899,6 +923,10 @@ function normalizePath(path) {
|
|
|
899
923
|
return withSingleSlashes;
|
|
900
924
|
}
|
|
901
925
|
|
|
926
|
+
// src/cli/pivv-opencode.ts
|
|
927
|
+
import { rm } from "fs/promises";
|
|
928
|
+
import { spawn } from "child_process";
|
|
929
|
+
|
|
902
930
|
// src/opencode/build-runtime-overlay.ts
|
|
903
931
|
import { mkdir, writeFile } from "fs/promises";
|
|
904
932
|
import { join } from "path";
|
|
@@ -1730,6 +1758,7 @@ async function launchOpenCodeProcess(request) {
|
|
|
1730
1758
|
// src/cli/vvcode.ts
|
|
1731
1759
|
var CLI_LOG_PREFIX = "[VvcodeCli]";
|
|
1732
1760
|
var BLOCK_RUN_OPENCODE_COMMAND = "BLOCK_RUN_OPENCODE_COMMAND";
|
|
1761
|
+
var KNOWN_TOP_LEVEL_COMMANDS = new Set(["help", "init", "opencode", "preset"]);
|
|
1733
1762
|
function resolveDefaultGlobalConfigPath() {
|
|
1734
1763
|
return join3(homedir(), ".config", "vvcode", "config.jsonc");
|
|
1735
1764
|
}
|
|
@@ -1738,7 +1767,7 @@ function createVvcodeCommand(dependencyOverrides = {}) {
|
|
|
1738
1767
|
const opencodeArgs = {
|
|
1739
1768
|
preset: {
|
|
1740
1769
|
type: "string",
|
|
1741
|
-
description: "Preset name defined in
|
|
1770
|
+
description: "Preset name defined in global or project vvcode config.",
|
|
1742
1771
|
alias: ["p"],
|
|
1743
1772
|
required: true
|
|
1744
1773
|
},
|
|
@@ -1755,15 +1784,63 @@ function createVvcodeCommand(dependencyOverrides = {}) {
|
|
|
1755
1784
|
default: dependencies.cwd()
|
|
1756
1785
|
}
|
|
1757
1786
|
};
|
|
1787
|
+
const configManagementArgs = {
|
|
1788
|
+
"global-config": {
|
|
1789
|
+
type: "string",
|
|
1790
|
+
description: "Path to the global vvcode config file.",
|
|
1791
|
+
alias: ["c"],
|
|
1792
|
+
default: dependencies.defaultGlobalConfigPath()
|
|
1793
|
+
},
|
|
1794
|
+
"project-root": {
|
|
1795
|
+
type: "string",
|
|
1796
|
+
description: "Project root where .vvcode/config.jsonc should be managed.",
|
|
1797
|
+
alias: ["r"],
|
|
1798
|
+
default: dependencies.cwd()
|
|
1799
|
+
}
|
|
1800
|
+
};
|
|
1758
1801
|
return defineCommand({
|
|
1759
1802
|
meta: {
|
|
1760
1803
|
name: "vvcode",
|
|
1761
1804
|
version: package_default.version,
|
|
1762
1805
|
description: "Packaged CLI for launching OpenCode with vvcode runtime semantics."
|
|
1763
1806
|
},
|
|
1764
|
-
args: opencodeArgs,
|
|
1765
|
-
default: "opencode",
|
|
1766
1807
|
subCommands: {
|
|
1808
|
+
help: defineCommand({
|
|
1809
|
+
meta: {
|
|
1810
|
+
name: "help",
|
|
1811
|
+
description: "Show vvcode command help."
|
|
1812
|
+
},
|
|
1813
|
+
args: {
|
|
1814
|
+
command: {
|
|
1815
|
+
type: "positional",
|
|
1816
|
+
description: "Optional subcommand name to show help for.",
|
|
1817
|
+
required: false
|
|
1818
|
+
}
|
|
1819
|
+
},
|
|
1820
|
+
async run({ args }) {
|
|
1821
|
+
const helpArgs = typeof args.command === "string" && args.command.length > 0 ? [args.command, "--help"] : ["--help"];
|
|
1822
|
+
await runMain(createVvcodeCommand(dependencyOverrides), { rawArgs: helpArgs });
|
|
1823
|
+
}
|
|
1824
|
+
}),
|
|
1825
|
+
init: defineCommand({
|
|
1826
|
+
meta: {
|
|
1827
|
+
name: "init",
|
|
1828
|
+
description: "Create a project-local .vvcode/config.jsonc scaffold."
|
|
1829
|
+
},
|
|
1830
|
+
args: {
|
|
1831
|
+
"project-root": configManagementArgs["project-root"]
|
|
1832
|
+
},
|
|
1833
|
+
async run({ args }) {
|
|
1834
|
+
const configPath = resolveProjectConfigPath(String(args.projectRoot));
|
|
1835
|
+
const existingConfig = await readOptionalRawVvcodeConfig(configPath);
|
|
1836
|
+
if (existingConfig !== null) {
|
|
1837
|
+
dependencies.writeStdout(`vvcode: project config already exists at ${configPath}`);
|
|
1838
|
+
return;
|
|
1839
|
+
}
|
|
1840
|
+
await writeRawVvcodeConfig(configPath, createEmptyRawVvcodeConfig());
|
|
1841
|
+
dependencies.writeStdout(`vvcode: initialized project config at ${configPath}`);
|
|
1842
|
+
}
|
|
1843
|
+
}),
|
|
1767
1844
|
opencode: defineCommand({
|
|
1768
1845
|
meta: {
|
|
1769
1846
|
name: "opencode",
|
|
@@ -1787,13 +1864,151 @@ function createVvcodeCommand(dependencyOverrides = {}) {
|
|
|
1787
1864
|
}
|
|
1788
1865
|
return launchResult;
|
|
1789
1866
|
}
|
|
1867
|
+
}),
|
|
1868
|
+
preset: defineCommand({
|
|
1869
|
+
meta: {
|
|
1870
|
+
name: "preset",
|
|
1871
|
+
description: "Inspect or manage project presets copied from global vvcode config."
|
|
1872
|
+
},
|
|
1873
|
+
default: "list",
|
|
1874
|
+
subCommands: {
|
|
1875
|
+
list: defineCommand({
|
|
1876
|
+
meta: {
|
|
1877
|
+
name: "list",
|
|
1878
|
+
description: "List available presets from global and project config."
|
|
1879
|
+
},
|
|
1880
|
+
args: configManagementArgs,
|
|
1881
|
+
async run({ args }) {
|
|
1882
|
+
const snapshot = await loadProjectConfigSnapshot(String(args.globalConfig), String(args.projectRoot));
|
|
1883
|
+
const presetNames = collectPresetNames(snapshot);
|
|
1884
|
+
if (presetNames.length === 0) {
|
|
1885
|
+
dependencies.writeStdout("vvcode: no presets found in global or project config");
|
|
1886
|
+
return;
|
|
1887
|
+
}
|
|
1888
|
+
for (const presetName of presetNames) {
|
|
1889
|
+
dependencies.writeStdout(`${presetName} ${describePresetSource(snapshot, presetName)}`);
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
}),
|
|
1893
|
+
add: defineCommand({
|
|
1894
|
+
meta: {
|
|
1895
|
+
name: "add",
|
|
1896
|
+
description: "Copy one preset and its referenced profiles from global config into the project config."
|
|
1897
|
+
},
|
|
1898
|
+
args: {
|
|
1899
|
+
name: {
|
|
1900
|
+
type: "positional",
|
|
1901
|
+
description: "Preset name to copy into the project config.",
|
|
1902
|
+
required: true
|
|
1903
|
+
},
|
|
1904
|
+
...configManagementArgs
|
|
1905
|
+
},
|
|
1906
|
+
async run({ args }) {
|
|
1907
|
+
const presetName = String(args.name);
|
|
1908
|
+
const snapshot = await loadProjectConfigSnapshot(String(args.globalConfig), String(args.projectRoot));
|
|
1909
|
+
const globalPresets = toObjectBucket(snapshot.globalConfig?.presets);
|
|
1910
|
+
const globalProfiles = toObjectBucket(snapshot.globalConfig?.profiles);
|
|
1911
|
+
if (!(presetName in globalPresets) || !isRecord2(globalPresets[presetName])) {
|
|
1912
|
+
throw new Error(`Preset "${presetName}" was not found in global config ${snapshot.globalConfigPath}`);
|
|
1913
|
+
}
|
|
1914
|
+
const projectConfig = snapshot.projectConfig ?? createEmptyRawVvcodeConfig();
|
|
1915
|
+
const projectPresets = toMutableBucket(projectConfig, "presets");
|
|
1916
|
+
const projectProfiles = toMutableBucket(projectConfig, "profiles");
|
|
1917
|
+
if (presetName in projectPresets) {
|
|
1918
|
+
dependencies.writeStdout(`vvcode: preset "${presetName}" already exists in ${snapshot.projectConfigPath}`);
|
|
1919
|
+
return;
|
|
1920
|
+
}
|
|
1921
|
+
const globalPreset = globalPresets[presetName];
|
|
1922
|
+
const copiedProfiles = [];
|
|
1923
|
+
const normalizedPreset = {};
|
|
1924
|
+
for (const [slotName, profileNameValue] of Object.entries(globalPreset)) {
|
|
1925
|
+
if (typeof profileNameValue !== "string" || profileNameValue.length === 0) {
|
|
1926
|
+
throw new Error(`Global preset "${presetName}" slot "${slotName}" must reference a non-empty profile name`);
|
|
1927
|
+
}
|
|
1928
|
+
const profileName = profileNameValue;
|
|
1929
|
+
const globalProfile = globalProfiles[profileName];
|
|
1930
|
+
if (!isRecord2(globalProfile)) {
|
|
1931
|
+
throw new Error(`Global preset "${presetName}" references missing profile "${profileName}"`);
|
|
1932
|
+
}
|
|
1933
|
+
if (profileName in projectProfiles) {
|
|
1934
|
+
if (!areJsonValuesEqual(projectProfiles[profileName], globalProfile)) {
|
|
1935
|
+
throw new Error(`Project config already defines profile "${profileName}" with different settings; remove it or rename the project profile before adding preset "${presetName}"`);
|
|
1936
|
+
}
|
|
1937
|
+
} else {
|
|
1938
|
+
projectProfiles[profileName] = globalProfile;
|
|
1939
|
+
copiedProfiles.push(profileName);
|
|
1940
|
+
}
|
|
1941
|
+
normalizedPreset[slotName] = profileName;
|
|
1942
|
+
}
|
|
1943
|
+
projectPresets[presetName] = normalizedPreset;
|
|
1944
|
+
await writeRawVvcodeConfig(snapshot.projectConfigPath, projectConfig);
|
|
1945
|
+
dependencies.writeStdout(`vvcode: added preset "${presetName}" to ${snapshot.projectConfigPath} (copied ${copiedProfiles.length} profiles)`);
|
|
1946
|
+
}
|
|
1947
|
+
}),
|
|
1948
|
+
remove: defineCommand({
|
|
1949
|
+
meta: {
|
|
1950
|
+
name: "remove",
|
|
1951
|
+
description: "Remove one preset from the project config and prune unreferenced copied profiles."
|
|
1952
|
+
},
|
|
1953
|
+
args: {
|
|
1954
|
+
name: {
|
|
1955
|
+
type: "positional",
|
|
1956
|
+
description: "Preset name to remove from the project config.",
|
|
1957
|
+
required: true
|
|
1958
|
+
},
|
|
1959
|
+
"project-root": configManagementArgs["project-root"]
|
|
1960
|
+
},
|
|
1961
|
+
async run({ args }) {
|
|
1962
|
+
const presetName = String(args.name);
|
|
1963
|
+
const projectRoot = resolve(String(args.projectRoot));
|
|
1964
|
+
const projectConfigPath = resolveProjectConfigPath(projectRoot);
|
|
1965
|
+
const projectConfig = await readOptionalRawVvcodeConfig(projectConfigPath);
|
|
1966
|
+
if (projectConfig === null) {
|
|
1967
|
+
throw new Error(`Project config was not found at ${projectConfigPath}`);
|
|
1968
|
+
}
|
|
1969
|
+
const projectPresets = toMutableBucket(projectConfig, "presets");
|
|
1970
|
+
const projectProfiles = toMutableBucket(projectConfig, "profiles");
|
|
1971
|
+
const removedPreset = projectPresets[presetName];
|
|
1972
|
+
if (!isRecord2(removedPreset)) {
|
|
1973
|
+
throw new Error(`Preset "${presetName}" was not found in project config ${projectConfigPath}`);
|
|
1974
|
+
}
|
|
1975
|
+
delete projectPresets[presetName];
|
|
1976
|
+
const stillReferencedProfiles = new Set;
|
|
1977
|
+
for (const presetValue of Object.values(projectPresets)) {
|
|
1978
|
+
if (!isRecord2(presetValue)) {
|
|
1979
|
+
continue;
|
|
1980
|
+
}
|
|
1981
|
+
for (const profileNameValue of Object.values(presetValue)) {
|
|
1982
|
+
if (typeof profileNameValue === "string" && profileNameValue.length > 0) {
|
|
1983
|
+
stillReferencedProfiles.add(profileNameValue);
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
const removedProfiles = [];
|
|
1988
|
+
for (const profileNameValue of Object.values(removedPreset)) {
|
|
1989
|
+
if (typeof profileNameValue !== "string" || profileNameValue.length === 0) {
|
|
1990
|
+
continue;
|
|
1991
|
+
}
|
|
1992
|
+
if (stillReferencedProfiles.has(profileNameValue)) {
|
|
1993
|
+
continue;
|
|
1994
|
+
}
|
|
1995
|
+
if (profileNameValue in projectProfiles) {
|
|
1996
|
+
delete projectProfiles[profileNameValue];
|
|
1997
|
+
removedProfiles.push(profileNameValue);
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
await writeRawVvcodeConfig(projectConfigPath, projectConfig);
|
|
2001
|
+
dependencies.writeStdout(`vvcode: removed preset "${presetName}" from ${projectConfigPath} (removed ${removedProfiles.length} profiles)`);
|
|
2002
|
+
}
|
|
2003
|
+
})
|
|
2004
|
+
}
|
|
1790
2005
|
})
|
|
1791
2006
|
}
|
|
1792
2007
|
});
|
|
1793
2008
|
}
|
|
1794
2009
|
async function runVvcodeCli(rawArgs = process.argv.slice(2), dependencyOverrides = {}) {
|
|
1795
2010
|
const vvcodeCommand = createVvcodeCommand(dependencyOverrides);
|
|
1796
|
-
await runMain(vvcodeCommand, { rawArgs });
|
|
2011
|
+
await runMain(vvcodeCommand, { rawArgs: normalizeRawArgs(rawArgs) });
|
|
1797
2012
|
}
|
|
1798
2013
|
function resolveVvcodeCliDependencies(dependencyOverrides) {
|
|
1799
2014
|
return {
|
|
@@ -1801,6 +2016,7 @@ function resolveVvcodeCliDependencies(dependencyOverrides) {
|
|
|
1801
2016
|
cwd: dependencyOverrides.cwd ?? (() => process.cwd()),
|
|
1802
2017
|
defaultGlobalConfigPath: dependencyOverrides.defaultGlobalConfigPath ?? resolveDefaultGlobalConfigPath,
|
|
1803
2018
|
writeStderr: dependencyOverrides.writeStderr ?? ((message) => console.error(message)),
|
|
2019
|
+
writeStdout: dependencyOverrides.writeStdout ?? ((message) => console.log(message)),
|
|
1804
2020
|
setExitCode: dependencyOverrides.setExitCode ?? ((code) => {
|
|
1805
2021
|
process.exitCode = code;
|
|
1806
2022
|
})
|
|
@@ -1820,6 +2036,72 @@ function formatLaunchFailure(launchResult) {
|
|
|
1820
2036
|
}
|
|
1821
2037
|
return failureFields.join(" ");
|
|
1822
2038
|
}
|
|
2039
|
+
function normalizeRawArgs(rawArgs) {
|
|
2040
|
+
if (rawArgs.length === 0) {
|
|
2041
|
+
return ["help"];
|
|
2042
|
+
}
|
|
2043
|
+
if (KNOWN_TOP_LEVEL_COMMANDS.has(rawArgs[0])) {
|
|
2044
|
+
return rawArgs;
|
|
2045
|
+
}
|
|
2046
|
+
if (rawArgs.some((arg) => arg === "-p" || arg === "--preset" || arg.startsWith("--preset="))) {
|
|
2047
|
+
return ["opencode", ...rawArgs];
|
|
2048
|
+
}
|
|
2049
|
+
return rawArgs;
|
|
2050
|
+
}
|
|
2051
|
+
async function loadProjectConfigSnapshot(globalConfigPath, projectRoot) {
|
|
2052
|
+
const normalizedProjectRoot = resolve(projectRoot);
|
|
2053
|
+
const projectConfigPath = resolveProjectConfigPath(normalizedProjectRoot);
|
|
2054
|
+
const [globalConfig, projectConfig] = await Promise.all([
|
|
2055
|
+
readOptionalRawVvcodeConfig(globalConfigPath),
|
|
2056
|
+
readOptionalRawVvcodeConfig(projectConfigPath)
|
|
2057
|
+
]);
|
|
2058
|
+
return {
|
|
2059
|
+
projectRoot: normalizedProjectRoot,
|
|
2060
|
+
projectConfigPath,
|
|
2061
|
+
globalConfigPath: resolve(globalConfigPath),
|
|
2062
|
+
globalConfig,
|
|
2063
|
+
projectConfig
|
|
2064
|
+
};
|
|
2065
|
+
}
|
|
2066
|
+
function collectPresetNames(snapshot) {
|
|
2067
|
+
const presetNames = new Set;
|
|
2068
|
+
for (const presetName of Object.keys(toObjectBucket(snapshot.globalConfig?.presets))) {
|
|
2069
|
+
presetNames.add(presetName);
|
|
2070
|
+
}
|
|
2071
|
+
for (const presetName of Object.keys(toObjectBucket(snapshot.projectConfig?.presets))) {
|
|
2072
|
+
presetNames.add(presetName);
|
|
2073
|
+
}
|
|
2074
|
+
return [...presetNames].sort((left, right) => left.localeCompare(right));
|
|
2075
|
+
}
|
|
2076
|
+
function describePresetSource(snapshot, presetName) {
|
|
2077
|
+
const hasGlobalPreset = presetName in toObjectBucket(snapshot.globalConfig?.presets);
|
|
2078
|
+
const hasProjectPreset = presetName in toObjectBucket(snapshot.projectConfig?.presets);
|
|
2079
|
+
if (hasProjectPreset && hasGlobalPreset) {
|
|
2080
|
+
return "project-overrides-global";
|
|
2081
|
+
}
|
|
2082
|
+
if (hasProjectPreset) {
|
|
2083
|
+
return "project";
|
|
2084
|
+
}
|
|
2085
|
+
return "global";
|
|
2086
|
+
}
|
|
2087
|
+
function toMutableBucket(config, key) {
|
|
2088
|
+
const bucket = config[key];
|
|
2089
|
+
if (isRecord2(bucket)) {
|
|
2090
|
+
return bucket;
|
|
2091
|
+
}
|
|
2092
|
+
const nextBucket = {};
|
|
2093
|
+
config[key] = nextBucket;
|
|
2094
|
+
return nextBucket;
|
|
2095
|
+
}
|
|
2096
|
+
function toObjectBucket(value) {
|
|
2097
|
+
return isRecord2(value) ? value : {};
|
|
2098
|
+
}
|
|
2099
|
+
function isRecord2(value) {
|
|
2100
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2101
|
+
}
|
|
2102
|
+
function areJsonValuesEqual(left, right) {
|
|
2103
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
2104
|
+
}
|
|
1823
2105
|
|
|
1824
2106
|
// src/cli/vvcode-entry.ts
|
|
1825
2107
|
await runVvcodeCli();
|