ccnew 0.1.10
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 +107 -0
- package/build/icon.ico +0 -0
- package/build/icon.png +0 -0
- package/core/apply.js +152 -0
- package/core/backup.js +53 -0
- package/core/constants.js +78 -0
- package/core/desktop-service.js +403 -0
- package/core/desktop-state.js +1021 -0
- package/core/index.js +1468 -0
- package/core/paths.js +99 -0
- package/core/presets.js +171 -0
- package/core/probe.js +70 -0
- package/core/routing.js +334 -0
- package/core/store.js +218 -0
- package/core/utils.js +225 -0
- package/core/writers/codex.js +102 -0
- package/core/writers/index.js +16 -0
- package/core/writers/openclaw.js +93 -0
- package/core/writers/opencode.js +91 -0
- package/desktop/assets/fml-icon.png +0 -0
- package/desktop/assets/march-mark.svg +26 -0
- package/desktop/main.js +275 -0
- package/desktop/preload.cjs +67 -0
- package/desktop/preload.js +49 -0
- package/desktop/renderer/app.js +327 -0
- package/desktop/renderer/index.html +130 -0
- package/desktop/renderer/styles.css +490 -0
- package/package.json +111 -0
- package/scripts/build-web.mjs +95 -0
- package/scripts/desktop-dev.mjs +90 -0
- package/scripts/desktop-pack-win.mjs +81 -0
- package/scripts/postinstall.mjs +49 -0
- package/scripts/prepublish-check.mjs +57 -0
- package/scripts/serve-site.mjs +51 -0
- package/site/app.js +10 -0
- package/site/assets/fml-icon.png +0 -0
- package/site/assets/march-mark.svg +26 -0
- package/site/index.html +337 -0
- package/site/styles.css +840 -0
- package/src/App.tsx +1557 -0
- package/src/components/layout/app-sidebar.tsx +103 -0
- package/src/components/layout/top-toolbar.tsx +44 -0
- package/src/components/layout/workspace-tabs.tsx +32 -0
- package/src/components/providers/inspector-panel.tsx +84 -0
- package/src/components/providers/metric-strip.tsx +26 -0
- package/src/components/providers/provider-editor.tsx +87 -0
- package/src/components/providers/provider-table.tsx +85 -0
- package/src/components/ui/logo-mark.tsx +32 -0
- package/src/features/mcp/mcp-view.tsx +45 -0
- package/src/features/prompts/prompts-view.tsx +40 -0
- package/src/features/providers/providers-view.tsx +40 -0
- package/src/features/providers/types.ts +26 -0
- package/src/features/skills/skills-view.tsx +44 -0
- package/src/hooks/use-control-workspace.ts +235 -0
- package/src/index.css +22 -0
- package/src/lib/client.ts +726 -0
- package/src/lib/query-client.ts +3 -0
- package/src/lib/workspace-sections.ts +34 -0
- package/src/main.tsx +14 -0
- package/src/types.ts +137 -0
- package/src/vite-env.d.ts +64 -0
- package/src-tauri/README.md +11 -0
package/README.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# ccon
|
|
2
|
+
|
|
3
|
+
`ccon` is a relay configuration manager for:
|
|
4
|
+
|
|
5
|
+
- Codex
|
|
6
|
+
- OpenCode
|
|
7
|
+
- OpenClaw
|
|
8
|
+
|
|
9
|
+
It exposes one install command and one primary setup command:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm i -g ccon
|
|
13
|
+
ccon fhl
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Main Commands
|
|
17
|
+
|
|
18
|
+
Quick setup:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
ccon fhl
|
|
22
|
+
ccon fhl sk-your-key
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Interactive menu:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
ccon
|
|
29
|
+
ccon menu
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Standard setup:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
ccon setup -k sk-your-key
|
|
36
|
+
ccon setup --preset fhl -k sk-your-key
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Platform management:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
ccon cx list
|
|
43
|
+
ccon cx current
|
|
44
|
+
ccon cx add -n fhl -u https://www.fhl.mom -k sk-xxx --model gpt-5.4
|
|
45
|
+
ccon cx use fhl
|
|
46
|
+
ccon oc list
|
|
47
|
+
ccon ow list
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Presets and probe:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
ccon preset list
|
|
54
|
+
ccon preset add -n team-a --provider-name teama --base-url https://example.com
|
|
55
|
+
ccon preset use team-a -k sk-xxx -p codex,opencode
|
|
56
|
+
ccon probe -u https://www.fhl.mom -u https://www.fhl.mom/v1
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Defaults
|
|
60
|
+
|
|
61
|
+
- Codex / OpenCode route: `https://www.fhl.mom`
|
|
62
|
+
- OpenClaw route: `https://www.fhl.mom/v1`
|
|
63
|
+
- Primary setup command: `ccon fhl`
|
|
64
|
+
- Default provider name: `fhl`
|
|
65
|
+
|
|
66
|
+
`ccon fhl` follows the old `gmn1` style selection flow when `--platform` is omitted:
|
|
67
|
+
|
|
68
|
+
- `Codex` checked by default
|
|
69
|
+
- `OpenCode` checked by default
|
|
70
|
+
- `OpenClaw` unchecked by default
|
|
71
|
+
|
|
72
|
+
## Local Verification
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
npm run verify:publish
|
|
76
|
+
node core/index.js --help
|
|
77
|
+
node core/index.js fhl --help
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Optional desktop checks:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npm run typecheck
|
|
84
|
+
npm run build:web
|
|
85
|
+
npm run desktop:check
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Customer Install Simulation
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npm pack
|
|
92
|
+
npm uninstall -g ccon
|
|
93
|
+
npm install -g .\\ccon-0.1.10.tgz
|
|
94
|
+
ccon --help
|
|
95
|
+
ccon fhl --help
|
|
96
|
+
ccon gmn1 --help
|
|
97
|
+
ccon fhl sk-demo-1234 --platform codex --no-probe
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Publish
|
|
101
|
+
|
|
102
|
+
Run publish commands inside `C:\Users\Administrator\work\march`:
|
|
103
|
+
|
|
104
|
+
```powershell
|
|
105
|
+
Set-Location C:\Users\Administrator\work\march
|
|
106
|
+
npm publish --access public --registry=https://registry.npmjs.org/
|
|
107
|
+
```
|
package/build/icon.ico
ADDED
|
Binary file
|
package/build/icon.png
ADDED
|
Binary file
|
package/core/apply.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { createPlatformBackup, restorePlatformBackup } from "./backup.js";
|
|
2
|
+
import { getPlatformTargetFiles } from "./paths.js";
|
|
3
|
+
import {
|
|
4
|
+
cloneProvider,
|
|
5
|
+
getCurrentProvider,
|
|
6
|
+
removeProvider,
|
|
7
|
+
resolveStoredProvider,
|
|
8
|
+
switchProvider,
|
|
9
|
+
updateProvider,
|
|
10
|
+
upsertProvider
|
|
11
|
+
} from "./store.js";
|
|
12
|
+
import { writePlatformConfig } from "./writers/index.js";
|
|
13
|
+
|
|
14
|
+
export function applyProvider(platform, providerInput, options = {}) {
|
|
15
|
+
const backup = options.backup === false ? null : createPlatformBackup(platform);
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
const provider = upsertProvider(platform, providerInput, { activate: options.activate !== false });
|
|
19
|
+
writePlatformConfig(platform, provider, {
|
|
20
|
+
mode: options.overwrite ? "overwrite" : "merge"
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
provider,
|
|
25
|
+
backupDir: backup?.backupDir || null,
|
|
26
|
+
targetFiles: getPlatformTargetFiles(platform)
|
|
27
|
+
};
|
|
28
|
+
} catch (error) {
|
|
29
|
+
if (backup) {
|
|
30
|
+
restorePlatformBackup(backup);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function applyStoredProvider(platform, nameOrId, options = {}) {
|
|
38
|
+
const backup = options.backup === false ? null : createPlatformBackup(platform);
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
const provider = resolveStoredProvider(platform, nameOrId);
|
|
42
|
+
if (options.activate !== false) {
|
|
43
|
+
switchProvider(platform, nameOrId);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const current = getCurrentProvider(platform) || provider;
|
|
47
|
+
writePlatformConfig(platform, current, {
|
|
48
|
+
mode: options.overwrite ? "overwrite" : "merge"
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
provider: current,
|
|
53
|
+
backupDir: backup?.backupDir || null,
|
|
54
|
+
targetFiles: getPlatformTargetFiles(platform)
|
|
55
|
+
};
|
|
56
|
+
} catch (error) {
|
|
57
|
+
if (backup) {
|
|
58
|
+
restorePlatformBackup(backup);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function applyEditedProvider(platform, nameOrId, updates, options = {}) {
|
|
66
|
+
const backup = options.backup === false ? null : createPlatformBackup(platform);
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const provider = updateProvider(platform, nameOrId, updates, {
|
|
70
|
+
activate: options.activate === true
|
|
71
|
+
});
|
|
72
|
+
const current = getCurrentProvider(platform);
|
|
73
|
+
|
|
74
|
+
if (current) {
|
|
75
|
+
writePlatformConfig(platform, current, {
|
|
76
|
+
mode: options.overwrite ? "overwrite" : "merge"
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
provider,
|
|
82
|
+
activeProvider: current,
|
|
83
|
+
backupDir: backup?.backupDir || null,
|
|
84
|
+
targetFiles: getPlatformTargetFiles(platform)
|
|
85
|
+
};
|
|
86
|
+
} catch (error) {
|
|
87
|
+
if (backup) {
|
|
88
|
+
restorePlatformBackup(backup);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function applyClonedProvider(platform, nameOrId, input, options = {}) {
|
|
96
|
+
const backup = options.backup === false ? null : createPlatformBackup(platform);
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const provider = cloneProvider(platform, nameOrId, input, {
|
|
100
|
+
activate: options.activate === true
|
|
101
|
+
});
|
|
102
|
+
const current = getCurrentProvider(platform);
|
|
103
|
+
|
|
104
|
+
if (current) {
|
|
105
|
+
writePlatformConfig(platform, current, {
|
|
106
|
+
mode: options.overwrite ? "overwrite" : "merge"
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
provider,
|
|
112
|
+
activeProvider: current,
|
|
113
|
+
backupDir: backup?.backupDir || null,
|
|
114
|
+
targetFiles: getPlatformTargetFiles(platform)
|
|
115
|
+
};
|
|
116
|
+
} catch (error) {
|
|
117
|
+
if (backup) {
|
|
118
|
+
restorePlatformBackup(backup);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function applyRemovedProvider(platform, nameOrId, options = {}) {
|
|
126
|
+
const backup = options.backup === false ? null : createPlatformBackup(platform);
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
const result = removeProvider(platform, nameOrId, {
|
|
130
|
+
activateFallback: options.activateFallback !== false
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
if (result.currentProvider) {
|
|
134
|
+
writePlatformConfig(platform, result.currentProvider, {
|
|
135
|
+
mode: options.overwrite ? "overwrite" : "merge"
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
removedProvider: result.removedProvider,
|
|
141
|
+
activeProvider: result.currentProvider,
|
|
142
|
+
backupDir: backup?.backupDir || null,
|
|
143
|
+
targetFiles: getPlatformTargetFiles(platform)
|
|
144
|
+
};
|
|
145
|
+
} catch (error) {
|
|
146
|
+
if (backup) {
|
|
147
|
+
restorePlatformBackup(backup);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
}
|
package/core/backup.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { getBackupDirRoot, getPlatformTargetFiles } from "./paths.js";
|
|
4
|
+
import { ensureDir, writeJson } from "./utils.js";
|
|
5
|
+
|
|
6
|
+
export function createPlatformBackup(platform) {
|
|
7
|
+
const backupDir = path.join(
|
|
8
|
+
getBackupDirRoot(),
|
|
9
|
+
`${platform}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
ensureDir(backupDir);
|
|
13
|
+
|
|
14
|
+
const entries = getPlatformTargetFiles(platform).map((originalPath, index) => {
|
|
15
|
+
if (!fs.existsSync(originalPath)) {
|
|
16
|
+
return { originalPath, backupPath: null, existed: false };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const backupPath = path.join(
|
|
20
|
+
backupDir,
|
|
21
|
+
`${String(index).padStart(2, "0")}-${path.basename(originalPath).replace(/[^\w.-]/g, "_")}.bak`
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
fs.copyFileSync(originalPath, backupPath);
|
|
25
|
+
return { originalPath, backupPath, existed: true };
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
writeJson(path.join(backupDir, "manifest.json"), {
|
|
29
|
+
platform,
|
|
30
|
+
createdAt: new Date().toISOString(),
|
|
31
|
+
entries
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return { backupDir, entries };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function restorePlatformBackup(result) {
|
|
38
|
+
for (const entry of result.entries) {
|
|
39
|
+
if (entry.existed) {
|
|
40
|
+
if (!entry.backupPath || !fs.existsSync(entry.backupPath)) {
|
|
41
|
+
throw new Error(`Missing backup file: ${entry.backupPath || entry.originalPath}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
ensureDir(path.dirname(entry.originalPath));
|
|
45
|
+
fs.copyFileSync(entry.backupPath, entry.originalPath);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (fs.existsSync(entry.originalPath)) {
|
|
50
|
+
fs.rmSync(entry.originalPath, { force: true });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export const APP_NAME = "ccon";
|
|
2
|
+
export const DEFAULT_PROVIDER_NAME = "fhl";
|
|
3
|
+
export const DEFAULT_BASE_URL = "https://www.fhl.mom";
|
|
4
|
+
export const DEFAULT_OPENCLAW_BASE_URL = "https://www.fhl.mom/v1";
|
|
5
|
+
export const DEFAULT_PRIMARY_MODEL = "gpt-5.4";
|
|
6
|
+
export const FHL_PROVIDER_NAME = "fhl";
|
|
7
|
+
export const FHL_BASE_URL = "https://www.fhl.mom";
|
|
8
|
+
export const FHL_OPENCLAW_BASE_URL = "https://www.fhl.mom/v1";
|
|
9
|
+
export const FHL_CANDIDATE_BASE_URLS = ["https://www.fhl.mom"];
|
|
10
|
+
// Backward compatibility with previous naming.
|
|
11
|
+
export const GMN_PROVIDER_NAME = FHL_PROVIDER_NAME;
|
|
12
|
+
export const GMN_BASE_URL = FHL_BASE_URL;
|
|
13
|
+
export const GMN_OPENCLAW_BASE_URL = FHL_OPENCLAW_BASE_URL;
|
|
14
|
+
export const GMN_CANDIDATE_BASE_URLS = FHL_CANDIDATE_BASE_URLS;
|
|
15
|
+
|
|
16
|
+
export const PLATFORM_META = {
|
|
17
|
+
codex: {
|
|
18
|
+
label: "Codex",
|
|
19
|
+
command: "cx",
|
|
20
|
+
defaultBaseUrl: DEFAULT_BASE_URL
|
|
21
|
+
},
|
|
22
|
+
opencode: {
|
|
23
|
+
label: "OpenCode",
|
|
24
|
+
command: "oc",
|
|
25
|
+
defaultBaseUrl: DEFAULT_BASE_URL
|
|
26
|
+
},
|
|
27
|
+
openclaw: {
|
|
28
|
+
label: "OpenClaw",
|
|
29
|
+
command: "ow",
|
|
30
|
+
defaultBaseUrl: DEFAULT_OPENCLAW_BASE_URL
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const SUPPORTED_PLATFORMS = Object.keys(PLATFORM_META);
|
|
35
|
+
export const DEFAULT_PLATFORM_SELECTION = [...SUPPORTED_PLATFORMS];
|
|
36
|
+
export const DEFAULT_CANDIDATE_BASE_URLS = [DEFAULT_BASE_URL];
|
|
37
|
+
|
|
38
|
+
export const BUILTIN_PRESETS = [
|
|
39
|
+
{
|
|
40
|
+
name: "march",
|
|
41
|
+
providerName: "fhl",
|
|
42
|
+
commonBaseUrl: "https://www.fhl.mom",
|
|
43
|
+
openclawBaseUrl: "https://www.fhl.mom/v1",
|
|
44
|
+
model: DEFAULT_PRIMARY_MODEL
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "openai",
|
|
48
|
+
providerName: "openai",
|
|
49
|
+
commonBaseUrl: "https://api.openai.com/v1",
|
|
50
|
+
openclawBaseUrl: "https://api.openai.com/v1",
|
|
51
|
+
model: DEFAULT_PRIMARY_MODEL
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: "gmn",
|
|
55
|
+
providerName: FHL_PROVIDER_NAME,
|
|
56
|
+
commonBaseUrl: FHL_BASE_URL,
|
|
57
|
+
openclawBaseUrl: FHL_OPENCLAW_BASE_URL,
|
|
58
|
+
model: DEFAULT_PRIMARY_MODEL
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: "fhl",
|
|
62
|
+
providerName: FHL_PROVIDER_NAME,
|
|
63
|
+
commonBaseUrl: FHL_BASE_URL,
|
|
64
|
+
openclawBaseUrl: FHL_OPENCLAW_BASE_URL,
|
|
65
|
+
model: DEFAULT_PRIMARY_MODEL
|
|
66
|
+
}
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
export const MODEL_DEFINITIONS = [
|
|
70
|
+
{ id: "gpt-5.4", reasoning: true, contextWindow: 1050000, maxTokens: 128000 },
|
|
71
|
+
{ id: "gpt-5.3-codex", reasoning: false, contextWindow: 400000, maxTokens: 128000 },
|
|
72
|
+
{ id: "gpt-5.2", reasoning: true, contextWindow: 1050000, maxTokens: 128000 },
|
|
73
|
+
{ id: "gpt-5.2-codex", reasoning: false, contextWindow: 400000, maxTokens: 128000 },
|
|
74
|
+
{ id: "gpt-5.1", reasoning: true, contextWindow: 1050000, maxTokens: 128000 },
|
|
75
|
+
{ id: "gpt-5.1-codex", reasoning: false, contextWindow: 400000, maxTokens: 128000 },
|
|
76
|
+
{ id: "gpt-5.1-codex-mini", reasoning: false, contextWindow: 400000, maxTokens: 128000 },
|
|
77
|
+
{ id: "gpt-5.1-codex-max", reasoning: false, contextWindow: 400000, maxTokens: 128000 }
|
|
78
|
+
];
|