Replace the marketplace service dependency and the native/global/user scope tiers with a single external directory ($OFFICER_ITEMS_DIR) holding skills, tools, tasks, processes and extensions as plain files. - tasks move from Postgres to TASK.md files (new file-backed task layer); task editing now works, which the DB path never supported - skills/tools/processes collapse into one shared file router (single dir) - remove the marketplace client (sync-marketplace/sync-version) and the boot-time sync; pi-bridge/pi-manager/sandbox point at the flat store - drop the dead tasks + vestigial skills/tools/processes/extensions + item_chats tables (migration 0004) - one-time migration script exports DB tasks and consolidates disk items Migration verified: all 6 tasks round-trip through the runtime parser identically to their DB rows (pipeline steps, triggers, script impls and agentic bodies all intact). NOTE: not yet functionally tested end-to-end — every item (each task mode, tool, skill, extension) still needs to be run/exercised in the app before this is trusted. To be done manually. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
85 lines
2.6 KiB
TypeScript
85 lines
2.6 KiB
TypeScript
import { mkdirSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import { homedir } from 'node:os';
|
|
import { DATA_PATH, ensureItemDirs } from './data-path';
|
|
import { ensureToolLoader } from './ensure-tool-loader';
|
|
// Queue is now owned by the sidecar process
|
|
import { startDiscordBotIfConfigured } from './channels/discord/bot';
|
|
import { startTelegramBotIfConfigured } from './channels/telegram/bot';
|
|
import { startWhatsAppBotIfConfigured } from './channels/whatsapp/bot';
|
|
|
|
mkdirSync(DATA_PATH, { recursive: true });
|
|
ensureItemDirs();
|
|
|
|
/** Check common locations for the Pi package directory. */
|
|
async function findPiPackageDir(): Promise<string | null> {
|
|
const candidates = [
|
|
join(homedir(), '.npm-global', 'lib', 'node_modules', '@mariozechner', 'pi-coding-agent'),
|
|
'/usr/local/lib/node_modules/@mariozechner/pi-coding-agent',
|
|
];
|
|
for (const dir of candidates) {
|
|
if (await Bun.file(join(dir, 'package.json')).exists()) return dir;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
async function ensurePiInstalled(): Promise<boolean> {
|
|
const dir = await findPiPackageDir();
|
|
if (!dir) return false;
|
|
try {
|
|
const pkg = await Bun.file(join(dir, 'package.json')).json();
|
|
if (pkg.version) {
|
|
console.log(`[bootstrap] Pi found: ${pkg.version}`);
|
|
return true;
|
|
}
|
|
} catch {}
|
|
return false;
|
|
}
|
|
|
|
async function installPi(): Promise<boolean> {
|
|
console.log('[bootstrap] Pi not found, installing...');
|
|
try {
|
|
const proc = Bun.spawn(['npm', 'install', '-g', '@mariozechner/pi-coding-agent'], {
|
|
stdout: 'pipe',
|
|
stderr: 'pipe',
|
|
});
|
|
const stderr = await new Response(proc.stderr).text();
|
|
await proc.exited;
|
|
if (proc.exitCode !== 0) {
|
|
console.error('[bootstrap] Pi installation failed:', stderr.trim());
|
|
return false;
|
|
}
|
|
console.log('[bootstrap] Pi installed successfully');
|
|
return true;
|
|
} catch (err) {
|
|
console.error('[bootstrap] Pi installation error:', err);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
(async () => {
|
|
const installed = await ensurePiInstalled();
|
|
if (!installed) {
|
|
const ok = await installPi();
|
|
if (!ok) {
|
|
console.error('[bootstrap] Could not install Pi — model discovery will not work');
|
|
return;
|
|
}
|
|
}
|
|
|
|
ensureToolLoader();
|
|
// Queue is initialized by the sidecar process
|
|
|
|
await startDiscordBotIfConfigured().catch((err) => {
|
|
console.error('[channels] Failed to start Discord bot:', err);
|
|
});
|
|
|
|
await startTelegramBotIfConfigured().catch((err) => {
|
|
console.error('[channels] Failed to start Telegram bot:', err);
|
|
});
|
|
|
|
await startWhatsAppBotIfConfigured().catch((err) => {
|
|
console.error('[channels] Failed to start WhatsApp bot:', err);
|
|
});
|
|
})();
|