diff --git a/.gitattributes b/.gitattributes index 2b55295aa..92e301fde 100644 --- a/.gitattributes +++ b/.gitattributes @@ -49,5 +49,5 @@ bin/* text eol=lf # The committed diagram-render bundle is hash-pinned (BUILD_INFO sha256); # a CRLF rewrite on Windows checkout would break the drift test and change # the content-addressed staged filename. -lib/diagram-render/dist/*.html text eol=lf +lib/diagram-render/dist/*.html text eol=lf whitespace=-trailing-space lib/diagram-render/dist/*.json text eol=lf diff --git a/browse/test/data-platform.test.ts b/browse/test/data-platform.test.ts index 7dc0f5844..2a795a7fa 100644 --- a/browse/test/data-platform.test.ts +++ b/browse/test/data-platform.test.ts @@ -118,10 +118,14 @@ describe('validateTempPath', () => { expect(() => validateTempPath('/tmp/nonexistent-file-12345.jpg')).toThrow(/not found/i); }); - it('rejects paths in cwd', () => { - // Create a real file in cwd to test the path check (not the existence check) - const cwdFile = path.join(process.cwd(), 'package.json'); - expect(() => validateTempPath(cwdFile)).toThrow(/temp directory/i); + it('rejects a temp-directory symlink that resolves outside temp', () => { + const link = path.join(TEMP_DIR, `test-temp-link-${Date.now()}`); + fs.symlinkSync('/etc/passwd', link); + try { + expect(() => validateTempPath(link)).toThrow(/temp directory/i); + } finally { + fs.unlinkSync(link); + } }); it('rejects absolute paths outside safe dirs', () => { diff --git a/browse/test/gstack-update-check.test.ts b/browse/test/gstack-update-check.test.ts index 0edd366e4..38efaa9b3 100644 --- a/browse/test/gstack-update-check.test.ts +++ b/browse/test/gstack-update-check.test.ts @@ -1,25 +1,29 @@ -/** - * Tests for bin/gstack-update-check bash script. - * - * Uses Bun.spawnSync to invoke the script with temp dirs and - * GSTACK_DIR / GSTACK_STATE_DIR / GSTACK_REMOTE_URL env overrides - * for full isolation. - */ +/** Tests for the retired passive updater and its explicit compatibility check. */ -import { describe, test, expect, beforeEach, afterEach } from 'bun:test'; -import { mkdtempSync, writeFileSync, rmSync, existsSync, readFileSync, mkdirSync, symlinkSync, utimesSync } from 'fs'; -import { join } from 'path'; -import { tmpdir } from 'os'; +import { afterEach, beforeEach, describe, expect, test } from 'bun:test'; +import { + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; -const SCRIPT = join(import.meta.dir, '..', '..', 'bin', 'gstack-update-check'); +const ROOT = join(import.meta.dir, '..', '..'); +const SCRIPT = join(ROOT, 'bin', 'gstack-update-check'); let gstackDir: string; let stateDir: string; -function run(extraEnv: Record = {}, args: string[] = []) { +function run(args: string[] = [], extraEnv: Record = {}) { const result = Bun.spawnSync(['bash', SCRIPT, ...args], { env: { ...process.env, + GSTACK_HOME: '', GSTACK_DIR: gstackDir, GSTACK_STATE_DIR: stateDir, GSTACK_REMOTE_URL: `file://${join(gstackDir, 'REMOTE_VERSION')}`, @@ -38,10 +42,9 @@ function run(extraEnv: Record = {}, args: string[] = []) { beforeEach(() => { gstackDir = mkdtempSync(join(tmpdir(), 'gstack-upd-test-')); stateDir = mkdtempSync(join(tmpdir(), 'gstack-state-test-')); - // Link real gstack-config so update_check config check works const binDir = join(gstackDir, 'bin'); mkdirSync(binDir); - symlinkSync(join(import.meta.dir, '..', '..', 'bin', 'gstack-config'), join(binDir, 'gstack-config')); + symlinkSync(join(ROOT, 'bin', 'gstack-config'), join(binDir, 'gstack-config')); }); afterEach(() => { @@ -49,500 +52,69 @@ afterEach(() => { rmSync(stateDir, { recursive: true, force: true }); }); -function writeSnooze(version: string, level: number, epochSeconds: number) { - writeFileSync(join(stateDir, 'update-snoozed'), `${version} ${level} ${epochSeconds}`); -} +describe('gstack-update-check compatibility boundary', () => { + test('passive invocation is a no-op even when an update and legacy state exist', () => { + writeFileSync(join(gstackDir, 'VERSION'), '1.0.0\n'); + writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '2.0.0\n'); + writeFileSync(join(stateDir, 'last-update-check'), 'UPGRADE_AVAILABLE 1.0.0 2.0.0'); + writeFileSync(join(stateDir, 'update-snoozed'), '2.0.0 3 1'); -function writeConfig(content: string) { - writeFileSync(join(stateDir, 'config.yaml'), content); -} - -function nowEpoch(): number { - return Math.floor(Date.now() / 1000); -} - -describe('gstack-update-check', () => { - // ─── Path A: No VERSION file ──────────────────────────────── - test('exits 0 with no output when VERSION file is missing', () => { - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe(''); + expect(run()).toEqual({ exitCode: 0, stdout: '', stderr: '' }); + expect(readFileSync(join(stateDir, 'last-update-check'), 'utf8')).toContain('UPGRADE_AVAILABLE'); + expect(existsSync(join(stateDir, 'update-snoozed'))).toBe(true); }); - // ─── Path B: Empty VERSION file ───────────────────────────── - test('exits 0 with no output when VERSION file is empty', () => { - writeFileSync(join(gstackDir, 'VERSION'), ''); - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe(''); - }); - - // ─── Path C: Just-upgraded marker ─────────────────────────── - test('outputs JUST_UPGRADED and deletes marker', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.4.0\n'); - writeFileSync(join(stateDir, 'just-upgraded-from'), '0.3.3\n'); - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe('JUST_UPGRADED 0.3.3 0.4.0'); - // Marker should be deleted - expect(existsSync(join(stateDir, 'just-upgraded-from'))).toBe(false); - // Cache should be written - const cache = readFileSync(join(stateDir, 'last-update-check'), 'utf-8'); - expect(cache).toContain('UP_TO_DATE'); - }); - - // ─── Path C2: Just-upgraded marker + newer remote ────────── - test('just-upgraded marker does not mask newer remote version', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.4.0\n'); - writeFileSync(join(stateDir, 'just-upgraded-from'), '0.3.3\n'); - writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '0.5.0\n'); - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - // Should output both the just-upgraded notice AND the new upgrade - expect(stdout).toContain('JUST_UPGRADED 0.3.3 0.4.0'); - expect(stdout).toContain('UPGRADE_AVAILABLE 0.4.0 0.5.0'); - // Cache should reflect the upgrade available, not UP_TO_DATE - const cache = readFileSync(join(stateDir, 'last-update-check'), 'utf-8'); - expect(cache).toContain('UPGRADE_AVAILABLE 0.4.0 0.5.0'); - }); - - // ─── Path C3: Just-upgraded marker + remote matches local ── - test('just-upgraded with no further updates writes UP_TO_DATE cache', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.4.0\n'); - writeFileSync(join(stateDir, 'just-upgraded-from'), '0.3.3\n'); - writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '0.4.0\n'); - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe('JUST_UPGRADED 0.3.3 0.4.0'); - const cache = readFileSync(join(stateDir, 'last-update-check'), 'utf-8'); - expect(cache).toContain('UP_TO_DATE'); - }); - - // ─── Path D1: Fresh cache, UP_TO_DATE ─────────────────────── - test('exits silently when cache says UP_TO_DATE and is fresh', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(stateDir, 'last-update-check'), 'UP_TO_DATE 0.3.3'); - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe(''); - }); - - // ─── Path D1b: Fresh UP_TO_DATE cache, but local version changed ── - test('re-checks when UP_TO_DATE cache version does not match local', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.4.0\n'); - // Cache says UP_TO_DATE for 0.3.3, but local is now 0.4.0 - writeFileSync(join(stateDir, 'last-update-check'), 'UP_TO_DATE 0.3.3'); - // Remote says 0.5.0 — should detect upgrade - writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '0.5.0\n'); - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe('UPGRADE_AVAILABLE 0.4.0 0.5.0'); - }); - - // ─── Path D2: Fresh cache, UPGRADE_AVAILABLE ──────────────── - test('echoes cached UPGRADE_AVAILABLE when cache is fresh', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(stateDir, 'last-update-check'), 'UPGRADE_AVAILABLE 0.3.3 0.4.0'); - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe('UPGRADE_AVAILABLE 0.3.3 0.4.0'); - }); - - // ─── Path D3: Fresh cache, but local version changed ──────── - test('re-checks when local version does not match cached old version', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.4.0\n'); - // Cache says 0.3.3 → 0.4.0 but we're already on 0.4.0 - writeFileSync(join(stateDir, 'last-update-check'), 'UPGRADE_AVAILABLE 0.3.3 0.4.0'); - // Remote also says 0.4.0 — should be up to date - writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '0.4.0\n'); - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe(''); // Up to date after re-check - const cache = readFileSync(join(stateDir, 'last-update-check'), 'utf-8'); - expect(cache).toContain('UP_TO_DATE'); - }); - - // ─── Path E: Versions match (remote fetch) ───────────────── - test('writes UP_TO_DATE cache when versions match', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '0.3.3\n'); - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe(''); - const cache = readFileSync(join(stateDir, 'last-update-check'), 'utf-8'); - expect(cache).toContain('UP_TO_DATE'); - }); - - // ─── Path F: Versions differ (remote fetch) ───────────────── - test('outputs UPGRADE_AVAILABLE when versions differ', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '0.4.0\n'); - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe('UPGRADE_AVAILABLE 0.3.3 0.4.0'); - const cache = readFileSync(join(stateDir, 'last-update-check'), 'utf-8'); - expect(cache).toContain('UPGRADE_AVAILABLE 0.3.3 0.4.0'); - }); - - // ─── Path G: Invalid remote response ──────────────────────── - test('treats invalid remote response as up to date', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '404 Not Found\n'); - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe(''); - const cache = readFileSync(join(stateDir, 'last-update-check'), 'utf-8'); - expect(cache).toContain('UP_TO_DATE'); - }); - - // ─── Path H: Curl fails (bad URL) ────────────────────────── - test('exits silently when remote URL is unreachable', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - - const { exitCode, stdout } = run({ - GSTACK_REMOTE_URL: 'file:///nonexistent/path/VERSION', + test('passive invocation performs no network or state setup', () => { + writeFileSync(join(gstackDir, 'VERSION'), '1.0.0\n'); + const missingStateDir = join(stateDir, 'not-created'); + const result = run([], { + GSTACK_STATE_DIR: missingStateDir, + GSTACK_REMOTE_URL: 'https://127.0.0.1:1/must-not-be-requested', }); - expect(exitCode).toBe(0); - expect(stdout).toBe(''); - const cache = readFileSync(join(stateDir, 'last-update-check'), 'utf-8'); - expect(cache).toContain('UP_TO_DATE'); + expect(result).toEqual({ exitCode: 0, stdout: '', stderr: '' }); + expect(existsSync(missingStateDir)).toBe(false); }); - // ─── Path I: Corrupt cache file ───────────────────────────── - test('falls through to remote fetch when cache is corrupt', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(stateDir, 'last-update-check'), 'garbage data here'); - // Remote says same version — should end up UP_TO_DATE - writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '0.3.3\n'); - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe(''); - // Cache should be overwritten with valid content - const cache = readFileSync(join(stateDir, 'last-update-check'), 'utf-8'); - expect(cache).toContain('UP_TO_DATE'); - }); - - // ─── State dir creation ───────────────────────────────────── - test('creates state dir if it does not exist', () => { - const newStateDir = join(stateDir, 'nested', 'dir'); - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '0.3.3\n'); - - const { exitCode } = run({ GSTACK_STATE_DIR: newStateDir }); - expect(exitCode).toBe(0); - expect(existsSync(join(newStateDir, 'last-update-check'))).toBe(true); - }); - - // ─── E2E regression: always exit 0 ─────────────────────────── - // Agents call this on every skill invocation. Exit code 1 breaks - // the preamble and confuses the agent. This test guards against - // regressions like the "exits 1 when up to date" bug. - test('exits 0 with real project VERSION and unreachable remote', () => { - // Simulate agent context: real VERSION file, network unavailable - const projectRoot = join(import.meta.dir, '..', '..'); - const versionFile = join(projectRoot, 'VERSION'); - if (!existsSync(versionFile)) return; // skip if no VERSION - const version = readFileSync(versionFile, 'utf-8').trim(); - - // Copy VERSION into test dir - writeFileSync(join(gstackDir, 'VERSION'), version + '\n'); - - // Remote is unreachable (simulates offline / CI / sandboxed agent) - const { exitCode, stdout } = run({ - GSTACK_REMOTE_URL: 'file:///nonexistent/path/VERSION', - }); - expect(exitCode).toBe(0); - // Should write UP_TO_DATE cache (not crash) - const cache = readFileSync(join(stateDir, 'last-update-check'), 'utf-8'); - expect(cache).toContain('UP_TO_DATE'); - }); - - test('exits 0 when up to date (not exit 1)', () => { - // Regression test: script previously exited 1 when versions matched. - // This broke every skill preamble that called it without || true. - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '0.3.3\n'); - - // First call: fetches remote, writes cache - const first = run(); - expect(first.exitCode).toBe(0); - expect(first.stdout).toBe(''); - - // Second call: reads fresh cache - const second = run(); - expect(second.exitCode).toBe(0); - expect(second.stdout).toBe(''); - - // Third call with upgrade available: still exit 0 - writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '0.4.0\n'); - rmSync(join(stateDir, 'last-update-check')); // force re-fetch - const third = run(); - expect(third.exitCode).toBe(0); - expect(third.stdout).toBe('UPGRADE_AVAILABLE 0.3.3 0.4.0'); - }); - - // ─── Snooze tests ─────────────────────────────────────────── - test('snoozed level 1 within 24h → silent (cached path)', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(stateDir, 'last-update-check'), 'UPGRADE_AVAILABLE 0.3.3 0.4.0'); - writeSnooze('0.4.0', 1, nowEpoch() - 3600); // 1h ago (within 24h) - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe(''); - }); - - test('snoozed level 1 expired (25h ago) → outputs UPGRADE_AVAILABLE', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(stateDir, 'last-update-check'), 'UPGRADE_AVAILABLE 0.3.3 0.4.0'); - writeSnooze('0.4.0', 1, nowEpoch() - 90000); // 25h ago - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe('UPGRADE_AVAILABLE 0.3.3 0.4.0'); - }); - - test('snoozed level 2 within 48h → silent', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(stateDir, 'last-update-check'), 'UPGRADE_AVAILABLE 0.3.3 0.4.0'); - writeSnooze('0.4.0', 2, nowEpoch() - 86400); // 24h ago (within 48h) - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe(''); - }); - - test('snoozed level 2 expired (49h ago) → outputs', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(stateDir, 'last-update-check'), 'UPGRADE_AVAILABLE 0.3.3 0.4.0'); - writeSnooze('0.4.0', 2, nowEpoch() - 176400); // 49h ago - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe('UPGRADE_AVAILABLE 0.3.3 0.4.0'); - }); - - test('snoozed level 3 within 7d → silent', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(stateDir, 'last-update-check'), 'UPGRADE_AVAILABLE 0.3.3 0.4.0'); - writeSnooze('0.4.0', 3, nowEpoch() - 518400); // 6d ago (within 7d) - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe(''); - }); - - test('snoozed level 3 expired (8d ago) → outputs', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(stateDir, 'last-update-check'), 'UPGRADE_AVAILABLE 0.3.3 0.4.0'); - writeSnooze('0.4.0', 3, nowEpoch() - 691200); // 8d ago - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe('UPGRADE_AVAILABLE 0.3.3 0.4.0'); - }); - - test('snooze ignored when version differs (new version resets snooze)', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(stateDir, 'last-update-check'), 'UPGRADE_AVAILABLE 0.3.3 0.5.0'); - // Snoozed for 0.4.0, but remote is now 0.5.0 - writeSnooze('0.4.0', 3, nowEpoch() - 60); // very recent - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe('UPGRADE_AVAILABLE 0.3.3 0.5.0'); - }); - - test('corrupt snooze file → outputs normally', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(stateDir, 'last-update-check'), 'UPGRADE_AVAILABLE 0.3.3 0.4.0'); - writeFileSync(join(stateDir, 'update-snoozed'), 'garbage'); - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe('UPGRADE_AVAILABLE 0.3.3 0.4.0'); - }); - - test('non-numeric epoch in snooze file → outputs', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(stateDir, 'last-update-check'), 'UPGRADE_AVAILABLE 0.3.3 0.4.0'); - writeFileSync(join(stateDir, 'update-snoozed'), '0.4.0 1 abc'); - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe('UPGRADE_AVAILABLE 0.3.3 0.4.0'); - }); - - test('non-numeric level in snooze file → outputs', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(stateDir, 'last-update-check'), 'UPGRADE_AVAILABLE 0.3.3 0.4.0'); - writeFileSync(join(stateDir, 'update-snoozed'), `0.4.0 abc ${nowEpoch()}`); - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe('UPGRADE_AVAILABLE 0.3.3 0.4.0'); - }); - - test('snooze respected on remote fetch path (no cache)', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '0.4.0\n'); - // No cache file — goes to remote fetch path - writeSnooze('0.4.0', 1, nowEpoch() - 3600); // 1h ago - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe(''); - // Cache should still be written - const cache = readFileSync(join(stateDir, 'last-update-check'), 'utf-8'); - expect(cache).toContain('UPGRADE_AVAILABLE 0.3.3 0.4.0'); - }); - - test('just-upgraded clears snooze file', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.4.0\n'); - writeFileSync(join(stateDir, 'just-upgraded-from'), '0.3.3\n'); - writeSnooze('0.4.0', 2, nowEpoch() - 3600); - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe('JUST_UPGRADED 0.3.3 0.4.0'); - expect(existsSync(join(stateDir, 'update-snoozed'))).toBe(false); - }); - - // ─── Config tests ────────────────────────────────────────── - test('update_check: false disables all checks', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '0.4.0\n'); - writeConfig('update_check: false\n'); - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe(''); - // No cache should be written - expect(existsSync(join(stateDir, 'last-update-check'))).toBe(false); - }); - - test('missing config.yaml does not crash', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '0.4.0\n'); - // No config file — should behave normally - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe('UPGRADE_AVAILABLE 0.3.3 0.4.0'); - }); - - // ─── --force flag tests ────────────────────────────────────── - - test('--force busts fresh UP_TO_DATE cache', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '0.4.0\n'); - writeFileSync(join(stateDir, 'last-update-check'), 'UP_TO_DATE 0.3.3'); - - // Without --force: cache hit, silent - const cached = run(); - expect(cached.stdout).toBe(''); - - // With --force: cache busted, re-fetches, finds upgrade - const forced = run({}, ['--force']); - expect(forced.exitCode).toBe(0); - expect(forced.stdout).toBe('UPGRADE_AVAILABLE 0.3.3 0.4.0'); - }); - - test('--force busts fresh UPGRADE_AVAILABLE cache', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '0.3.3\n'); - writeFileSync(join(stateDir, 'last-update-check'), 'UPGRADE_AVAILABLE 0.3.3 0.4.0'); - - // Without --force: cache hit, outputs stale upgrade - const cached = run(); - expect(cached.stdout).toBe('UPGRADE_AVAILABLE 0.3.3 0.4.0'); - - // With --force: cache busted, re-fetches, now up to date - const forced = run({}, ['--force']); - expect(forced.exitCode).toBe(0); - expect(forced.stdout).toBe(''); - const cache = readFileSync(join(stateDir, 'last-update-check'), 'utf-8'); - expect(cache).toContain('UP_TO_DATE'); - }); - - test('--force clears snooze so user can upgrade after snoozing', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '0.4.0\n'); - writeSnooze('0.4.0', 1, nowEpoch() - 60); // snoozed 1 min ago (within 24h) - - // Without --force: snoozed, silent - const snoozed = run(); - expect(snoozed.exitCode).toBe(0); - expect(snoozed.stdout).toBe(''); - - // With --force: snooze cleared, outputs upgrade - const forced = run({}, ['--force']); - expect(forced.exitCode).toBe(0); - expect(forced.stdout).toBe('UPGRADE_AVAILABLE 0.3.3 0.4.0'); - // Snooze file should be deleted - expect(existsSync(join(stateDir, 'update-snoozed'))).toBe(false); - }); - - // ─── Split TTL tests ───────────────────────────────────────── - - // ─── Semver-order guard ───────────────────────────────────── - // When the upstream raw CDN serves a stale (older) VERSION right after a - // release, the script previously emitted a backwards UPGRADE_AVAILABLE - // line. The guard treats REMOTE < LOCAL as up-to-date. - - test('remote older than local (stale CDN) → silent, cache UP_TO_DATE', () => { - writeFileSync(join(gstackDir, 'VERSION'), '1.34.0.0\n'); - writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '1.33.2.0\n'); - - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe(''); - const cache = readFileSync(join(stateDir, 'last-update-check'), 'utf-8'); - expect(cache).toContain('UP_TO_DATE 1.34.0.0'); - }); - - test('multi-segment sort: 1.9.0.0 < 1.10.0.0', () => { + test('--force reports and caches a newer valid version', () => { writeFileSync(join(gstackDir, 'VERSION'), '1.9.0.0\n'); writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '1.10.0.0\n'); - const { stdout } = run(); - expect(stdout).toBe('UPGRADE_AVAILABLE 1.9.0.0 1.10.0.0'); + expect(run(['--force']).stdout).toBe('UPGRADE_AVAILABLE 1.9.0.0 1.10.0.0'); + expect(readFileSync(join(stateDir, 'last-update-check'), 'utf8').trim()) + .toBe('UPGRADE_AVAILABLE 1.9.0.0 1.10.0.0'); }); - test('multi-segment reverse sort: 1.10.0.0 > 1.9.0.0 → no rewind', () => { + test('--force never offers a downgrade', () => { writeFileSync(join(gstackDir, 'VERSION'), '1.10.0.0\n'); writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '1.9.0.0\n'); - const { stdout } = run(); - expect(stdout).toBe(''); - const cache = readFileSync(join(stateDir, 'last-update-check'), 'utf-8'); - expect(cache).toContain('UP_TO_DATE 1.10.0.0'); + expect(run(['--force']).stdout).toBe(''); + expect(readFileSync(join(stateDir, 'last-update-check'), 'utf8').trim()) + .toBe('UP_TO_DATE 1.10.0.0'); }); - test('UP_TO_DATE cache expires after 60 min (not 720)', () => { - writeFileSync(join(gstackDir, 'VERSION'), '0.3.3\n'); - writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '0.4.0\n'); - writeFileSync(join(stateDir, 'last-update-check'), 'UP_TO_DATE 0.3.3'); + test('--force treats malformed or unavailable responses as non-updates', () => { + writeFileSync(join(gstackDir, 'VERSION'), '1.0.0\n'); + writeFileSync(join(gstackDir, 'REMOTE_VERSION'), 'not a version\n'); - // Set cache mtime to 90 minutes ago (past 60-min TTL) - const ninetyMinAgo = new Date(Date.now() - 90 * 60 * 1000); - const cachePath = join(stateDir, 'last-update-check'); - utimesSync(cachePath, ninetyMinAgo, ninetyMinAgo); + expect(run(['--force']).stdout).toBe(''); + expect(readFileSync(join(stateDir, 'last-update-check'), 'utf8').trim()) + .toBe('UP_TO_DATE 1.0.0'); + }); - // Cache should be stale at 60-min TTL, re-fetches and finds upgrade - const { exitCode, stdout } = run(); - expect(exitCode).toBe(0); - expect(stdout).toBe('UPGRADE_AVAILABLE 0.3.3 0.4.0'); + test('--force clears obsolete snooze state and consumes the upgrade marker', () => { + writeFileSync(join(gstackDir, 'VERSION'), '1.0.0\n'); + writeFileSync(join(gstackDir, 'REMOTE_VERSION'), '1.0.0\n'); + writeFileSync(join(stateDir, 'just-upgraded-from'), '0.9.0\n'); + writeFileSync(join(stateDir, 'update-snoozed'), '1.0.0 3 9999999999'); + + expect(run(['--force']).stdout).toBe('JUST_UPGRADED 0.9.0 1.0.0'); + expect(existsSync(join(stateDir, 'just-upgraded-from'))).toBe(false); + expect(existsSync(join(stateDir, 'update-snoozed'))).toBe(false); + }); + + test('--force with no local version exits cleanly without creating a cache', () => { + expect(run(['--force'])).toEqual({ exitCode: 0, stdout: '', stderr: '' }); + expect(existsSync(join(stateDir, 'last-update-check'))).toBe(false); }); }); diff --git a/browse/test/path-validation.test.ts b/browse/test/path-validation.test.ts index 838d22098..c9c7f8cc2 100644 --- a/browse/test/path-validation.test.ts +++ b/browse/test/path-validation.test.ts @@ -4,7 +4,7 @@ import { validateReadPath, SENSITIVE_COOKIE_NAME, SENSITIVE_COOKIE_VALUE } from import { BLOCKED_METADATA_HOSTS } from '../src/url-validation'; import { readFileSync, symlinkSync, unlinkSync, writeFileSync, realpathSync } from 'fs'; import { tmpdir } from 'os'; -import { join } from 'path'; +import { join, relative } from 'path'; describe('validateOutputPath', () => { it('allows paths within /tmp', () => { @@ -82,7 +82,8 @@ describe('validateReadPath', () => { }); it('blocks nested path traversal', () => { - expect(() => validateReadPath('src/../../etc/passwd')).toThrow(/Path must be within/); + const escapeToEtc = relative(process.cwd(), '/etc/passwd'); + expect(() => validateReadPath(`src/../${escapeToEtc}`)).toThrow(/Path must be within/); }); it('blocks symlink inside safe dir pointing outside', () => { diff --git a/bun.lock b/bun.lock index 1dd1ec869..a540f38eb 100644 --- a/bun.lock +++ b/bun.lock @@ -5,43 +5,52 @@ "": { "name": "gstack", "dependencies": { - "@anthropic-ai/sdk": "^0.78.0", + "@anthropic-ai/sdk": "^0.112.4", "@ngrok/ngrok": "^1.7.0", "diff": "^9.0.0", "html-to-docx": "1.8.0", - "marked": "^18.0.2", + "marked": "^18.0.6", "playwright": "^1.58.2", "sharp": "^0.34.5", - "socks": "^2.8.8", + "socks": "^2.8.9", "xterm": "5", "xterm-addon-fit": "^0.8.0", }, "devDependencies": { - "@anthropic-ai/claude-agent-sdk": "0.2.117", - "@huggingface/transformers": "^4.1.0", + "@anthropic-ai/claude-agent-sdk": "0.3.216", + "@huggingface/transformers": "4.2.0", }, }, }, + "overrides": { + "@protobufjs/utf8": "1.1.1", + "adm-zip": "0.6.0", + "fast-uri": "3.1.2", + "hono": "4.12.25", + "ip-address": "10.2.0", + "protobufjs": "7.6.5", + "qs": "6.15.2", + }, "packages": { - "@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.2.117", "", { "dependencies": { "@anthropic-ai/sdk": "^0.81.0", "@modelcontextprotocol/sdk": "^1.29.0" }, "optionalDependencies": { "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.2.117", "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.2.117", "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.2.117", "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.2.117", "@anthropic-ai/claude-agent-sdk-linux-x64": "0.2.117", "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.2.117", "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.2.117", "@anthropic-ai/claude-agent-sdk-win32-x64": "0.2.117" }, "peerDependencies": { "zod": "^4.0.0" } }, "sha512-pVBss1Vu0w87nKCBhWtjMggSgCh6GVUtdRmuE58ZvXv0E2q0JcnUCQHehmn92BAW0+VCwPY8q/k7uKWkgwz/gA=="], + "@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.3.216", "", { "optionalDependencies": { "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.216", "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.216", "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.216", "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.216", "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.216", "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.216", "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.216", "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.216" }, "peerDependencies": { "@anthropic-ai/sdk": ">=0.93.0", "@modelcontextprotocol/sdk": "^1.29.0", "zod": "^4.0.0" } }, "sha512-Fl/d9yGW7Pm0aGwUNkJMvruOVobleYcoprGJqufdP4J9W2XL/2xKXqanY8KqUdfySRMI2N46rY4/lryq5SfgFg=="], - "@anthropic-ai/claude-agent-sdk-darwin-arm64": ["@anthropic-ai/claude-agent-sdk-darwin-arm64@0.2.117", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ZeC/Lz8XMKQ5w+GmjTziPR8bSSarBtNCJMkMAYRT9ekNmyXSWXEwGLENe5TDDmtpzNNzAB1mQNuIYoqTsqgV3w=="], + "@anthropic-ai/claude-agent-sdk-darwin-arm64": ["@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.216", "", { "os": "darwin", "cpu": "arm64" }, "sha512-TWtTUabXj+AMOBMknSe3EVQb/7qucw5pHYi0HWoKoixQt1JE6J/CiLDBIY69OD3eQn9k1XG6LaurT239kFxLUw=="], - "@anthropic-ai/claude-agent-sdk-darwin-x64": ["@anthropic-ai/claude-agent-sdk-darwin-x64@0.2.117", "", { "os": "darwin", "cpu": "x64" }, "sha512-DKyggGzzpDcr9S435xlpbpwkEYKZNbePSekug75tJclK8l4ddD9+M9BFgMiSUq9F1Zt53kUaRDihDu/cBKvkdQ=="], + "@anthropic-ai/claude-agent-sdk-darwin-x64": ["@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.216", "", { "os": "darwin", "cpu": "x64" }, "sha512-tULuvqhJUwGTj71Uln4uPumm0la4EO1XydFbISTbdc1BsuvGx3FOtFcVs0Qg3dhNBFAoU/iYVTO/B1rImeJZig=="], - "@anthropic-ai/claude-agent-sdk-linux-arm64": ["@anthropic-ai/claude-agent-sdk-linux-arm64@0.2.117", "", { "os": "linux", "cpu": "arm64" }, "sha512-jyHmyZQavpPOe3zxBRX3KbdOAJ8JwZ8m/wMr5bhHhhcstugm/vJx6IIs7D44VvFjk+8sqdvR2ZrliL8PUcJL0g=="], + "@anthropic-ai/claude-agent-sdk-linux-arm64": ["@anthropic-ai/claude-agent-sdk-linux-arm64@0.3.216", "", { "os": "linux", "cpu": "arm64" }, "sha512-kX6x0otwOuA1zIeEiuAKQqOk2TUAOkDUzm4MmLoQHOM2xWvr/pc+xY4DZxaX4ef9dUFQuHA4r5Vtbk7tPTL7Bw=="], - "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": ["@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.2.117", "", { "os": "linux", "cpu": "arm64" }, "sha512-bJU5gEOmM4VCOn4h8vipOKgdhPATePQ23mMpvyVqtVyipWppHfOUfVkqXb+SrF/hfkNSMYxDuoKxbJ+MmKtGjg=="], + "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": ["@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.216", "", { "os": "linux", "cpu": "arm64" }, "sha512-sisWj2nhQolKu6aGWnu+I7d8EU6/m5J3G6bGfR7YvZ1wkQTQZAX3aOq6DVLIfCaZSH22wtqyuXhE/gn5eU1syw=="], - "@anthropic-ai/claude-agent-sdk-linux-x64": ["@anthropic-ai/claude-agent-sdk-linux-x64@0.2.117", "", { "os": "linux", "cpu": "x64" }, "sha512-Zb5PXKrDNbQ1dyNYwxZMNL+F2Dhgjh9f9B21wZUJqkhJL69hRJwJyxO42HiNmB2zGCaTxQTyjPhLdB/eQJo74Q=="], + "@anthropic-ai/claude-agent-sdk-linux-x64": ["@anthropic-ai/claude-agent-sdk-linux-x64@0.3.216", "", { "os": "linux", "cpu": "x64" }, "sha512-WbJTLQafcYw9wl+gh/YpepdbWsOoJS7JZQA0obpzBBWzpx9PqPbjUDXDfCDrtzDI2fmr3Nz0//vC12bvlMZd8g=="], - "@anthropic-ai/claude-agent-sdk-linux-x64-musl": ["@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.2.117", "", { "os": "linux", "cpu": "x64" }, "sha512-LIkKTAYZGugEVssAuWCPqlDWSqhVZAveNPNsfKLbuG1naIMCR04fUqil6i3d3mAAfk7FaS5D4IdHp45psi+GDw=="], + "@anthropic-ai/claude-agent-sdk-linux-x64-musl": ["@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.3.216", "", { "os": "linux", "cpu": "x64" }, "sha512-3Ts2Ab6oEGG2r+epmWc6lOR1ahECjvH4y+lPb32qLKMdYxT2PU6TAc4Z/USLLuqDpgw3nSb8xuiYEH77rv88fw=="], - "@anthropic-ai/claude-agent-sdk-win32-arm64": ["@anthropic-ai/claude-agent-sdk-win32-arm64@0.2.117", "", { "os": "win32", "cpu": "arm64" }, "sha512-uetggH3B83PiH0a9D/5MVXB5Hqnlr2DVajehwAP2x0Mt4DBd632ICnHpu6pnSP+vVkWgq3FgQlkHe91RfP+peA=="], + "@anthropic-ai/claude-agent-sdk-win32-arm64": ["@anthropic-ai/claude-agent-sdk-win32-arm64@0.3.216", "", { "os": "win32", "cpu": "arm64" }, "sha512-xGB8rKatsXl9enqmPXixYNvdjGh1AL2jFmMRC9lR9M1prf2FGl7dkpdHz8YyItKAciRwpPIfts/9dSGhxlgT3A=="], - "@anthropic-ai/claude-agent-sdk-win32-x64": ["@anthropic-ai/claude-agent-sdk-win32-x64@0.2.117", "", { "os": "win32", "cpu": "x64" }, "sha512-TT4KngAokDTJSvQ2mrAP6ZRkXj50OLj7Tb1zZA4CnkmrrEidgs4KrMx7er1ZwoivngIvCekV9+TbtC9giknr5w=="], + "@anthropic-ai/claude-agent-sdk-win32-x64": ["@anthropic-ai/claude-agent-sdk-win32-x64@0.3.216", "", { "os": "win32", "cpu": "x64" }, "sha512-cGbBgoKNzB6wRL6bMOwM2iJEG/wx0B6FCblmKF+ZAYKcj5oNi3jM6oQsnPJbKfrzVKrip3YEpXxopQ9O30LrSg=="], - "@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.78.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-PzQhR715td/m1UaaN5hHXjYB8Gl2lF9UVhrrGrZeysiF6Rb74Wc9GCB8hzLdzmQtBd1qe89F9OptgB9Za1Ib5w=="], + "@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.112.4", "", { "dependencies": { "json-schema-to-ts": "^3.1.1", "standardwebhooks": "^1.0.0" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-7eXJJnrmBI5GMC6drrCiSkycVsT7crRZX3qv5HusLSm+qiILjmtqP7gf+UiT7ASu/7Gdj+Zfl4f2haV8wATKUg=="], "@babel/runtime": ["@babel/runtime@7.29.2", "", {}, "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g=="], @@ -53,7 +62,7 @@ "@huggingface/tokenizers": ["@huggingface/tokenizers@0.1.3", "", {}, "sha512-8rF/RRT10u+kn7YuUbUg0OF30K8rjTc78aHpxT+qJ1uWSqxT1MHi8+9ltwYfkFYJzT/oS+qw3JVfHtNMGAdqyA=="], - "@huggingface/transformers": ["@huggingface/transformers@4.1.0", "", { "dependencies": { "@huggingface/jinja": "^0.5.6", "@huggingface/tokenizers": "^0.1.3", "onnxruntime-node": "1.24.3", "onnxruntime-web": "1.26.0-dev.20260410-5e55544225", "sharp": "^0.34.5" } }, "sha512-WiMf9eyvF6V2pj4gs12A7GQV3svyFIBtB/W+Hn5lT5E5DyqWUno1ZrWoAfJv69X1RNv/0GoOo6DFmL6NOYd+rg=="], + "@huggingface/transformers": ["@huggingface/transformers@4.2.0", "", { "dependencies": { "@huggingface/jinja": "^0.5.6", "@huggingface/tokenizers": "^0.1.3", "onnxruntime-node": "1.24.3", "onnxruntime-web": "1.26.0-dev.20260416-b7804b056c", "sharp": "^0.34.5" } }, "sha512-8BRCoBMH0XsWaEIamuR0LrJGAfftgHAfb2Vrffy0VKlSAE/MnUJ5/h/zTfEP3fDIft+nk7TqB8xXEyABGitBjQ=="], "@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="], @@ -147,27 +156,27 @@ "@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="], - "@protobufjs/codegen": ["@protobufjs/codegen@2.0.4", "", {}, "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="], + "@protobufjs/codegen": ["@protobufjs/codegen@2.0.5", "", {}, "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g=="], - "@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.0", "", {}, "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="], + "@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.1", "", {}, "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg=="], - "@protobufjs/fetch": ["@protobufjs/fetch@1.1.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ=="], + "@protobufjs/fetch": ["@protobufjs/fetch@1.1.1", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1" } }, "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw=="], "@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="], - "@protobufjs/inquire": ["@protobufjs/inquire@1.1.0", "", {}, "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="], - "@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="], "@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="], - "@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="], + "@protobufjs/utf8": ["@protobufjs/utf8@1.1.1", "", {}, "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg=="], + + "@stablelib/base64": ["@stablelib/base64@1.0.1", "", {}, "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ=="], "@types/node": ["@types/node@25.5.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw=="], "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], - "adm-zip": ["adm-zip@0.5.17", "", {}, "sha512-+Ut8d9LLqwEvHHJl1+PIHqoyDxFgVN847JTVM3Izi3xHDWPE4UtzzXysMZQs64DMcrJfBeS/uoEP4AD3HQHnQQ=="], + "adm-zip": ["adm-zip@0.6.0", "", {}, "sha512-XleryMhbuksdKtofnWZ9Sk+4CUTbms4Mb/EU32SZwToAyZ5RgVos/ki8n+yr0LWHOGKuakbXTuuYNHLQjhddgg=="], "ajv": ["ajv@8.18.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="], @@ -265,7 +274,9 @@ "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], - "fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="], + "fast-sha256": ["fast-sha256@1.3.0", "", {}, "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ=="], + + "fast-uri": ["fast-uri@3.1.2", "", {}, "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ=="], "finalhandler": ["finalhandler@2.1.1", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="], @@ -301,7 +312,7 @@ "hasown": ["hasown@2.0.3", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg=="], - "hono": ["hono@4.12.14", "", {}, "sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w=="], + "hono": ["hono@4.12.25", "", {}, "sha512-2NFaIyNVgJmBs/ecmtGzlmluTFs5cHEWGTdu0t1HBwYzoGXOL5nUQBRMXsXWla5i4KkG//QMzVP88m1+I3fdAQ=="], "html-entities": ["html-entities@2.6.0", "", {}, "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ=="], @@ -357,7 +368,7 @@ "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], - "marked": ["marked@18.0.2", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-NsmlUYBS/Zg57rgDWMYdnre6OTj4e+qq/JS2ot3KrYLSoHLw+sDu0Nm1ZGpRgYAq6c+b1ekaY5NzVchMCQnzcg=="], + "marked": ["marked@18.0.6", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-MrV5puXBfuiy6wl6DLaq3BtIJQAJToAd5zt/ZKhRfGRAuFPALE7/4Y7jnxRQoEgK/pBgurGqLyAuRgZ2xOjr6w=="], "matcher": ["matcher@3.0.0", "", { "dependencies": { "escape-string-regexp": "^4.0.0" } }, "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng=="], @@ -397,7 +408,7 @@ "onnxruntime-node": ["onnxruntime-node@1.24.3", "", { "dependencies": { "adm-zip": "^0.5.16", "global-agent": "^3.0.0", "onnxruntime-common": "1.24.3" }, "os": [ "linux", "win32", "darwin", ] }, "sha512-JH7+czbc8ALA819vlTgcV+Q214/+VjGeBHDjX81+ZCD0PCVCIFGFNtT0V4sXG/1JXypKPgScQcB3ij/hk3YnTg=="], - "onnxruntime-web": ["onnxruntime-web@1.26.0-dev.20260410-5e55544225", "", { "dependencies": { "flatbuffers": "^25.1.24", "guid-typescript": "^1.0.9", "long": "^5.2.3", "onnxruntime-common": "1.24.0-dev.20251116-b39e144322", "platform": "^1.3.6", "protobufjs": "^7.2.4" } }, "sha512-hHd9n8DzIfGSAjM4Dvslesc8i6h9HEEcl8qt7X3LfhUxMgls6FBJ32j2xrDtJjKJFEehFeJmyB/pvad1I8KS8w=="], + "onnxruntime-web": ["onnxruntime-web@1.26.0-dev.20260416-b7804b056c", "", { "dependencies": { "flatbuffers": "^25.1.24", "guid-typescript": "^1.0.9", "long": "^5.2.3", "onnxruntime-common": "1.24.0-dev.20251116-b39e144322", "platform": "^1.3.6", "protobufjs": "^7.2.4" } }, "sha512-MD6Ss4GSpQBo6zqoJzyT9LRbKYs7x/JVN23FT24EcEvlqF4VuzPOeH6X38orZPKHQDbprn7K+SBpu0/mj2CQiw=="], "pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], @@ -419,13 +430,13 @@ "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], - "protobufjs": ["protobufjs@7.5.5", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg=="], + "protobufjs": ["protobufjs@7.6.5", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.5", "@protobufjs/eventemitter": "^1.1.1", "@protobufjs/fetch": "^1.1.1", "@protobufjs/float": "^1.0.2", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.1", "@types/node": ">=13.7.0", "long": "^5.3.2" } }, "sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw=="], "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], "punycode": ["punycode@1.4.1", "", {}, "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ=="], - "qs": ["qs@6.15.1", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg=="], + "qs": ["qs@6.15.2", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw=="], "queue": ["queue@6.0.2", "", { "dependencies": { "inherits": "~2.0.3" } }, "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA=="], @@ -477,10 +488,12 @@ "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], - "socks": ["socks@2.8.8", "", { "dependencies": { "ip-address": "^10.1.1", "smart-buffer": "^4.2.0" } }, "sha512-NlGELfPrgX2f1TAAcz0WawlLn+0r3FyhhCRpFFK2CemXenPYvzMWWZINv3eDNo9ucdwme7oCHRY0Jnbs4aIkog=="], + "socks": ["socks@2.8.9", "", { "dependencies": { "ip-address": "^10.1.1", "smart-buffer": "^4.2.0" } }, "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw=="], "sprintf-js": ["sprintf-js@1.1.3", "", {}, "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="], + "standardwebhooks": ["standardwebhooks@1.0.0", "", { "dependencies": { "@stablelib/base64": "^1.0.0", "fast-sha256": "^1.3.0" } }, "sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg=="], + "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], "string-template": ["string-template@0.2.1", "", {}, "sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw=="], @@ -533,8 +546,6 @@ "zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="], - "@anthropic-ai/claude-agent-sdk/@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.81.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-D4K5PvEV6wPiRtVlVsJHIUhHAmOZ6IT/I9rKlTf84gR7GyyAurPJK7z9BOf/AZqC5d1DhYQGJNKRmV+q8dGhgw=="], - "@oozcitak/infra/@oozcitak/util": ["@oozcitak/util@8.0.0", "", {}, "sha512-+9Hq6yuoq/3TRV/n/xcpydGBq2qN2/DEDMqNTG7rm95K6ZE2/YY/sPyx62+1n8QsE9O26e5M1URlXsk+AnN9Jw=="], "@oozcitak/url/@oozcitak/infra": ["@oozcitak/infra@1.0.3", "", { "dependencies": { "@oozcitak/util": "1.0.1" } }, "sha512-9O2wxXGnRzy76O1XUxESxDGsXT5kzETJPvYbreO4mv6bqe1+YSuux2cZTagjJ/T4UfEwFJz5ixanOqB0QgYAag=="], @@ -549,8 +560,6 @@ "express/mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], - "express-rate-limit/ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="], - "htmlparser2/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], "onnxruntime-web/onnxruntime-common": ["onnxruntime-common@1.24.0-dev.20251116-b39e144322", "", {}, "sha512-BOoomdHYmNRL5r4iQ4bMvsl2t0/hzVQ3OM3PHD0gxeXu1PmggqBv3puZicEUVOA3AtHHYmqZtjMj9FOfGrATTw=="], diff --git a/lib/diagram-render/bun.lock b/lib/diagram-render/bun.lock index a9472740e..9a666b99c 100644 --- a/lib/diagram-render/bun.lock +++ b/lib/diagram-render/bun.lock @@ -5,14 +5,19 @@ "": { "name": "@gstack/diagram-render", "dependencies": { - "@excalidraw/excalidraw": "0.18.0", - "@excalidraw/mermaid-to-excalidraw": "1.1.2", - "mermaid": "11.12.2", + "@excalidraw/excalidraw": "0.18.1", + "@excalidraw/mermaid-to-excalidraw": "2.2.2", + "mermaid": "11.16.0", "react": "18.3.1", "react-dom": "18.3.1", }, }, }, + "overrides": { + "dompurify": "3.4.11", + "lodash-es": "4.18.1", + "nanoid": "5.0.9", + }, "packages": { "@antfu/install-pkg": ["@antfu/install-pkg@1.1.0", "", { "dependencies": { "package-manager-detector": "^1.3.0", "tinyexec": "^1.0.1" } }, "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ=="], @@ -26,17 +31,17 @@ "@chevrotain/regexp-to-ast": ["@chevrotain/regexp-to-ast@11.0.3", "", {}, "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA=="], - "@chevrotain/types": ["@chevrotain/types@11.0.3", "", {}, "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ=="], + "@chevrotain/types": ["@chevrotain/types@11.1.2", "", {}, "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw=="], "@chevrotain/utils": ["@chevrotain/utils@11.0.3", "", {}, "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ=="], - "@excalidraw/excalidraw": ["@excalidraw/excalidraw@0.18.0", "", { "dependencies": { "@braintree/sanitize-url": "6.0.2", "@excalidraw/laser-pointer": "1.3.1", "@excalidraw/mermaid-to-excalidraw": "1.1.2", "@excalidraw/random-username": "1.1.0", "@radix-ui/react-popover": "1.1.6", "@radix-ui/react-tabs": "1.0.2", "browser-fs-access": "0.29.1", "canvas-roundrect-polyfill": "0.0.1", "clsx": "1.1.1", "cross-env": "7.0.3", "es6-promise-pool": "2.5.0", "fractional-indexing": "3.2.0", "fuzzy": "0.1.3", "image-blob-reduce": "3.0.1", "jotai": "2.11.0", "jotai-scope": "0.7.2", "lodash.debounce": "4.0.8", "lodash.throttle": "4.1.1", "nanoid": "3.3.3", "open-color": "1.9.1", "pako": "2.0.3", "perfect-freehand": "1.2.0", "pica": "7.1.1", "png-chunk-text": "1.0.0", "png-chunks-encode": "1.0.0", "png-chunks-extract": "1.0.0", "points-on-curve": "1.0.1", "pwacompat": "2.0.17", "roughjs": "4.6.4", "sass": "1.51.0", "tunnel-rat": "0.1.2" }, "peerDependencies": { "react": "^17.0.2 || ^18.2.0 || ^19.0.0", "react-dom": "^17.0.2 || ^18.2.0 || ^19.0.0" } }, "sha512-QkIiS+5qdy8lmDWTKsuy0sK/fen/LRDtbhm2lc2xcFcqhv2/zdg95bYnl+wnwwXGHo7kEmP65BSiMHE7PJ3Zpw=="], + "@excalidraw/excalidraw": ["@excalidraw/excalidraw@0.18.1", "", { "dependencies": { "@braintree/sanitize-url": "6.0.2", "@excalidraw/laser-pointer": "1.3.1", "@excalidraw/mermaid-to-excalidraw": "2.2.2", "@excalidraw/random-username": "1.1.0", "@radix-ui/react-popover": "1.1.6", "@radix-ui/react-tabs": "1.0.2", "browser-fs-access": "0.29.1", "canvas-roundrect-polyfill": "0.0.1", "clsx": "1.1.1", "cross-env": "7.0.3", "es6-promise-pool": "2.5.0", "fractional-indexing": "3.2.0", "fuzzy": "0.1.3", "image-blob-reduce": "3.0.1", "jotai": "2.11.0", "jotai-scope": "0.7.2", "lodash.debounce": "4.0.8", "lodash.throttle": "4.1.1", "nanoid": "3.3.3", "open-color": "1.9.1", "pako": "2.0.3", "perfect-freehand": "1.2.0", "pica": "7.1.1", "png-chunk-text": "1.0.0", "png-chunks-encode": "1.0.0", "png-chunks-extract": "1.0.0", "points-on-curve": "1.0.1", "pwacompat": "2.0.17", "roughjs": "4.6.4", "sass": "1.51.0", "tunnel-rat": "0.1.2" }, "peerDependencies": { "react": "^17.0.2 || ^18.2.0 || ^19.0.0", "react-dom": "^17.0.2 || ^18.2.0 || ^19.0.0" } }, "sha512-6i5Gt7IDTOH//qa0Z315Ly5iVRhjWpu2whrlQFqkuwrkKUWgRsMk0P5qdE7bpyDpai7jeLeWYkyj1eVAfni1lw=="], "@excalidraw/laser-pointer": ["@excalidraw/laser-pointer@1.3.1", "", {}, "sha512-psA1z1N2qeAfsORdXc9JmD2y4CmDwmuMRxnNdJHZexIcPwaNEyIpNcelw+QkL9rz9tosaN9krXuKaRqYpRAR6g=="], "@excalidraw/markdown-to-text": ["@excalidraw/markdown-to-text@0.1.2", "", {}, "sha512-1nDXBNAojfi3oSFwJswKREkFm5wrSjqay81QlyRv2pkITG/XYB5v+oChENVBQLcxQwX4IUATWvXM5BcaNhPiIg=="], - "@excalidraw/mermaid-to-excalidraw": ["@excalidraw/mermaid-to-excalidraw@1.1.2", "", { "dependencies": { "@excalidraw/markdown-to-text": "0.1.2", "mermaid": "10.9.3", "nanoid": "4.0.2" } }, "sha512-hAFv/TTIsOdoy0dL5v+oBd297SQ+Z88gZ5u99fCIFuEMHfQuPgLhU/ztKhFSTs7fISwVo6fizny/5oQRR3d4tQ=="], + "@excalidraw/mermaid-to-excalidraw": ["@excalidraw/mermaid-to-excalidraw@2.2.2", "", { "dependencies": { "@excalidraw/markdown-to-text": "0.1.2", "@mermaid-js/parser": "^0.6.3", "mermaid": "^11.12.1", "nanoid": "4.0.2" } }, "sha512-5VKQq5CdRocC82vOIUpQ5ufJOVV9FpBTdHGA+ULqazeIVV+cr299877omQCibsdS3Bpitz2fsnTwnIXEmLVDSg=="], "@excalidraw/random-username": ["@excalidraw/random-username@1.1.0", "", {}, "sha512-nULYsQxkWHnbmHvcs+efMkJ4/9TtvNyFeLyHdeGxW0zHs6P+jYVqcRff9A6Vq9w9JXeDRnRh2VKvTtS19GW2qA=="], @@ -166,17 +171,11 @@ "@types/d3-zoom": ["@types/d3-zoom@3.0.8", "", { "dependencies": { "@types/d3-interpolate": "*", "@types/d3-selection": "*" } }, "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw=="], - "@types/debug": ["@types/debug@4.1.13", "", { "dependencies": { "@types/ms": "*" } }, "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw=="], - "@types/geojson": ["@types/geojson@7946.0.16", "", {}, "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg=="], - "@types/mdast": ["@types/mdast@3.0.15", "", { "dependencies": { "@types/unist": "^2" } }, "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ=="], - - "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], - "@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="], - "@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], + "@upsetjs/venn.js": ["@upsetjs/venn.js@2.0.0", "", { "optionalDependencies": { "d3-selection": "^3.0.0", "d3-transition": "^3.0.1" } }, "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw=="], "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], @@ -190,8 +189,6 @@ "canvas-roundrect-polyfill": ["canvas-roundrect-polyfill@0.0.1", "", {}, "sha512-yWq+R3U3jE+coOeEb3a3GgE2j/0MMiDKM/QpLb6h9ihf5fGY9UXtvK9o4vNqjWXoZz7/3EaSVU3IX53TvFFUOw=="], - "character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="], - "chevrotain": ["chevrotain@11.0.3", "", { "dependencies": { "@chevrotain/cst-dts-gen": "11.0.3", "@chevrotain/gast": "11.0.3", "@chevrotain/regexp-to-ast": "11.0.3", "@chevrotain/types": "11.0.3", "@chevrotain/utils": "11.0.3", "lodash-es": "4.17.21" } }, "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw=="], "chevrotain-allstar": ["chevrotain-allstar@0.3.1", "", { "dependencies": { "lodash-es": "^4.17.21" }, "peerDependencies": { "chevrotain": "^11.0.0" } }, "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw=="], @@ -280,25 +277,17 @@ "d3-zoom": ["d3-zoom@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", "d3-interpolate": "1 - 3", "d3-selection": "2 - 3", "d3-transition": "2 - 3" } }, "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw=="], - "dagre-d3-es": ["dagre-d3-es@7.0.13", "", { "dependencies": { "d3": "^7.9.0", "lodash-es": "^4.17.21" } }, "sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q=="], + "dagre-d3-es": ["dagre-d3-es@7.0.14", "", { "dependencies": { "d3": "^7.9.0", "lodash-es": "^4.17.21" } }, "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg=="], "dayjs": ["dayjs@1.11.21", "", {}, "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA=="], - "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], - - "decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="], - "delaunator": ["delaunator@5.1.0", "", { "dependencies": { "robust-predicates": "^3.0.2" } }, "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ=="], - "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], - "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="], - "diff": ["diff@5.2.2", "", {}, "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A=="], + "dompurify": ["dompurify@3.4.11", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-zhlUV12GsaRzMsf9q5M254YhA4+VuF0fG+QFqu6aYpoGlKtz+w8//jBcGVYBgQkR5GHjUomejY84AV+/uPbWdw=="], - "dompurify": ["dompurify@3.4.9", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-4dPSRMRDqHvs0V4YDFCsaIZo4if5u0xM+llyxiM2fwuZFdKArUBAF3VtI2+n8NKg9P870WMdYk0UhqQNoWXbfQ=="], - - "elkjs": ["elkjs@0.9.3", "", {}, "sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ=="], + "es-toolkit": ["es-toolkit@1.49.0", "", {}, "sha512-G5iZ6Pc/FNRY/soKZHC+TxGDD83rHUDXxzaWhGCX44vAv/tMs56WMusnm/KMNK+luUPsgA9U28cGr4RDlSzL2g=="], "es6-promise-pool": ["es6-promise-pool@2.5.0", "", {}, "sha512-VHErXfzR/6r/+yyzPKeBvO0lgjfC5cbDCQWjWwMZWSb6YU39TGIl51OUmCfWCq4ylMdJSB8zkz2vIuIeIxXApA=="], @@ -350,8 +339,6 @@ "khroma": ["khroma@2.1.0", "", {}, "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw=="], - "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], - "langium": ["langium@3.3.1", "", { "dependencies": { "chevrotain": "~11.0.3", "chevrotain-allstar": "~0.3.0", "vscode-languageserver": "~9.0.1", "vscode-languageserver-textdocument": "~1.0.11", "vscode-uri": "~3.0.8" } }, "sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w=="], "layout-base": ["layout-base@1.0.2", "", {}, "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg=="], @@ -366,63 +353,11 @@ "marked": ["marked@16.4.2", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA=="], - "mdast-util-from-markdown": ["mdast-util-from-markdown@1.3.1", "", { "dependencies": { "@types/mdast": "^3.0.0", "@types/unist": "^2.0.0", "decode-named-character-reference": "^1.0.0", "mdast-util-to-string": "^3.1.0", "micromark": "^3.0.0", "micromark-util-decode-numeric-character-reference": "^1.0.0", "micromark-util-decode-string": "^1.0.0", "micromark-util-normalize-identifier": "^1.0.0", "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0", "unist-util-stringify-position": "^3.0.0", "uvu": "^0.5.0" } }, "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww=="], - - "mdast-util-to-string": ["mdast-util-to-string@3.2.0", "", { "dependencies": { "@types/mdast": "^3.0.0" } }, "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg=="], - - "mermaid": ["mermaid@11.12.2", "", { "dependencies": { "@braintree/sanitize-url": "^7.1.1", "@iconify/utils": "^3.0.1", "@mermaid-js/parser": "^0.6.3", "@types/d3": "^7.4.3", "cytoscape": "^3.29.3", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.2.0", "d3": "^7.9.0", "d3-sankey": "^0.12.3", "dagre-d3-es": "7.0.13", "dayjs": "^1.11.18", "dompurify": "^3.2.5", "katex": "^0.16.22", "khroma": "^2.1.0", "lodash-es": "^4.17.21", "marked": "^16.2.1", "roughjs": "^4.6.6", "stylis": "^4.3.6", "ts-dedent": "^2.2.0", "uuid": "^11.1.0" } }, "sha512-n34QPDPEKmaeCG4WDMGy0OT6PSyxKCfy2pJgShP+Qow2KLrvWjclwbc3yXfSIf4BanqWEhQEpngWwNp/XhZt6w=="], - - "micromark": ["micromark@3.2.0", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "micromark-core-commonmark": "^1.0.1", "micromark-factory-space": "^1.0.0", "micromark-util-character": "^1.0.0", "micromark-util-chunked": "^1.0.0", "micromark-util-combine-extensions": "^1.0.0", "micromark-util-decode-numeric-character-reference": "^1.0.0", "micromark-util-encode": "^1.0.0", "micromark-util-normalize-identifier": "^1.0.0", "micromark-util-resolve-all": "^1.0.0", "micromark-util-sanitize-uri": "^1.0.0", "micromark-util-subtokenize": "^1.0.0", "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.1", "uvu": "^0.5.0" } }, "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA=="], - - "micromark-core-commonmark": ["micromark-core-commonmark@1.1.0", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-factory-destination": "^1.0.0", "micromark-factory-label": "^1.0.0", "micromark-factory-space": "^1.0.0", "micromark-factory-title": "^1.0.0", "micromark-factory-whitespace": "^1.0.0", "micromark-util-character": "^1.0.0", "micromark-util-chunked": "^1.0.0", "micromark-util-classify-character": "^1.0.0", "micromark-util-html-tag-name": "^1.0.0", "micromark-util-normalize-identifier": "^1.0.0", "micromark-util-resolve-all": "^1.0.0", "micromark-util-subtokenize": "^1.0.0", "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.1", "uvu": "^0.5.0" } }, "sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw=="], - - "micromark-factory-destination": ["micromark-factory-destination@1.1.0", "", { "dependencies": { "micromark-util-character": "^1.0.0", "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0" } }, "sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg=="], - - "micromark-factory-label": ["micromark-factory-label@1.1.0", "", { "dependencies": { "micromark-util-character": "^1.0.0", "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0", "uvu": "^0.5.0" } }, "sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w=="], - - "micromark-factory-space": ["micromark-factory-space@1.1.0", "", { "dependencies": { "micromark-util-character": "^1.0.0", "micromark-util-types": "^1.0.0" } }, "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ=="], - - "micromark-factory-title": ["micromark-factory-title@1.1.0", "", { "dependencies": { "micromark-factory-space": "^1.0.0", "micromark-util-character": "^1.0.0", "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0" } }, "sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ=="], - - "micromark-factory-whitespace": ["micromark-factory-whitespace@1.1.0", "", { "dependencies": { "micromark-factory-space": "^1.0.0", "micromark-util-character": "^1.0.0", "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0" } }, "sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ=="], - - "micromark-util-character": ["micromark-util-character@1.2.0", "", { "dependencies": { "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0" } }, "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg=="], - - "micromark-util-chunked": ["micromark-util-chunked@1.1.0", "", { "dependencies": { "micromark-util-symbol": "^1.0.0" } }, "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ=="], - - "micromark-util-classify-character": ["micromark-util-classify-character@1.1.0", "", { "dependencies": { "micromark-util-character": "^1.0.0", "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0" } }, "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw=="], - - "micromark-util-combine-extensions": ["micromark-util-combine-extensions@1.1.0", "", { "dependencies": { "micromark-util-chunked": "^1.0.0", "micromark-util-types": "^1.0.0" } }, "sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA=="], - - "micromark-util-decode-numeric-character-reference": ["micromark-util-decode-numeric-character-reference@1.1.0", "", { "dependencies": { "micromark-util-symbol": "^1.0.0" } }, "sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw=="], - - "micromark-util-decode-string": ["micromark-util-decode-string@1.1.0", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^1.0.0", "micromark-util-decode-numeric-character-reference": "^1.0.0", "micromark-util-symbol": "^1.0.0" } }, "sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ=="], - - "micromark-util-encode": ["micromark-util-encode@1.1.0", "", {}, "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw=="], - - "micromark-util-html-tag-name": ["micromark-util-html-tag-name@1.2.0", "", {}, "sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q=="], - - "micromark-util-normalize-identifier": ["micromark-util-normalize-identifier@1.1.0", "", { "dependencies": { "micromark-util-symbol": "^1.0.0" } }, "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q=="], - - "micromark-util-resolve-all": ["micromark-util-resolve-all@1.1.0", "", { "dependencies": { "micromark-util-types": "^1.0.0" } }, "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA=="], - - "micromark-util-sanitize-uri": ["micromark-util-sanitize-uri@1.2.0", "", { "dependencies": { "micromark-util-character": "^1.0.0", "micromark-util-encode": "^1.0.0", "micromark-util-symbol": "^1.0.0" } }, "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A=="], - - "micromark-util-subtokenize": ["micromark-util-subtokenize@1.1.0", "", { "dependencies": { "micromark-util-chunked": "^1.0.0", "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0", "uvu": "^0.5.0" } }, "sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A=="], - - "micromark-util-symbol": ["micromark-util-symbol@1.1.0", "", {}, "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag=="], - - "micromark-util-types": ["micromark-util-types@1.1.0", "", {}, "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg=="], - - "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], - - "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + "mermaid": ["mermaid@11.16.0", "", { "dependencies": { "@braintree/sanitize-url": "^7.1.2", "@iconify/utils": "^3.0.2", "@mermaid-js/parser": "^1.2.0", "@types/d3": "^7.4.3", "@upsetjs/venn.js": "^2.0.0", "cytoscape": "^3.33.3", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.2.0", "d3": "^7.9.0", "d3-sankey": "^0.12.3", "dagre-d3-es": "7.0.14", "dayjs": "^1.11.20", "dompurify": "^3.3.3", "es-toolkit": "^1.45.1", "katex": "^0.16.45", "khroma": "^2.1.0", "marked": "^16.3.0", "roughjs": "^4.6.6", "stylis": "^4.3.6", "ts-dedent": "^2.2.0", "uuid": "^11.1.0 || ^12 || ^13 || ^14.0.0" } }, "sha512-Zvm3kbstgdpvIJPPItlL7fppIZ3kibvc1oZIGxdvk9t6UFz6flv+Jw7FtRGKwfcI8OckmH04LqG6LlS6X4B1pA=="], "multimath": ["multimath@2.0.0", "", { "dependencies": { "glur": "^1.1.2", "object-assign": "^4.1.1" } }, "sha512-toRx66cAMJ+Ccz7pMIg38xSIrtnbozk0dchXezwQDMgQmbGpfxjtv68H+L00iFL8hxDaVjrmwAFSb3I6bg8Q2g=="], - "nanoid": ["nanoid@3.3.3", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w=="], - - "non-layered-tidy-tree-layout": ["non-layered-tidy-tree-layout@2.0.2", "", {}, "sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw=="], + "nanoid": ["nanoid@5.0.9", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q=="], "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], @@ -474,8 +409,6 @@ "rw": ["rw@1.3.3", "", {}, "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="], - "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], - "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], "sass": ["sass@1.51.0", "", { "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", "source-map-js": ">=0.6.2 <2.0.0" }, "bin": { "sass": "sass.js" } }, "sha512-haGdpTgywJTvHC2b91GSq+clTKGbtkkZmVAb82jZQN/wTy6qs8DdFm2lhEQbEwrY0QDRgSQ3xDurqM977C3noA=="], @@ -502,8 +435,6 @@ "tunnel-rat": ["tunnel-rat@0.1.2", "", { "dependencies": { "zustand": "^4.3.2" } }, "sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ=="], - "unist-util-stringify-position": ["unist-util-stringify-position@3.0.3", "", { "dependencies": { "@types/unist": "^2.0.0" } }, "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg=="], - "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="], "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="], @@ -512,8 +443,6 @@ "uuid": ["uuid@11.1.1", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ=="], - "uvu": ["uvu@0.5.6", "", { "dependencies": { "dequal": "^2.0.0", "diff": "^5.0.0", "kleur": "^4.0.3", "sade": "^1.7.3" }, "bin": { "uvu": "bin.js" } }, "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA=="], - "vscode-jsonrpc": ["vscode-jsonrpc@8.2.0", "", {}, "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA=="], "vscode-languageserver": ["vscode-languageserver@9.0.1", "", { "dependencies": { "vscode-languageserver-protocol": "3.17.5" }, "bin": { "installServerIntoExtension": "bin/installServerIntoExtension" } }, "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g=="], @@ -526,21 +455,15 @@ "vscode-uri": ["vscode-uri@3.0.8", "", {}, "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw=="], - "web-worker": ["web-worker@1.5.0", "", {}, "sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw=="], - "webworkify": ["webworkify@1.5.0", "", {}, "sha512-AMcUeyXAhbACL8S2hqqdqOLqvJ8ylmIbNwUIqQujRSouf4+eUFaXbG6F1Rbu+srlJMmxQWsiU7mOJi0nMBfM1g=="], "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], "zustand": ["zustand@4.5.7", "", { "dependencies": { "use-sync-external-store": "^1.2.2" }, "peerDependencies": { "@types/react": ">=16.8", "immer": ">=9.0.6", "react": ">=16.8" }, "optionalPeers": ["@types/react", "immer", "react"] }, "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw=="], - "@chevrotain/cst-dts-gen/lodash-es": ["lodash-es@4.17.21", "", {}, "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="], + "@chevrotain/cst-dts-gen/@chevrotain/types": ["@chevrotain/types@11.0.3", "", {}, "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ=="], - "@chevrotain/gast/lodash-es": ["lodash-es@4.17.21", "", {}, "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="], - - "@excalidraw/mermaid-to-excalidraw/mermaid": ["mermaid@10.9.3", "", { "dependencies": { "@braintree/sanitize-url": "^6.0.1", "@types/d3-scale": "^4.0.3", "@types/d3-scale-chromatic": "^3.0.0", "cytoscape": "^3.28.1", "cytoscape-cose-bilkent": "^4.1.0", "d3": "^7.4.0", "d3-sankey": "^0.12.3", "dagre-d3-es": "7.0.10", "dayjs": "^1.11.7", "dompurify": "^3.0.5 <3.1.7", "elkjs": "^0.9.0", "katex": "^0.16.9", "khroma": "^2.0.0", "lodash-es": "^4.17.21", "mdast-util-from-markdown": "^1.3.0", "non-layered-tidy-tree-layout": "^2.0.2", "stylis": "^4.1.3", "ts-dedent": "^2.2.0", "uuid": "^9.0.0", "web-worker": "^1.2.0" } }, "sha512-V80X1isSEvAewIL3xhmz/rVmc27CVljcsbWxkxlWJWY/1kQa4XOABqpDl2qQLGKzpKm6WbTfUEKImBlUfFYArw=="], - - "@excalidraw/mermaid-to-excalidraw/nanoid": ["nanoid@4.0.2", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw=="], + "@chevrotain/gast/@chevrotain/types": ["@chevrotain/types@11.0.3", "", {}, "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ=="], "@radix-ui/react-collection/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA=="], @@ -576,7 +499,7 @@ "@radix-ui/react-tabs/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-use-callback-ref": "1.0.0" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-FohDoZvk3mEXh9AWAVyRTYR4Sq7/gavuofglmiXB2g1aKyboUD4YtgWxKj8O5n+Uak52gXQ4wKz5IFST4vtJHg=="], - "chevrotain/lodash-es": ["lodash-es@4.17.21", "", {}, "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="], + "chevrotain/@chevrotain/types": ["@chevrotain/types@11.0.3", "", {}, "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ=="], "cytoscape-fcose/cose-base": ["cose-base@2.2.0", "", { "dependencies": { "layout-base": "^2.0.0" } }, "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g=="], @@ -588,18 +511,14 @@ "mermaid/@braintree/sanitize-url": ["@braintree/sanitize-url@7.1.2", "", {}, "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA=="], + "mermaid/@mermaid-js/parser": ["@mermaid-js/parser@1.2.0", "", { "dependencies": { "@chevrotain/types": "~11.1.2" } }, "sha512-oYPyv8A4As1yH5Bx+04iQEQxXuIQDe0GKCNSRgao6z8AM9jixXIfP0vsppRLvGf+nKIOb9/LdpWA4YuJiVvESA=="], + "mermaid/roughjs": ["roughjs@4.6.6", "", { "dependencies": { "hachure-fill": "^0.5.2", "path-data-parser": "^0.1.0", "points-on-curve": "^0.2.0", "points-on-path": "^0.2.1" } }, "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ=="], "points-on-path/points-on-curve": ["points-on-curve@0.2.0", "", {}, "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A=="], "roughjs/points-on-curve": ["points-on-curve@0.2.0", "", {}, "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A=="], - "@excalidraw/mermaid-to-excalidraw/mermaid/dagre-d3-es": ["dagre-d3-es@7.0.10", "", { "dependencies": { "d3": "^7.8.2", "lodash-es": "^4.17.21" } }, "sha512-qTCQmEhcynucuaZgY5/+ti3X/rnszKZhEQH/ZdWdtP1tA/y3VoHJzcVrO9pjjJCNpigfscAtoUB5ONcd2wNn0A=="], - - "@excalidraw/mermaid-to-excalidraw/mermaid/dompurify": ["dompurify@3.1.6", "", {}, "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ=="], - - "@excalidraw/mermaid-to-excalidraw/mermaid/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="], - "@radix-ui/react-roving-focus/@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ=="], "@radix-ui/react-roving-focus/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.0" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw=="], diff --git a/lib/diagram-render/dist/BUILD_INFO.json b/lib/diagram-render/dist/BUILD_INFO.json index b664e6309..4e635998c 100644 --- a/lib/diagram-render/dist/BUILD_INFO.json +++ b/lib/diagram-render/dist/BUILD_INFO.json @@ -1,13 +1,13 @@ { "name": "gstack-diagram-render", - "sha256": "da9c363071afbe79e06807bd1e67dbacc1123187db7b99e2608dd4a1a9567e94", + "sha256": "90148189fc8688870cbb822593112b5621bcbf265f4c44f363598390e665d329", "srcSha256": "07238fae312bc0444f62b0a0a3404a8a38c45cef505aa1528c60a0ded17cbe06", - "bytes": 9645479, - "bunVersion": "1.3.13", + "bytes": 7953601, + "bunVersion": "1.3.14", "deps": { - "@excalidraw/excalidraw": "0.18.0", - "@excalidraw/mermaid-to-excalidraw": "1.1.2", - "mermaid": "11.12.2", + "@excalidraw/excalidraw": "0.18.1", + "@excalidraw/mermaid-to-excalidraw": "2.2.2", + "mermaid": "11.16.0", "react": "18.3.1", "react-dom": "18.3.1" } diff --git a/lib/diagram-render/dist/diagram-render.html b/lib/diagram-render/dist/diagram-render.html index 25de82b9f..5997541bd 100644 --- a/lib/diagram-render/dist/diagram-render.html +++ b/lib/diagram-render/dist/diagram-render.html @@ -20,11 +20,11 @@ window.addEventListener("unhandledrejection", function (e) {
loading
diff --git a/lib/diagram-render/package.json b/lib/diagram-render/package.json index f164ba704..3aa6580f0 100644 --- a/lib/diagram-render/package.json +++ b/lib/diagram-render/package.json @@ -7,10 +7,15 @@ "build": "bun run scripts/build.ts" }, "dependencies": { - "@excalidraw/excalidraw": "0.18.0", - "@excalidraw/mermaid-to-excalidraw": "1.1.2", - "mermaid": "11.12.2", + "@excalidraw/excalidraw": "0.18.1", + "@excalidraw/mermaid-to-excalidraw": "2.2.2", + "mermaid": "11.16.0", "react": "18.3.1", "react-dom": "18.3.1" + }, + "overrides": { + "dompurify": "3.4.11", + "lodash-es": "4.18.1", + "nanoid": "5.0.9" } } diff --git a/package.json b/package.json index bd4ab1dcd..f022449f2 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "server": "bun run browse/src/server.ts", "test": "bun run scripts/test-free-strict.ts", "check:gstack2-generated": "bun run scripts/gstack2/check-generated.ts", - "test:gstack2": "bun run gen:gstack2 && bun run check:gstack2-generated && bun test --timeout 30000 test/gstack2-*.test.ts", + "test:gstack2": "bun run gen:gstack2 && bun run check:gstack2-generated && bun run scripts/gstack2/test-suite.ts", "test:gstack2:install": "bun run scripts/gstack2/test-install-matrix.ts --full", "test:gstack2:parity": "bun run ensure:gstack2-runtime && bun run scripts/gstack2/run-parity.ts", "test:free": "bun run scripts/test-free-shards.ts", @@ -70,17 +70,26 @@ "slop:diff": "bun run scripts/slop-diff.ts" }, "dependencies": { - "@anthropic-ai/sdk": "^0.78.0", + "@anthropic-ai/sdk": "^0.112.4", "@ngrok/ngrok": "^1.7.0", "diff": "^9.0.0", "html-to-docx": "1.8.0", - "marked": "^18.0.2", + "marked": "^18.0.6", "playwright": "^1.58.2", "sharp": "^0.34.5", - "socks": "^2.8.8", + "socks": "^2.8.9", "xterm": "5", "xterm-addon-fit": "^0.8.0" }, + "overrides": { + "@protobufjs/utf8": "1.1.1", + "adm-zip": "0.6.0", + "fast-uri": "3.1.2", + "hono": "4.12.25", + "ip-address": "10.2.0", + "protobufjs": "7.6.5", + "qs": "6.15.2" + }, "engines": { "bun": ">=1.0.0", "node": ">=18.0.0" @@ -96,7 +105,7 @@ "devtools" ], "devDependencies": { - "@anthropic-ai/claude-agent-sdk": "0.2.117", - "@huggingface/transformers": "^4.1.0" + "@anthropic-ai/claude-agent-sdk": "0.3.216", + "@huggingface/transformers": "4.2.0" } } diff --git a/runtime/cli.js b/runtime/cli.js index 385a2933e..dfdad4096 100644 --- a/runtime/cli.js +++ b/runtime/cli.js @@ -28,7 +28,6 @@ import { import { CAPABILITY_READINESS_CAPABILITIES, capabilityReadiness, - formatCapabilityReadiness, runDoctor, formatDoctor, } from "./doctor.js"; @@ -99,6 +98,11 @@ export async function main(argv = process.argv.slice(2), options = {}) { throw cliError(`Unknown command: ${command}`, "USAGE"); } } catch (error) { + const structuredResult = error?.executionResult ?? error?.cause?.executionResult; + if (structuredResult) { + write(stderr, renderExecutionResult(structuredResult, { json: true })); + return 1; + } const json = args.includes("--json"); const safeMessage = redactSensitiveText(error?.message ?? String(error)); if (json) { @@ -171,12 +175,47 @@ async function doctorCommand({ args, home, cwd, stdout }) { } const report = await runDoctor({ home, cwd, expectedSkillApi: parsed.values.get("--skill-api") }); const result = capability ? capabilityReadiness(report, capability) : report; + if (capability) { + const envelope = capabilityExecutionResult(result); + write(stdout, renderExecutionResult(envelope, { json: parsed.flags.has("--json") })); + return envelope.status === "success" ? 0 : 1; + } write(stdout, parsed.flags.has("--json") ? `${JSON.stringify(result, null, 2)}\n` - : capability ? formatCapabilityReadiness(result) : formatDoctor(result)); + : formatDoctor(result)); return result.ok ? 0 : 1; } +function capabilityExecutionResult(result) { + const statusByReadiness = { + ready: "success", + degraded: "degraded", + unavailable: "degraded", + unsupported: "unsupported", + failed: "failed", + }; + const codeByReadiness = { + ready: null, + degraded: EXECUTION_RESULT_ERROR_CODES.DEGRADED, + unavailable: EXECUTION_RESULT_ERROR_CODES.CAPABILITY_UNAVAILABLE, + unsupported: EXECUTION_RESULT_ERROR_CODES.CAPABILITY_UNSUPPORTED, + failed: EXECUTION_RESULT_ERROR_CODES.CAPABILITY_FAILED, + }; + const readiness = result.readiness.status; + const evidence = result.readiness.evidence?.map((item) => + `${item.id}: ${item.status} — ${item.message}`) ?? [ + `platform: ${result.platform.status}`, + `judgment: ${result.judgment.status}`, + ]; + return executionResult({ + status: statusByReadiness[readiness], + code: codeByReadiness[readiness], + summary: result.readiness.message, + evidence, + data: result, + }); +} + async function configCommand({ args, home, cwd, stdout }) { const [action, ...tail] = args; if (action === "get") { @@ -387,9 +426,12 @@ async function runExternalCommand(command, { cwd, env, stdout, stderr }) { child.once("close", (code, signal) => { if (code === 0) { if (captured.truncated) { - reject(cliError( + reject(executionResultError( `External command ${path.basename(executable)} exceeded the ${maxCapturedBytes}-byte result limit; verify its side effect before reconciling it as applied.`, EXECUTION_RESULT_ERROR_CODES.DEGRADED, + "degraded", + ["output exceeded 1048576-byte capture limit"], + { executable: path.basename(executable), exitCode: 0, truncated: true }, )); return; } @@ -398,9 +440,12 @@ async function runExternalCommand(command, { cwd, env, stdout, stderr }) { if (captured.stderr.trim()) evidence.push("non-empty stderr"); const name = path.basename(executable); if (evidence.length === 0) { - reject(cliError( + reject(executionResultError( `External command ${name} exited 0 but produced no output; verify its side effect before reconciling it as applied.`, EXECUTION_RESULT_ERROR_CODES.EMPTY, + "degraded", + ["exit code 0", "stdout and stderr were empty"], + { executable: name, exitCode: 0, stdout: "", stderr: "" }, )); return; } @@ -417,15 +462,30 @@ async function runExternalCommand(command, { cwd, env, stdout, stderr }) { })); return; } - const error = cliError( + const error = executionResultError( `External command ${path.basename(executable)} ${signal ? `ended by ${signal}` : `exited ${code}`}`, - "EXTERNAL_COMMAND_FAILED", + EXECUTION_RESULT_ERROR_CODES.FAILED, + "failed", + [signal ? `terminated by signal ${signal}` : `exit code ${code}`], + { + executable: path.basename(executable), + exitCode: code, + signal: signal ?? null, + stdout: captured.stdout, + stderr: captured.stderr, + }, ); reject(error); }); }); } +function executionResultError(summary, code, status, evidence, data) { + const error = cliError(summary, code); + error.executionResult = executionResult({ status, code, summary, evidence, data }); + return error; +} + async function withOwnedRuntimeMutation(home, callback) { return withRuntimeLifecycleLock(home, async () => { await assertManagedHome(home); diff --git a/runtime/execution-result.js b/runtime/execution-result.js index dd9212880..89f603b7a 100644 --- a/runtime/execution-result.js +++ b/runtime/execution-result.js @@ -14,6 +14,9 @@ export const EXECUTION_RESULT_ERROR_CODES = Object.freeze({ DEGRADED: "EXECUTION_DEGRADED", UNSUPPORTED: "EXECUTION_UNSUPPORTED", FAILED: "EXECUTION_FAILED", + CAPABILITY_UNAVAILABLE: "CAPABILITY_UNAVAILABLE", + CAPABILITY_UNSUPPORTED: "CAPABILITY_UNSUPPORTED", + CAPABILITY_FAILED: "CAPABILITY_FAILED", }); export const EXECUTION_RESULT_SCHEMA = Object.freeze({ diff --git a/runtime/install.js b/runtime/install.js index 8d3dbe2e6..a5e05c1ac 100644 --- a/runtime/install.js +++ b/runtime/install.js @@ -281,6 +281,9 @@ export const DEFAULT_RUNTIME_BUNDLE = Object.freeze([ entry("node_modules/detect-libc"), entry("node_modules/semver"), entry("node_modules/@anthropic-ai/sdk"), + entry("node_modules/standardwebhooks"), + entry("node_modules/@stablelib/base64"), + entry("node_modules/fast-sha256"), entry(platformBinary("design/dist/design"), "core", true), entry("design/dist/.version", "core"), entry(platformBinary("make-pdf/dist/pdf"), "core", true), diff --git a/scripts/gstack2/ensure-runtime-payloads.ts b/scripts/gstack2/ensure-runtime-payloads.ts index c46984833..b7884c2e0 100644 --- a/scripts/gstack2/ensure-runtime-payloads.ts +++ b/scripts/gstack2/ensure-runtime-payloads.ts @@ -8,7 +8,12 @@ import { } from '../../runtime/install.js'; const ROOT = path.resolve(import.meta.dir, '../..'); -const REQUIRED_CAPABILITIES = ['browse', 'gstack-design', 'make-pdf'] as const; +const REQUIRED_CAPABILITIES = [ + 'browse', + 'gstack-design', + 'make-pdf', + ...(process.platform === 'darwin' ? ['gstack-ios-qa-daemon', 'gstack-ios-qa-mint'] : []), +] as const; export interface RuntimePayloadEntry { path: string; diff --git a/scripts/gstack2/test-suite.ts b/scripts/gstack2/test-suite.ts new file mode 100644 index 000000000..72535eeec --- /dev/null +++ b/scripts/gstack2/test-suite.ts @@ -0,0 +1,22 @@ +#!/usr/bin/env bun + +import { collectFreeTestFiles } from '../test-free-shards'; +import { runStrictTestShard } from '../test-free-strict'; + +const GSTACK2_TEST_TIMEOUT_MS = 30_000; +const files = collectFreeTestFiles().filter((file) => /^test\/gstack2-.*\.test\.ts$/.test(file)); + +if (files.length === 0) { + throw new Error('No GStack 2 test files were discovered.'); +} + +console.log(`[test:gstack2] ${files.length} files across ${files.length} isolated processes`); +for (let index = 0; index < files.length; index += 1) { + const file = files[index]; + console.log(`[test:gstack2] file ${index + 1}/${files.length}: ${file}`); + const exitCode = await runStrictTestShard([file], GSTACK2_TEST_TIMEOUT_MS); + if (exitCode !== 0) { + process.exitCode = exitCode; + break; + } +} diff --git a/scripts/test-free-shards.ts b/scripts/test-free-shards.ts index 943f2ad4c..c98ed9482 100755 --- a/scripts/test-free-shards.ts +++ b/scripts/test-free-shards.ts @@ -302,8 +302,11 @@ export function planBoundedFreeTestShards( return shards; } -export function buildShardArgs(files: string[]): string[] { - return ['test', ...files, '--max-concurrency=1', `--timeout=${FREE_TEST_TIMEOUT_MS}`]; +export function buildShardArgs(files: string[], timeoutMs = FREE_TEST_TIMEOUT_MS): string[] { + if (!Number.isInteger(timeoutMs) || timeoutMs <= 0) { + throw new Error(`Test timeout must be a positive integer. Received: ${timeoutMs}`); + } + return ['test', ...files, '--max-concurrency=1', `--timeout=${timeoutMs}`]; } type CliOptions = { diff --git a/scripts/test-free-strict.ts b/scripts/test-free-strict.ts index ba3a2fbbd..ad0268d13 100644 --- a/scripts/test-free-strict.ts +++ b/scripts/test-free-strict.ts @@ -261,9 +261,12 @@ export async function runDefaultFreeTests(): Promise { return slopSignal === null ? 0 : terminationSignalExitCode(slopSignal); } -export async function runStrictTestShard(files: string[]): Promise { +export async function runStrictTestShard( + files: string[], + timeoutMs?: number, +): Promise { if (files.length === 0) throw new Error('Cannot run an empty free-test shard.'); - const child = spawn(process.execPath, buildShardArgs(exactTestFileSelectors(files)), { + const child = spawn(process.execPath, buildShardArgs(exactTestFileSelectors(files), timeoutMs), { cwd: ROOT, env: process.env, stdio: ['inherit', 'pipe', 'pipe'], diff --git a/test/gstack2-capability-readiness.test.ts b/test/gstack2-capability-readiness.test.ts index 9691adfc6..fc5e8ee73 100644 --- a/test/gstack2-capability-readiness.test.ts +++ b/test/gstack2-capability-readiness.test.ts @@ -101,10 +101,15 @@ describe("capability readiness", () => { expect(exit).toBe(1); expect(stderr.value()).toBe(""); expect(result).toMatchObject({ - ok: false, - capability: "pdf", - judgment: { status: "available" }, - readiness: { status: "unavailable" }, + schemaVersion: 1, + status: "degraded", + code: "CAPABILITY_UNAVAILABLE", + data: { + ok: false, + capability: "pdf", + judgment: { status: "available" }, + readiness: { status: "unavailable" }, + }, }); } finally { await fs.rm(root, { recursive: true, force: true }); diff --git a/test/gstack2-runtime-effect-cli.test.ts b/test/gstack2-runtime-effect-cli.test.ts index b1f8f4b3c..0ff1edfaa 100644 --- a/test/gstack2-runtime-effect-cli.test.ts +++ b/test/gstack2-runtime-effect-cli.test.ts @@ -107,11 +107,33 @@ describe('gstack state external-effect CLI', () => { 'state', 'effect', 'run_empty', 'silent.tool', '--', silent, ], { cwd, env, stdout: out, stderr: err }); expect(code).toBe(1); - expect(err.value()).toContain('may have occurred'); + expect(JSON.parse(err.value())).toMatchObject({ + status: 'degraded', + code: 'EXECUTION_EMPTY', + evidence: ['exit code 0', 'stdout and stderr were empty'], + }); expect(out.value()).not.toContain('"status":"success"'); + const retryError = sink(); expect(await main([ 'state', 'effect', 'run_empty', 'silent.tool', '--', silent, - ], { cwd, env, stdout: out, stderr: err })).toBe(1); - expect(err.value()).toContain('was already claimed'); + ], { cwd, env, stdout: out, stderr: retryError })).toBe(1); + expect(retryError.value()).toContain('was already claimed'); + }); + + test('a nonzero command returns a structured failed result', async () => { + const { cwd, env } = await fixture(); + const out = sink(); + const err = sink(); + await main(['state', 'begin', 'ship', '--run-id', 'run_failed'], { cwd, env, stdout: out, stderr: err }); + const code = await main([ + 'state', 'effect', 'run_failed', 'failed.tool', '--', process.execPath, '-e', 'process.exit(7)', + ], { cwd, env, stdout: out, stderr: err }); + expect(code).toBe(1); + expect(JSON.parse(err.value())).toMatchObject({ + status: 'failed', + code: 'EXECUTION_FAILED', + evidence: ['exit code 7'], + data: { exitCode: 7 }, + }); }); }); diff --git a/test/gstack2-runtime-install.test.ts b/test/gstack2-runtime-install.test.ts index fd2c71103..307654d89 100644 --- a/test/gstack2-runtime-install.test.ts +++ b/test/gstack2-runtime-install.test.ts @@ -376,6 +376,9 @@ describe("GStack 2 managed runtime installer", () => { "node_modules/sharp", "node_modules/detect-libc", "node_modules/semver", + "node_modules/standardwebhooks", + "node_modules/@stablelib/base64", + "node_modules/fast-sha256", ...runtimeNativePackagePaths(), ]) expect(bundlePaths.has(dependency)).toBe(true); expect(bundlePaths.has("node_modules/@img")).toBe(false); diff --git a/test/gstack2-runtime-payloads.test.ts b/test/gstack2-runtime-payloads.test.ts index 6d83d426c..b2496730e 100644 --- a/test/gstack2-runtime-payloads.test.ts +++ b/test/gstack2-runtime-payloads.test.ts @@ -45,7 +45,9 @@ describe('GStack 2 generated runtime payload prerequisites', () => { expect(result.built).toBe(true); expect(calls).toHaveLength(1); expect(calls[0].map((entry) => entry.path)).toEqual(REQUIRED_RUNTIME_PAYLOADS.map((entry) => entry.path)); - expect(new Set(calls[0].map((entry) => entry.build))).toEqual(new Set(['core'])); + expect(new Set(calls[0].map((entry) => entry.build))).toEqual( + new Set(process.platform === 'darwin' ? ['core', 'ios'] : ['core']), + ); }); test('does not rebuild payloads that already exist', async () => { diff --git a/test/gstack2-semantic-parity.test.ts b/test/gstack2-semantic-parity.test.ts index e9bc9eecd..c4ea299a1 100644 --- a/test/gstack2-semantic-parity.test.ts +++ b/test/gstack2-semantic-parity.test.ts @@ -18,7 +18,7 @@ describe('GStack 2 semantic parity', () => { expect(result.sections).toBe(16); expect(result.policyUnits).toBe(AUTHORITY_POLICY_CASES.length); expect(result.checks).toBeGreaterThan(250); - }); + }, 15_000); test('authority-policy units cover evidence, trust, and routing controls', () => { expect(AUTHORITY_POLICY_CASES.length).toBeGreaterThanOrEqual(9); diff --git a/test/release-hardening.test.ts b/test/release-hardening.test.ts index 7db3fad03..53edc0998 100644 --- a/test/release-hardening.test.ts +++ b/test/release-hardening.test.ts @@ -72,7 +72,8 @@ describe("release and CI hardening", () => { expect(workflow).toContain("versions/current.json"); expect(workflow).not.toContain('active="$GSTACK_HOME/versions/2.0.0"'); expect(workflow).toContain(".gstack-runtime-browsers"); - expect(workflow).toContain('chromium.launch({ headless: true, channel: "chromium" })'); + expect(workflow).toContain('for (const options of [{ headless: true }, { headless: true, channel: "chromium" }])'); + expect(workflow).toContain("chromium.launch(options)"); expect(workflow).not.toContain("--with-deps"); expect(workflow).toContain(".gstack-runtime-tools/bun"); expect(workflow).toContain('"$GSTACK_HOME/bin/bun" --version'); @@ -99,7 +100,9 @@ describe("release and CI hardening", () => { expect(installer).toContain('entry(managedBunRelativePath(), "managed-bun", true)'); const browser = read("browse/src/cli.ts"); expect(browser).toContain("Every installed/compiled client must use the adjacent Node-compatible daemon"); - expect(browser).toContain("if (IS_COMPILED && !NODE_SERVER_SCRIPT)"); + expect(browser).toContain("if (isCompiled)"); + expect(browser).toContain("if (!nodeServerScript)"); + expect(browser).toContain("return { isCompiled, nodeServerScript, sourceServerScript: null }"); }); test("Windows setup lane installs, doctors, and uninstalls rather than only building", () => { diff --git a/test/test-free-shards.test.ts b/test/test-free-shards.test.ts index 3fc540143..0361ef279 100644 --- a/test/test-free-shards.test.ts +++ b/test/test-free-shards.test.ts @@ -5,6 +5,7 @@ import * as os from 'os'; import { DEFAULT_MAX_FILES_PER_SHARD, FREE_TEST_ROOTS, + buildShardArgs, isFreeTestFile, collectFreeTestFiles, containsScheduledProcessExitZero, @@ -138,6 +139,16 @@ describe('test-free-shards: sharding', () => { expect(() => assignFilesToShards(['a.test.ts'], -1)).toThrow(); }); + test('buildShardArgs accepts a suite-specific timeout without enabling file concurrency', () => { + expect(buildShardArgs(['test/gstack2-skills.test.ts'], 30_000)).toEqual([ + 'test', + 'test/gstack2-skills.test.ts', + '--max-concurrency=1', + '--timeout=30000', + ]); + expect(() => buildShardArgs(['test/example.test.ts'], 0)).toThrow(); + }); + test('shards are stable across runs (same files always land in same shard)', () => { const files = ['x.test.ts', 'y.test.ts', 'z.test.ts']; const a = assignFilesToShards(files, 5);