#!/usr/bin/env node // No-model native resource-loader check: real project discovery plus seat extensions. // Usage: node scripts/test-goal-discovery.mjs conflict|explicit|shared|unified [brain] // Reads only the extensions list; never copies credentials, starts sessions or runs tools. import assert from 'node:assert/strict'; import { mkdtempSync, readFileSync, realpathSync, rmSync, existsSync, unlinkSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { dirname, join, relative } from 'node:path'; import { pathToFileURL } from 'node:url'; import { execFileSync } from 'node:child_process'; import { randomUUID } from 'node:crypto'; const [cwd, settingsPath, expected, brain = cwd] = process.argv.slice(2); assert.ok(cwd && settingsPath && ['conflict', 'explicit', 'shared', 'unified'].includes(expected)); const wantsShared = expected === 'shared' || expected === 'unified'; const extensions = JSON.parse(readFileSync(settingsPath, 'utf8')).extensions; assert.ok(Array.isArray(extensions) && extensions.every(x => typeof x === 'string')); const agentDir = mkdtempSync(join(tmpdir(), 'goal-discovery-')); process.env.PI_CODING_AGENT_DIR = agentDir; process.env.MOSAIC_LAUNCH_INCARNATION = 'discovery-test-' + randomUUID(); process.env.PI_OFFLINE = '1'; // Loading the shared extension must not quarantine any operator-owned legacy state. for (const dir of new Set([cwd, brain])) { assert.equal(existsSync(join(dir, '.pi/state/goal/goal-state.json')), false); } try { const binary = realpathSync(execFileSync('which', ['pi'], { encoding: 'utf8' }).trim()); const { DefaultResourceLoader, SettingsManager } = await import(pathToFileURL(join(dirname(binary), 'index.js')).href); const settingsManager = SettingsManager.inMemory({ extensions }); settingsManager.setProjectTrusted(true); const loader = new DefaultResourceLoader({ cwd, agentDir, settingsManager, noExtensions: expected === 'explicit' || expected === 'shared', additionalExtensionPaths: [...(expected === 'shared' ? [join(brain, '.pi/extensions/goal'), join(brain, 'fleet/extensions/wrapper-guard')] : expected === 'explicit' ? extensions : []), join(brain, 'tools/unslop-hook/extension.ts')], noSkills: true, noPromptTemplates: true, noThemes: true, noContextFiles: true }); await loader.reload(); const loaded = loader.getExtensions(); if (expected === 'conflict') { assert.ok(loaded.errors.some(e => e.error.includes('Tool "goal_report" conflicts with')), JSON.stringify(loaded.errors)); console.log('PASS negative control: combined discovery reproduces goal_report conflict'); } else { assert.deepEqual(loaded.errors, []); const owners = loaded.extensions.filter(e => e.tools.has('goal_report')); assert.equal(owners.length, 1); assert.equal(realpathSync(owners[0].path.replace(/\/index\.ts$/, '')), realpathSync(join(brain, wantsShared ? '.pi/extensions/goal' : 'fleet/extensions/goal'))); const guardNames = extensions.filter(p => /\/(wrapper-guard|mosaic-core)$/.test(p)).map(p => p.split('/').at(-1)); assert.ok(guardNames.length, 'test must include the configured enforcement extension'); for (const name of guardNames) { const guards = loaded.extensions.filter(e => e.path.replace(/\/index\.ts$/, '').endsWith('/' + name)); assert.equal(guards.length, 1, `${name} must remain loaded`); assert.ok(guards[0].handlers.get('tool_call')?.length, `${name} interception must remain registered`); } assert.equal(owners[0].commands.has('goal'), true); assert.equal(loaded.extensions.filter(e => e.path.endsWith('/unslop-hook/extension.ts')).length, 1, 'launcher unslop extension must remain loaded'); if (wantsShared) { assert.ok(owners[0].shortcuts.has('alt+g'), 'NG full recall shortcut must be registered'); } // Only the synthetic native suite opts into an owned fixture write. Live checks // merely load registrations and never run a goal command or read private state. if (process.env.MOSAIC_GOAL_DISCOVERY_FIXTURE_ROOT === brain) { assert.ok(brain.startsWith(join(tmpdir(), 'goal58-native-'))); assert.equal(readFileSync(join(brain, '.goal-discovery-owned-fixture'), 'utf8'), 'synthetic goal58 fixture'); const filename = `goal-state.${process.env.MOSAIC_LAUNCH_INCARNATION}.json`; const possible = [...new Set([join(brain, '.pi/state/goal', filename), join(brain, 'fleet/state/goal', filename), join(cwd, '.pi/state/goal', filename)])]; assert.ok(possible.every(p => !existsSync(p)), 'fixture identity must be new'); await owners[0].commands.get('goal').handler('owned goal58 fixture', { mode: 'print', hasUI: false }); const written = possible.filter(existsSync); assert.equal(written.length, 1, 'one incarnation state store per selected entrypoint'); assert.equal(JSON.parse(readFileSync(written[0], 'utf8')).text, 'owned goal58 fixture'); console.log(`PASS owned fixture state path: ${relative(brain, dirname(written[0]))}`); unlinkSync(written[0]); } console.log(`PASS ${expected} discovery: exactly one ${wantsShared ? 'shared NG' : 'legacy'} goal_report and /goal; ${guardNames.join(', ')} interception and unslop retained`); } } finally { rmSync(agentDir, { recursive: true, force: true }); }