-
Notifications
You must be signed in to change notification settings - Fork 24
feat(desktop, analytics): add packaging and usage export #172
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
42f1bcc
6e2d283
f15c332
04966dc
d69d704
adccc52
e232564
dcb7205
6242a2b
bd6cd6b
af1e3b5
b13f13a
948fdd3
c621391
e91b464
90cab7f
89cfa3f
b56e661
25cb231
abcbbe0
e60905b
77f6d43
21cc4d4
4be79e9
4ebfd74
64b24bc
ba938f1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| name: desktop-build | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| pull_request: | ||
| paths: | ||
| - 'src-tauri/**' | ||
| - 'tools/desktop/**' | ||
| - 'web-ui/**' | ||
| - 'cli.js' | ||
| - 'cli/**' | ||
| - 'lib/**' | ||
| - 'plugins/**' | ||
| - 'package.json' | ||
| - 'package-lock.json' | ||
| - '.github/workflows/desktop-build.yml' | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| tauri: | ||
| name: ${{ matrix.name }} | ||
| runs-on: ${{ matrix.os }} | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| - name: macOS | ||
| os: macos-latest | ||
| - name: Windows | ||
| os: windows-latest | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| - name: Setup Node | ||
| uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 | ||
| with: | ||
| node-version: '22' | ||
| cache: npm | ||
|
|
||
| - name: Setup Rust | ||
| uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 | ||
|
|
||
| - name: Install dependencies | ||
| run: npm ci | ||
|
|
||
| - name: Verify npm package payload | ||
| run: npm pack --dry-run --json | ||
|
|
||
| - name: Stage desktop runtime resources | ||
| run: npm run desktop:stage | ||
|
|
||
| - name: Build desktop app | ||
| run: npm run desktop:build | ||
|
|
||
| - name: Verify Windows app UAC manifest | ||
| if: matrix.name == 'Windows' | ||
| shell: pwsh | ||
| run: | | ||
| $exe = Join-Path $PWD 'src-tauri/target/release/codexmate-desktop.exe' | ||
| if (!(Test-Path $exe)) { | ||
| throw "Built app exe not found: $exe" | ||
| } | ||
|
|
||
| $mt = Get-ChildItem "${env:ProgramFiles(x86)}\Windows Kits\10\bin" -Recurse -Filter mt.exe | | ||
| Sort-Object FullName -Descending | | ||
| Select-Object -First 1 | ||
| if (!$mt) { | ||
| throw 'Windows manifest tool mt.exe not found' | ||
| } | ||
|
|
||
| $manifest = Join-Path $env:RUNNER_TEMP 'codexmate-desktop.manifest.xml' | ||
| & $mt.FullName -nologo "-inputresource:$exe;#1" "-out:$manifest" | ||
| if ($LASTEXITCODE -ne 0) { | ||
| throw "mt.exe failed to extract manifest from $exe" | ||
| } | ||
|
|
||
| $text = Get-Content $manifest -Raw | ||
| Write-Host $text | ||
| if ($text -notmatch 'requestedExecutionLevel\s+level="requireAdministrator"\s+uiAccess="false"') { | ||
| throw 'Windows app manifest does not require administrator privileges' | ||
| } | ||
| Copy-Item $manifest (Join-Path (Split-Path $exe) 'codexmate-desktop.manifest.xml') -Force | ||
|
|
||
| - name: Upload desktop bundles | ||
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 | ||
| with: | ||
| name: codexmate-desktop-${{ matrix.name }} | ||
| path: | | ||
| src-tauri/target/release/bundle/** | ||
| src-tauri/target/release/codexmate-desktop.exe | ||
| src-tauri/target/release/codexmate-desktop.manifest.xml | ||
| if-no-files-found: error |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -162,7 +162,8 @@ const { | |||||
| extractSessionDetailPreviewFromTailText, | ||||||
| extractSessionDetailPreviewFromFileFast | ||||||
| } = require('./lib/cli-sessions'); | ||||||
| const { listSessionUsageCore } = require('./cli/session-usage'); | ||||||
| const { listSessionUsageCore, exportSessionUsageCore } = require('./cli/session-usage'); | ||||||
| const { parseAnalyticsExportArgs } = require('./cli/analytics-export-args'); | ||||||
| const { | ||||||
| readBundledWebUiCss, | ||||||
| readBundledWebUiHtml, | ||||||
|
|
@@ -5204,6 +5205,12 @@ async function listSessionUsage(params = {}) { | |||||
| }); | ||||||
| } | ||||||
|
|
||||||
| async function exportSessionUsage(params = {}) { | ||||||
| return exportSessionUsageCore(params, { | ||||||
| listSessionUsage | ||||||
| }); | ||||||
| } | ||||||
|
|
||||||
| function listSessionPaths(params = {}) { | ||||||
| const source = typeof params.source === 'string' ? params.source.trim().toLowerCase() : ''; | ||||||
| if (source && source !== 'codex' && source !== 'claude' && source !== 'gemini' && source !== 'codebuddy' && source !== 'all') { | ||||||
|
|
@@ -9796,6 +9803,47 @@ async function cmdExportSession(args = []) { | |||||
| console.log(); | ||||||
| } | ||||||
|
|
||||||
| function printAnalyticsUsage() { | ||||||
| console.log('\n用法:'); | ||||||
| console.log(' codexmate analytics export [--format csv|json] [--from YYYY-MM-DD] [--to YYYY-MM-DD] [--model <MODEL>] [--source <codex|claude|gemini|codebuddy|all>] [--output <PATH|->] [-o <PATH|->]'); | ||||||
| console.log(''); | ||||||
| } | ||||||
|
|
||||||
| async function cmdAnalytics(args = []) { | ||||||
| const subcommand = args[0]; | ||||||
| if (subcommand !== 'export') { | ||||||
| printAnalyticsUsage(); | ||||||
| process.exit(subcommand ? 1 : 0); | ||||||
| } | ||||||
| const parsed = parseAnalyticsExportArgs(args.slice(1)); | ||||||
| if (parsed.options.help) { | ||||||
| printAnalyticsUsage(); | ||||||
| process.exit(0); | ||||||
| } | ||||||
| if (parsed.error) { | ||||||
| console.error('错误:', parsed.error); | ||||||
| printAnalyticsUsage(); | ||||||
| process.exit(1); | ||||||
| } | ||||||
|
|
||||||
| const result = await exportSessionUsage(parsed.options); | ||||||
| if (result && result.error) { | ||||||
| console.error('导出失败:', result.error); | ||||||
| process.exit(1); | ||||||
| } | ||||||
| const output = parsed.options.output || (result && result.fileName) || `usage-export.${parsed.options.format}`; | ||||||
| if (output === '-') { | ||||||
| process.stdout.write(result && result.content ? result.content : ''); | ||||||
| return; | ||||||
| } | ||||||
| const outputPath = path.resolve(process.cwd(), output); | ||||||
| ensureDir(path.dirname(outputPath)); | ||||||
| fs.writeFileSync(outputPath, result && result.content ? result.content : '', 'utf-8'); | ||||||
| console.log(`\n✓ Usage 已导出: ${outputPath}`); | ||||||
| console.log(` 格式: ${result.format}; rows: ${Array.isArray(result.rows) ? result.rows.length : 0}`); | ||||||
| console.log(); | ||||||
| } | ||||||
|
|
||||||
| function parseStartOptions(args = []) { | ||||||
| const options = { host: '', noBrowser: false }; | ||||||
| if (!Array.isArray(args)) { | ||||||
|
|
@@ -11077,6 +11125,20 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser | |||||
| } | ||||||
| } | ||||||
| break; | ||||||
| case 'export-sessions-usage': | ||||||
| { | ||||||
| const usageParams = isPlainObject(params) ? params : {}; | ||||||
| const source = typeof usageParams.source === 'string' ? usageParams.source.trim().toLowerCase() : ''; | ||||||
| if (source && source !== 'codex' && source !== 'claude' && source !== 'gemini' && source !== 'codebuddy' && source !== 'all') { | ||||||
| result = { error: 'Invalid source. Must be codex, claude, gemini, codebuddy, or all' }; | ||||||
| } else { | ||||||
| result = await exportSessionUsage({ | ||||||
| ...usageParams, | ||||||
| source: source || 'all' | ||||||
| }); | ||||||
| } | ||||||
| } | ||||||
| break; | ||||||
| case 'list-session-paths': | ||||||
| { | ||||||
| const source = typeof params.source === 'string' ? params.source.trim().toLowerCase() : ''; | ||||||
|
|
@@ -15960,6 +16022,7 @@ function printMainHelp() { | |||||
| console.log(' codexmate delete-model <模型> 删除模型'); | ||||||
| console.log(' codexmate workflow <list|get|validate|run|runs> MCP 工作流中心'); | ||||||
| console.log(' codexmate task <plan|run|runs|queue|retry|cancel|logs> 本地任务编排'); | ||||||
| console.log(' codexmate analytics export [--format csv|json] [--from YYYY-MM-DD] [--to YYYY-MM-DD] [--model <MODEL>] [--output <PATH|->] [-o <PATH|->] 导出 Usage 数据'); | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add Line [16025] omits Suggested patch- console.log(' codexmate analytics export [--format csv|json] [--from YYYY-MM-DD] [--to YYYY-MM-DD] [--model <MODEL>] [--output <PATH|->] [-o <PATH|->] 导出 Usage 数据');
+ console.log(' codexmate analytics export [--format csv|json] [--from YYYY-MM-DD] [--to YYYY-MM-DD] [--model <MODEL>] [--source <codex|claude|gemini|codebuddy|all>] [--output <PATH|->] [-o <PATH|->] 导出 Usage 数据');📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| console.log(' codexmate run [--host <HOST>] [--no-browser] 启动 Web 界面'); | ||||||
| console.log(' codexmate update [--check] 检查并快速更新工具'); | ||||||
| console.log(' codexmate codex [参数...] [--follow-up <文本>|--queued-follow-up <文本> 可重复] 等同于 codex --yolo'); | ||||||
|
|
@@ -16052,6 +16115,7 @@ async function main() { | |||||
| case 'proxy': await cmdProxy(args.slice(1)); break; | ||||||
| case 'workflow': await cmdWorkflow(args.slice(1)); break; | ||||||
| case 'task': await cmdTask(args.slice(1)); break; | ||||||
| case 'analytics': await cmdAnalytics(args.slice(1)); break; | ||||||
| case 'run': cmdStart(parseStartOptions(args.slice(1))); break; | ||||||
| case 'update': await cmdToolUpdate(args.slice(1)); break; | ||||||
| case 'start': | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: SakuraByteCore/codexmate
Length of output: 5620
Disable npm cache for the Node 18
setup-nodestep inrelease.yml..github/workflows/release.ymlconfiguresactions/setup-node@...withnode-version: '18'andcache: 'npm'; omitting the npm cache in the release job reduces cross-run cache-contamination/cache-poisoning risk.🔒 Suggested change
- name: Setup Node uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 with: node-version: '18' - cache: 'npm'📝 Committable suggestion
🧰 Tools
🪛 zizmor (1.25.2)
[error] 235-235: runtime artifacts potentially vulnerable to a cache poisoning attack (cache-poisoning): this step
(cache-poisoning)
🤖 Prompt for AI Agents