Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
366d934
feat(missions): add native session mesh control plane
pascalandr Sep 4, 2026
729eb41
feat(ui): add live Mission Control map
pascalandr Sep 4, 2026
dec86c5
feat(missions): enforce native playbook contracts
pascalandr Sep 4, 2026
511339e
fix(missions): preserve optional native locations
pascalandr Sep 4, 2026
32a2785
fix(missions): serialize durable control-plane mutations
pascalandr Sep 5, 2026
6164633
fix(missions): enforce mission and explicit actor admission limits
pascalandr Sep 5, 2026
b26cfc9
Merge branch 'dev' into feat/session-native-missions-v2
pascalandr Sep 7, 2026
512f85c
merge(dev): preserve mission and clipboard CI coverage
pascalandr Sep 9, 2026
a235f89
merge(dev): refresh Missions branch
pascalandr Sep 10, 2026
fb07e29
merge(dev): migrate Missions to the current native plugin contract
pascalandr Sep 16, 2026
19daab1
merge(dev): resolve Missions against current native runtime
pascalandr Sep 19, 2026
541d58d
Merge branch 'dev' into feat/session-native-missions-v2
pascalandr Sep 19, 2026
8fefb27
Merge branch 'dev' into feat/session-native-missions-v2
pascalandr Sep 19, 2026
fd1f2e8
Merge branch 'dev' into feat/session-native-missions-v2
pascalandr Sep 19, 2026
b19ff68
merge(dev): keep Missions on queued event routing
pascalandr Sep 19, 2026
26178e1
merge(dev): retain Missions with scrollbar cascade
pascalandr Sep 19, 2026
999ca97
fix(setup): recover interrupted Windows OpenCode installations (#783)
pascalandr Sep 25, 2026
d873cfd
docs: refresh README and workspace screenshot for 0.20 (#782)
pascalandr Sep 26, 2026
14b1eaa
fix(models): persist favorites mode independently of the active model…
pascalandr Sep 26, 2026
f26bed2
chore(opencode): qualify and recommend stable 2.0.18
pascalandr Sep 26, 2026
a77e37e
chore(opencode): qualify and recommend stable 2.0.18 (#788)
pascalandr Sep 26, 2026
4d74086
feat(missions): bundle project coordination with the desktop runtime
pascalandr Sep 26, 2026
258e20a
fix(missions): unblock dispatch behind unrelated workspace scans
pascalandr Sep 27, 2026
fa8925a
fix(missions): allow cold ownership validation during discovery
pascalandr Sep 27, 2026
c76edff
feat(missions): add revisable plans and persistent mission control
pascalandr Sep 27, 2026
e11e26a
fix(missions): preserve reload exclusion and admit escaped contracts
pascalandr Sep 27, 2026
562ec02
fix(missions): recover report wakeups and stabilize revised task cont…
pascalandr Sep 27, 2026
fb421d5
fix(missions): preserve lifecycle errors across native RPC
pascalandr Sep 27, 2026
bfe8e70
fix(missions): resolve multi-step fixes by unique implementer session
pascalandr Sep 27, 2026
b584ffc
merge(dev): reconcile Missions with the current V2 baseline
pascalandr Sep 28, 2026
bf6a769
fix(missions): refresh Git availability context before admission
pascalandr Sep 28, 2026
6e6be58
fix(setup): show sustained OpenCode installation progress (#784)
pascalandr Sep 28, 2026
0b348e8
fix(electron): avoid destroyed window access on close (#785)
pascalandr Sep 28, 2026
e26a15a
feat(missions): streamline mission navigation
pascalandr Sep 29, 2026
824d94d
chore(opencode): qualify and recommend stable 2.0.19
pascalandr Sep 29, 2026
47f9e43
chore(opencode): qualify and recommend stable 2.0.19 (#799)
pascalandr Sep 29, 2026
716ae00
fix(missions): replace reader return action with upper-right close ic…
pascalandr Sep 30, 2026
eb1bf48
fix(ui): expose close actions in existing preview and utility toolbar…
pascalandr Sep 30, 2026
d995750
fix(status): keep connected MCP indicators static at rest (#806)
pascalandr Sep 30, 2026
e392411
chore(opencode): qualify and recommend stable 2.0.20
pascalandr Sep 30, 2026
6fd423d
chore(opencode): qualify and recommend stable 2.0.20 (#810)
pascalandr Sep 30, 2026
d57560e
fix(files): restore workspace-root and visible parent navigation (#807)
pascalandr Sep 30, 2026
db1f552
fix(usage): use selected native V2 Codex credentials (#811)
pascalandr Sep 30, 2026
0822c79
fix(mobile): responsive conversation controls and proportional prompt…
pascalandr Sep 30, 2026
43e3ba7
chore(opencode): qualify and recommend stable 2.0.21
pascalandr Sep 30, 2026
ebafc2c
chore(opencode): qualify and recommend stable 2.0.21 (#815)
pascalandr Sep 30, 2026
77692a7
fix(proxy): preserve missing-session errors for orphaned sub-sessions…
pascalandr Sep 30, 2026
ee5f738
feat(files): unify Workspace, Changes and Commits with central previe…
pascalandr Oct 1, 2026
ad056ff
fix(usage): prevent quota panel flicker and explain older service lim…
pascalandr Oct 1, 2026
fb2ae42
fix(layout): make desktop minimums zoom-aware and compact headers at …
pascalandr Oct 1, 2026
c2d9c66
feat(missions): add durable execution controls and specialist cleanup
pascalandr Oct 1, 2026
46a4ea0
fix(tauri): prevent macOS startup window event feedback (#821)
pascalandr Oct 1, 2026
b1484f1
fix(info): distinguish server platform from client environment (#820)
pascalandr Oct 1, 2026
366830f
fix(usage): preserve quotas during provider catalogue refreshes (#823)
pascalandr Oct 1, 2026
bbbc5e3
merge(dev): resolve mission integration conflicts
pascalandr Oct 1, 2026
f6a18d0
fix: reduce compaction and cross-session responsiveness stalls
pascalandr Oct 1, 2026
acac9be
chore: keep issue 824 investigation reports out of the PR
pascalandr Oct 1, 2026
1795cce
fix: clear deleted task membership and fence test network lifecycle
pascalandr Oct 2, 2026
c4e36a7
test(ui): model browser context in plugin SSE reconnect fixture
pascalandr Oct 2, 2026
9718335
test(ui): retain bounded header fixture bootstrap diagnostics
pascalandr Oct 2, 2026
287eb9b
test(timeline): preserve the native thumb grab offset
pascalandr Oct 2, 2026
8572752
fix(composer): prevent picker Enter from submitting drafts (#827)
pascalandr Oct 2, 2026
d8576bd
fix: reduce compaction and cross-session responsiveness stalls (#824)…
pascalandr Oct 2, 2026
8d89f7f
Merge branch 'dev' into feat/session-native-missions-v2
pascalandr Oct 2, 2026
0983db3
fix(ci): stabilize Windows native tests and artifact comments (#828)
pascalandr Oct 2, 2026
97c361c
feat(transcript): native Code Mode presentation (1/8) (#789)
pascalandr Oct 2, 2026
92bc8c4
feat(websearch): native results and provider consent (2/8) (#790)
pascalandr Oct 2, 2026
1999600
feat(composer): native skill attachments (3/8) (#791)
pascalandr Oct 2, 2026
c118478
feat(missions): add native dynamic session workflows (#673)
pascalandr Oct 2, 2026
ee77c1e
feat(settings): scoped web search configuration (4/8) (#792)
pascalandr Oct 2, 2026
a80b364
feat(chat): dock native questions and permissions above the composer …
pascalandr Oct 2, 2026
a9e624b
fix(opencode): qualify 2.0.22 and fence parent session creation (#830)
pascalandr Oct 2, 2026
c954841
revert(missions): undo PR #673 without dropping later dev changes
pascalandr Oct 2, 2026
d8f9118
revert(missions): undo accidental merge of PR #673 (#831)
pascalandr Oct 2, 2026
394482f
feat(accounts): native account controls and opt-in Codex quota select…
pascalandr Oct 2, 2026
270e533
fix(tls): generate positive serials and repair local certificates (#834)
pascalandr Oct 2, 2026
4122438
fix(usage): preserve quotas on duplicate connection notifications (#835)
pascalandr Oct 2, 2026
7cf9b01
fix(chat): simplify and polish question and permission requests (#836)
pascalandr Oct 2, 2026
c05f795
fix(events): prevent relay timeout on worktree discovery waits (#837)
pascalandr Oct 3, 2026
961f279
feat(chat): preserve permission decisions and richer question receipt…
pascalandr Oct 3, 2026
a076d01
fix(history): fill search pages and remove redundant counting (#839)
pascalandr Oct 3, 2026
8ce70ec
fix(performance): recover pending requests without warming historical…
pascalandr Oct 3, 2026
e3cf0c1
chore(release): prepare stable 0.20.1 (#842)
pascalandr Oct 3, 2026
0465499
Merge branch 'main' into dev
pascalandr Oct 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
33 changes: 33 additions & 0 deletions .github/scripts/comment-pr-artifacts.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const marker = '<!-- codenomad-pr-artifacts -->'

async function commentPRArtifacts({ github, context, core, allowedActors = '' }) {
const { owner, repo } = context.repo
const run = context.payload.workflow_run
if (!run || run.event !== 'pull_request' || run.status !== 'completed' || run.conclusion !== 'success') return
if (run.path !== '.github/workflows/pr-build.yml') return
const artifacts = await github.paginate(github.rest.actions.listWorkflowRunArtifacts, { owner, repo, run_id: run.id, per_page: 100 })
const active = artifacts.filter(artifact => !artifact.expired)
if (!active.length) { core.info('No active artifacts to announce.'); return }
const associated = run.pull_requests?.length ? run.pull_requests : await github.paginate(
github.rest.repos.listPullRequestsAssociatedWithCommit, { owner, repo, commit_sha: run.head_sha, per_page: 100 })
const allowed = new Set(allowedActors.split(',').map(actor => actor.trim()).filter(Boolean))
const runUrl = `https://github.com/${owner}/${repo}/actions/runs/${run.id}`
// Artifact names are untrusted display text, never code or a URL to execute.
const displayName = name => String(name).replace(/[\r\n]/g, ' ').replace(/[\\`*_[\]<>]/g, '\\$&')
const body = [marker, 'PR builds are available as GitHub Actions artifacts:', '', runUrl, '',
'Artifacts expire according to the retention shown on the run.', 'Artifacts:',
...active.map(artifact => `- ${displayName(artifact.name)}`)].join('\n')
for (const number of new Set(associated.map(pr => pr.number))) {
const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number: number })
// A completed old run must not advertise obsolete artifacts after a push.
if (pr.head.sha !== run.head_sha || pr.draft) continue
if (!['dev', 'DEV-v2'].includes(pr.base.ref) && !allowed.has(pr.user.login)) continue
const comments = await github.paginate(github.rest.issues.listComments, { owner, repo, issue_number: number, per_page: 100 })
const existing = comments.find(comment => comment.user?.login === 'github-actions[bot]' && comment.body?.startsWith(marker))
if (existing) await github.rest.issues.updateComment({ owner, repo, comment_id: existing.id, body })
else await github.rest.issues.createComment({ owner, repo, issue_number: number, body })
core.info(`Announced artifacts for completed run ${run.id} on PR #${number}.`)
}
}

module.exports = { commentPRArtifacts }
75 changes: 75 additions & 0 deletions .github/scripts/comment-pr-artifacts.test.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { commentPRArtifacts } = require('./comment-pr-artifacts.cjs')

function fixture() {
const run = { id: 123, head_sha: 'reviewed', event: 'pull_request', status: 'completed', conclusion: 'success',
path: '.github/workflows/pr-build.yml', pull_requests: [{ number: 825 }] }
const pr = { head: { sha: 'reviewed' }, base: { ref: 'dev' }, user: { login: 'contributor' }, draft: false }
const calls = [], writes = [], artifacts = [{ name: 'build-windows', expired: false }], comments = []
const methods = { artifacts: {}, associated: {}, comments: {} }
const github = {
rest: { actions: { listWorkflowRunArtifacts: methods.artifacts }, repos: { listPullRequestsAssociatedWithCommit: methods.associated },
pulls: { get: async () => ({ data: pr }) }, issues: {
listComments: methods.comments, createComment: async input => writes.push(input), updateComment: async input => writes.push(input),
} },
paginate: async (method, input) => {
calls.push(input)
if (method === methods.artifacts) return artifacts
if (method === methods.associated) return [{ number: 825 }]
if (method === methods.comments) return comments
throw new Error('Unexpected API')
},
}
const execute = (allowedActors = '') => commentPRArtifacts({ github, context: { repo: { owner: 'owner', repo: 'repo' }, payload: { workflow_run: run } },
core: { info() {} }, allowedActors })
return { run, pr, calls, writes, artifacts, comments, execute, github }
}

test('completed run posts artifacts without searching or waiting for another workflow', async () => {
const f = fixture(); await f.execute()
assert.equal(f.writes.length, 1)
assert.equal(f.writes[0].issue_number, 825)
assert.match(f.writes[0].body, /actions\/runs\/123/)
assert.equal(f.calls[0].run_id, 123)
})
test('failed, canceled, incomplete and unrelated runs perform no artifact or comment calls', async () => {
for (const patch of [{ conclusion: 'failure' }, { conclusion: 'cancelled' }, { status: 'in_progress' },
{ event: 'push' }, { path: '.github/workflows/other.yml' }]) {
const f = fixture(); Object.assign(f.run, patch); await f.execute()
assert.deepEqual(f.calls, []); assert.deepEqual(f.writes, [])
}
})
test('missing PR association uses GitHub commit association and still verifies the current head', async () => {
const f = fixture(); f.run.pull_requests = []; await f.execute()
assert(f.calls.some(call => call.commit_sha === 'reviewed'))
assert.equal(f.writes.length, 1)
})
test('obsolete heads, drafts and unauthorized targets do not get artifact announcements', async () => {
for (const change of [pr => { pr.head.sha = 'new-head' }, pr => { pr.draft = true }, pr => { pr.base.ref = 'main' }]) {
const f = fixture(); change(f.pr); await f.execute(); assert.deepEqual(f.writes, [])
}
})
test('expired or absent artifacts are skipped rather than falsely advertised', async () => {
const f = fixture(); f.artifacts[0].expired = true; await f.execute(); assert.deepEqual(f.writes, [])
})
test('explicitly allowed authors retain access for non-dev PR targets', async () => {
const f = fixture(); f.pr.base.ref = 'main'; await f.execute('maintainer, contributor')
assert.equal(f.writes.length, 1)
})
test('a rerun updates only the bot-owned artifact comment', async () => {
const f = fixture()
f.comments.push({ id: 1, user: { login: 'contributor' }, body: '<!-- codenomad-pr-artifacts -->' },
{ id: 2, user: { login: 'github-actions[bot]' }, body: '<!-- codenomad-pr-artifacts -->\nold' })
await f.execute(); assert.equal(f.writes[0].comment_id, 2)
})
test('artifact names are escaped display text, not executable markdown content', async () => {
const f = fixture(); f.artifacts[0].name = '[bad](url)\n<script>`code`'; await f.execute()
assert(!f.writes[0].body.includes('<script>'))
assert(f.writes[0].body.includes('\\[bad\\]'))
})
test('GitHub API errors remain real helper failures', async () => {
const f = fixture(); f.github.paginate = async () => { throw new Error('API unavailable') }
// An unavailable client must not be converted into a successful announcement.
await assert.rejects(f.execute, /API unavailable/)
})
128 changes: 17 additions & 111 deletions .github/workflows/comment-pr-artifacts.yml
Original file line number Diff line number Diff line change
@@ -1,128 +1,34 @@
name: Comment PR Artifacts

on:
pull_request_target:
types:
- opened
- edited
- synchronize
- reopened
- ready_for_review
workflow_run:
workflows: [PR Build Validation]
types: [completed]

permissions:
actions: read
contents: read
issues: write
pull-requests: write
pull-requests: read

jobs:
comment:
runs-on: ubuntu-latest
env:
ALLOWED_ACTORS: ${{ vars.ALLOWED_NON_DEV_PR_ACTORS }}
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
BASE_REF: ${{ github.event.pull_request.base.ref }}
IS_DRAFT: ${{ github.event.pull_request.draft }}
PR_NUMBER: ${{ github.event.pull_request.number }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
RETENTION_DAYS: 7
# A failed validation remains red in its own workflow, not a second
# misleading failure in a helper with no artifacts to announce.
if: ${{ github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' }}
steps:
- name: Check PR authorization
id: auth
shell: bash
run: |
set -euo pipefail
if [ "$BASE_REF" = "dev" ] || [ "$BASE_REF" = "DEV-v2" ]; then
echo "allowed=true" >> "$GITHUB_OUTPUT"
exit 0
fi

normalized=",${ALLOWED_ACTORS},"
if [[ "$normalized" == *",${PR_AUTHOR},"* ]]; then
echo "allowed=true" >> "$GITHUB_OUTPUT"
else
echo "allowed=false" >> "$GITHUB_OUTPUT"
fi

- name: Wait for PR build and comment
if: ${{ steps.auth.outputs.allowed == 'true' && env.IS_DRAFT != 'true' }}
- name: Checkout trusted default-branch helper only
uses: actions/checkout@v4
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
- name: Comment completed PR build artifacts
uses: actions/github-script@v8
env:
ALLOWED_ACTORS: ${{ vars.ALLOWED_NON_DEV_PR_ACTORS }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const prNumber = Number(process.env.PR_NUMBER);
const headSha = process.env.HEAD_SHA;
const retentionDays = Number(process.env.RETENTION_DAYS || '7');
const marker = '<!-- codenomad-pr-artifacts -->';

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

const maxAttempts = 90;
let matchedRun = null;
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
const runs = await github.paginate(github.rest.actions.listWorkflowRuns, {
owner,
repo,
workflow_id: 'pr-build.yml',
event: 'pull_request',
per_page: 100,
});

const matchingRuns = runs
.filter((run) => run.head_sha === headSha)
.sort((a, b) => new Date(b.created_at) - new Date(a.created_at));

matchedRun = matchingRuns[0] || null;
if (matchedRun && matchedRun.status === 'completed') {
break;
}

core.info(`Waiting for PR Build Validation run for ${headSha} (attempt ${attempt}/${maxAttempts})`);
await sleep(20000);
}

if (!matchedRun) {
core.setFailed(`Could not find PR Build Validation run for ${headSha}.`);
return;
}

if (matchedRun.status !== 'completed') {
core.setFailed(`PR Build Validation run ${matchedRun.id} did not complete in time.`);
return;
}

if (matchedRun.conclusion !== 'success') {
core.setFailed(`PR Build Validation run ${matchedRun.id} concluded ${matchedRun.conclusion}.`);
return;
}

const artifacts = await github.paginate(
github.rest.actions.listWorkflowRunArtifacts,
{ owner, repo, run_id: matchedRun.id, per_page: 100 }
);
const active = artifacts.filter((artifact) => !artifact.expired);

const runUrl = matchedRun.html_url;
const artifactsBlock = active.length
? ['Artifacts:', ...active.map((artifact) => `- ${artifact.name}`)].join('\n')
: 'Artifacts: (none found on this run)';

const body = [
marker,
'PR builds are available as GitHub Actions artifacts:',
'',
runUrl,
'',
`Artifacts expire in ${retentionDays} days.`,
artifactsBlock,
].join('\n');

const created = await github.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body,
});
core.info(`Created artifacts comment: ${created.data.html_url}`);
const { commentPRArtifacts } = require('./.github/scripts/comment-pr-artifacts.cjs');
await commentPRArtifacts({ github, context, core, allowedActors: process.env.ALLOWED_ACTORS });
28 changes: 26 additions & 2 deletions .github/workflows/pr-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,13 @@ jobs:
$plugin = Join-Path $env:PRUNING_NATIVE_INSTALL 'node_modules/@neuralnomads/codenomad-session-pruning'
$fixtures = node -p "require('node:path').join(require('node:fs').realpathSync(require('node:os').tmpdir()), 'opencode')"
"PRUNING_NATIVE_FIXTURES=$fixtures" >> $env:GITHUB_ENV
node scripts/test-session-pruning-native.mjs $cli $plugin
node scripts/run-session-pruning-native.mjs $cli $plugin
if ($LASTEXITCODE) { exit $LASTEXITCODE }
npm run build:pruning --workspace @neuralnomads/codenomad
if ($LASTEXITCODE) { exit $LASTEXITCODE }
node --import tsx --test packages/server/src/opencode/pruning-installation.test.ts
if ($LASTEXITCODE) { exit $LASTEXITCODE }
node scripts/test-session-pruning-native.mjs $cli --ui
node scripts/run-session-pruning-native.mjs $cli --ui
- name: Upload isolated native failure diagnostics
if: ${{ failure() && env.PRUNING_NATIVE_FIXTURES != '' }}
uses: actions/upload-artifact@v4
Expand All @@ -123,6 +123,8 @@ jobs:
${{ env.PRUNING_NATIVE_FIXTURES }}/codenomad-pruning-native-*/before-restart.log
${{ env.PRUNING_NATIVE_FIXTURES }}/codenomad-pruning-native-*/discovery.json
${{ env.PRUNING_NATIVE_FIXTURES }}/codenomad-pruning-native-*/ui-*.png
${{ env.PRUNING_NATIVE_FIXTURES }}/codenomad-pruning-native-*/test-diagnostics.jsonl
${{ env.PRUNING_NATIVE_FIXTURES }}/native-fixture-run-*/
if-no-files-found: ignore
retention-days: 7
- name: Upload opt-in plugin package
Expand Down Expand Up @@ -227,6 +229,9 @@ jobs:
- name: Test desktop packaging invariants
run: node --test scripts/desktop-server-resources.test.cjs scripts/prepare-node-runtime.test.cjs

- name: Test CI fixture diagnostics and artifact announcements
run: node --test scripts/native-fixture-diagnostics.test.mjs .github/scripts/comment-pr-artifacts.test.cjs

- name: Test Electron client state
env:
CODENOMAD_TEST_ZSH: /bin/zsh
Expand Down Expand Up @@ -331,7 +336,10 @@ jobs:
packages/ui/src/stores/session-list-startup.test.ts
packages/ui/src/stores/app-tabs.test.ts
packages/ui/src/stores/forms.test.ts
packages/ui/src/stores/preferences-favorites-mode.test.ts
packages/ui/src/stores/instances-restore-ownership.test.ts
packages/ui/src/stores/instances-pending-compaction.test.ts
packages/ui/src/stores/instances-pending-requests.test.ts
packages/ui/src/stores/message-v2/bus.test.ts
packages/ui/src/stores/message-v2/transcript-eviction.test.ts
packages/ui/src/stores/opencode-data.test.ts
Expand Down Expand Up @@ -376,6 +384,9 @@ jobs:
working-directory: packages/tauri-app/src-tauri
run: CODENOMAD_TEST_ZSH=/bin/zsh CODENOMAD_TEST_NODE="$(command -v node)" cargo test --locked

- name: Test owned Tauri zoom input script
run: node --test packages/tauri-app/tests/window-zoom-script.test.mjs

tests-tauri-windows:
needs: authorize
if: ${{ needs.authorize.outputs.allowed == 'true' && !github.event.pull_request.draft }}
Expand Down Expand Up @@ -410,6 +421,9 @@ jobs:
working-directory: packages/tauri-app/src-tauri
run: cargo test --locked -- --test-threads=1

- name: Test owned Tauri zoom input script
run: node --test packages/tauri-app/tests/window-zoom-script.test.mjs

- name: Reproduce and prevent Tao input deadlocks
run: node scripts/test-tauri-input-deadlock.mjs --baseline

Expand Down Expand Up @@ -523,6 +537,16 @@ jobs:
working-directory: packages/tauri-app/src-tauri
run: CODENOMAD_TEST_ZSH=/bin/zsh CODENOMAD_TEST_NODE="$(command -v node)" cargo test --locked -- --test-threads=4

- name: Reproduce and prevent macOS window event feedback
timeout-minutes: 10
run: |
node --test scripts/test-tauri-macos-window-result.test.mjs
node scripts/test-tauri-macos-window.mjs --baseline
node scripts/test-tauri-macos-window.mjs --baseline

- name: Test owned Tauri zoom input script
run: node --test packages/tauri-app/tests/window-zoom-script.test.mjs

- name: Test desktop shell startup on macOS
env:
CODENOMAD_TEST_ZSH: /bin/zsh
Expand Down
2 changes: 1 addition & 1 deletion .opencode/skills/codenomad-architecture-guide/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ description: |

- Runtime requirements live in `opencode/runtime-support.ts`; each blocking requirement needs demonstrated API/behavior evidence. Distinguish technically incompatible, recommended/tested and unverified versions. Setup uses bundled Node/npm and a versioned user prefix; shared-daemon restart is explicit and uses the existing native-parent launch bridge. Retire obsolete wire translations while retaining current identity/authority checks. See `dev-docs/OPENCODE_V2_POST_BETA.md` for precise retirement boundaries and validation evidence.

- Server and UI pin the official `@opencode/client@2.0.16` together; the pruning plugin pins `@opencode/plugin@2.0.16`. Review official V2 docs, installed declarations, generated wire paths and native integration tests when upgrading. Qualify against the latest published stable runtime, but never infer the minimum from that version or from the dependency pin. Record technical minimum requirements and tested scenarios in PR/CI logs and update `dev-docs/OPENCODE_V2_COMPATIBILITY.md` in place rather than adding per-version reports. The runtime CLI is managed independently.
- Server and UI pin the official `@opencode/client@2.0.21` together; the pruning plugin pins `@opencode/plugin@2.0.21`. Review official V2 docs, installed declarations, generated wire paths and native integration tests when upgrading. Qualify against the latest published stable runtime, but never infer the minimum from that version or from the dependency pin. Record technical minimum requirements and tested scenarios in PR/CI logs and update `dev-docs/OPENCODE_V2_COMPATIBILITY.md` in place rather than adding per-version reports. The runtime CLI is managed independently.
- Do not use `@opencode-ai/sdk`, `@opencode-ai/sdk/v2/client`, or `createOpencodeClient()`; follow installed `@opencode/client` declarations.
- There is no legacy `packages/opencode-plugin/`. Do not restore the V1 compatibility runtime or add general plugin extension points. The narrow integrations are the bundled `codenomad.automation` plugin and bundled session-pruning RPC; see `dev-docs/DEVELOPER_MODE.md`, `dev-docs/BROWSER_AUTOMATION.md` and `dev-docs/SESSION_PRUNING_RPC.md`. All automation tools follow backend presence without a Developer Mode gate, sharing the authenticated native transport and execution-time session/window fences.
- The server uses the selected host or WSL CLI's official `service status`, `service start`, and `service get password` lifecycle to connect to one externally owned global OpenCode daemon. It owns no private port/database/registration/PID and never stops the daemon on backend shutdown. WSL requires Windows localhost forwarding and uses no cross-namespace PID operations.
Expand Down
Loading
Loading