brainclaw 1.5.3 → 1.5.5

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/LICENSE CHANGED
@@ -1,74 +1,21 @@
1
- Business Source License 1.1
2
-
3
- Licensor: Juan Berdah
4
- Licensed Work: brainclaw
5
- The Licensed Work is (c) 2024-2026 Juan Berdah
6
- Change Date: Four years from the release date of each version
7
- Change License: MIT License
8
-
9
- For information about alternative licensing arrangements, contact the Licensor.
10
-
11
- ---
12
-
13
- Parameters
14
-
15
- Licensor: Juan Berdah
16
- Licensed Work: brainclaw
17
- Additional Use Grant: You may make production use of the Licensed Work, including use
18
- for internal business operations, provided that you do not use the
19
- Licensed Work to build or offer a competing product or service that
20
- provides shared agent memory, coordination, or context management
21
- for coding agents or development teams.
22
- Change Date: Four years after the release date of each version
23
- Change License: MIT License
24
-
25
- ---
26
-
27
- Notice
28
-
29
- The Business Source License (this document, or the "License") is not an Open Source
30
- license. However, the Licensed Work will eventually be made available under an Open
31
- Source License, as stated in this License.
32
-
33
- Use Limitation: The additional use grant in the Parameters specifies the permitted
34
- production use. If your use case falls outside that grant, you need a separate
35
- commercial license from the Licensor.
36
-
37
- License text
38
-
39
- The Licensor hereby grants you the right to copy, modify, create derivative works,
40
- redistribute, and make non-production use of the Licensed Work. The Licensor may
41
- make an Additional Use Grant, above, permitting limited production use.
42
-
43
- Effective on the Change Date, or the fourth anniversary of the first publicly available
44
- distribution of a specific version of the Licensed Work under this License, whichever
45
- comes first, the Licensor hereby grants you rights under the terms of the Change
46
- License, and the rights granted in the paragraph above terminate.
47
-
48
- If your use of the Licensed Work does not comply with the requirements currently in
49
- effect as described in this License, you must purchase a commercial license from the
50
- Licensor, its affiliated entities, or authorized resellers, or you must refrain from
51
- using the Licensed Work.
52
-
53
- All copies of the original and modified Licensed Work, and derivative works of the
54
- Licensed Work, are subject to this License. This License applies separately for each
55
- version of the Licensed Work and the Change Date may vary for each version of the
56
- Licensed Work released by the licensor.
57
-
58
- You must conspicuously display this License on each original or modified copy of the
59
- Licensed Work. If you receive the Licensed Work in original or modified form from a
60
- third party, the terms and conditions set forth in this License apply to your use of
61
- that work.
62
-
63
- Any use of the Licensed Work in violation of this License will automatically terminate
64
- your rights under this License for the current and all future versions of the Licensed
65
- Work.
66
-
67
- This License does not grant you any right in any trademark or logo of Licensor or its
68
- affiliates (provided that you may use a trademark or logo of Licensor as expressly
69
- required by this License).
70
-
71
- TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN "AS
72
- IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS OR
73
- IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
74
- PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE.
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2026 Juan Berdah
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -108,28 +108,52 @@ If you want the least surprising setup today, use Linux first. If you are on Win
108
108
 
109
109
  ---
110
110
 
111
- ## Get Started
112
-
113
- ### 1. Install
114
-
115
- ```bash
116
- npm install -g brainclaw
117
- ```
118
-
119
- ### 2. Initialize a project
120
-
121
- ```bash
122
- cd your-project
123
- brainclaw init
124
- ```
125
-
126
- This creates `.brainclaw/` in your repo, detects your coding agent, writes MCP config and instruction files, and sets up session hooks. It takes about 10 seconds.
127
-
128
- ### 3. Restart your agent
129
-
130
- Restart your coding agent (or reload MCP servers) so it picks up the new configuration. After that, brainclaw tools are available.
131
-
132
- ### 4. Start working
111
+ ## Get Started
112
+
113
+ ### 1. Let your coding agent lead
114
+
115
+ The smoothest first-run path is agent-first:
116
+
117
+ 1. ask your coding agent to inspect the package and explain what brainclaw does
118
+ 2. ask it to install brainclaw and initialize or join the project you're working on
119
+ 3. use the CLI yourself when you need an explicit operator or fallback path
120
+
121
+ If you want to drive setup manually, use the steps below.
122
+
123
+ ### 2. Install
124
+
125
+ ```bash
126
+ npm install -g brainclaw
127
+ ```
128
+
129
+ ### 3. Bootstrap this machine
130
+
131
+ ```bash
132
+ brainclaw setup-machine --yes
133
+ ```
134
+
135
+ This detects the installed agents on the current machine, writes the machine-level MCP and user config Brainclaw manages, and does **not** scan or initialize repositories.
136
+
137
+ ### 4. Initialize or refresh the current project
138
+
139
+ ```bash
140
+ cd your-project
141
+ brainclaw init
142
+ ```
143
+
144
+ `brainclaw init` is now safe to rerun. It creates `.brainclaw/` when the project is new, or refreshes the managed Brainclaw and agent integration files when the project already has memory.
145
+
146
+ If you are explicitly adding another agent to an existing Brainclaw project, use:
147
+
148
+ ```bash
149
+ brainclaw enable-agent <agent-name>
150
+ ```
151
+
152
+ ### 5. Restart your agent
153
+
154
+ Restart your coding agent (or reload MCP servers) so it picks up the new configuration. After that, brainclaw tools are available.
155
+
156
+ ### 6. Start working
133
157
 
134
158
  Pick one of the canonical entry points depending on what you're doing:
135
159
 
@@ -161,7 +185,7 @@ For agents without MCP (e.g. Copilot reads `.github/copilot-instructions.md`), r
161
185
  brainclaw export --detect --write
162
186
  ```
163
187
 
164
- ### 5. Verify it works
188
+ ### 7. Verify it works
165
189
 
166
190
  ```bash
167
191
  brainclaw status # see active sessions, claims, plans
@@ -172,11 +196,11 @@ brainclaw agent-board # see what each agent is doing
172
196
 
173
197
  To configure brainclaw for all your repos and agents at once:
174
198
 
175
- ```bash
176
- brainclaw setup --yes
177
- ```
178
-
179
- This scans your projects, detects installed agents (Claude Code, Codex, Cursor, Copilot, Cline, Mistral Vibe, etc.), and writes MCP configs for each.
199
+ ```bash
200
+ brainclaw setup --yes
201
+ ```
202
+
203
+ This is the broader multi-repo wizard. It bootstraps the machine, scans your project roots, and initializes selected repositories in one pass.
180
204
 
181
205
  ### Existing projects
182
206
 
@@ -380,15 +404,15 @@ For older releases (v0.x and the early v1.0 launch series), `git log` on `master
380
404
 
381
405
  ---
382
406
 
383
- ## License
384
-
385
- Current releases of brainclaw are published under the [Business Source License 1.1](LICENSE) — (c) 2024-2026 Juan Berdah.
386
-
387
- The long-term direction is simpler than the current wording might suggest:
388
-
389
- - the local-first brainclaw core is intended to move to MIT after the closed beta
390
- - cloud shared-memory, remote collaboration services, advanced dashboards, and related hosted add-ons will live in separate commercial products
391
-
392
- The intended MIT core covers what makes brainclaw useful inside a repo today: local project memory, local MCP and CLI coordination, onboarding and bootstrap, plans, claims, handoffs, runtime notes, and local agent integrations.
407
+ ## License
408
+
409
+ brainclaw core is published under the [MIT License](LICENSE) — (c) 2024-2026 Juan Berdah.
410
+
411
+ The licensing split is simple:
412
+
413
+ - the local-first brainclaw core is MIT
414
+ - cloud shared-memory, remote collaboration services, advanced dashboards, and related hosted add-ons will live in separate commercial products
415
+
416
+ The MIT core covers what makes brainclaw useful inside a repo today: local project memory, local MCP and CLI coordination, onboarding and bootstrap, plans, claims, handoffs, runtime notes, and local agent integrations.
393
417
 
394
418
  The goal is not to close brainclaw down. The goal is to keep the local-first core open and genuinely useful on its own, while keeping hosted collaboration features separate.
Binary file
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import path from 'node:path';
3
3
  import { Command } from 'commander';
4
4
  import { runInit } from './commands/init.js';
5
- import { runSetup } from './commands/setup.js';
5
+ import { runSetup, runSetupMachine } from './commands/setup.js';
6
6
  import { runUpgrade } from './commands/upgrade.js';
7
7
  import { patchAllMcpConfigs } from './core/agent-files.js';
8
8
  import { runReconcile } from './commands/reconcile.js';
@@ -47,6 +47,7 @@ import { cleanupStaleCandidates } from './core/candidates.js';
47
47
  import { runListClaims } from './commands/list-claims.js';
48
48
  import { runReleaseClaim } from './commands/release-claim.js';
49
49
  import { runClaimResource } from './commands/claim-resource.js';
50
+ import { runAssignmentResource } from './commands/assignment-resource.js';
50
51
  import { runMemoryCommand } from './commands/memory.js';
51
52
  import { runReleaseClaims } from './commands/release-claims.js';
52
53
  import { runAgentBoard } from './commands/agent-board.js';
@@ -109,6 +110,42 @@ const program = new Command();
109
110
  function collect(value, previous) {
110
111
  return [...previous, value];
111
112
  }
113
+ function parseLeadingGlobalOptions(argv) {
114
+ const result = {};
115
+ for (let i = 0; i < argv.length; i++) {
116
+ const token = argv[i];
117
+ if (!token.startsWith('-')) {
118
+ break;
119
+ }
120
+ if (token === '--verbose') {
121
+ result.verbose = true;
122
+ continue;
123
+ }
124
+ if (token === '--debug') {
125
+ result.debug = true;
126
+ continue;
127
+ }
128
+ if (token === '--cwd') {
129
+ result.cwd = argv[i + 1];
130
+ i++;
131
+ continue;
132
+ }
133
+ if (token.startsWith('--cwd=')) {
134
+ result.cwd = token.slice('--cwd='.length);
135
+ continue;
136
+ }
137
+ if (token === '--project') {
138
+ result.project = argv[i + 1];
139
+ i++;
140
+ continue;
141
+ }
142
+ if (token.startsWith('--project=')) {
143
+ result.project = token.slice('--project='.length);
144
+ continue;
145
+ }
146
+ }
147
+ return result;
148
+ }
112
149
  function isCodevEnabled() {
113
150
  return process.env.BRAINCLAW_ENABLE_CODEV === '1';
114
151
  }
@@ -121,11 +158,11 @@ program
121
158
  .option('--cwd <path>', 'Override working directory for this invocation')
122
159
  .option('--project <name>', 'Run the command against a linked project (cross_project_links or workspace store-chain child). Resolves via resolveProjectCwd; mutually exclusive with --cwd.')
123
160
  .hook('preAction', (_thisCommand, actionCommand) => {
124
- const root = actionCommand.optsWithGlobals();
161
+ const root = parseLeadingGlobalOptions(process.argv.slice(2));
125
162
  initLogLevel({ verbose: root.verbose, debug: root.debug });
126
163
  // Skip effective cwd resolution for commands that create the store
127
164
  const cmdName = actionCommand.name();
128
- const skipResolution = cmdName === 'init' || cmdName === 'setup';
165
+ const skipResolution = cmdName === 'init' || cmdName === 'setup' || cmdName === 'setup-machine';
129
166
  // pln#359 phase 1c — `--project <name>` resolves a linked project to an
130
167
  // absolute path via resolveProjectCwd, then feeds the same chdir flow
131
168
  // as --cwd. Mutually exclusive with --cwd to avoid ambiguity.
@@ -165,9 +202,9 @@ program
165
202
  // --- init ---
166
203
  program
167
204
  .command('init')
168
- .description('Initialize project memory in .brainclaw/ storage directory')
205
+ .description('Initialize or refresh project memory in .brainclaw/ storage directory')
169
206
  .option('-y, --yes', 'Skip interactive wizard and use defaults')
170
- .option('--force', 'Overwrite existing project memory directory')
207
+ .option('--force', 'Rebuild managed Brainclaw config and generated files from defaults')
171
208
  .option('--compact', 'Enable compact markdown mode')
172
209
  .option('--topology <mode>', 'Topology mode: embedded, sidecar, local-only')
173
210
  .option('--project-mode <mode>', 'Project mode: single-project, multi-project, auto')
@@ -181,7 +218,7 @@ program
181
218
  // --- setup ---
182
219
  program
183
220
  .command('setup')
184
- .description('Interactive onboarding wizard — global agent install + multi-repo init')
221
+ .description('Interactive onboarding wizard — machine bootstrap plus multi-repo init')
185
222
  .option('--roots <paths>', 'Comma-separated root directories to scan (skips interactive prompt)')
186
223
  .option('--agents <agents>', 'Agents to configure: all, detected, or comma-separated names')
187
224
  .option('--repos <mode>', 'Repo selection: all, current, or comma-separated numbers')
@@ -189,6 +226,15 @@ program
189
226
  .action(async (options) => {
190
227
  await runSetup(options);
191
228
  });
229
+ // --- setup-machine ---
230
+ program
231
+ .command('setup-machine')
232
+ .description('Machine-only onboarding — detect/configure agents and MCP without scanning or initializing repositories')
233
+ .option('--agents <agents>', 'Agents to configure: all, detected, or comma-separated names')
234
+ .option('-y, --yes', 'Accept all defaults non-interactively')
235
+ .action(async (options) => {
236
+ await runSetupMachine(options);
237
+ });
192
238
  // --- memory-log ---
193
239
  program
194
240
  .command('memory-log')
@@ -1003,6 +1049,26 @@ program
1003
1049
  .action((subcommand, args, options) => {
1004
1050
  runClaimResource(subcommand, args, { ...options, planStatus: options.planStatus, localOnly: options.localOnly });
1005
1051
  });
1052
+ // --- assignment ---
1053
+ program
1054
+ .command('assignment <subcommand> [args...]')
1055
+ .description('Manage work assignments (list, show, update, cancel)')
1056
+ .option('--json', 'Output as JSON for list/show')
1057
+ .option('--all', 'Include terminal assignments in list')
1058
+ .option('--status <status>', 'Status filter for list or target status for update')
1059
+ .option('--agent <agent>', 'Filter by agent name')
1060
+ .option('--claim <id>', 'Filter by linked claim ID')
1061
+ .option('--plan <id>', 'Filter by linked plan ID')
1062
+ .option('--sequence <id>', 'Filter by linked sequence ID')
1063
+ .option('--reason <text>', 'Optional status reason for update/cancel')
1064
+ .action((subcommand, args, options) => {
1065
+ runAssignmentResource(subcommand, args, {
1066
+ ...options,
1067
+ claim: options.claim,
1068
+ plan: options.plan,
1069
+ sequence: options.sequence,
1070
+ });
1071
+ });
1006
1072
  // --- list-claims ---
1007
1073
  program
1008
1074
  .command('list-claims')
@@ -0,0 +1,182 @@
1
+ import { memoryExists } from '../core/io.js';
2
+ import { listAssignments, loadAssignment, transitionAssignment } from '../core/assignments.js';
3
+ import { resolveCurrentAgentName } from '../core/agent-registry.js';
4
+ import { AssignmentStatusSchema } from '../core/schema.js';
5
+ const TERMINAL_STATUSES = new Set(['completed', 'cancelled', 'expired', 'rerouted']);
6
+ const KNOWN_SUBCOMMANDS = new Set(['list', 'ls', 'show', 'get', 'update', 'cancel']);
7
+ export function runAssignmentResource(subcommand, args, options = {}) {
8
+ const normalized = subcommand.trim().toLowerCase();
9
+ if (normalized === 'list' || normalized === 'ls') {
10
+ runListAssignmentsCommand(options);
11
+ return;
12
+ }
13
+ if (normalized === 'show' || normalized === 'get') {
14
+ const id = args[0];
15
+ if (!id) {
16
+ console.error(`Error: assignment ${normalized} requires <id>.`);
17
+ process.exit(1);
18
+ }
19
+ runShowAssignmentCommand(id, options);
20
+ return;
21
+ }
22
+ if (normalized === 'update') {
23
+ const id = args[0];
24
+ if (!id) {
25
+ console.error('Error: assignment update requires <id>.');
26
+ process.exit(1);
27
+ }
28
+ const status = options.status;
29
+ if (!status) {
30
+ console.error('Error: assignment update requires --status <status>.');
31
+ process.exit(1);
32
+ }
33
+ runTransitionAssignmentCommand(id, status, options);
34
+ return;
35
+ }
36
+ if (normalized === 'cancel') {
37
+ const id = args[0];
38
+ if (!id) {
39
+ console.error('Error: assignment cancel requires <id>.');
40
+ process.exit(1);
41
+ }
42
+ runTransitionAssignmentCommand(id, 'cancelled', options);
43
+ return;
44
+ }
45
+ if (normalized.startsWith('asgn_') || KNOWN_SUBCOMMANDS.has(normalized)) {
46
+ console.error(`Error: unknown assignment subcommand "${subcommand}".`);
47
+ console.error(' Available: list, show, get, update, cancel');
48
+ process.exit(1);
49
+ }
50
+ console.error('Error: missing assignment subcommand.');
51
+ console.error(' Available: list, show, get, update, cancel');
52
+ process.exit(1);
53
+ }
54
+ function runListAssignmentsCommand(options) {
55
+ ensureInitialized(options.cwd);
56
+ const requestedStatus = parseAssignmentStatus(options.status);
57
+ let assignments = listAssignments(options.cwd, {
58
+ status: requestedStatus,
59
+ agent: options.agent,
60
+ claim_id: options.claim,
61
+ plan_id: options.plan,
62
+ sequence_id: options.sequence,
63
+ });
64
+ if (!options.all && !requestedStatus) {
65
+ assignments = assignments.filter((assignment) => !TERMINAL_STATUSES.has(assignment.status));
66
+ }
67
+ if (options.json) {
68
+ console.log(JSON.stringify(assignments, null, 2));
69
+ return;
70
+ }
71
+ if (assignments.length === 0) {
72
+ console.log(options.all ? 'No assignments.' : 'No active assignments.');
73
+ return;
74
+ }
75
+ console.log(`${assignments.length} ${options.all ? 'assignment(s)' : 'active assignment(s)'}:`);
76
+ console.log('');
77
+ for (const assignment of assignments) {
78
+ const extras = [];
79
+ if (assignment.plan_id)
80
+ extras.push(`plan ${assignment.plan_id}`);
81
+ if (assignment.claim_id)
82
+ extras.push(`claim ${assignment.claim_id}`);
83
+ if (assignment.sequence_id)
84
+ extras.push(`sequence ${assignment.sequence_id}`);
85
+ if (assignment.worktree_path)
86
+ extras.push(`worktree ${assignment.worktree_path}`);
87
+ const suffix = extras.length > 0 ? ` [${extras.join(', ')}]` : '';
88
+ console.log(` [${assignment.id}] ${assignment.agent} (${assignment.status}) -> ${assignment.scope}: ${assignment.description}${suffix}`);
89
+ }
90
+ }
91
+ function runShowAssignmentCommand(id, options) {
92
+ ensureInitialized(options.cwd);
93
+ const assignment = requireAssignment(id, options.cwd);
94
+ if (options.json) {
95
+ console.log(JSON.stringify(assignment, null, 2));
96
+ return;
97
+ }
98
+ console.log(`Assignment: ${assignment.id}`);
99
+ console.log(` Agent: ${assignment.agent}`);
100
+ console.log(` Status: ${assignment.status}`);
101
+ console.log(` Scope: ${assignment.scope}`);
102
+ console.log(` Description: ${assignment.description}`);
103
+ console.log(` Claim: ${assignment.claim_id}`);
104
+ if (assignment.message_id)
105
+ console.log(` Message: ${assignment.message_id}`);
106
+ if (assignment.plan_id)
107
+ console.log(` Plan: ${assignment.plan_id}`);
108
+ if (assignment.sequence_id)
109
+ console.log(` Sequence: ${assignment.sequence_id}`);
110
+ if (assignment.session_id)
111
+ console.log(` Session: ${assignment.session_id}`);
112
+ if (assignment.status_reason)
113
+ console.log(` Reason: ${assignment.status_reason}`);
114
+ if (assignment.worktree_path)
115
+ console.log(` Worktree: ${assignment.worktree_path}`);
116
+ console.log(` Created: ${assignment.created_at}`);
117
+ if (assignment.updated_at)
118
+ console.log(` Updated: ${assignment.updated_at}`);
119
+ if (assignment.offered_at)
120
+ console.log(` Offered: ${assignment.offered_at}`);
121
+ if (assignment.accepted_at)
122
+ console.log(` Accepted: ${assignment.accepted_at}`);
123
+ if (assignment.started_at)
124
+ console.log(` Started: ${assignment.started_at}`);
125
+ if (assignment.completed_at)
126
+ console.log(` Completed: ${assignment.completed_at}`);
127
+ if (assignment.cancelled_at)
128
+ console.log(` Cancelled: ${assignment.cancelled_at}`);
129
+ if (assignment.failed_at)
130
+ console.log(` Failed: ${assignment.failed_at}`);
131
+ if (assignment.blocked_at)
132
+ console.log(` Blocked: ${assignment.blocked_at}`);
133
+ if (assignment.timed_out_at)
134
+ console.log(` Timed out: ${assignment.timed_out_at}`);
135
+ if (assignment.expired_at)
136
+ console.log(` Expired: ${assignment.expired_at}`);
137
+ if (assignment.rerouted_at)
138
+ console.log(` Rerouted: ${assignment.rerouted_at}`);
139
+ }
140
+ function runTransitionAssignmentCommand(id, statusInput, options) {
141
+ ensureInitialized(options.cwd);
142
+ const nextStatus = parseAssignmentStatus(statusInput, 'status');
143
+ const actor = resolveCurrentAgentName(options.cwd);
144
+ try {
145
+ const result = transitionAssignment(id, nextStatus, {
146
+ actor,
147
+ status_reason: options.reason,
148
+ }, options.cwd);
149
+ const verb = nextStatus === 'cancelled' ? 'cancelled' : 'updated';
150
+ console.log(`✔ Assignment ${verb}: [${result.assignment.id}] ${result.previous_status} -> ${result.assignment.status}`);
151
+ }
152
+ catch (error) {
153
+ console.error(`Error: ${error.message}`);
154
+ process.exit(1);
155
+ }
156
+ }
157
+ function ensureInitialized(cwd) {
158
+ if (!memoryExists(cwd)) {
159
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
160
+ process.exit(1);
161
+ }
162
+ }
163
+ function requireAssignment(id, cwd) {
164
+ const assignment = loadAssignment(id, cwd);
165
+ if (!assignment) {
166
+ console.error(`Error: assignment not found: ${id}`);
167
+ process.exit(1);
168
+ }
169
+ return assignment;
170
+ }
171
+ function parseAssignmentStatus(value, label = 'filter') {
172
+ if (value === undefined) {
173
+ return undefined;
174
+ }
175
+ const parsed = AssignmentStatusSchema.safeParse(value);
176
+ if (!parsed.success) {
177
+ console.error(`Error: invalid ${label} '${value}'. Expected one of: ${AssignmentStatusSchema.options.join(', ')}`);
178
+ process.exit(1);
179
+ }
180
+ return parsed.data;
181
+ }
182
+ //# sourceMappingURL=assignment-resource.js.map