OIP3DDPF7YOAAGDPJWJ3INIQESE4MLR4J4FYH7E66YMTD76EXQ4AC interface ManagerState {root: string;trunkChannel: string;remote?: string;features: Record<string, FeatureState>;}interface PijulManagerArgs {action: 'init' | 'spawn' | 'sync' | 'record' | 'push' | 'status' | 'close';feature?: string;trunk?: string;remote?: string;workspaceRoot?: string;agent?: string;message?: string;}
}const STATE_DIR_NAME = '.opencode';const STATE_FILE_NAME = 'pijul-manager.json';const DEFAULT_TRUNK_CHANNEL = 'main';function nowIso(): string {return new Date().toISOString();}function slugify(value: string): string {return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 64);}async function ensureDir(dirPath: string): Promise<void> {await fs.mkdir(dirPath, { recursive: true });}async function pathExists(targetPath: string): Promise<boolean> {try {await fs.access(targetPath);return true;} catch {return false;}}async function readState(root: string): Promise<ManagerState> {const statePath = path.join(root, STATE_DIR_NAME, STATE_FILE_NAME);if (!(await pathExists(statePath))) {return {root,trunkChannel: DEFAULT_TRUNK_CHANNEL,features: {},};}const raw = await fs.readFile(statePath, 'utf8');const parsed = JSON.parse(raw) as ManagerState;return {root,trunkChannel: parsed.trunkChannel ?? DEFAULT_TRUNK_CHANNEL,remote: parsed.remote,features: parsed.features ?? {},};}async function writeState(root: string, state: ManagerState): Promise<void> {const stateDir = path.join(root, STATE_DIR_NAME);await ensureDir(stateDir);const statePath = path.join(stateDir, STATE_FILE_NAME);await fs.writeFile(statePath, `${JSON.stringify(state, null, 2)}\n`, 'utf8');}async function ensurePijulRepo(root: string): Promise<void> {const pijulDir = path.join(root, '.pijul');if (!existsSync(pijulDir)) {throw new Error(`No .pijul directory found in ${root}`);}}async function runCommand(command: string, args: string[], cwd: string): Promise<{ exitCode: number; stdout: string; stderr: string }> {const proc = Bun.spawn([command, ...args], {cwd,stdout: 'pipe',stderr: 'pipe',});const stdout = await new Response(proc.stdout).text();const stderr = await new Response(proc.stderr).text();const exitCode = await proc.exited;return { exitCode, stdout: stdout.trim(), stderr: stderr.trim() };
async function pijulDiffIsClean(cwd: string): Promise<boolean> {const result = await runCommand('pijul', ['diff'], cwd);return result.exitCode === 0 && result.stdout.length === 0 && result.stderr.length === 0;}function formatFeatureState(feature: FeatureState): string {return `${feature.feature} (${feature.status}) - channel=${feature.channel} workspace=${feature.workspace}`;}
const pijulManagerTool = tool({description: 'Manage parallel feature work on Pijul repositories.',args: {action: z.enum(['init', 'spawn', 'sync', 'record', 'push', 'status', 'close']),feature: z.string().optional(),trunk: z.string().optional(),remote: z.string().optional(),workspaceRoot: z.string().optional(),agent: z.string().optional(),message: z.string().optional(),},async execute(args: PijulManagerArgs) {const action = args.action;if (!action) {return 'Missing action. Expected one of: init, spawn, sync, record, push, status, close.';}const root = process.cwd();await ensurePijulRepo(root);const state = await readState(root);if (action === 'init') {state.trunkChannel = args.trunk?.trim() || state.trunkChannel || DEFAULT_TRUNK_CHANNEL;if (args.remote) state.remote = args.remote.trim();await writeState(root, state);return `Initialized pijul manager. trunk=${state.trunkChannel}${state.remote ? ` remote=${state.remote}` : ''}`;}
if (action === 'status') {const features = Object.values(state.features);if (features.length === 0) return 'No active feature channels.';return features.map(formatFeatureState).join('\n');}if (action === 'close') {const featureKey = args.feature ? slugify(args.feature) : '';if (!featureKey || !state.features[featureKey]) {return 'Unknown feature; provide a valid feature name.';}state.features[featureKey].status = 'pushed';await writeState(root, state);return `Closed feature ${featureKey}.`;}if (action === 'spawn') {if (!args.feature) return 'Missing feature name.';const featureKey = slugify(args.feature);if (!featureKey) return 'Invalid feature name.';const channel = `feature/${featureKey}`;const stateDir = path.join(root, STATE_DIR_NAME);const workspaceRoot = args.workspaceRoot? path.resolve(args.workspaceRoot): path.join(stateDir, 'workspaces');const workspace = path.join(workspaceRoot, featureKey);await ensureDir(workspaceRoot);if (await pathExists(workspace)) {state.features[featureKey] = {feature: featureKey,channel,workspace,agent: args.agent,status: 'active',lastSyncedTrunk: state.features[featureKey]?.lastSyncedTrunk,lastPush: state.features[featureKey]?.lastPush,};await writeState(root, state);return `Workspace already exists at ${workspace}.`;}const cloneResult = await runCommand('pijul', ['clone', root, workspace, '--no-prompt'], root);if (cloneResult.exitCode !== 0) {return `Failed to clone repo: ${cloneResult.stderr || cloneResult.stdout}`;}const channelResult = await runCommand('pijul', ['channel', 'new', channel, '--no-prompt'], workspace);if (channelResult.exitCode !== 0) {const combined = `${channelResult.stdout}\n${channelResult.stderr}`.toLowerCase();if (!combined.includes('already') && !combined.includes('exists')) {return `Failed to create channel: ${channelResult.stderr || channelResult.stdout}`;}}const switchResult = await runCommand('pijul', ['channel', 'switch', channel, '--no-prompt'], workspace);if (switchResult.exitCode !== 0) {return `Failed to switch channel: ${switchResult.stderr || switchResult.stdout}`;}state.features[featureKey] = {feature: featureKey,channel,workspace,agent: args.agent,status: 'active',};await writeState(root, state);return `Spawned ${featureKey} in ${workspace} on ${channel}.`;}if (action === 'sync') {if (!args.feature) return 'Missing feature name.';const featureKey = slugify(args.feature);const feature = state.features[featureKey];if (!feature) return 'Unknown feature; spawn it first.';const pullResult = await runCommand('pijul',['pull', root, '--from-channel', state.trunkChannel, '-a', '--no-prompt'],feature.workspace,);if (pullResult.exitCode !== 0) {return `Failed to pull trunk: ${pullResult.stderr || pullResult.stdout}`;}const clean = await pijulDiffIsClean(feature.workspace);feature.lastSyncedTrunk = nowIso();feature.status = clean ? 'ready' : 'blocked';await writeState(root, state);if (!clean) {return `Sync completed, but working copy has unresolved changes. Resolve conflicts, record changes, then retry.`;}return `Synced ${featureKey} with trunk (${state.trunkChannel}).`;}if (action === 'record') {if (!args.feature) return 'Missing feature name.';const featureKey = slugify(args.feature);const feature = state.features[featureKey];if (!feature) return 'Unknown feature; spawn it first.';const message = args.message?.trim() || `WIP: ${featureKey}`;const addResult = await runCommand('pijul',['add', '--recursive', '--no-prompt', '.'],feature.workspace,);if (addResult.exitCode !== 0) {return `Failed to add files: ${addResult.stderr || addResult.stdout}`;}const recordResult = await runCommand('pijul',['record', '-a', '-m', message, '--no-prompt'],feature.workspace,);if (recordResult.exitCode !== 0) {return `Failed to record changes: ${recordResult.stderr || recordResult.stdout}`;}feature.status = 'ready';await writeState(root, state);return `Recorded changes for ${featureKey}.`;}if (action === 'push') {if (!args.feature) return 'Missing feature name.';const featureKey = slugify(args.feature);const feature = state.features[featureKey];if (!feature) return 'Unknown feature; spawn it first.';const syncResult = await runCommand('pijul',['pull', root, '--from-channel', state.trunkChannel, '-a', '--no-prompt'],feature.workspace,);if (syncResult.exitCode !== 0) {return `Failed to sync trunk before push: ${syncResult.stderr || syncResult.stdout}`;}const featureClean = await pijulDiffIsClean(feature.workspace);if (!featureClean) {feature.status = 'blocked';await writeState(root, state);return 'Feature workspace has unrecorded changes; resolve and record before push.';}const trunkClean = await pijulDiffIsClean(root);if (!trunkClean) {return 'Trunk workspace has unrecorded changes; clean trunk before pushing.';}const switchResult = await runCommand('pijul', ['channel', 'switch', state.trunkChannel, '--no-prompt'], root);if (switchResult.exitCode !== 0) {return `Failed to switch trunk channel: ${switchResult.stderr || switchResult.stdout}`;}const pullResult = await runCommand('pijul',['pull', feature.workspace, '--from-channel', feature.channel, '-a', '--no-prompt'],root,);if (pullResult.exitCode !== 0) {return `Failed to pull feature changes into trunk: ${pullResult.stderr || pullResult.stdout}`;}const trunkAfterPullClean = await pijulDiffIsClean(root);if (!trunkAfterPullClean) {feature.status = 'blocked';await writeState(root, state);return 'Trunk has unresolved changes after pull; resolve conflicts in trunk then retry push.';}if (state.remote) {const pushResult = await runCommand('pijul',['push', state.remote, '--from-channel', state.trunkChannel, '-a', '--no-prompt'],root,);if (pushResult.exitCode !== 0) {return `Failed to push trunk: ${pushResult.stderr || pushResult.stdout}`;}}feature.status = 'pushed';feature.lastPush = nowIso();await writeState(root, state);return `Pushed ${featureKey} to trunk (${state.trunkChannel}).`;}return `Unknown action: ${action}`;},});
---description: Sync a feature workspace with trunk.---You are a feature sub-agent. Sync your workspace with trunk before proceeding.Call `pijul_manager` with:- action: "sync"- feature: the current feature nameIf the tool reports unresolved changes, resolve conflicts, record changes, and retry.
---description: Show all active Pijul feature channels.---Call `pijul_manager` with action "status" and summarize active features, status, and readiness.
---description: Create a feature channel and workspace for a sub-agent.---You are the coordinator. Create a Pijul feature workspace and channel for the requested feature.1. Call the `pijul_manager` tool with action "spawn" and the feature name.2. Share the workspace path and channel with the user.3. Open a subtask for the feature agent that includes:- Goals, constraints, and acceptance criteria from the user.- The rule: run `pijul_manager` action "sync" before "push".- The rule: resolve conflicts locally and keep trunk clean.
---description: Record all current changes for a feature.---You are a feature sub-agent. Record all changes before pushing.Call `pijul_manager` with:- action: "record"- feature: the current feature name- message: a short change summary
---description: Push a feature channel into trunk.---You are a feature sub-agent. Push your ready feature into trunk after syncing.Call `pijul_manager` with:- action: "push"- feature: the current feature nameIf the tool reports unresolved changes, resolve conflicts locally and retry.
---description: Initialize pijul manager settings.---Call `pijul_manager` with action "init".If the user provides a trunk channel or remote, include:- trunk: channel name- remote: remote URL
---description: Send design direction to a feature sub-agent.---Send the following direction to the feature sub-agent:- Feature name- Updated goals or design constraints- Acceptance criteria updates- Files or areas to avoid touchingRemind the sub-agent to sync with trunk before pushing and to resolve conflicts locally.
{"lockfileVersion": 1,"configVersion": 1,"workspaces": {"": {"name": "opencode-anarchy","dependencies": {"@opencode-ai/plugin": "1.0.85",},"devDependencies": {"@types/node": "^20.11.5","bun-types": "latest","typescript": "^5.8.3",},},},"packages": {"@opencode-ai/plugin": ["@opencode-ai/plugin@1.0.85", "", { "dependencies": { "@opencode-ai/sdk": "1.0.85", "zod": "4.1.8" } }, "sha512-4uU15occ/rZALIvDk3VwKdZwUZVAcNEcBZNJQKKMX+Lp+sQ/YvHKqawwz1ktOIS2UDsCKh+gyvV8fRCuUBEdKQ=="],"@opencode-ai/sdk": ["@opencode-ai/sdk@1.0.85", "", {}, "sha512-7qVa7Psu7dFQBI1aMeQZXRho/6QMebHS2klNRaYO8b+n4jMUg20HEBIMFw5S1B2RF00+DFiTDxbbdByfirRNtg=="],"@types/node": ["@types/node@20.19.30", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g=="],"bun-types": ["bun-types@1.3.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-qyschsA03Qz+gou+apt6HNl6HnI+sJJLL4wLDke4iugsE6584CMupOtTY1n+2YC9nGVrEKUlTs99jjRLKgWnjQ=="],"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],"zod": ["zod@4.1.8", "", {}, "sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ=="],}}
.opencode