free-coding-models 0.3.42 → 0.3.44
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/CHANGELOG.md +6 -8
- package/README.md +95 -0
- package/package.json +1 -1
- package/src/app.js +11 -2
- package/src/command-palette.js +1 -0
- package/src/config.js +3 -1
- package/src/key-handler.js +105 -1
- package/src/openclaw.js +25 -3
- package/src/opencode.js +28 -0
- package/src/render-table.js +32 -24
- package/src/telemetry.js +32 -13
- package/src/tool-bootstrap.js +14 -0
- package/src/tool-launchers.js +21 -3
- package/src/tool-metadata.js +4 -1
- package/src/utils.js +4 -2
- package/web/dist/assets/{index-fk7MxoC4.js → index-baoFTSG_.js} +1 -1
- package/web/dist/index.html +1 -1
package/src/telemetry.js
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* All telemetry is strictly opt-in-by-default, fire-and-forget, and anonymous:
|
|
8
8
|
* - A stable `anonymousId` (UUID prefixed with "anon_") is generated once and stored
|
|
9
9
|
* in ~/.free-coding-models.json. No personal data is ever collected.
|
|
10
|
-
* - PostHog is used for product analytics (app_start
|
|
10
|
+
* - PostHog is used for product analytics (`app_start`, `app_use`, and lightweight
|
|
11
|
+
* `app_action` events covering launches and key product actions).
|
|
11
12
|
* - Discord webhooks carry anonymous feature requests (J key) and bug reports (I key).
|
|
12
13
|
* - `isTelemetryEnabled()` checks: CLI flag → env var → default (enabled).
|
|
13
14
|
* - `telemetryDebug()` writes to stderr only when FREE_CODING_MODELS_TELEMETRY_DEBUG=1.
|
|
@@ -29,6 +30,7 @@
|
|
|
29
30
|
* → getTelemetrySystem() — Convert platform to human label
|
|
30
31
|
* → getTelemetryTerminal() — Infer terminal family from env hints
|
|
31
32
|
* → isTelemetryEnabled(config, cliArgs) — Resolve effective enabled state
|
|
33
|
+
* → buildTelemetryProperties(payload) — Build sanitized PostHog event properties
|
|
32
34
|
* → sendUsageTelemetry(config, cliArgs, payload)— Fire-and-forget PostHog ping
|
|
33
35
|
* → sendFeatureRequest(message) — Post anonymous feature request to Discord
|
|
34
36
|
* → sendBugReport(message) — Post anonymous bug report to Discord
|
|
@@ -37,7 +39,7 @@
|
|
|
37
39
|
* parseTelemetryEnv, isTelemetryDebugEnabled, telemetryDebug,
|
|
38
40
|
* ensureTelemetryConfig, getTelemetryDistinctId,
|
|
39
41
|
* getTelemetrySystem, getTelemetryTerminal,
|
|
40
|
-
* isTelemetryEnabled, sendUsageTelemetry,
|
|
42
|
+
* isTelemetryEnabled, buildTelemetryProperties, sendUsageTelemetry,
|
|
41
43
|
* sendFeatureRequest, sendBugReport
|
|
42
44
|
*
|
|
43
45
|
* @see src/config.js — saveConfig is imported here to persist the generated anonymousId
|
|
@@ -205,11 +207,37 @@ export function isTelemetryEnabled(config, cliArgs) {
|
|
|
205
207
|
return true
|
|
206
208
|
}
|
|
207
209
|
|
|
210
|
+
/**
|
|
211
|
+
* 📖 Build the final analytics properties object while keeping the base schema
|
|
212
|
+
* 📖 stable and stripping undefined values from optional action-specific fields.
|
|
213
|
+
* @param {{ version?: string, mode?: string, properties?: Record<string, unknown> } | undefined} payload
|
|
214
|
+
* @returns {Record<string, unknown>}
|
|
215
|
+
*/
|
|
216
|
+
export function buildTelemetryProperties(payload) {
|
|
217
|
+
const extraProperties = payload?.properties && typeof payload.properties === 'object' && !Array.isArray(payload.properties)
|
|
218
|
+
? payload.properties
|
|
219
|
+
: {}
|
|
220
|
+
|
|
221
|
+
const merged = {
|
|
222
|
+
...extraProperties,
|
|
223
|
+
$process_person_profile: false,
|
|
224
|
+
source: 'cli',
|
|
225
|
+
app: 'free-coding-models',
|
|
226
|
+
version: payload?.version || LOCAL_VERSION,
|
|
227
|
+
app_version: payload?.version || LOCAL_VERSION,
|
|
228
|
+
mode: payload?.mode || 'opencode',
|
|
229
|
+
system: getTelemetrySystem(),
|
|
230
|
+
terminal: getTelemetryTerminal(),
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return Object.fromEntries(Object.entries(merged).filter(([, value]) => value !== undefined))
|
|
234
|
+
}
|
|
235
|
+
|
|
208
236
|
/**
|
|
209
237
|
* 📖 Fire-and-forget analytics ping: never blocks UX, never throws.
|
|
210
238
|
* @param {Record<string, unknown>} config
|
|
211
239
|
* @param {{ noTelemetry?: boolean }} cliArgs
|
|
212
|
-
* @param {{ event?: string, version?: string, mode?: string, ts?: string }} payload
|
|
240
|
+
* @param {{ event?: string, version?: string, mode?: string, ts?: string, properties?: Record<string, unknown> }} payload
|
|
213
241
|
*/
|
|
214
242
|
export async function sendUsageTelemetry(config, cliArgs, payload) {
|
|
215
243
|
if (!isTelemetryEnabled(config, cliArgs)) {
|
|
@@ -256,16 +284,7 @@ export async function sendUsageTelemetry(config, cliArgs, payload) {
|
|
|
256
284
|
event: payload?.event || 'app_start',
|
|
257
285
|
distinct_id: distinctId,
|
|
258
286
|
timestamp,
|
|
259
|
-
properties:
|
|
260
|
-
$process_person_profile: false,
|
|
261
|
-
source: 'cli',
|
|
262
|
-
app: 'free-coding-models',
|
|
263
|
-
version: payload?.version || LOCAL_VERSION,
|
|
264
|
-
app_version: payload?.version || LOCAL_VERSION,
|
|
265
|
-
mode: payload?.mode || 'opencode',
|
|
266
|
-
system: getTelemetrySystem(),
|
|
267
|
-
terminal: getTelemetryTerminal(),
|
|
268
|
-
},
|
|
287
|
+
properties: buildTelemetryProperties(payload),
|
|
269
288
|
}
|
|
270
289
|
|
|
271
290
|
await fetch(endpoint, {
|
package/src/tool-bootstrap.js
CHANGED
|
@@ -280,6 +280,20 @@ export const TOOL_BOOTSTRAP_METADATA = {
|
|
|
280
280
|
},
|
|
281
281
|
},
|
|
282
282
|
},
|
|
283
|
+
jcode: {
|
|
284
|
+
binary: 'jcode',
|
|
285
|
+
docsUrl: 'https://github.com/1jehuang/jcode',
|
|
286
|
+
install: {
|
|
287
|
+
default: {
|
|
288
|
+
shellCommand: 'curl -fsSL https://raw.githubusercontent.com/1jehuang/jcode/master/scripts/install.sh | bash',
|
|
289
|
+
summary: 'Install jcode via the official installer script.',
|
|
290
|
+
},
|
|
291
|
+
win32: {
|
|
292
|
+
shellCommand: 'irm https://raw.githubusercontent.com/1jehuang/jcode/master/scripts/install.ps1 | iex',
|
|
293
|
+
summary: 'Install jcode via the official PowerShell installer.',
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
},
|
|
283
297
|
}
|
|
284
298
|
|
|
285
299
|
export function getToolBootstrapMeta(mode) {
|
package/src/tool-launchers.js
CHANGED
|
@@ -272,7 +272,7 @@ function writePiConfig(model, apiKey, baseUrl, paths = getDefaultToolPaths()) {
|
|
|
272
272
|
const modelsBackupPath = backupIfExists(modelsFilePath)
|
|
273
273
|
const modelsConfig = readJson(modelsFilePath, { providers: {} })
|
|
274
274
|
if (!modelsConfig.providers || typeof modelsConfig.providers !== 'object') modelsConfig.providers = {}
|
|
275
|
-
modelsConfig.providers.
|
|
275
|
+
modelsConfig.providers[model.providerKey] = {
|
|
276
276
|
baseUrl,
|
|
277
277
|
api: 'openai-completions',
|
|
278
278
|
apiKey,
|
|
@@ -284,7 +284,7 @@ function writePiConfig(model, apiKey, baseUrl, paths = getDefaultToolPaths()) {
|
|
|
284
284
|
const settingsFilePath = paths.piSettingsPath
|
|
285
285
|
const settingsBackupPath = backupIfExists(settingsFilePath)
|
|
286
286
|
const settingsConfig = readJson(settingsFilePath, {})
|
|
287
|
-
settingsConfig.defaultProvider =
|
|
287
|
+
settingsConfig.defaultProvider = model.providerKey
|
|
288
288
|
settingsConfig.defaultModel = model.modelId
|
|
289
289
|
writeJson(settingsFilePath, settingsConfig)
|
|
290
290
|
|
|
@@ -667,7 +667,7 @@ export function prepareExternalToolLaunch(mode, model, config, options = {}) {
|
|
|
667
667
|
const result = writePiConfig(model, apiKey, baseUrl, paths)
|
|
668
668
|
return {
|
|
669
669
|
command: 'pi',
|
|
670
|
-
args: ['--provider',
|
|
670
|
+
args: ['--provider', model.providerKey, '--model', model.modelId, '--api-key', apiKey],
|
|
671
671
|
env,
|
|
672
672
|
apiKey,
|
|
673
673
|
baseUrl,
|
|
@@ -758,6 +758,19 @@ export function prepareExternalToolLaunch(mode, model, config, options = {}) {
|
|
|
758
758
|
}
|
|
759
759
|
}
|
|
760
760
|
|
|
761
|
+
if (mode === 'jcode') {
|
|
762
|
+
console.log(chalk.dim(` 📖 jcode will use provider: ${model.providerKey} / model: ${model.modelId}`))
|
|
763
|
+
return {
|
|
764
|
+
command: 'jcode',
|
|
765
|
+
args: ['run', '--provider', model.providerKey, '--model', model.modelId, '--api-key', apiKey],
|
|
766
|
+
env,
|
|
767
|
+
apiKey,
|
|
768
|
+
baseUrl,
|
|
769
|
+
meta,
|
|
770
|
+
configArtifacts: [],
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
761
774
|
return {
|
|
762
775
|
blocked: true,
|
|
763
776
|
exitCode: 1,
|
|
@@ -854,6 +867,11 @@ export async function startExternalTool(mode, model, config) {
|
|
|
854
867
|
return spawnCommand(resolveLaunchCommand(mode, launchPlan.command), launchPlan.args, launchPlan.env)
|
|
855
868
|
}
|
|
856
869
|
|
|
870
|
+
if (mode === 'jcode') {
|
|
871
|
+
console.log(chalk.dim(` 📖 Launching jcode...`))
|
|
872
|
+
return spawnCommand(resolveLaunchCommand(mode, launchPlan.command), launchPlan.args, launchPlan.env)
|
|
873
|
+
}
|
|
874
|
+
|
|
857
875
|
console.log(chalk.red(` X Unsupported external tool mode: ${mode}`))
|
|
858
876
|
return 1
|
|
859
877
|
}
|
package/src/tool-metadata.js
CHANGED
|
@@ -41,6 +41,7 @@ export const TOOL_METADATA = {
|
|
|
41
41
|
cline: { label: 'Cline', emoji: '🧠', flag: '--cline', color: [100, 220, 180] },
|
|
42
42
|
rovo: { label: 'Rovo Dev CLI', emoji: '🦘', flag: '--rovo', color: [148, 163, 184], cliOnly: true },
|
|
43
43
|
gemini: { label: 'Gemini CLI', emoji: '♊', flag: '--gemini', color: [66, 165, 245], cliOnly: true },
|
|
44
|
+
jcode: { label: 'jcode', emoji: '🪼', flag: '--jcode', color: [255, 140, 0] },
|
|
44
45
|
xcode: { label: 'Xcode Intelligence',emoji: '🛠️', flag: '--xcode', color: [20, 126, 251] },
|
|
45
46
|
}
|
|
46
47
|
|
|
@@ -62,16 +63,17 @@ export const COMPAT_COLUMN_SLOTS = [
|
|
|
62
63
|
{ emoji: '🧠', toolKeys: ['cline'], color: [100, 220, 180] },
|
|
63
64
|
{ emoji: '🦘', toolKeys: ['rovo'], color: [148, 163, 184] },
|
|
64
65
|
{ emoji: '♊', toolKeys: ['gemini'], color: [66, 165, 245] },
|
|
66
|
+
{ emoji: '🪼', toolKeys: ['jcode'], color: [255, 140, 0] },
|
|
65
67
|
{ emoji: '🛠️', toolKeys: ['xcode'], color: [20, 126, 251] },
|
|
66
68
|
]
|
|
67
69
|
|
|
68
70
|
export const TOOL_MODE_ORDER = [
|
|
69
71
|
'opencode',
|
|
72
|
+
'pi',
|
|
70
73
|
'opencode-desktop',
|
|
71
74
|
'openclaw',
|
|
72
75
|
'crush',
|
|
73
76
|
'goose',
|
|
74
|
-
'pi',
|
|
75
77
|
'aider',
|
|
76
78
|
'qwen',
|
|
77
79
|
'openhands',
|
|
@@ -82,6 +84,7 @@ export const TOOL_MODE_ORDER = [
|
|
|
82
84
|
'xcode',
|
|
83
85
|
'rovo',
|
|
84
86
|
'gemini',
|
|
87
|
+
'jcode',
|
|
85
88
|
]
|
|
86
89
|
|
|
87
90
|
export function getToolMeta(mode) {
|
package/src/utils.js
CHANGED
|
@@ -392,10 +392,10 @@ export function findBestModel(results) {
|
|
|
392
392
|
// --openhands, --amp, --pi, --no-telemetry, --json, --help/-h (case-insensitive)
|
|
393
393
|
// - Value flag: --tier <letter> (the next non-flag arg is the tier value)
|
|
394
394
|
//
|
|
395
|
-
//
|
|
395
|
+
// Returns:
|
|
396
396
|
// { apiKey, bestMode, fiableMode, openCodeMode, openCodeDesktopMode, openClawMode,
|
|
397
397
|
// aiderMode, crushMode, gooseMode, qwenMode, openHandsMode, ampMode,
|
|
398
|
-
// piMode, noTelemetry, jsonMode, helpMode, tierFilter }
|
|
398
|
+
// piMode, jcodeMode, noTelemetry, jsonMode, helpMode, tierFilter }
|
|
399
399
|
//
|
|
400
400
|
// 📖 Note: apiKey may be null here — the main CLI falls back to env vars and saved config.
|
|
401
401
|
export function parseArgs(argv) {
|
|
@@ -460,6 +460,7 @@ export function parseArgs(argv) {
|
|
|
460
460
|
const clineMode = flags.includes('--cline')
|
|
461
461
|
const xcodeMode = flags.includes('--xcode')
|
|
462
462
|
const geminiMode = flags.includes('--gemini')
|
|
463
|
+
const jcodeMode = flags.includes('--jcode')
|
|
463
464
|
const noTelemetry = flags.includes('--no-telemetry')
|
|
464
465
|
const jsonMode = flags.includes('--json')
|
|
465
466
|
const helpMode = flags.includes('--help') || flags.includes('-h')
|
|
@@ -505,6 +506,7 @@ export function parseArgs(argv) {
|
|
|
505
506
|
xcodeMode,
|
|
506
507
|
rovoMode,
|
|
507
508
|
geminiMode,
|
|
509
|
+
jcodeMode,
|
|
508
510
|
noTelemetry,
|
|
509
511
|
jsonMode,
|
|
510
512
|
helpMode,
|