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.
Files changed (62) hide show
  1. package/README.md +107 -0
  2. package/build/icon.ico +0 -0
  3. package/build/icon.png +0 -0
  4. package/core/apply.js +152 -0
  5. package/core/backup.js +53 -0
  6. package/core/constants.js +78 -0
  7. package/core/desktop-service.js +403 -0
  8. package/core/desktop-state.js +1021 -0
  9. package/core/index.js +1468 -0
  10. package/core/paths.js +99 -0
  11. package/core/presets.js +171 -0
  12. package/core/probe.js +70 -0
  13. package/core/routing.js +334 -0
  14. package/core/store.js +218 -0
  15. package/core/utils.js +225 -0
  16. package/core/writers/codex.js +102 -0
  17. package/core/writers/index.js +16 -0
  18. package/core/writers/openclaw.js +93 -0
  19. package/core/writers/opencode.js +91 -0
  20. package/desktop/assets/fml-icon.png +0 -0
  21. package/desktop/assets/march-mark.svg +26 -0
  22. package/desktop/main.js +275 -0
  23. package/desktop/preload.cjs +67 -0
  24. package/desktop/preload.js +49 -0
  25. package/desktop/renderer/app.js +327 -0
  26. package/desktop/renderer/index.html +130 -0
  27. package/desktop/renderer/styles.css +490 -0
  28. package/package.json +111 -0
  29. package/scripts/build-web.mjs +95 -0
  30. package/scripts/desktop-dev.mjs +90 -0
  31. package/scripts/desktop-pack-win.mjs +81 -0
  32. package/scripts/postinstall.mjs +49 -0
  33. package/scripts/prepublish-check.mjs +57 -0
  34. package/scripts/serve-site.mjs +51 -0
  35. package/site/app.js +10 -0
  36. package/site/assets/fml-icon.png +0 -0
  37. package/site/assets/march-mark.svg +26 -0
  38. package/site/index.html +337 -0
  39. package/site/styles.css +840 -0
  40. package/src/App.tsx +1557 -0
  41. package/src/components/layout/app-sidebar.tsx +103 -0
  42. package/src/components/layout/top-toolbar.tsx +44 -0
  43. package/src/components/layout/workspace-tabs.tsx +32 -0
  44. package/src/components/providers/inspector-panel.tsx +84 -0
  45. package/src/components/providers/metric-strip.tsx +26 -0
  46. package/src/components/providers/provider-editor.tsx +87 -0
  47. package/src/components/providers/provider-table.tsx +85 -0
  48. package/src/components/ui/logo-mark.tsx +32 -0
  49. package/src/features/mcp/mcp-view.tsx +45 -0
  50. package/src/features/prompts/prompts-view.tsx +40 -0
  51. package/src/features/providers/providers-view.tsx +40 -0
  52. package/src/features/providers/types.ts +26 -0
  53. package/src/features/skills/skills-view.tsx +44 -0
  54. package/src/hooks/use-control-workspace.ts +235 -0
  55. package/src/index.css +22 -0
  56. package/src/lib/client.ts +726 -0
  57. package/src/lib/query-client.ts +3 -0
  58. package/src/lib/workspace-sections.ts +34 -0
  59. package/src/main.tsx +14 -0
  60. package/src/types.ts +137 -0
  61. package/src/vite-env.d.ts +64 -0
  62. 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
+ ];