mindsystem-cc 3.2.2 → 3.3.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.
Files changed (56) hide show
  1. package/README.md +2 -2
  2. package/agents/ms-code-simplifier.md +215 -0
  3. package/agents/ms-consolidator.md +377 -0
  4. package/agents/ms-executor.md +32 -261
  5. package/{commands/ms/simplify-flutter.md → agents/ms-flutter-simplifier.md} +41 -49
  6. package/agents/ms-researcher.md +2 -2
  7. package/commands/ms/complete-milestone.md +24 -3
  8. package/commands/ms/do-work.md +17 -3
  9. package/commands/ms/execute-phase.md +29 -14
  10. package/commands/ms/help.md +4 -23
  11. package/commands/ms/new-milestone.md +42 -30
  12. package/commands/ms/new-project.md +5 -14
  13. package/commands/ms/progress.md +1 -1
  14. package/commands/ms/research-project.md +8 -0
  15. package/commands/ms/review-design.md +1 -1
  16. package/commands/ms/whats-new.md +3 -3
  17. package/mindsystem/references/git-integration.md +2 -2
  18. package/mindsystem/references/goal-backward.md +2 -2
  19. package/mindsystem/references/principles.md +1 -1
  20. package/mindsystem/templates/adhoc-summary.md +3 -0
  21. package/mindsystem/templates/codebase/architecture.md +2 -2
  22. package/mindsystem/templates/codebase/structure.md +1 -1
  23. package/mindsystem/templates/config.json +2 -12
  24. package/mindsystem/templates/decisions.md +145 -0
  25. package/mindsystem/workflows/complete-milestone.md +58 -25
  26. package/mindsystem/workflows/create-milestone.md +60 -20
  27. package/mindsystem/workflows/do-work.md +81 -4
  28. package/mindsystem/workflows/execute-phase.md +66 -0
  29. package/mindsystem/workflows/execute-plan.md +1 -53
  30. package/mindsystem/workflows/map-codebase.md +9 -1
  31. package/mindsystem/workflows/plan-phase.md +0 -39
  32. package/mindsystem/workflows/transition.md +0 -74
  33. package/mindsystem/workflows/verify-work.md +1 -1
  34. package/package.json +1 -1
  35. package/scripts/generate-adhoc-patch.sh +79 -0
  36. package/scripts/ms-lookup/uv.lock +17 -17
  37. package/commands/ms/discuss-milestone.md +0 -48
  38. package/commands/ms/linear.md +0 -195
  39. package/mindsystem/templates/milestone-context.md +0 -93
  40. package/scripts/ms-linear/ms_linear/__init__.py +0 -3
  41. package/scripts/ms-linear/ms_linear/__main__.py +0 -6
  42. package/scripts/ms-linear/ms_linear/__pycache__/__init__.cpython-314.pyc +0 -0
  43. package/scripts/ms-linear/ms_linear/__pycache__/__main__.cpython-314.pyc +0 -0
  44. package/scripts/ms-linear/ms_linear/__pycache__/cli.cpython-314.pyc +0 -0
  45. package/scripts/ms-linear/ms_linear/__pycache__/client.cpython-314.pyc +0 -0
  46. package/scripts/ms-linear/ms_linear/__pycache__/config.cpython-314.pyc +0 -0
  47. package/scripts/ms-linear/ms_linear/__pycache__/errors.cpython-314.pyc +0 -0
  48. package/scripts/ms-linear/ms_linear/__pycache__/output.cpython-314.pyc +0 -0
  49. package/scripts/ms-linear/ms_linear/cli.py +0 -604
  50. package/scripts/ms-linear/ms_linear/client.py +0 -503
  51. package/scripts/ms-linear/ms_linear/config.py +0 -104
  52. package/scripts/ms-linear/ms_linear/errors.py +0 -29
  53. package/scripts/ms-linear/ms_linear/output.py +0 -45
  54. package/scripts/ms-linear/pyproject.toml +0 -16
  55. package/scripts/ms-linear/uv.lock +0 -196
  56. package/scripts/ms-linear-wrapper.sh +0 -22
@@ -1,604 +0,0 @@
1
- """Main CLI entry point for ms-linear."""
2
-
3
- import json
4
- from typing import Optional
5
-
6
- import typer
7
-
8
- from ms_linear import __version__
9
- from ms_linear.client import LinearClient
10
- from ms_linear.config import load_config
11
- from ms_linear.errors import MsLinearError
12
- from ms_linear.output import format_error, format_success, output_json
13
-
14
- app = typer.Typer(
15
- name="ms-linear",
16
- help="Mindsystem Linear CLI - create, update, and manage Linear issues",
17
- add_completion=False,
18
- )
19
-
20
-
21
- def version_callback(value: bool) -> None:
22
- """Print version and exit."""
23
- if value:
24
- typer.echo(f"ms-linear {__version__}")
25
- raise typer.Exit()
26
-
27
-
28
- @app.callback()
29
- def main(
30
- version: Optional[bool] = typer.Option(
31
- None,
32
- "--version",
33
- "-v",
34
- callback=version_callback,
35
- is_eager=True,
36
- help="Show version and exit",
37
- ),
38
- ) -> None:
39
- """Mindsystem Linear CLI - create, update, and manage Linear issues."""
40
- pass
41
-
42
-
43
- @app.command()
44
- def create(
45
- title: str = typer.Argument(..., help="Issue title"),
46
- description: Optional[str] = typer.Option(
47
- None,
48
- "--description",
49
- "-d",
50
- help="Issue description (markdown)",
51
- ),
52
- priority: Optional[int] = typer.Option(
53
- None,
54
- "--priority",
55
- "-p",
56
- help="Priority: 0=None, 1=Urgent, 2=High, 3=Normal, 4=Low",
57
- ),
58
- estimate: Optional[int] = typer.Option(
59
- None,
60
- "--estimate",
61
- "-e",
62
- help="Estimate (team-specific scale)",
63
- ),
64
- parent: Optional[str] = typer.Option(
65
- None,
66
- "--parent",
67
- help="Parent issue ID for sub-issues",
68
- ),
69
- project: Optional[str] = typer.Option(
70
- None,
71
- "--project",
72
- help="Project name (resolved to ID) - overrides config default",
73
- ),
74
- no_project: bool = typer.Option(
75
- False,
76
- "--no-project",
77
- help="Don't assign to any project (ignores config default)",
78
- ),
79
- json_pretty: bool = typer.Option(
80
- False,
81
- "--json-pretty",
82
- "-P",
83
- help="Pretty-print JSON output",
84
- ),
85
- ) -> None:
86
- """Create a new issue.
87
-
88
- Examples:
89
- ms-linear create "Fix login bug"
90
- ms-linear create "Add OAuth" -d "Support Google and GitHub OAuth"
91
- ms-linear create "Auth subtask" --parent ABC-123
92
- ms-linear create "Mobile bug" --project "Mobile App"
93
- ms-linear create "Backlog item" --no-project
94
- """
95
- command = "create"
96
-
97
- try:
98
- config = load_config()
99
- client = LinearClient()
100
-
101
- # Resolve project name to ID if provided
102
- project_id = None
103
- if project:
104
- project_info = client.find_project_by_name(project, config.team_id)
105
- project_id = project_info["id"]
106
-
107
- issue = client.create_issue(
108
- config=config,
109
- title=title,
110
- description=description,
111
- priority=priority,
112
- estimate=estimate,
113
- parent_id=parent,
114
- project_id=project_id,
115
- no_project=no_project,
116
- )
117
-
118
- metadata = {
119
- "teamId": config.team_id,
120
- }
121
- if project_id:
122
- metadata["projectId"] = project_id
123
- elif config.project_id and not no_project:
124
- metadata["projectId"] = config.project_id
125
-
126
- response = format_success(
127
- command=command,
128
- result={
129
- "identifier": issue.get("identifier"),
130
- "title": issue.get("title"),
131
- "url": issue.get("url"),
132
- "state": issue.get("state", {}).get("name"),
133
- },
134
- metadata=metadata,
135
- )
136
- typer.echo(output_json(response, pretty=json_pretty))
137
-
138
- except MsLinearError as e:
139
- error_response = format_error(command, e)
140
- typer.echo(output_json(error_response, pretty=json_pretty))
141
- raise typer.Exit(code=1)
142
-
143
-
144
- @app.command()
145
- def update(
146
- issue_id: str = typer.Argument(..., help="Issue ID (e.g., ABC-123)"),
147
- title: Optional[str] = typer.Option(
148
- None,
149
- "--title",
150
- "-t",
151
- help="New title",
152
- ),
153
- description: Optional[str] = typer.Option(
154
- None,
155
- "--description",
156
- "-d",
157
- help="New description",
158
- ),
159
- priority: Optional[int] = typer.Option(
160
- None,
161
- "--priority",
162
- "-p",
163
- help="New priority: 0=None, 1=Urgent, 2=High, 3=Normal, 4=Low",
164
- ),
165
- json_pretty: bool = typer.Option(
166
- False,
167
- "--json-pretty",
168
- "-P",
169
- help="Pretty-print JSON output",
170
- ),
171
- ) -> None:
172
- """Update an existing issue.
173
-
174
- Examples:
175
- ms-linear update ABC-123 -t "New title"
176
- ms-linear update ABC-123 -d "Updated description"
177
- ms-linear update ABC-123 -p 2
178
- """
179
- command = "update"
180
-
181
- try:
182
- client = LinearClient()
183
-
184
- issue = client.update_issue(
185
- issue_id=issue_id,
186
- title=title,
187
- description=description,
188
- priority=priority,
189
- )
190
-
191
- response = format_success(
192
- command=command,
193
- result={
194
- "identifier": issue.get("identifier"),
195
- "title": issue.get("title"),
196
- "url": issue.get("url"),
197
- "state": issue.get("state", {}).get("name"),
198
- },
199
- )
200
- typer.echo(output_json(response, pretty=json_pretty))
201
-
202
- except MsLinearError as e:
203
- error_response = format_error(command, e)
204
- typer.echo(output_json(error_response, pretty=json_pretty))
205
- raise typer.Exit(code=1)
206
-
207
-
208
- @app.command()
209
- def done(
210
- issue_id: str = typer.Argument(..., help="Issue ID (e.g., ABC-123)"),
211
- json_pretty: bool = typer.Option(
212
- False,
213
- "--json-pretty",
214
- "-P",
215
- help="Pretty-print JSON output",
216
- ),
217
- ) -> None:
218
- """Mark an issue as completed.
219
-
220
- Examples:
221
- ms-linear done ABC-123
222
- """
223
- command = "done"
224
-
225
- try:
226
- client = LinearClient()
227
- issue = client.mark_done(issue_id)
228
-
229
- response = format_success(
230
- command=command,
231
- result={
232
- "identifier": issue.get("identifier"),
233
- "title": issue.get("title"),
234
- "url": issue.get("url"),
235
- "state": issue.get("state", {}).get("name"),
236
- },
237
- )
238
- typer.echo(output_json(response, pretty=json_pretty))
239
-
240
- except MsLinearError as e:
241
- error_response = format_error(command, e)
242
- typer.echo(output_json(error_response, pretty=json_pretty))
243
- raise typer.Exit(code=1)
244
-
245
-
246
- @app.command()
247
- def state(
248
- issue_id: str = typer.Argument(..., help="Issue ID (e.g., ABC-123)"),
249
- state_name: str = typer.Argument(..., help="Target state name"),
250
- json_pretty: bool = typer.Option(
251
- False,
252
- "--json-pretty",
253
- "-P",
254
- help="Pretty-print JSON output",
255
- ),
256
- ) -> None:
257
- """Change an issue's state.
258
-
259
- Examples:
260
- ms-linear state ABC-123 "In Progress"
261
- ms-linear state ABC-123 "Done"
262
- ms-linear state ABC-123 "Backlog"
263
- """
264
- command = "state"
265
-
266
- try:
267
- client = LinearClient()
268
- issue = client.change_state(issue_id, state_name)
269
-
270
- response = format_success(
271
- command=command,
272
- result={
273
- "identifier": issue.get("identifier"),
274
- "title": issue.get("title"),
275
- "url": issue.get("url"),
276
- "state": issue.get("state", {}).get("name"),
277
- },
278
- )
279
- typer.echo(output_json(response, pretty=json_pretty))
280
-
281
- except MsLinearError as e:
282
- error_response = format_error(command, e)
283
- typer.echo(output_json(error_response, pretty=json_pretty))
284
- raise typer.Exit(code=1)
285
-
286
-
287
- @app.command("break")
288
- def break_issue(
289
- issue_id: str = typer.Argument(..., help="Parent issue ID (e.g., ABC-123)"),
290
- issues: str = typer.Option(
291
- ...,
292
- "--issues",
293
- "-i",
294
- help='JSON array of sub-issues: [{"title": "...", "description": "...", "priority": N, "estimate": N}]',
295
- ),
296
- project: Optional[str] = typer.Option(
297
- None,
298
- "--project",
299
- help="Project name for sub-issues (default: inherit from parent)",
300
- ),
301
- no_project: bool = typer.Option(
302
- False,
303
- "--no-project",
304
- help="Don't assign sub-issues to any project",
305
- ),
306
- json_pretty: bool = typer.Option(
307
- False,
308
- "--json-pretty",
309
- "-P",
310
- help="Pretty-print JSON output",
311
- ),
312
- ) -> None:
313
- """Break down an issue into sub-issues.
314
-
315
- The --issues parameter must be a JSON array of objects with at minimum a "title" field.
316
- Optional fields: description, priority, estimate.
317
-
318
- By default, sub-issues inherit the parent's project. Use --project to override
319
- or --no-project to create without project assignment.
320
-
321
- Examples:
322
- ms-linear break ABC-123 --issues '[{"title": "Design"}, {"title": "Implement"}, {"title": "Test"}]'
323
- ms-linear break ABC-123 --issues '[{"title": "Task"}]' --project "Backend"
324
- """
325
- command = "break"
326
-
327
- try:
328
- config = load_config()
329
- client = LinearClient()
330
-
331
- # Parse JSON issues
332
- try:
333
- issues_data = json.loads(issues)
334
- except json.JSONDecodeError as e:
335
- from ms_linear.errors import ErrorCode, MsLinearError
336
-
337
- raise MsLinearError(
338
- code=ErrorCode.INVALID_INPUT,
339
- message=f"Invalid JSON for --issues: {e}",
340
- suggestions=["Ensure --issues is valid JSON array"],
341
- )
342
-
343
- if not isinstance(issues_data, list):
344
- from ms_linear.errors import ErrorCode, MsLinearError
345
-
346
- raise MsLinearError(
347
- code=ErrorCode.INVALID_INPUT,
348
- message="--issues must be a JSON array",
349
- suggestions=['Use format: [{"title": "..."}, {"title": "..."}]'],
350
- )
351
-
352
- # Resolve project name to ID if provided
353
- project_id = None
354
- if project:
355
- project_info = client.find_project_by_name(project, config.team_id)
356
- project_id = project_info["id"]
357
-
358
- created = client.create_sub_issues(
359
- config, issue_id, issues_data, project_id=project_id, no_project=no_project
360
- )
361
-
362
- response = format_success(
363
- command=command,
364
- result={
365
- "parent": issue_id,
366
- "created": [
367
- {
368
- "identifier": i.get("identifier"),
369
- "title": i.get("title"),
370
- "url": i.get("url"),
371
- }
372
- for i in created
373
- ],
374
- },
375
- metadata={
376
- "count": len(created),
377
- "teamId": config.team_id,
378
- },
379
- )
380
- typer.echo(output_json(response, pretty=json_pretty))
381
-
382
- except MsLinearError as e:
383
- error_response = format_error(command, e)
384
- typer.echo(output_json(error_response, pretty=json_pretty))
385
- raise typer.Exit(code=1)
386
-
387
-
388
- @app.command()
389
- def get(
390
- issue_id: str = typer.Argument(..., help="Issue ID (e.g., ABC-123)"),
391
- json_pretty: bool = typer.Option(
392
- False,
393
- "--json-pretty",
394
- "-P",
395
- help="Pretty-print JSON output",
396
- ),
397
- ) -> None:
398
- """Fetch issue details.
399
-
400
- Examples:
401
- ms-linear get ABC-123
402
- """
403
- command = "get"
404
-
405
- try:
406
- client = LinearClient()
407
- issue = client.get_issue(issue_id)
408
-
409
- # Format children if present
410
- children = issue.get("children", {}).get("nodes", [])
411
- children_data = [
412
- {
413
- "identifier": c.get("identifier"),
414
- "title": c.get("title"),
415
- "state": c.get("state", {}).get("name"),
416
- }
417
- for c in children
418
- ]
419
-
420
- result = {
421
- "identifier": issue.get("identifier"),
422
- "title": issue.get("title"),
423
- "description": issue.get("description"),
424
- "priority": issue.get("priority"),
425
- "estimate": issue.get("estimate"),
426
- "url": issue.get("url"),
427
- "state": {
428
- "id": issue.get("state", {}).get("id"),
429
- "name": issue.get("state", {}).get("name"),
430
- "type": issue.get("state", {}).get("type"),
431
- },
432
- "team": {
433
- "id": issue.get("team", {}).get("id"),
434
- "key": issue.get("team", {}).get("key"),
435
- "name": issue.get("team", {}).get("name"),
436
- },
437
- }
438
-
439
- # Add parent if exists
440
- parent = issue.get("parent")
441
- if parent:
442
- result["parent"] = {
443
- "identifier": parent.get("identifier"),
444
- "title": parent.get("title"),
445
- }
446
-
447
- # Add children if any
448
- if children_data:
449
- result["children"] = children_data
450
-
451
- # Add project if exists
452
- project = issue.get("project")
453
- if project:
454
- result["project"] = {
455
- "id": project.get("id"),
456
- "name": project.get("name"),
457
- }
458
-
459
- response = format_success(command=command, result=result)
460
- typer.echo(output_json(response, pretty=json_pretty))
461
-
462
- except MsLinearError as e:
463
- error_response = format_error(command, e)
464
- typer.echo(output_json(error_response, pretty=json_pretty))
465
- raise typer.Exit(code=1)
466
-
467
-
468
- @app.command()
469
- def states(
470
- team_id: Optional[str] = typer.Option(
471
- None,
472
- "--team",
473
- "-t",
474
- help="Filter by team ID (optional)",
475
- ),
476
- json_pretty: bool = typer.Option(
477
- False,
478
- "--json-pretty",
479
- "-P",
480
- help="Pretty-print JSON output",
481
- ),
482
- ) -> None:
483
- """List workflow states.
484
-
485
- Without --team, returns all states across all teams.
486
- With --team, returns states for that specific team.
487
-
488
- Examples:
489
- ms-linear states
490
- ms-linear states --team abc123-team-uuid
491
- """
492
- command = "states"
493
-
494
- try:
495
- client = LinearClient()
496
- states_list = client.get_workflow_states(team_id)
497
-
498
- # Group by team for cleaner output
499
- teams: dict[str, dict] = {}
500
- for state in states_list:
501
- team = state.get("team", {})
502
- team_key = team.get("key", "unknown")
503
- if team_key not in teams:
504
- teams[team_key] = {
505
- "id": team.get("id"),
506
- "key": team_key,
507
- "name": team.get("name"),
508
- "states": [],
509
- }
510
- teams[team_key]["states"].append(
511
- {
512
- "id": state.get("id"),
513
- "name": state.get("name"),
514
- "type": state.get("type"),
515
- "position": state.get("position"),
516
- }
517
- )
518
-
519
- # Sort states by position within each team
520
- for team_data in teams.values():
521
- team_data["states"].sort(key=lambda s: s.get("position", 0))
522
-
523
- response = format_success(
524
- command=command,
525
- result={"teams": list(teams.values())},
526
- metadata={"totalStates": len(states_list)},
527
- )
528
- typer.echo(output_json(response, pretty=json_pretty))
529
-
530
- except MsLinearError as e:
531
- error_response = format_error(command, e)
532
- typer.echo(output_json(error_response, pretty=json_pretty))
533
- raise typer.Exit(code=1)
534
-
535
-
536
- @app.command()
537
- def projects(
538
- team_id: Optional[str] = typer.Option(
539
- None,
540
- "--team",
541
- "-t",
542
- help="Filter by team ID (optional)",
543
- ),
544
- json_pretty: bool = typer.Option(
545
- False,
546
- "--json-pretty",
547
- "-P",
548
- help="Pretty-print JSON output",
549
- ),
550
- ) -> None:
551
- """List projects.
552
-
553
- Without --team, returns all projects across all teams.
554
- With --team, returns projects for that specific team.
555
-
556
- Examples:
557
- ms-linear projects
558
- ms-linear projects --team abc123-team-uuid
559
- """
560
- command = "projects"
561
-
562
- try:
563
- client = LinearClient()
564
- projects_list = client.get_projects(team_id)
565
-
566
- # Group by team for cleaner output
567
- teams: dict[str, dict] = {}
568
- for project in projects_list:
569
- team = project.get("team", {})
570
- team_key = team.get("key", "unknown")
571
- if team_key not in teams:
572
- teams[team_key] = {
573
- "id": team.get("id"),
574
- "key": team_key,
575
- "name": team.get("name"),
576
- "projects": [],
577
- }
578
- teams[team_key]["projects"].append(
579
- {
580
- "id": project.get("id"),
581
- "name": project.get("name"),
582
- "state": project.get("state"),
583
- }
584
- )
585
-
586
- # Sort projects by name within each team
587
- for team_data in teams.values():
588
- team_data["projects"].sort(key=lambda p: p.get("name", "").lower())
589
-
590
- response = format_success(
591
- command=command,
592
- result={"teams": list(teams.values())},
593
- metadata={"totalProjects": len(projects_list)},
594
- )
595
- typer.echo(output_json(response, pretty=json_pretty))
596
-
597
- except MsLinearError as e:
598
- error_response = format_error(command, e)
599
- typer.echo(output_json(error_response, pretty=json_pretty))
600
- raise typer.Exit(code=1)
601
-
602
-
603
- if __name__ == "__main__":
604
- app()