openstoat 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/openstoat ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bun
2
+ import '../dist/index.js';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * OpenStoat Agent Manual - SKILL-style documentation for AI agents
3
+ * Use when: orchestrating tasks, planning work, executing tasks, or handing off to humans.
4
+ */
5
+ export declare const AGENT_MANUAL = "\n# OpenStoat CLI - Agent Operational Manual\n\n## When to Use\n\nUse OpenStoat when:\n- Planning and breaking down work into executable tasks\n- Creating tasks for agents or humans to execute\n- Claiming and executing tasks as an agent worker\n- Handing off work to humans (credentials, review, deploy)\n- Self-unblocking when blocked by human input\n- Querying task status, dependencies, or project context\n\n## Core Concepts\n\n| Concept | Description |\n|---------|-------------|\n| **Project** | Template-bound workspace. Every task belongs to one project. Get project ID via `project ls`. |\n| **Task** | Atomic work unit. Status: ready \u2192 in_progress \u2192 done. Owner: agent_worker | human_worker. |\n| **Handoff** | Required on every completion. Min 200 chars. Transfers context to downstream tasks. |\n| **Self-unblock** | When agent is blocked by human: create human task, then run self-unblock with --depends-on. |\n\n## Role-Based Workflows\n\n### Agent Planner\n\n1. **Before creating tasks** (mandatory): List existing tasks to avoid duplicates.\n `openstoat task ls --project <project_id> --status ready,in_progress`\n\n2. **Create tasks**: Use `task create` with all required fields. Set owner=agent_worker for agent tasks, owner=human_worker for human tasks (credentials, review, deploy).\n\n3. **Dependencies**: Use --depends-on when task B waits for task A. Omit when no dependencies.\n\n### Agent Worker\n\n1. **Claim**: `openstoat task claim <task_id> --as agent_worker --logs-append \"...\"`\n2. **Start**: `openstoat task start <task_id> --as agent_worker --logs-append \"...\"`\n3. **Done**: `openstoat task done <task_id> --output \"...\" --handoff-summary \"...\" --logs-append \"...\"`\n - handoff-summary: min 200 chars. Describe what was done and context for downstream.\n\n### Agent Worker (Blocked by Human)\n\n1. Create human task: `openstoat task create --project X --owner human_worker --task-type credentials ...`\n2. Self-unblock: `openstoat task self-unblock <my_task_id> --depends-on <human_task_id> --logs-append \"Blocked: ...\"`\n3. Task moves in_progress \u2192 ready. Resume after human completes the dependency.\n\n### Human Worker\n\nSame flow as Agent Worker but use --as human_worker when claiming/starting/done.\n\n---\n\n## Command Reference\n\n### project init\nInitialize a project with bound template. Required before creating tasks.\n --id (required): Project ID. Use this as --project in task commands.\n --name (required): Display name.\n --template (required): Template name (e.g. checkout-default-v1).\n\n### project ls\nList all projects. Output: id, name, status.\n\n### project show <project_id>\nShow project details (JSON).\n\n### task ls\nList tasks. **Planner must run before create to avoid duplicates.**\n --project (required): Project ID.\n --status: Filter. Comma-separated: ready,in_progress,done.\n --owner: Filter: agent_worker | human_worker.\n --json: Output as JSON.\n\n### task create\nCreate a task. All fields required except --depends-on, --created-by.\n --project (required)\n --title (required)\n --description (required)\n --acceptance-criteria (required, pass multiple): e.g. --acceptance-criteria \"A\" --acceptance-criteria \"B\"\n --depends-on (optional, pass multiple): Task IDs this task depends on.\n --status (required): ready | in_progress | done. New tasks typically ready.\n --owner (required): agent_worker | human_worker\n --task-type (required): implementation | testing | review | credentials | deploy | docs | custom\n --created-by (optional): e.g. agent_planner\n\n### task claim <task_id>\nWorker claims a ready task. Moves ready \u2192 in_progress.\n --as (required): agent_worker | human_worker\n --logs-append (recommended for agents): Append to task logs.\n\n### task start <task_id>\nWorker starts working. Use after claim or to append progress.\n --as (required): agent_worker | human_worker\n --logs-append (optional): Append to task logs.\n\n### task done <task_id>\nWorker completes task. Moves in_progress \u2192 done. Handoff mandatory.\n --output (required): What was delivered.\n --handoff-summary (required, min 200 chars): Context for downstream tasks.\n --logs-append (optional)\n --as (required): agent_worker | human_worker\n\n### task self-unblock <task_id>\nRollback in_progress \u2192 ready when blocked by human. Must add new --depends-on.\n --depends-on (required, pass multiple): New human task ID(s). At least one.\n --logs-append (optional)\n --as: agent_worker only (default)\n\n### task show <task_id>\nShow task details. Use --json for machine-readable output.\n\n### daemon init\nInteractively create `.openstoat.json` (project, agent) in current directory.\n\n### daemon start\nStart worker daemon. Polls for ready agent_worker tasks and invokes external agents.\n --poll-interval (default 5000): Poll interval in ms.\n Config: read from `.openstoat.json` in current directory. Example: `{ \"project\": \"<project_id>\", \"agent\": \"/path/to/agent\" }`\n\n### daemon stop | status | logs\nStop, check status, or view daemon logs.\n\n---\n\n## Rules (Do Not Violate)\n\n1. **No generic status update**: There is no `task update --status`. Use claim, start, done, self-unblock only.\n2. **Planner duplicate check**: Always run `task ls` before `task create` to avoid duplicates.\n3. **Handoff required**: Every `task done` must include --handoff-summary (min 200 chars).\n4. **Self-unblock guard**: in_progress \u2192 ready only via self-unblock, and only with new --depends-on.\n5. **Logs for agents**: Agent workers should use --logs-append on claim, start, done for audit trail.\n6. **Project required**: Every task has --project. Get project IDs from `project ls`.\n\n---\n\n## Examples\n\n# Planner: list then create\nopenstoat task ls --project proj_1 --status ready,in_progress\nopenstoat task create --project proj_1 --title \"Add Paddle mapping\" --description \"...\" \\\n --acceptance-criteria \"Mapping works\" --acceptance-criteria \"Tests pass\" \\\n --status ready --owner agent_worker --task-type implementation\n\n# Worker: full lifecycle\nopenstoat task claim task_001 --as agent_worker --logs-append \"Claimed\"\nopenstoat task start task_001 --as agent_worker --logs-append \"Started\"\nopenstoat task done task_001 --output \"Implemented\" \\\n --handoff-summary \"Implemented Paddle mapping in src/payments/provider-map.ts. No migration. Integration tests pass. Downstream can use PaddleProvider class.\" \\\n --as agent_worker --logs-append \"Done\"\n\n# Self-unblock (agent blocked, needs human)\nopenstoat task create --project proj_1 --title \"Provide API key\" --description \"...\" \\\n --acceptance-criteria \"Key delivered\" --status ready --owner human_worker --task-type credentials\nopenstoat task self-unblock task_X --depends-on task_H --logs-append \"Blocked: need API key\"\n";
6
+ //# sourceMappingURL=agent-manual.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-manual.d.ts","sourceRoot":"","sources":["../src/agent-manual.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,eAAO,MAAM,YAAY,2uNA0JxB,CAAC"}
@@ -0,0 +1,159 @@
1
+ /**
2
+ * OpenStoat Agent Manual - SKILL-style documentation for AI agents
3
+ * Use when: orchestrating tasks, planning work, executing tasks, or handing off to humans.
4
+ */
5
+ export const AGENT_MANUAL = `
6
+ # OpenStoat CLI - Agent Operational Manual
7
+
8
+ ## When to Use
9
+
10
+ Use OpenStoat when:
11
+ - Planning and breaking down work into executable tasks
12
+ - Creating tasks for agents or humans to execute
13
+ - Claiming and executing tasks as an agent worker
14
+ - Handing off work to humans (credentials, review, deploy)
15
+ - Self-unblocking when blocked by human input
16
+ - Querying task status, dependencies, or project context
17
+
18
+ ## Core Concepts
19
+
20
+ | Concept | Description |
21
+ |---------|-------------|
22
+ | **Project** | Template-bound workspace. Every task belongs to one project. Get project ID via \`project ls\`. |
23
+ | **Task** | Atomic work unit. Status: ready → in_progress → done. Owner: agent_worker | human_worker. |
24
+ | **Handoff** | Required on every completion. Min 200 chars. Transfers context to downstream tasks. |
25
+ | **Self-unblock** | When agent is blocked by human: create human task, then run self-unblock with --depends-on. |
26
+
27
+ ## Role-Based Workflows
28
+
29
+ ### Agent Planner
30
+
31
+ 1. **Before creating tasks** (mandatory): List existing tasks to avoid duplicates.
32
+ \`openstoat task ls --project <project_id> --status ready,in_progress\`
33
+
34
+ 2. **Create tasks**: Use \`task create\` with all required fields. Set owner=agent_worker for agent tasks, owner=human_worker for human tasks (credentials, review, deploy).
35
+
36
+ 3. **Dependencies**: Use --depends-on when task B waits for task A. Omit when no dependencies.
37
+
38
+ ### Agent Worker
39
+
40
+ 1. **Claim**: \`openstoat task claim <task_id> --as agent_worker --logs-append "..."\`
41
+ 2. **Start**: \`openstoat task start <task_id> --as agent_worker --logs-append "..."\`
42
+ 3. **Done**: \`openstoat task done <task_id> --output "..." --handoff-summary "..." --logs-append "..."\`
43
+ - handoff-summary: min 200 chars. Describe what was done and context for downstream.
44
+
45
+ ### Agent Worker (Blocked by Human)
46
+
47
+ 1. Create human task: \`openstoat task create --project X --owner human_worker --task-type credentials ...\`
48
+ 2. Self-unblock: \`openstoat task self-unblock <my_task_id> --depends-on <human_task_id> --logs-append "Blocked: ..."\`
49
+ 3. Task moves in_progress → ready. Resume after human completes the dependency.
50
+
51
+ ### Human Worker
52
+
53
+ Same flow as Agent Worker but use --as human_worker when claiming/starting/done.
54
+
55
+ ---
56
+
57
+ ## Command Reference
58
+
59
+ ### project init
60
+ Initialize a project with bound template. Required before creating tasks.
61
+ --id (required): Project ID. Use this as --project in task commands.
62
+ --name (required): Display name.
63
+ --template (required): Template name (e.g. checkout-default-v1).
64
+
65
+ ### project ls
66
+ List all projects. Output: id, name, status.
67
+
68
+ ### project show <project_id>
69
+ Show project details (JSON).
70
+
71
+ ### task ls
72
+ List tasks. **Planner must run before create to avoid duplicates.**
73
+ --project (required): Project ID.
74
+ --status: Filter. Comma-separated: ready,in_progress,done.
75
+ --owner: Filter: agent_worker | human_worker.
76
+ --json: Output as JSON.
77
+
78
+ ### task create
79
+ Create a task. All fields required except --depends-on, --created-by.
80
+ --project (required)
81
+ --title (required)
82
+ --description (required)
83
+ --acceptance-criteria (required, pass multiple): e.g. --acceptance-criteria "A" --acceptance-criteria "B"
84
+ --depends-on (optional, pass multiple): Task IDs this task depends on.
85
+ --status (required): ready | in_progress | done. New tasks typically ready.
86
+ --owner (required): agent_worker | human_worker
87
+ --task-type (required): implementation | testing | review | credentials | deploy | docs | custom
88
+ --created-by (optional): e.g. agent_planner
89
+
90
+ ### task claim <task_id>
91
+ Worker claims a ready task. Moves ready → in_progress.
92
+ --as (required): agent_worker | human_worker
93
+ --logs-append (recommended for agents): Append to task logs.
94
+
95
+ ### task start <task_id>
96
+ Worker starts working. Use after claim or to append progress.
97
+ --as (required): agent_worker | human_worker
98
+ --logs-append (optional): Append to task logs.
99
+
100
+ ### task done <task_id>
101
+ Worker completes task. Moves in_progress → done. Handoff mandatory.
102
+ --output (required): What was delivered.
103
+ --handoff-summary (required, min 200 chars): Context for downstream tasks.
104
+ --logs-append (optional)
105
+ --as (required): agent_worker | human_worker
106
+
107
+ ### task self-unblock <task_id>
108
+ Rollback in_progress → ready when blocked by human. Must add new --depends-on.
109
+ --depends-on (required, pass multiple): New human task ID(s). At least one.
110
+ --logs-append (optional)
111
+ --as: agent_worker only (default)
112
+
113
+ ### task show <task_id>
114
+ Show task details. Use --json for machine-readable output.
115
+
116
+ ### daemon init
117
+ Interactively create \`.openstoat.json\` (project, agent) in current directory.
118
+
119
+ ### daemon start
120
+ Start worker daemon. Polls for ready agent_worker tasks and invokes external agents.
121
+ --poll-interval (default 5000): Poll interval in ms.
122
+ Config: read from \`.openstoat.json\` in current directory. Example: \`{ "project": "<project_id>", "agent": "/path/to/agent" }\`
123
+
124
+ ### daemon stop | status | logs
125
+ Stop, check status, or view daemon logs.
126
+
127
+ ---
128
+
129
+ ## Rules (Do Not Violate)
130
+
131
+ 1. **No generic status update**: There is no \`task update --status\`. Use claim, start, done, self-unblock only.
132
+ 2. **Planner duplicate check**: Always run \`task ls\` before \`task create\` to avoid duplicates.
133
+ 3. **Handoff required**: Every \`task done\` must include --handoff-summary (min 200 chars).
134
+ 4. **Self-unblock guard**: in_progress → ready only via self-unblock, and only with new --depends-on.
135
+ 5. **Logs for agents**: Agent workers should use --logs-append on claim, start, done for audit trail.
136
+ 6. **Project required**: Every task has --project. Get project IDs from \`project ls\`.
137
+
138
+ ---
139
+
140
+ ## Examples
141
+
142
+ # Planner: list then create
143
+ openstoat task ls --project proj_1 --status ready,in_progress
144
+ openstoat task create --project proj_1 --title "Add Paddle mapping" --description "..." \\
145
+ --acceptance-criteria "Mapping works" --acceptance-criteria "Tests pass" \\
146
+ --status ready --owner agent_worker --task-type implementation
147
+
148
+ # Worker: full lifecycle
149
+ openstoat task claim task_001 --as agent_worker --logs-append "Claimed"
150
+ openstoat task start task_001 --as agent_worker --logs-append "Started"
151
+ openstoat task done task_001 --output "Implemented" \\
152
+ --handoff-summary "Implemented Paddle mapping in src/payments/provider-map.ts. No migration. Integration tests pass. Downstream can use PaddleProvider class." \\
153
+ --as agent_worker --logs-append "Done"
154
+
155
+ # Self-unblock (agent blocked, needs human)
156
+ openstoat task create --project proj_1 --title "Provide API key" --description "..." \\
157
+ --acceptance-criteria "Key delivered" --status ready --owner human_worker --task-type credentials
158
+ openstoat task self-unblock task_X --depends-on task_H --logs-append "Blocked: need API key"
159
+ `;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Daemon commands: start, stop, status, logs, init
3
+ * Worker daemon polls for ready agent_worker tasks and invokes external agents.
4
+ */
5
+ import type { Argv } from 'yargs';
6
+ export declare const daemonCommands: {
7
+ command: string;
8
+ describe: string;
9
+ builder: (yargs: Argv) => Argv<{}>;
10
+ handler: () => void;
11
+ };
12
+ //# sourceMappingURL=daemon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/commands/daemon.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAOlC,eAAO,MAAM,cAAc;;;qBAGR,IAAI;;CAyEtB,CAAC"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Daemon commands: start, stop, status, logs, init
3
+ * Worker daemon polls for ready agent_worker tasks and invokes external agents.
4
+ */
5
+ import { startDaemon } from 'openstoat-daemon';
6
+ import { listProjects } from 'openstoat-core';
7
+ import { loadProjectConfig, saveProjectConfig } from 'openstoat-core';
8
+ import { installSkills } from '../lib/installSkills.js';
9
+ import { prompt } from '../lib/prompt.js';
10
+ export const daemonCommands = {
11
+ command: 'daemon <action>',
12
+ describe: 'Worker daemon. Polls for ready agent_worker tasks and invokes external agents.',
13
+ builder: (yargs) => yargs
14
+ .command({
15
+ command: 'init',
16
+ describe: 'Interactively create .openstoat.json (project, agent) in current directory.',
17
+ handler: async () => {
18
+ const existing = loadProjectConfig();
19
+ const projects = listProjects();
20
+ console.log('Initialize OpenStoat daemon config (.openstoat.json)\n');
21
+ let project = existing?.project ?? '';
22
+ if (projects.length > 0) {
23
+ console.log('Existing projects:');
24
+ for (const p of projects) {
25
+ console.log(` ${p.id}\t${p.name}`);
26
+ }
27
+ project = await prompt('Project ID', project);
28
+ }
29
+ else {
30
+ console.log('No projects yet. Run `openstoat project init` first, or enter a project ID to use later.');
31
+ project = await prompt('Project ID', project);
32
+ }
33
+ const agent = await prompt('Agent executable path (for daemon to invoke)', existing?.agent ?? '');
34
+ const config = {};
35
+ if (project)
36
+ config.project = project;
37
+ if (agent)
38
+ config.agent = agent;
39
+ saveProjectConfig(config);
40
+ console.log('\nCreated .openstoat.json');
41
+ console.log(JSON.stringify(config, null, 2));
42
+ },
43
+ })
44
+ .command({
45
+ command: 'start',
46
+ describe: 'Start daemon. Polls for ready agent_worker tasks, invokes configured external agent.',
47
+ builder: (y) => y.option('poll-interval', {
48
+ type: 'number',
49
+ default: 5000,
50
+ describe: 'Poll interval in ms (default 5000)',
51
+ }),
52
+ handler: (argv) => {
53
+ console.log('Daemon starting...');
54
+ installSkills(process.cwd());
55
+ const pollInterval = argv['poll-interval'] || 5000;
56
+ startDaemon(pollInterval);
57
+ },
58
+ })
59
+ .command({
60
+ command: 'stop',
61
+ describe: 'Stop daemon',
62
+ handler: () => {
63
+ console.log('Daemon stop: run daemon in foreground and use Ctrl+C. PID file not implemented in MVP.');
64
+ },
65
+ })
66
+ .command({
67
+ command: 'status',
68
+ describe: 'Check daemon status',
69
+ handler: () => {
70
+ console.log('Daemon status: not running (PID file not implemented in MVP.');
71
+ },
72
+ })
73
+ .command({
74
+ command: 'logs',
75
+ describe: 'View daemon logs',
76
+ handler: () => {
77
+ console.log('Daemon logs: stdout/stderr when running.');
78
+ },
79
+ })
80
+ .demandCommand(1, 'Specify init, start, stop, status, or logs'),
81
+ handler: () => { },
82
+ };
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Install commands: skill
3
+ * Installs OpenStoat skills to .agent/skills and .claude/skills.
4
+ */
5
+ import type { Argv } from 'yargs';
6
+ export declare const installCommands: {
7
+ command: string;
8
+ describe: string;
9
+ builder: (yargs: Argv) => Argv<{}>;
10
+ handler: () => void;
11
+ };
12
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAGlC,eAAO,MAAM,eAAe;;;qBAGT,IAAI;;CAiCtB,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Install commands: skill
3
+ * Installs OpenStoat skills to .agent/skills and .claude/skills.
4
+ */
5
+ import { installSkills } from '../lib/installSkills.js';
6
+ export const installCommands = {
7
+ command: 'install <target>',
8
+ describe: 'Install OpenStoat assets. Use "skill" to install planner and worker skills.',
9
+ builder: (yargs) => yargs
10
+ .command({
11
+ command: 'skill',
12
+ describe: 'Install planner and worker skills. Use --here to install to current directory (no skills/, .agent, or .claude).',
13
+ builder: (y) => y
14
+ .option('cwd', {
15
+ type: 'string',
16
+ default: process.cwd(),
17
+ describe: 'Target directory (default: current working directory)',
18
+ })
19
+ .option('here', {
20
+ type: 'boolean',
21
+ default: false,
22
+ describe: 'Install to current directory (./openstoat-planner, ./openstoat-worker)',
23
+ }),
24
+ handler: (argv) => {
25
+ const targetRoot = argv.cwd || process.cwd();
26
+ const installed = installSkills(targetRoot, { here: argv.here });
27
+ if (installed.length > 0) {
28
+ console.log('Installed skills to:');
29
+ for (const p of installed) {
30
+ console.log(` ${p}`);
31
+ }
32
+ }
33
+ else {
34
+ console.log('No skills installed.');
35
+ }
36
+ },
37
+ })
38
+ .demandCommand(1, 'Specify skill'),
39
+ handler: () => { },
40
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Project commands: init, ls, show
3
+ */
4
+ import type { Argv } from 'yargs';
5
+ export declare const projectCommands: {
6
+ command: string;
7
+ describe: string;
8
+ builder: (yargs: Argv) => Argv<{}>;
9
+ handler: () => void;
10
+ };
11
+ //# sourceMappingURL=project.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/commands/project.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAGlC,eAAO,MAAM,eAAe;;;qBAGT,IAAI;;CA4DtB,CAAC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Project commands: init, ls, show
3
+ */
4
+ import { createProject, getProject, listProjects } from 'openstoat-core';
5
+ export const projectCommands = {
6
+ command: 'project <action>',
7
+ describe: 'Manage projects. Each project is template-bound. Use project ID as --project in task commands.',
8
+ builder: (yargs) => yargs
9
+ .command({
10
+ command: 'init',
11
+ describe: 'Initialize project with bound template. Required before creating tasks.',
12
+ builder: (y) => y
13
+ .option('id', {
14
+ type: 'string',
15
+ demandOption: true,
16
+ describe: 'Project ID. Use this as --project in all task commands.',
17
+ })
18
+ .option('name', {
19
+ type: 'string',
20
+ demandOption: true,
21
+ describe: 'Display name',
22
+ })
23
+ .option('template', {
24
+ type: 'string',
25
+ demandOption: true,
26
+ describe: 'Template name (e.g. checkout-default-v1). Defines default owner per task_type.',
27
+ }),
28
+ handler: (argv) => {
29
+ const project = createProject(argv.id, argv.name, argv.template);
30
+ console.log(`Project initialized: ${project.id}`);
31
+ },
32
+ })
33
+ .command({
34
+ command: 'ls',
35
+ describe: 'List projects. Output: id, name, status. Get --project for task commands.',
36
+ handler: () => {
37
+ const projects = listProjects();
38
+ if (projects.length === 0) {
39
+ console.log('No projects found.');
40
+ return;
41
+ }
42
+ for (const p of projects) {
43
+ console.log(`${p.id}\t${p.name}\t${p.status}`);
44
+ }
45
+ },
46
+ })
47
+ .command({
48
+ command: 'show <project_id>',
49
+ describe: 'Show project details (JSON). Includes template_context.',
50
+ builder: (y) => y.positional('project_id', { type: 'string', demandOption: true }),
51
+ handler: (argv) => {
52
+ const project = getProject(argv.project_id);
53
+ if (!project) {
54
+ console.error(`Project '${argv.project_id}' not found.`);
55
+ process.exit(1);
56
+ }
57
+ console.log(JSON.stringify(project, null, 2));
58
+ },
59
+ })
60
+ .demandCommand(1, 'Specify init, ls, or show'),
61
+ handler: () => { },
62
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Task commands: ls, create, claim, start, done, self-unblock, show
3
+ */
4
+ import type { Argv } from 'yargs';
5
+ export declare const taskCommands: {
6
+ command: string;
7
+ describe: string;
8
+ builder: (yargs: Argv) => Argv<{}>;
9
+ handler: () => void;
10
+ };
11
+ //# sourceMappingURL=task.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../../src/commands/task.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAYlC,eAAO,MAAM,YAAY;;;qBAIN,IAAI;;CAgOtB,CAAC"}
@@ -0,0 +1,212 @@
1
+ /**
2
+ * Task commands: ls, create, claim, start, done, self-unblock, show
3
+ */
4
+ import { createTask, getTask, listTasks, claimTask, startTask, completeTask, selfUnblockTask, } from 'openstoat-core';
5
+ export const taskCommands = {
6
+ command: 'task <action>',
7
+ describe: 'Manage tasks. Planner: ls before create, then create. Worker: claim → start → done. Self-unblock when blocked by human.',
8
+ builder: (yargs) => yargs
9
+ .command({
10
+ command: 'ls',
11
+ describe: 'List tasks. PLANNER: run before create to avoid duplicates. Use --status ready,in_progress for unfinished.',
12
+ builder: (y) => y
13
+ .option('project', {
14
+ type: 'string',
15
+ demandOption: true,
16
+ describe: 'Project ID (from project ls)',
17
+ })
18
+ .option('status', {
19
+ type: 'string',
20
+ describe: 'Filter by status (comma-separated: ready,in_progress,done)',
21
+ })
22
+ .option('owner', {
23
+ type: 'string',
24
+ describe: 'Filter by owner (agent_worker or human_worker)',
25
+ })
26
+ .option('json', {
27
+ type: 'boolean',
28
+ default: false,
29
+ describe: 'Output as JSON',
30
+ }),
31
+ handler: (argv) => {
32
+ const statusStr = argv.status;
33
+ const statuses = statusStr
34
+ ? statusStr.split(',').map((s) => s.trim())
35
+ : undefined;
36
+ const tasks = listTasks(argv.project, {
37
+ status: statuses,
38
+ owner: argv.owner,
39
+ });
40
+ if (argv.json) {
41
+ console.log(JSON.stringify(tasks, null, 2));
42
+ }
43
+ else {
44
+ if (tasks.length === 0) {
45
+ console.log('No tasks found.');
46
+ return;
47
+ }
48
+ for (const t of tasks) {
49
+ console.log(`${t.id}\t${t.status}\t${t.owner}\t${t.title}`);
50
+ }
51
+ }
52
+ },
53
+ })
54
+ .command({
55
+ command: 'create',
56
+ describe: 'Create a task. All required: --project, --title, --description, --acceptance-criteria (×N), --status, --owner, --task-type. Use --depends-on for dependencies.',
57
+ builder: (y) => y
58
+ .option('project', { type: 'string', demandOption: true })
59
+ .option('title', { type: 'string', demandOption: true })
60
+ .option('description', { type: 'string', demandOption: true })
61
+ .option('acceptance-criteria', {
62
+ type: 'array',
63
+ demandOption: true,
64
+ describe: 'Pass multiple times: --acceptance-criteria "A" --acceptance-criteria "B"',
65
+ })
66
+ .option('depends-on', {
67
+ type: 'array',
68
+ default: [],
69
+ describe: 'Task IDs this task depends on; omit when no dependencies',
70
+ })
71
+ .option('status', {
72
+ type: 'string',
73
+ demandOption: true,
74
+ choices: ['ready', 'in_progress', 'done'],
75
+ })
76
+ .option('owner', {
77
+ type: 'string',
78
+ demandOption: true,
79
+ choices: ['agent_worker', 'human_worker'],
80
+ })
81
+ .option('task-type', {
82
+ type: 'string',
83
+ demandOption: true,
84
+ choices: ['implementation', 'testing', 'review', 'credentials', 'deploy', 'docs', 'custom'],
85
+ describe: 'implementation|testing|review|credentials|deploy|docs|custom. credentials/review/deploy often human_worker.',
86
+ })
87
+ .option('created-by', { type: 'string', describe: 'Creator role (e.g. agent_planner)' }),
88
+ handler: (argv) => {
89
+ const task = createTask({
90
+ project: argv.project,
91
+ title: argv.title,
92
+ description: argv.description,
93
+ acceptance_criteria: argv['acceptance-criteria'] || [],
94
+ depends_on: argv['depends-on'] || [],
95
+ status: argv.status,
96
+ owner: argv.owner,
97
+ task_type: argv['task-type'],
98
+ created_by: argv['created-by'],
99
+ });
100
+ console.log(task.id);
101
+ },
102
+ })
103
+ .command({
104
+ command: 'claim <task_id>',
105
+ describe: 'WORKER: claim ready task. Moves ready→in_progress. Use --logs-append for audit.',
106
+ builder: (y) => y
107
+ .positional('task_id', { type: 'string', demandOption: true })
108
+ .option('as', {
109
+ type: 'string',
110
+ demandOption: true,
111
+ choices: ['agent_worker', 'human_worker'],
112
+ })
113
+ .option('logs-append', { type: 'string', describe: 'Append to task logs (required for agents)' }),
114
+ handler: (argv) => {
115
+ const task = claimTask(argv.task_id, argv.as, argv['logs-append']);
116
+ console.log(`Claimed ${task.id}`);
117
+ },
118
+ })
119
+ .command({
120
+ command: 'start <task_id>',
121
+ describe: 'WORKER: start/continue task. Use --logs-append to record progress.',
122
+ builder: (y) => y
123
+ .positional('task_id', { type: 'string', demandOption: true })
124
+ .option('as', {
125
+ type: 'string',
126
+ demandOption: true,
127
+ choices: ['agent_worker', 'human_worker'],
128
+ })
129
+ .option('logs-append', { type: 'string' }),
130
+ handler: (argv) => {
131
+ const task = startTask(argv.task_id, argv.as, argv['logs-append']);
132
+ console.log(`Started ${task.id}`);
133
+ },
134
+ })
135
+ .command({
136
+ command: 'done <task_id>',
137
+ describe: 'WORKER: complete task. Handoff mandatory (min 200 chars). Transfers context to downstream.',
138
+ builder: (y) => y
139
+ .positional('task_id', { type: 'string', demandOption: true })
140
+ .option('output', { type: 'string', demandOption: true, describe: 'What was delivered' })
141
+ .option('handoff-summary', {
142
+ type: 'string',
143
+ demandOption: true,
144
+ describe: 'Context for downstream tasks. Min 200 chars. No credentials in body.',
145
+ })
146
+ .option('logs-append', { type: 'string' })
147
+ .option('as', {
148
+ type: 'string',
149
+ demandOption: true,
150
+ choices: ['agent_worker', 'human_worker'],
151
+ }),
152
+ handler: (argv) => {
153
+ const task = completeTask(argv.task_id, {
154
+ output: argv.output,
155
+ handoff_summary: argv['handoff-summary'],
156
+ logs_append: argv['logs-append'],
157
+ }, argv.as);
158
+ console.log(`Done ${task.id}`);
159
+ },
160
+ })
161
+ .command({
162
+ command: 'self-unblock <task_id>',
163
+ describe: 'WORKER: rollback in_progress→ready when blocked. Must add --depends-on (human task). Create human task first.',
164
+ builder: (y) => y
165
+ .positional('task_id', { type: 'string', demandOption: true })
166
+ .option('depends-on', {
167
+ type: 'array',
168
+ demandOption: true,
169
+ describe: 'New human task ID(s) - at least one required',
170
+ })
171
+ .option('logs-append', { type: 'string' })
172
+ .option('as', {
173
+ type: 'string',
174
+ default: 'agent_worker',
175
+ choices: ['agent_worker'],
176
+ }),
177
+ handler: (argv) => {
178
+ const deps = argv['depends-on'];
179
+ const task = selfUnblockTask(argv.task_id, {
180
+ depends_on: deps,
181
+ logs_append: argv['logs-append'],
182
+ }, 'agent_worker');
183
+ console.log(`Self-unblocked ${task.id}`);
184
+ },
185
+ })
186
+ .command({
187
+ command: 'show <task_id>',
188
+ describe: 'Show task details. Use --json for machine-readable. Read handoff from dependent tasks.',
189
+ builder: (y) => y
190
+ .positional('task_id', { type: 'string', demandOption: true })
191
+ .option('json', { type: 'boolean', default: false }),
192
+ handler: (argv) => {
193
+ const task = getTask(argv.task_id);
194
+ if (!task) {
195
+ console.error(`Task '${argv.task_id}' not found.`);
196
+ process.exit(1);
197
+ }
198
+ console.log(argv.json ? JSON.stringify(task, null, 2) : formatTask(task));
199
+ },
200
+ })
201
+ .demandCommand(1, 'Specify ls, create, claim, start, done, self-unblock, or show'),
202
+ handler: () => { },
203
+ };
204
+ function formatTask(t) {
205
+ let out = `ID: ${t.id}\nTitle: ${t.title}\nStatus: ${t.status}\nOwner: ${t.owner}\n`;
206
+ if (t.logs.length > 0) {
207
+ out += 'Logs:\n';
208
+ for (const log of t.logs)
209
+ out += ` - ${log}\n`;
210
+ }
211
+ return out;
212
+ }
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * OpenStoat CLI - Agent super-manual for task orchestration
4
+ * CLI is the operational guide for both agents and humans.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG"}