@polderlabs/bizar 10.24.0 → 10.25.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/AGENTS.md +14 -12
- package/README.md +3 -3
- package/cli/bin.mjs +27 -21
- package/cli/commands/claim.mjs +37 -267
- package/cli/commands/control.mjs +3 -1
- package/cli/commands/goal-bootstrap.mjs +20 -122
- package/cli/commands/guard.mjs +57 -202
- package/cli/commands/install.mjs +14 -11
- package/cli/commands/openkan.mjs +72 -0
- package/cli/commands/planning.mjs +26 -0
- package/cli/commands/spec-list.mjs +20 -3
- package/cli/commands/task.mjs +27 -234
- package/cli/commands/workflow-gc.mjs +10 -16
- package/cli/control-store.mjs +7 -31
- package/cli/openkan-store.mjs +60 -0
- package/cli/openkan.mjs +320 -0
- package/cli/provision.mjs +34 -1
- package/config/claude/CLAUDE.md +14 -12
- package/config/claude/agents/_shared/AGENT_BASELINE.md +1 -1
- package/config/claude/commands/bizar.md +2 -2
- package/config/claude/commands/guard.md +1 -1
- package/config/claude/commands/plow-through.md +1 -1
- package/config/claude/commands/sprint.md +4 -5
- package/config/claude/commands/team.md +1 -1
- package/config/claude/hooks/goal-bootstrap.mjs +29 -106
- package/config/claude/hooks/path-ownership-guard.mjs +14 -25
- package/config/claude/hooks/precompact-priorities.sh +2 -2
- package/config/claude/hooks/sessionend-recall.mjs +13 -17
- package/config/claude/hooks/sessionstart-prime.mjs +36 -84
- package/config/claude/hooks/thinking-route.mjs +1 -1
- package/config/claude/hooks/verify-deliverables.mjs +5 -11
- package/config/skills/autopilot/SKILL.md +1 -1
- package/config/skills/bizar/SKILL.md +4 -4
- package/config/skills/goal-bootstrap/SKILL.md +10 -78
- package/config/skills/guard/SKILL.md +9 -56
- package/config/skills/harness-engineering/SKILL.md +6 -6
- package/config/skills/openkan/SKILL.md +34 -0
- package/package.json +1 -1
- package/packages/sdk/dist/agent/goal-bootstrap.d.ts +59 -9
- package/packages/sdk/dist/agent/goal-bootstrap.js +183 -34
- package/cli/feature-list-bridge.mjs +0 -400
- package/cli/progress-parser.mjs +0 -251
- package/cli/task-ledger.mjs +0 -795
package/AGENTS.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# AGENTS.md — Bizar Harness
|
|
2
2
|
|
|
3
|
-
Bizar Harness is a Claude Code-native, guarded-autonomy harness. It ships project and user-level agents, skills, slash commands, hooks, an MCP server, CLI utilities, and verification scripts.
|
|
3
|
+
Bizar Harness is a Claude Code-native, guarded-autonomy harness. It ships project and user-level agents, skills, slash commands, hooks, an MCP server, CLI utilities, and verification scripts. OpenKan is bundled as Bizar’s default durable planning, progression, task, and PRD-goal system; Bizar integrates with it only through the `.ok/` workspace and its supported CLI boundary.
|
|
4
4
|
|
|
5
|
-
If you are an agent: read this file,
|
|
5
|
+
If you are an agent: read this file, inspect `.ok/` with `bizar task list` and `bizar goals list`, then run `make check` before changing code.
|
|
6
6
|
|
|
7
7
|
## Commands
|
|
8
8
|
|
|
@@ -15,15 +15,17 @@ make check-arch # architectural and removed-surface checks
|
|
|
15
15
|
make verify-removed-surfaces # prove deleted subsystems are absent
|
|
16
16
|
make verify-repo-structure # prove tracked/package paths are clean
|
|
17
17
|
make clean-check # debug-artifact/static hygiene gate
|
|
18
|
-
|
|
18
|
+
bizar task list # OpenKan task progression
|
|
19
|
+
bizar plan list # OpenKan plans
|
|
20
|
+
bizar goals list # OpenKan PRD goals
|
|
19
21
|
make session-start # lifecycle compatibility target
|
|
20
22
|
make session-end # lifecycle compatibility target
|
|
21
23
|
```
|
|
22
24
|
|
|
23
25
|
## Hard constraints
|
|
24
26
|
|
|
25
|
-
- **MUST**
|
|
26
|
-
- **MUST**
|
|
27
|
+
- **MUST** keep the scoped OpenKan task current in `.ok/`: claim before implementation, update status/evidence at each durable handoff, and complete only with verification evidence.
|
|
28
|
+
- **MUST** use OpenKan PRDs and plans for durable goals and progression; `PROGRESS.md` and `feature_list.json` are legacy historical records, not live control state.
|
|
27
29
|
- **MUST** keep one logical operation per commit and keep its docs in the same commit.
|
|
28
30
|
- **MUST** run targeted tests, then `make check`; run `make e2e` for cross-component changes.
|
|
29
31
|
- **MUST** verify evidence before claiming completion.
|
|
@@ -52,7 +54,7 @@ Agents execute clear, local, reversible work autonomously — they inspect,
|
|
|
52
54
|
edit, test, and iterate without pausing for routine decisions. Routine
|
|
53
55
|
decisions (file layout, naming, scope of a single commit, choosing between
|
|
54
56
|
two equivalent stdlib calls, picking a verification command from the Makefile,
|
|
55
|
-
or
|
|
57
|
+
or completing an OpenKan task after `make check` is green) do NOT require
|
|
56
58
|
human approval and MUST NOT trigger a permission handoff. PreToolUse hooks
|
|
57
59
|
still deny prohibited actions and escalate externally visible or irreversible
|
|
58
60
|
actions with `permissionDecision: "ask"`; that escalation list is the
|
|
@@ -176,16 +178,16 @@ isolation.
|
|
|
176
178
|
- `scripts/` + `.harness/` + `templates/` — verification, feature/eval state, audit output, and reusable contracts.
|
|
177
179
|
|
|
178
180
|
The harness has no embedded browser/server UI layer or local web editor.
|
|
179
|
-
`bizar control` is a machine-readable subprocess boundary
|
|
180
|
-
|
|
181
|
+
`bizar control` is a machine-readable subprocess boundary over the default OpenKan
|
|
182
|
+
workspace; OpenKan owns durable task/plan/PRD state, HTTP, WebSocket, and presentation concerns. Session
|
|
181
183
|
handoff, control inbox, and learning logs are bounded operational records for
|
|
182
184
|
autonomy; they are not a general note vault, semantic search service, or
|
|
183
185
|
knowledge-base API.
|
|
184
186
|
|
|
185
187
|
## State and evidence
|
|
186
188
|
|
|
187
|
-
-
|
|
188
|
-
- `feature_list.json` —
|
|
189
|
+
- `.ok/` — authoritative OpenKan tasks, plans, PRDs, progression, evidence, and scoped ownership.
|
|
190
|
+
- `PROGRESS.md` and `feature_list.json` — legacy historical records; do not use them for new work.
|
|
189
191
|
- `DECISIONS.md` and `docs/decisions/` — current architecture decisions.
|
|
190
192
|
- `.harness/evals/` — feature evaluation records.
|
|
191
193
|
- `~/.config/bizar/telemetry/` — local correlation and rejected-action feedback.
|
|
@@ -194,7 +196,7 @@ knowledge-base API.
|
|
|
194
196
|
## Definition of done
|
|
195
197
|
|
|
196
198
|
1. Behavior is implemented with a regression test.
|
|
197
|
-
2. Documentation and
|
|
199
|
+
2. Documentation and OpenKan task/plan/PRD state describe the actual code.
|
|
198
200
|
3. `make verify-removed-surfaces`, `make verify-repo-structure`, `make check-arch`, `make test`, `make e2e`, `make clean-check`, and `make check` pass as applicable.
|
|
199
|
-
4.
|
|
201
|
+
4. The OpenKan task records fresh verification evidence and no required work remains.
|
|
200
202
|
5. `/simplify` reviews the staged diff before the approval-gated commit.
|
package/README.md
CHANGED
|
@@ -52,8 +52,8 @@ bizar install
|
|
|
52
52
|
bizar models
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
Restart Claude Code after installation. The installer adds Bizar's agents,
|
|
56
|
-
|
|
55
|
+
Restart Claude Code after installation. The installer adds Bizar's agents, skills, commands, hooks, settings, and the
|
|
56
|
+
default OpenKan planning runtime to your user-level Claude configuration.
|
|
57
57
|
It preserves your configured gateway endpoint and credential values during a
|
|
58
58
|
clean reinstall.
|
|
59
59
|
|
|
@@ -242,7 +242,7 @@ make check
|
|
|
242
242
|
- [Documentation index](docs/INDEX.md)
|
|
243
243
|
- [Architecture](docs/architecture.md)
|
|
244
244
|
- [Model routing decisions](docs/decisions/)
|
|
245
|
-
- [
|
|
245
|
+
- [Durable project progress, plans, and goals](.ok/)
|
|
246
246
|
- [MIT license](LICENSE)
|
|
247
247
|
|
|
248
248
|
## License
|
package/cli/bin.mjs
CHANGED
|
@@ -126,9 +126,12 @@ function showHelp() {
|
|
|
126
126
|
run Run Claude Code once (optionally --bg)
|
|
127
127
|
rca Analyze a GitHub issue (Claude Code CLI sample)
|
|
128
128
|
cost <subcommand> Atomic cost gate (SQLite-backed room budget tracker)
|
|
129
|
-
|
|
130
|
-
task <subcommand>
|
|
131
|
-
|
|
129
|
+
openkan <subcommand> Install, initialise, and operate the default OpenKan workspace
|
|
130
|
+
task <subcommand> OpenKan-backed durable task lifecycle
|
|
131
|
+
plan <subcommand> OpenKan plans and phases
|
|
132
|
+
goals <subcommand> OpenKan PRDs, goals, and milestones
|
|
133
|
+
claim <subcommand> OpenKan task lease shortcut
|
|
134
|
+
control <subcommand> Machine-readable agents/tasks/plans/goals/sessions/messages API
|
|
132
135
|
workflow <subcommand> Session-bound autopilot workflow state
|
|
133
136
|
hook <name> Run a portable Claude Code hook
|
|
134
137
|
worktree-merge <branch> Merge a feature branch with archive tag (no work lost)
|
|
@@ -387,8 +390,6 @@ async function main() {
|
|
|
387
390
|
}
|
|
388
391
|
|
|
389
392
|
case 'claim': {
|
|
390
|
-
// F-035 MetaHarness — GitHub-style claim protocol over feature_list.json.
|
|
391
|
-
// Subcommands: <featureId> | release | handoff | steal | status | list | transition
|
|
392
393
|
const mod = await importCommand('claim');
|
|
393
394
|
if (!mod) {
|
|
394
395
|
console.error(chalk.red(` ✗ Could not load claim command module`));
|
|
@@ -420,6 +421,21 @@ async function main() {
|
|
|
420
421
|
break;
|
|
421
422
|
}
|
|
422
423
|
|
|
424
|
+
case 'openkan': {
|
|
425
|
+
const mod = await importCommand('openkan');
|
|
426
|
+
if (!mod) { process.exit(EXIT_ERROR); return; }
|
|
427
|
+
await mod.run(cmd, cmdArgs, isHelpRequest);
|
|
428
|
+
break;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
case 'plan':
|
|
432
|
+
case 'goals': {
|
|
433
|
+
const mod = await importCommand('planning');
|
|
434
|
+
if (!mod) { process.exit(EXIT_ERROR); return; }
|
|
435
|
+
await mod.run(cmd, cmdArgs, isHelpRequest);
|
|
436
|
+
break;
|
|
437
|
+
}
|
|
438
|
+
|
|
423
439
|
case 'control': {
|
|
424
440
|
const mod = await importCommand('control');
|
|
425
441
|
if (!mod) {
|
|
@@ -532,8 +548,8 @@ async function main() {
|
|
|
532
548
|
|
|
533
549
|
case 'guard': {
|
|
534
550
|
// F-206 — `/guard` progress-guarding loop. The CLI is read-only
|
|
535
|
-
// with respect to the repo (plan +
|
|
536
|
-
//
|
|
551
|
+
// with respect to the repo (plan + OpenKan .ok state + checks.jsonl).
|
|
552
|
+
// See cli/commands/guard.mjs for the verdict
|
|
537
553
|
// semantics and side-effect rules.
|
|
538
554
|
const mod = await importCommand('guard');
|
|
539
555
|
if (!mod) {
|
|
@@ -548,20 +564,10 @@ async function main() {
|
|
|
548
564
|
}
|
|
549
565
|
|
|
550
566
|
case 'goal-bootstrap': {
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
// charter) under docs/specs/. See cli/commands/goal-bootstrap.mjs.
|
|
556
|
-
const mod = await importCommand('goal-bootstrap');
|
|
557
|
-
if (!mod) {
|
|
558
|
-
console.error(chalk.red(` ✗ Could not load goal-bootstrap command module`));
|
|
559
|
-
process.exit(EXIT_ERROR);
|
|
560
|
-
return;
|
|
561
|
-
}
|
|
562
|
-
dbg('loaded command module:', 'goal-bootstrap');
|
|
563
|
-
const code = await mod.run(cmdArgs);
|
|
564
|
-
if (typeof code === 'number') process.exit(code);
|
|
567
|
+
console.error(chalk.yellow(' ! goal-bootstrap is retired; OpenKan PRDs are the default goal system.'));
|
|
568
|
+
const mod = await importCommand('planning');
|
|
569
|
+
if (!mod) { process.exit(EXIT_ERROR); return; }
|
|
570
|
+
await mod.run('goals', cmdArgs, isHelpRequest);
|
|
565
571
|
break;
|
|
566
572
|
}
|
|
567
573
|
|
package/cli/commands/claim.mjs
CHANGED
|
@@ -1,282 +1,52 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* F-035 (MetaHarness) — `bizar claim` subcommand surface.
|
|
5
|
-
*
|
|
6
|
-
* Wraps cli/feature-list-bridge.mjs (over feature_list.json).
|
|
7
|
-
*
|
|
8
|
-
* Subcommands:
|
|
9
|
-
* bizar claim <featureId> # claim with --who (or $USER)
|
|
10
|
-
* --who <id> (default: $USER)
|
|
11
|
-
* --type <human|agent> (default: human)
|
|
12
|
-
* --reason <text> Free-form claim reason
|
|
13
|
-
* bizar claim release <featureId> # release
|
|
14
|
-
* --who <id> Optional claimant check
|
|
15
|
-
* --reason <text>
|
|
16
|
-
* bizar claim handoff <featureId> --to <id> # handoff
|
|
17
|
-
* --from <id>
|
|
18
|
-
* --reason <text>
|
|
19
|
-
* bizar claim steal <featureId> --by <id> # steal
|
|
20
|
-
* --type <human|agent>
|
|
21
|
-
* --reason <steal-reason> Must be one of STEAL_REASONS
|
|
22
|
-
* bizar claim status <featureId> # Show current claim + history
|
|
23
|
-
* bizar claim list # list all features with status
|
|
24
|
-
* --status <s> One of CLAIM_STATUSES (repeatable)
|
|
25
|
-
* --by-claimant <id> Filter by claimant id
|
|
26
|
-
* --human-only / --agent-only
|
|
27
|
-
* bizar claim transition <featureId> <newStatus> # active|paused|blocked|completed
|
|
28
|
-
* --who <id>
|
|
29
|
-
* --reason <text>
|
|
30
|
-
*
|
|
31
|
-
* --json flag for machine output.
|
|
32
|
-
*/
|
|
1
|
+
/** OpenKan task-claim shortcut replacing the feature_list.json claim bridge. */
|
|
2
|
+
import { OpenKanError, runOpenKanOk } from '../openkan.mjs';
|
|
33
3
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
function parseFlags(args) {
|
|
39
|
-
const flags = { _: [], statuses: [] };
|
|
40
|
-
for (let i = 0; i < args.length; i++) {
|
|
41
|
-
const a = args[i];
|
|
42
|
-
if (a === '--json') flags.json = true;
|
|
43
|
-
else if (a === '--who' && i + 1 < args.length) { flags.who = args[++i]; }
|
|
44
|
-
else if (a.startsWith('--who=')) flags.who = a.slice('--who='.length);
|
|
45
|
-
else if (a === '--type' && i + 1 < args.length) { flags.type = args[++i]; }
|
|
46
|
-
else if (a.startsWith('--type=')) flags.type = a.slice('--type='.length);
|
|
47
|
-
else if (a === '--reason' && i + 1 < args.length) { flags.reason = args[++i]; }
|
|
48
|
-
else if (a.startsWith('--reason=')) flags.reason = a.slice('--reason='.length);
|
|
49
|
-
else if (a === '--to' && i + 1 < args.length) { flags.to = args[++i]; }
|
|
50
|
-
else if (a.startsWith('--to=')) flags.to = a.slice('--to='.length);
|
|
51
|
-
else if (a === '--from' && i + 1 < args.length) { flags.from = args[++i]; }
|
|
52
|
-
else if (a.startsWith('--from=')) flags.from = a.slice('--from='.length);
|
|
53
|
-
else if (a === '--by' && i + 1 < args.length) { flags.by = args[++i]; }
|
|
54
|
-
else if (a.startsWith('--by=')) flags.by = a.slice('--by='.length);
|
|
55
|
-
else if (a === '--status' && i + 1 < args.length) { flags.statuses.push(args[++i]); }
|
|
56
|
-
else if (a.startsWith('--status=')) flags.statuses.push(a.slice('--status='.length));
|
|
57
|
-
else if (a === '--by-claimant' && i + 1 < args.length) { flags.byClaimant = args[++i]; }
|
|
58
|
-
else if (a.startsWith('--by-claimant=')) flags.byClaimant = a.slice('--by-claimant='.length);
|
|
59
|
-
else if (a === '--human-only') flags.humanOnly = true;
|
|
60
|
-
else if (a === '--agent-only') flags.agentOnly = true;
|
|
61
|
-
else if (a === '--file' && i + 1 < args.length) { flags.file = args[++i]; }
|
|
62
|
-
else if (a.startsWith('--file=')) flags.file = a.slice('--file='.length);
|
|
63
|
-
else if (a === '--help' || a === '-h') flags.help = true;
|
|
64
|
-
else flags._.push(a);
|
|
65
|
-
}
|
|
66
|
-
return flags;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function makeClaimant(flags, fallbackId) {
|
|
70
|
-
const id = flags.who || flags.by || fallbackId;
|
|
71
|
-
const type = flags.type || 'human';
|
|
72
|
-
if (!id) return null;
|
|
73
|
-
return { type, id, name: id };
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function bridge(flags) {
|
|
77
|
-
return new FeatureListBridge({
|
|
78
|
-
filePath: flags.file || defaultFeatureListPath(),
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function showHelp() {
|
|
83
|
-
console.log(`
|
|
84
|
-
bizar claim — GitHub-ish claim protocol over feature_list.json
|
|
4
|
+
function help() {
|
|
5
|
+
process.stdout.write(`
|
|
6
|
+
bizar claim — claim an OpenKan task lease
|
|
85
7
|
|
|
86
8
|
Usage:
|
|
87
|
-
bizar claim <
|
|
88
|
-
bizar claim release <
|
|
89
|
-
bizar claim
|
|
90
|
-
bizar claim
|
|
91
|
-
bizar claim status <featureId>
|
|
92
|
-
bizar claim list [--status <s>] [--by-claimant <id>] [--human-only|--agent-only]
|
|
93
|
-
bizar claim transition <featureId> <active|paused|blocked|completed> [--who <id>]
|
|
9
|
+
bizar claim <task-id> [--who <agent>] [--lease-ms <ms>]
|
|
10
|
+
bizar claim release <task-id> [--who <agent>]
|
|
11
|
+
bizar claim heartbeat <task-id> [--who <agent>] [--lease-ms <ms>]
|
|
12
|
+
bizar claim list [--status <status>] [--json]
|
|
94
13
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
Status states (must match exactly):
|
|
99
|
-
${CLAIM_STATUSES.join(' | ')}
|
|
100
|
-
|
|
101
|
-
Flags:
|
|
102
|
-
--json Machine-readable JSON output
|
|
103
|
-
--file <path> Override feature_list.json path
|
|
104
|
-
--who <id> / --by <id> Claimant identifier (default: $USER)
|
|
105
|
-
--type human|agent Claimant type (default: human)
|
|
106
|
-
--reason <text> Free-form reason (mandatory for steal)
|
|
107
|
-
--to / --from <id> Recipient / sender for handoff
|
|
108
|
-
--human-only / --agent-only Restrict list to human or agent claims
|
|
109
|
-
--status <s> Filter list (repeat for multiple)
|
|
110
|
-
--by-claimant <id> Filter list by claimant id
|
|
111
|
-
--help, -h Show this help
|
|
112
|
-
|
|
113
|
-
Examples:
|
|
114
|
-
bizar claim F-035 --who mike --reason "porting MetaHarness from ruflo"
|
|
115
|
-
bizar claim steal F-014 --by steve --reason stale
|
|
116
|
-
bizar claim handoff F-035 --to karen --from mike
|
|
117
|
-
bizar claim list --status claimed --agent-only
|
|
14
|
+
Claims are OpenKan .ok locks, not feature_list.json annotations. Use
|
|
15
|
+
\`bizar task update\` for status transitions and \`bizar goals\` for PRDs.
|
|
118
16
|
`);
|
|
119
17
|
}
|
|
120
18
|
|
|
121
|
-
function
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
19
|
+
function owner(args) {
|
|
20
|
+
const i = args.findIndex((arg) => arg === '--who' || arg === '--owner');
|
|
21
|
+
const equals = args.find((arg) => arg.startsWith('--who=') || arg.startsWith('--owner='));
|
|
22
|
+
return equals ? equals.slice(equals.indexOf('=') + 1) : i >= 0 ? args[i + 1] : process.env.BIZAR_AGENT_ID || process.env.USER || 'agent';
|
|
23
|
+
}
|
|
24
|
+
function withoutWho(args) {
|
|
25
|
+
return args.filter((arg, index) => !['--who', '--owner'].includes(arg) && args[index - 1] !== '--who' && args[index - 1] !== '--owner' && !arg.startsWith('--who=') && !arg.startsWith('--owner='));
|
|
129
26
|
}
|
|
130
27
|
|
|
131
28
|
export async function run(name, args, isHelpRequest) {
|
|
132
29
|
if (name !== 'claim') return false;
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
return true;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const [sub, ...rest] = flags._;
|
|
140
|
-
const fallback = process.env.USER || 'unknown';
|
|
141
|
-
const who = flags.who || fallback;
|
|
142
|
-
|
|
30
|
+
if (isHelpRequest || args.length === 0 || ['--help', '-h', 'help'].includes(args[0])) { help(); return true; }
|
|
31
|
+
const [subcommand, taskId] = args;
|
|
32
|
+
const agent = owner(args);
|
|
143
33
|
try {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
if (sub === 'list' || sub === 'ls') {
|
|
152
|
-
const filters = {};
|
|
153
|
-
if (flags.statuses.length) filters.status = flags.statuses;
|
|
154
|
-
if (flags.byClaimant) filters.claimantId = flags.byClaimant;
|
|
155
|
-
if (flags.humanOnly) filters.claimedByHuman = true;
|
|
156
|
-
if (flags.agentOnly) filters.claimedByAgent = true;
|
|
157
|
-
const rows = br.list(filters);
|
|
158
|
-
out({ count: rows.length, features: rows }, flags, (r) => {
|
|
159
|
-
console.log(chalk.bold(` Claims (${r.count}):`));
|
|
160
|
-
for (const f of r.features) {
|
|
161
|
-
const who = f.claimant ? `${f.claimant.name || f.claimant.id} (${f.claimant.type})` : '—';
|
|
162
|
-
console.log(` ${chalk.cyan(f.id)} [${f.claimStatus || 'unclaimed'}] by ${who}`);
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
return true;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (sub === 'status' || sub === 'show' || sub === 'get') {
|
|
169
|
-
const featureId = rest[0];
|
|
170
|
-
if (!featureId) {
|
|
171
|
-
console.error(chalk.red(' ✗ Usage: bizar claim status <featureId>'));
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
const feature = br.get(featureId);
|
|
175
|
-
out(feature, flags, (f) => {
|
|
176
|
-
console.log(chalk.bold(` ${chalk.cyan(f.id)} — ${f.behavior || ''}`));
|
|
177
|
-
const who = f.claimant ? `${f.claimant.name || f.claimant.id} (${f.claimant.type})` : 'unclaimed';
|
|
178
|
-
console.log(` state = ${f.state}`);
|
|
179
|
-
console.log(` claim = ${f.claimStatus || 'unclaimed'} (by ${who})`);
|
|
180
|
-
console.log(` claimedAt = ${f.claimedAt || '—'}`);
|
|
181
|
-
console.log(` claimReason = ${f.claimReason || '—'}`);
|
|
182
|
-
const hist = Array.isArray(f.claimHistory) ? f.claimHistory : [];
|
|
183
|
-
console.log(` history = ${hist.length} event(s)`);
|
|
184
|
-
for (const e of hist.slice(-8)) {
|
|
185
|
-
console.log(` ${e.ts} ${chalk.dim(e.event)}${e.reason ? ' — ' + e.reason : ''}`);
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
return true;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (sub === 'release') {
|
|
192
|
-
const featureId = rest[0];
|
|
193
|
-
if (!featureId) {
|
|
194
|
-
console.error(chalk.red(' ✗ Usage: bizar claim release <featureId> [--who <id>] [--reason <text>]'));
|
|
195
|
-
return false;
|
|
196
|
-
}
|
|
197
|
-
const claimant = makeClaimant({ who, type: flags.type }, fallback);
|
|
198
|
-
const result = br.release(featureId, claimant, flags.reason || '');
|
|
199
|
-
out(result, flags, (r) =>
|
|
200
|
-
console.log(chalk.green(` ✓ Released ${featureId}`) + (r.previousClaimant ? chalk.dim(` (was held by ${r.previousClaimant.name || r.previousClaimant.id})`) : '')),
|
|
201
|
-
);
|
|
202
|
-
return true;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (sub === 'handoff') {
|
|
206
|
-
const featureId = rest[0];
|
|
207
|
-
if (!featureId || !flags.to) {
|
|
208
|
-
console.error(chalk.red(' ✗ Usage: bizar claim handoff <featureId> --to <id> [--from <id>] [--reason <text>]'));
|
|
209
|
-
return false;
|
|
210
|
-
}
|
|
211
|
-
const fromClaimant = flags.from ? { type: flags.type || 'human', id: flags.from, name: flags.from } : null;
|
|
212
|
-
const toClaimant = { type: flags.type || 'human', id: flags.to, name: flags.to };
|
|
213
|
-
const result = br.handoff(featureId, fromClaimant, toClaimant, flags.reason || '');
|
|
214
|
-
out(result, flags, (r) =>
|
|
215
|
-
console.log(chalk.green(` ✓ Handed off ${featureId} → ${flags.to}`)),
|
|
216
|
-
);
|
|
217
|
-
return true;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (sub === 'steal') {
|
|
221
|
-
const featureId = rest[0];
|
|
222
|
-
if (!featureId || !flags.by) {
|
|
223
|
-
console.error(chalk.red(' ✗ Usage: bizar claim steal <featureId> --by <id> --reason <reason>'));
|
|
224
|
-
return false;
|
|
225
|
-
}
|
|
226
|
-
if (!flags.reason) {
|
|
227
|
-
console.error(chalk.red(' ✗ steal requires --reason (one of: ' + STEAL_REASONS.join(', ') + ')'));
|
|
228
|
-
return false;
|
|
229
|
-
}
|
|
230
|
-
const newClaimant = { type: flags.type || 'human', id: flags.by, name: flags.by };
|
|
231
|
-
const result = br.steal(featureId, newClaimant, flags.reason);
|
|
232
|
-
out(result, flags, (r) =>
|
|
233
|
-
console.log(chalk.green(` ✓ Stole ${featureId} (reason: ${r.stealReason}); previous owner: ${r.previousClaimant?.name || r.previousClaimant?.id || '—'}`)),
|
|
234
|
-
);
|
|
235
|
-
return true;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
if (sub === 'transition') {
|
|
239
|
-
const [featureId, newStatus] = rest;
|
|
240
|
-
if (!featureId || !newStatus) {
|
|
241
|
-
console.error(chalk.red(' ✗ Usage: bizar claim transition <featureId> <active|paused|blocked|completed> [--who <id>]'));
|
|
242
|
-
return false;
|
|
243
|
-
}
|
|
244
|
-
if (!CLAIM_STATUSES.includes(newStatus)) {
|
|
245
|
-
console.error(chalk.red(` ✗ Unknown status '${newStatus}'. Must be one of: ${CLAIM_STATUSES.join(', ')}`));
|
|
246
|
-
return false;
|
|
247
|
-
}
|
|
248
|
-
const claimant = makeClaimant({ who: flags.who, type: flags.type }, fallback);
|
|
249
|
-
const result = br.transition(featureId, newStatus, claimant, flags.reason || '');
|
|
250
|
-
out(result, flags, (r) =>
|
|
251
|
-
console.log(chalk.green(` ✓ ${featureId} → ${newStatus}` + (r.unchanged ? ' (unchanged)' : ''))),
|
|
252
|
-
);
|
|
253
|
-
return true;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Default: `bizar claim <featureId>` — claim it.
|
|
257
|
-
if (!sub.startsWith('-') && sub) {
|
|
258
|
-
const featureId = sub;
|
|
259
|
-
const claimant = makeClaimant({ who: flags.who, type: flags.type }, fallback);
|
|
260
|
-
if (!claimant) {
|
|
261
|
-
console.error(chalk.red(' ✗ No claimant id (set $USER or pass --who <id>)'));
|
|
262
|
-
return false;
|
|
263
|
-
}
|
|
264
|
-
const result = br.claim(featureId, claimant, flags.reason || '');
|
|
265
|
-
out(result, flags, (r) =>
|
|
266
|
-
console.log(chalk.green(` ✓ Claimed ${featureId} by ${r.feature.claimant.name || r.feature.claimant.id} (${r.feature.claimStatus})`)),
|
|
267
|
-
);
|
|
268
|
-
return true;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
console.error(chalk.red(` ✗ Unknown subcommand: ${sub}`));
|
|
272
|
-
showHelp();
|
|
273
|
-
return false;
|
|
274
|
-
} catch (err) {
|
|
275
|
-
if (err instanceof ClaimError) {
|
|
276
|
-
console.error(chalk.red(` ✗ ${err.code}: ${err.message}`));
|
|
34
|
+
let command;
|
|
35
|
+
if (subcommand === 'list' || subcommand === 'ls') command = ['task', 'list', ...args.slice(1)];
|
|
36
|
+
else if (subcommand === 'release' || subcommand === 'heartbeat') {
|
|
37
|
+
if (!taskId) { help(); process.exitCode = 2; return true; }
|
|
38
|
+
command = ['task', subcommand, taskId, '--owner', agent, ...withoutWho(args.slice(2))];
|
|
277
39
|
} else {
|
|
278
|
-
|
|
279
|
-
}
|
|
280
|
-
|
|
40
|
+
command = ['task', 'claim', subcommand, '--owner', agent, ...withoutWho(args.slice(1))];
|
|
41
|
+
}
|
|
42
|
+
const result = runOpenKanOk(command);
|
|
43
|
+
if (result.stdout) process.stdout.write(result.stdout);
|
|
44
|
+
if (result.stderr) process.stderr.write(result.stderr);
|
|
45
|
+
if (!result.ok) process.exitCode = result.status || 1;
|
|
46
|
+
} catch (error) {
|
|
47
|
+
const prefix = error instanceof OpenKanError ? error.code : 'OPENKAN_ERROR';
|
|
48
|
+
process.stderr.write(` ✗ ${prefix}: ${error.message || String(error)}\n`);
|
|
49
|
+
process.exitCode = 1;
|
|
281
50
|
}
|
|
51
|
+
return true;
|
|
282
52
|
}
|
package/cli/commands/control.mjs
CHANGED
|
@@ -43,7 +43,7 @@ function help() {
|
|
|
43
43
|
|
|
44
44
|
Usage:
|
|
45
45
|
bizar control snapshot --json
|
|
46
|
-
bizar control agents|tasks|sessions|messages --json
|
|
46
|
+
bizar control agents|tasks|plans|goals|sessions|messages --json
|
|
47
47
|
bizar control message --agent <agent>|--session <id> --text <text> [--from <sender>]
|
|
48
48
|
bizar control session start --agent <agent> --prompt <text> [--name <name>]
|
|
49
49
|
bizar control session send <id> --text <text> [--from <sender>]
|
|
@@ -64,6 +64,8 @@ export async function run(name, args, isHelpRequest) {
|
|
|
64
64
|
if (resource === 'snapshot') print(getControlSnapshot(root), flags);
|
|
65
65
|
else if (resource === 'agents') print({ agents: listControlAgents(root) }, flags);
|
|
66
66
|
else if (resource === 'tasks') print(listControlTasks(root), flags);
|
|
67
|
+
else if (resource === 'plans') print({ plans: listControlTasks(root).plans }, flags);
|
|
68
|
+
else if (resource === 'goals') print({ goals: listControlTasks(root).goals }, flags);
|
|
67
69
|
else if (resource === 'sessions') print({ sessions: listControlSessions(root) }, flags);
|
|
68
70
|
else if (resource === 'messages') print(listControlMessages(root, { status: flags.status }), flags);
|
|
69
71
|
else if (resource === 'message') {
|