Row 128 round 1, Researcher's candidate (agents/researcher/work/queue-128/, row128.patch, manifest 9eed6a78, 8 paths, base0f3eb25ea). Filbert approved round 1 (comment 28895). `mosaic project create` and `project list` call project.create and project.list; `init` and `check` keep their arguments and refusals. `mosaic threads`, `thread create`, `thread open` and `thread read` cover the thread verbs, and `mosaic talk --thread` sends thread.send as a REQUEST and prints only the reply to the sent message. `mosaic follow --thread` is the same loop without the send. A thread reference is its id, an id prefix of 8 or more characters, or <project>/<name>; unknown, short and ambiguous references refuse with exit 2 before any send. Every verb refuses inside an agent run. There is no default thread, so a plain `talk assistant` still meets thread-required-use-thread-send. Acceptance 314 step 1 now creates the project and the assistant thread. New: packages/cli/src/thread.mjs, packages/cli/tests/thread-cli.test.mjs. Sage's landing gate ran on77b1a6e8aplus the candidate: 25 steps, all rc 0 (15 packages, 10 script suites), 14:44:02Z to 14:48:42Z, network sage-r128_default removed. The commit sits on7de8b7270, which adds one docs/SESSIONS.md line that no test reads. Co-Authored-By: Claude Opus 5.5 <[email protected]>
57 lines
2.8 KiB
JavaScript
57 lines
2.8 KiB
JavaScript
import { configDir, loadBusiness } from '../../business/src/index.mjs';
|
|
import { checkProject, initProject, ProjectError } from '../../project/src/index.mjs';
|
|
import { loadSystem, rolesDir } from './config.mjs';
|
|
import { CliError } from './errors.mjs';
|
|
import { shortId } from './format.mjs';
|
|
import { parseArgs } from './thread.mjs';
|
|
import { refuseInsideAgent } from './transport.mjs';
|
|
|
|
export const PROJECT_USAGE = 'mosaic project init|check <business> <project>';
|
|
// Row 128 (#1622): create and list work on the bus record (project.create, project.list); init
|
|
// and check above work on the repository on disk and never contact the bus.
|
|
export const PROJECT_BUS_USAGE = [
|
|
'mosaic project create <name> [--repo <repo>] [--business <id>]',
|
|
'mosaic project list [--business <id>] [--json]',
|
|
].join('\n ');
|
|
|
|
export async function projectBusCommand(args, io, callFor) {
|
|
const [sub, ...rest] = args;
|
|
const parsed = parseArgs(rest, PROJECT_BUS_USAGE, sub === 'create'
|
|
? { values: ['--repo', '--business'] }
|
|
: { flags: ['--json'], values: ['--business'] });
|
|
if (parsed.positional.length !== (sub === 'create' ? 1 : 0))
|
|
throw new CliError(`project ${sub} takes ${sub === 'create' ? 'one name' : 'no arguments'}\n${PROJECT_BUS_USAGE}`, 4);
|
|
const call = callFor(parsed);
|
|
if (sub === 'create') {
|
|
const [name] = parsed.positional;
|
|
const made = await call('project.create', { name, ...(parsed.values['--repo'] === undefined ? {} : { repo: parsed.values['--repo'] }) });
|
|
return io.stdout.write(`created project ${name} id ${made.id}\n`);
|
|
}
|
|
const projects = await call('project.list');
|
|
if (parsed.flags.has('--json')) return io.stdout.write(`${JSON.stringify(projects, null, 2)}\n`);
|
|
io.stdout.write(projects.length === 0 ? 'no projects\n' : projects.map(p => `${p.name} ${p.repo ?? '-'} ${shortId(p.id)}\n`).join(''));
|
|
}
|
|
|
|
export async function projectCommand(args, io, deps = {}) {
|
|
if (args.length !== 3 || !['init', 'check'].includes(args[0]) || args.some(arg => arg.startsWith('--')))
|
|
throw new CliError(PROJECT_USAGE, 4);
|
|
const [verb, id, project] = args;
|
|
if (verb === 'init') refuseInsideAgent(io.env);
|
|
try {
|
|
const system = deps.system ?? loadSystem({ env: io.env });
|
|
const business = loadBusiness(id, { dir: configDir(io.env), rolesDir: rolesDir(io.env) });
|
|
const context = { business, project, dataRoot: system.dataRoot };
|
|
if (verb === 'init') {
|
|
const result = await initProject(context);
|
|
io.stdout.write(`initialized ${result.repo}\ncommit ${result.commit}\n`);
|
|
} else {
|
|
const result = await checkProject(context);
|
|
if (!result.ok) throw new CliError(result.problems.join('\n'), 2);
|
|
io.stdout.write(`checked ${result.repo}: valid\n`);
|
|
}
|
|
} catch (error) {
|
|
if (error instanceof CliError) throw error;
|
|
throw new CliError(error.message, error instanceof ProjectError ? 2 : 3);
|
|
}
|
|
}
|