-
Notifications
You must be signed in to change notification settings - Fork 4
feat: add windows build & update messages style #6
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
Changes from all commits
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,45 @@ | ||
| name: Release Windows | ||
|
|
||
| on: | ||
| push: | ||
| tags: | ||
| - 'v*.*.*' | ||
|
|
||
| env: | ||
| NODE_VERSION: 20 | ||
| PNPM_VERSION: 10.32.1 | ||
|
|
||
| jobs: | ||
| release: | ||
| runs-on: windows-latest | ||
| permissions: | ||
| contents: write | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: pnpm/action-setup@v4 | ||
| with: | ||
| version: ${{ env.PNPM_VERSION }} | ||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: ${{ env.NODE_VERSION }} | ||
| - name: Verify tag matches package version | ||
| shell: bash | ||
| run: | | ||
| VERSION="$(node -p "JSON.parse(require('node:fs').readFileSync('package.json', 'utf8')).version")" | ||
| if [[ "v${VERSION}" != "${GITHUB_REF_NAME}" ]]; then | ||
| echo "Tag ${GITHUB_REF_NAME} does not match package.json version ${VERSION}" >&2 | ||
| exit 1 | ||
| fi | ||
| - name: Install dependencies | ||
| run: pnpm install --frozen-lockfile | ||
| - name: Build app | ||
| run: pnpm build | ||
| - name: Build Windows release artifacts | ||
| run: pnpm exec node ./scripts/run-electron-builder.cjs --win nsis --x64 --arm64 --publish never | ||
| - name: Publish GitHub release | ||
| uses: softprops/action-gh-release@v2 | ||
| with: | ||
| files: | | ||
| dist/*.exe | ||
| dist/*.exe.blockmap | ||
| dist/latest.yml | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,8 +34,14 @@ dmg: | |
| type: link | ||
| path: /Applications | ||
| win: | ||
| icon: resources/icon.ico | ||
| artifactName: Agent-Trace-${version}-${arch}.${ext} | ||
| target: | ||
| - nsis | ||
| nsis: | ||
| oneClick: false | ||
| allowToChangeInstallationDirectory: true | ||
| deleteAppDataOnUninstall: true | ||
|
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.
Setting Useful? React with 👍 / 👎. |
||
| linux: | ||
| target: | ||
| - AppImage | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,13 +8,73 @@ interface MarkdownRendererProps { | |
| className?: string; | ||
| } | ||
|
|
||
| function normalizeXmlContent(text: string): string { | ||
| const lines = text.split('\n'); | ||
| const result: string[] = []; | ||
| let xmlDepth = 0; | ||
| let inXmlBlock = false; | ||
|
|
||
| for (const line of lines) { | ||
| const trimmed = line.trim(); | ||
|
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.
Useful? React with 👍 / 👎. |
||
|
|
||
| // Detect XML tags | ||
| const hasOpenTag = /<[\w-]+>/.test(trimmed); | ||
| const hasCloseTag = /<\/[\w-]+>/.test(trimmed); | ||
| const isStandaloneOpenTag = /^<[\w-]+>$/.test(trimmed); | ||
| const isStandaloneCloseTag = /^<\/[\w-]+>$/.test(trimmed); | ||
|
|
||
| // Track if we're inside an XML block | ||
| if (hasOpenTag || hasCloseTag) { | ||
| inXmlBlock = true; | ||
| } | ||
|
|
||
| // For lines inside XML blocks, normalize indentation | ||
| if (inXmlBlock) { | ||
| // Empty lines | ||
| if (!trimmed) { | ||
| result.push(''); | ||
| continue; | ||
| } | ||
|
|
||
| // Standalone closing tag - decrease depth first | ||
| if (isStandaloneCloseTag) { | ||
| xmlDepth = Math.max(0, xmlDepth - 1); | ||
| const indent = '\u00A0\u00A0'.repeat(xmlDepth); | ||
| result.push(indent + trimmed); | ||
| continue; | ||
| } | ||
|
|
||
| // Standalone opening tag | ||
| if (isStandaloneOpenTag) { | ||
| const indent = '\u00A0\u00A0'.repeat(xmlDepth); | ||
| result.push(indent + trimmed); | ||
| xmlDepth++; | ||
| continue; | ||
| } | ||
|
|
||
| // Content inside XML tags - use current depth | ||
| const indent = '\u00A0\u00A0'.repeat(xmlDepth); | ||
| result.push(indent + trimmed); | ||
| } else { | ||
| // Outside XML blocks, preserve original line | ||
| result.push(line); | ||
| } | ||
| } | ||
|
|
||
| return result.join('\n'); | ||
| } | ||
|
|
||
| export function MarkdownRenderer({ content, className }: MarkdownRendererProps) { | ||
| // Normalize XML content indentation, then escape tags | ||
| let processedContent = normalizeXmlContent(content); | ||
| processedContent = processedContent.replace(/</g, '<').replace(/>/g, '>'); | ||
|
|
||
| const components: Components = { | ||
| // Custom component styles to match theme | ||
| h1: ({ node, ...props }) => <h1 className="text-lg font-semibold text-foreground mb-2" {...props} />, | ||
| h2: ({ node, ...props }) => <h2 className="text-base font-semibold text-foreground mb-2" {...props} />, | ||
| h3: ({ node, ...props }) => <h3 className="text-sm font-semibold text-foreground mb-1" {...props} />, | ||
| p: ({ node, ...props }) => <p className="text-sm text-foreground/90 mb-2 break-words whitespace-pre-wrap" {...props} />, | ||
| h1: ({ node, ...props }) => <h1 className="text-base font-semibold text-foreground mb-3" {...props} />, | ||
| h2: ({ node, ...props }) => <h2 className="text-sm font-semibold text-foreground mb-2.5" {...props} />, | ||
| h3: ({ node, ...props }) => <h3 className="text-xs font-semibold text-foreground mb-2" {...props} />, | ||
| p: ({ node, ...props }) => <p className="text-xs text-foreground/75 mb-3 break-words whitespace-pre-wrap leading-relaxed" {...props} />, | ||
| code: ({ node, className: codeClassName, children, ...props }) => { | ||
| const match = /language-(\w+)/.exec(codeClassName || ''); | ||
| const isInline = !match; | ||
|
|
@@ -24,14 +84,28 @@ export function MarkdownRenderer({ content, className }: MarkdownRendererProps) | |
| return <code className="block bg-muted p-3 rounded overflow-auto text-xs font-mono whitespace-pre-wrap break-all" {...props}>{children}</code>; | ||
| }, | ||
| a: ({ node, ...props }) => <a className="text-primary hover:underline break-words" {...props} />, | ||
| ul: ({ node, ...props }) => <ul className="list-disc list-inside mb-2 text-sm" {...props} />, | ||
| ol: ({ node, ...props }) => <ol className="list-decimal list-inside mb-2 text-sm" {...props} />, | ||
| ul: ({ node, ...props }) => <ul className="list-disc list-inside mb-3 text-xs text-foreground/75 space-y-1 leading-relaxed" {...props} />, | ||
| ol: ({ node, ...props }) => <ol className="list-decimal list-inside mb-3 text-xs text-foreground/75 space-y-1 leading-relaxed" {...props} />, | ||
| li: ({ node, ...props }) => <li className="text-xs text-foreground/75 leading-relaxed" {...props} />, | ||
| blockquote: ({ node, ...props }) => <blockquote className="border-l-2 border-muted-foreground/30 pl-3 my-3 text-xs text-foreground/70 italic leading-relaxed" {...props} />, | ||
| strong: ({ node, ...props }) => <strong className="font-semibold text-foreground" {...props} />, | ||
| em: ({ node, ...props }) => <em className="italic text-foreground/80" {...props} />, | ||
| hr: ({ node, ...props }) => <hr className="my-4 border-border" {...props} />, | ||
| table: ({ node, ...props }) => <table className="w-full text-xs border-collapse my-3" {...props} />, | ||
| thead: ({ node, ...props }) => <thead className="border-b border-border" {...props} />, | ||
| tbody: ({ node, ...props }) => <tbody {...props} />, | ||
| tr: ({ node, ...props }) => <tr className="border-b border-border/50" {...props} />, | ||
| th: ({ node, ...props }) => <th className="text-left p-2 font-semibold text-foreground" {...props} />, | ||
| td: ({ node, ...props }) => <td className="p-2 text-foreground/75" {...props} />, | ||
| }; | ||
|
|
||
| return ( | ||
| <div className={cn('prose prose-sm dark:prose-invert max-w-none break-words', className)}> | ||
| <ReactMarkdown remarkPlugins={[remarkGfm]} components={components}> | ||
| {content} | ||
| <ReactMarkdown | ||
| remarkPlugins={[remarkGfm]} | ||
| components={components} | ||
| > | ||
| {processedContent} | ||
| </ReactMarkdown> | ||
| </div> | ||
| ); | ||
|
|
||
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.
This workflow now publishes Windows updater artifacts (
latest.ymland blockmaps), butsrc/main/update/update-service.tsstill hard-codessupported = platform === "darwin" && isPackaged, andsrc/shared/update.tsstill tells non-macOS users updates are unsupported. For every packaged Windows build produced here, the Settings update flow will still no-op and display the macOS-only message, so the new release metadata cannot actually be consumed in-app.Useful? React with 👍 / 👎.