Implements the full gated session flow and prompt intelligence system: - Prisma schema: add gated, priority, summary, chapters, linkTarget fields - Session gate: state machine (gated → begin_session → ungated) with LLM-powered tool selection based on prompt index - Tag matcher: intelligent prompt-to-tool matching with project/server/action tags - LLM selector: tiered provider selection (fast for gating, heavy for complex tasks) - Link resolver: cross-project MCP resource references (project/server:uri format) - Prompt summary service: LLM-generated summaries and chapter extraction - System project bootstrap: ensures default project exists on startup - Structural link health checks: enrichWithLinkStatus on prompt GET endpoints - CLI: create prompt --priority/--link, create project --gated/--no-gated, describe project shows prompts section, get prompts shows PRI/LINK/STATUS - Apply/edit: priority, linkTarget, gated fields supported - Shell completions: fish updated with new flags - 1,253 tests passing across all packages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
66 lines
2.6 KiB
TypeScript
66 lines
2.6 KiB
TypeScript
import { Command } from 'commander';
|
|
import type { ApiClient } from '../api-client.js';
|
|
import { resolveNameOrId, resolveResource } from './shared.js';
|
|
|
|
export interface ProjectOpsDeps {
|
|
client: ApiClient;
|
|
log: (...args: string[]) => void;
|
|
getProject: () => string | undefined;
|
|
}
|
|
|
|
function requireProject(deps: ProjectOpsDeps): string {
|
|
const project = deps.getProject();
|
|
if (!project) {
|
|
deps.log('Error: --project <name> is required for this command.');
|
|
process.exitCode = 1;
|
|
throw new Error('--project required');
|
|
}
|
|
return project;
|
|
}
|
|
|
|
export function createAttachServerCommand(deps: ProjectOpsDeps): Command {
|
|
const { client, log } = deps;
|
|
|
|
return new Command('attach-server')
|
|
.description('Attach a server to a project (requires --project)')
|
|
.argument('<server-name>', 'Server name to attach')
|
|
.action(async (serverName: string) => {
|
|
const projectName = requireProject(deps);
|
|
const projectId = await resolveNameOrId(client, 'projects', projectName);
|
|
await client.post(`/api/v1/projects/${projectId}/servers`, { server: serverName });
|
|
log(`server '${serverName}' attached to project '${projectName}'`);
|
|
});
|
|
}
|
|
|
|
export function createDetachServerCommand(deps: ProjectOpsDeps): Command {
|
|
const { client, log } = deps;
|
|
|
|
return new Command('detach-server')
|
|
.description('Detach a server from a project (requires --project)')
|
|
.argument('<server-name>', 'Server name to detach')
|
|
.action(async (serverName: string) => {
|
|
const projectName = requireProject(deps);
|
|
const projectId = await resolveNameOrId(client, 'projects', projectName);
|
|
await client.delete(`/api/v1/projects/${projectId}/servers/${serverName}`);
|
|
log(`server '${serverName}' detached from project '${projectName}'`);
|
|
});
|
|
}
|
|
|
|
export function createApproveCommand(deps: ProjectOpsDeps): Command {
|
|
const { client, log } = deps;
|
|
|
|
return new Command('approve')
|
|
.description('Approve a pending prompt request (atomic: delete request, create prompt)')
|
|
.argument('<resource>', 'Resource type (promptrequest)')
|
|
.argument('<name>', 'Resource name or ID')
|
|
.action(async (resourceArg: string, nameOrId: string) => {
|
|
const resource = resolveResource(resourceArg);
|
|
if (resource !== 'promptrequests') {
|
|
throw new Error(`approve is only supported for 'promptrequest', got '${resourceArg}'`);
|
|
}
|
|
const id = await resolveNameOrId(client, 'promptrequests', nameOrId);
|
|
const prompt = await client.post<{ id: string; name: string }>(`/api/v1/promptrequests/${id}/approve`, {});
|
|
log(`prompt request approved → prompt '${prompt.name}' created (id: ${prompt.id})`);
|
|
});
|
|
}
|