@polderlabs/bizar-plugin 0.6.0 → 0.6.1
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/README.md +1 -1
- package/index.ts +60 -3
- package/package.json +1 -1
- package/src/background-state.ts +41 -0
- package/src/background.ts +147 -11
- package/src/commands-impl.ts +4 -4
- package/src/commands.ts +278 -101
- package/src/reasoning-clean.ts +360 -0
- package/src/serve.ts +12 -3
- package/src/tools/bg-spawn.ts +21 -1
- package/tests/attach-handler-bug.test.ts +5 -3
- package/tests/background-state.test.ts +1 -1
- package/tests/background.test.ts +1 -1
- package/tests/block.test.ts +3 -1
- package/tests/canonical-key-order.test.ts +11 -7
- package/tests/event.test.ts +1 -1
- package/tests/fingerprint.test.ts +22 -21
- package/tests/http-client.test.ts +5 -3
- package/tests/options.test.ts +10 -8
- package/tests/settings.test.ts +2 -2
- package/tests/stall-think.test.ts +13 -12
- package/tests/state.test.ts +2 -1
- package/tests/tools/bg-spawn.test.ts +12 -12
- package/tests/update-deadlock.test.ts +1 -1
package/src/commands.ts
CHANGED
|
@@ -70,6 +70,27 @@ export type SideEffect =
|
|
|
70
70
|
args: unknown;
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
+
/** Dialog component types that can be rendered in the dashboard. */
|
|
74
|
+
export type DialogComponent =
|
|
75
|
+
| "visual-plan"
|
|
76
|
+
| "plan-create"
|
|
77
|
+
| "plan-list"
|
|
78
|
+
| "help"
|
|
79
|
+
| "audit"
|
|
80
|
+
| "generic";
|
|
81
|
+
|
|
82
|
+
export interface DialogDescriptor {
|
|
83
|
+
id: string;
|
|
84
|
+
title: string;
|
|
85
|
+
command: string;
|
|
86
|
+
component: DialogComponent;
|
|
87
|
+
data?: Record<string, unknown>;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function generateId(): string {
|
|
91
|
+
return `dlg_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
92
|
+
}
|
|
93
|
+
|
|
73
94
|
export interface SlashCommandResult {
|
|
74
95
|
handled: true;
|
|
75
96
|
/** Text shown to the user / LLM. */
|
|
@@ -78,6 +99,8 @@ export interface SlashCommandResult {
|
|
|
78
99
|
settingsPatch?: Partial<PlanSettings>;
|
|
79
100
|
/** Optional side-effect to perform (file I/O lives in the hook, not here). */
|
|
80
101
|
sideEffect?: SideEffect;
|
|
102
|
+
/** Optional dialog to open in the dashboard instead of showing text. */
|
|
103
|
+
dialog?: DialogDescriptor;
|
|
81
104
|
}
|
|
82
105
|
|
|
83
106
|
/**
|
|
@@ -285,43 +308,82 @@ export function parseSlashCommand(
|
|
|
285
308
|
|
|
286
309
|
function handleVisualPlan(arg: string, ctx: ParseContext): SlashCommandResult {
|
|
287
310
|
const lc = arg.toLowerCase();
|
|
311
|
+
const currentEnabled = ctx.currentSettings.visualPlanEnabled;
|
|
288
312
|
|
|
289
313
|
if (lc === "") {
|
|
290
|
-
// No argument — return current state
|
|
291
|
-
const on = ctx.currentSettings.visualPlanEnabled ? "on" : "off";
|
|
314
|
+
// No argument — return current state as a dialog
|
|
292
315
|
return {
|
|
293
316
|
handled: true,
|
|
294
|
-
response:
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
317
|
+
response: "",
|
|
318
|
+
dialog: {
|
|
319
|
+
id: generateId(),
|
|
320
|
+
title: "Visual Plan",
|
|
321
|
+
command: "/visual-plan",
|
|
322
|
+
component: "visual-plan",
|
|
323
|
+
data: {
|
|
324
|
+
enabled: currentEnabled,
|
|
325
|
+
previousEnabled: currentEnabled,
|
|
326
|
+
defaultTemplate: ctx.currentSettings.defaultTemplate,
|
|
327
|
+
lastUsedSlug: ctx.currentSettings.lastUsedSlug ?? null,
|
|
328
|
+
mode: "status",
|
|
329
|
+
},
|
|
330
|
+
},
|
|
301
331
|
};
|
|
302
332
|
}
|
|
303
333
|
|
|
304
334
|
if (lc === "on" || lc === "true" || lc === "1" || lc === "enable") {
|
|
305
335
|
return {
|
|
306
336
|
handled: true,
|
|
307
|
-
response: "
|
|
337
|
+
response: "",
|
|
308
338
|
settingsPatch: { visualPlanEnabled: true },
|
|
339
|
+
dialog: {
|
|
340
|
+
id: generateId(),
|
|
341
|
+
title: "Visual Plan",
|
|
342
|
+
command: "/visual-plan on",
|
|
343
|
+
component: "visual-plan",
|
|
344
|
+
data: {
|
|
345
|
+
enabled: true,
|
|
346
|
+
previousEnabled: currentEnabled,
|
|
347
|
+
mode: "toggle",
|
|
348
|
+
},
|
|
349
|
+
},
|
|
309
350
|
};
|
|
310
351
|
}
|
|
311
352
|
|
|
312
353
|
if (lc === "off" || lc === "false" || lc === "0" || lc === "disable") {
|
|
313
354
|
return {
|
|
314
355
|
handled: true,
|
|
315
|
-
response: "
|
|
356
|
+
response: "",
|
|
316
357
|
settingsPatch: { visualPlanEnabled: false },
|
|
358
|
+
dialog: {
|
|
359
|
+
id: generateId(),
|
|
360
|
+
title: "Visual Plan",
|
|
361
|
+
command: "/visual-plan off",
|
|
362
|
+
component: "visual-plan",
|
|
363
|
+
data: {
|
|
364
|
+
enabled: false,
|
|
365
|
+
previousEnabled: currentEnabled,
|
|
366
|
+
mode: "toggle",
|
|
367
|
+
},
|
|
368
|
+
},
|
|
317
369
|
};
|
|
318
370
|
}
|
|
319
371
|
|
|
320
372
|
if (lc === "status" || lc === "state" || lc === "?") {
|
|
321
|
-
const on = ctx.currentSettings.visualPlanEnabled ? "on" : "off";
|
|
322
373
|
return {
|
|
323
374
|
handled: true,
|
|
324
|
-
response:
|
|
375
|
+
response: "",
|
|
376
|
+
dialog: {
|
|
377
|
+
id: generateId(),
|
|
378
|
+
title: "Visual Plan",
|
|
379
|
+
command: "/visual-plan status",
|
|
380
|
+
component: "visual-plan",
|
|
381
|
+
data: {
|
|
382
|
+
enabled: currentEnabled,
|
|
383
|
+
previousEnabled: currentEnabled,
|
|
384
|
+
mode: "status",
|
|
385
|
+
},
|
|
386
|
+
},
|
|
325
387
|
};
|
|
326
388
|
}
|
|
327
389
|
|
|
@@ -382,21 +444,30 @@ function handlePlan(arg: string, ctx: ParseContext): SlashCommandResult {
|
|
|
382
444
|
function helpPlan(): SlashCommandResult {
|
|
383
445
|
return {
|
|
384
446
|
handled: true,
|
|
385
|
-
response:
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
447
|
+
response: "",
|
|
448
|
+
dialog: {
|
|
449
|
+
id: generateId(),
|
|
450
|
+
title: "Plan Commands",
|
|
451
|
+
command: "/plan",
|
|
452
|
+
component: "help",
|
|
453
|
+
data: {
|
|
454
|
+
commands: [
|
|
455
|
+
{ cmd: "/plan new <slug> [template]", desc: "Create a new plan" },
|
|
456
|
+
{ cmd: "/plan list", desc: "List all plans in the worktree" },
|
|
457
|
+
{ cmd: "/plan open <slug>", desc: "Open a plan in the viewer" },
|
|
458
|
+
{ cmd: "/plan get <slug>", desc: "Fetch the full canvas" },
|
|
459
|
+
{ cmd: "/plan add <slug> --title T --type kind", desc: "Add an element to a plan" },
|
|
460
|
+
{ cmd: "/plan update <slug> <id> [--x N --y N …]", desc: "Patch an existing element" },
|
|
461
|
+
{ cmd: "/plan delete <slug> <id>", desc: "Remove an element" },
|
|
462
|
+
{ cmd: "/plan comment <slug> [id] \"text\"", desc: "Add a comment" },
|
|
463
|
+
{ cmd: "/plan comments <slug> [id]", desc: "Read comments on a plan" },
|
|
464
|
+
{ cmd: "/plan status <slug> <status>", desc: "Set the plan's status" },
|
|
465
|
+
{ cmd: "/plan wait <slug> [--timeout N]", desc: "Wait for feedback (deferred)" },
|
|
466
|
+
],
|
|
467
|
+
templates: KNOWN_TEMPLATES,
|
|
468
|
+
statuses: PLAN_STATUSES,
|
|
469
|
+
},
|
|
470
|
+
},
|
|
400
471
|
};
|
|
401
472
|
}
|
|
402
473
|
|
|
@@ -406,7 +477,18 @@ function handlePlanNew(args: string[], ctx: ParseContext): SlashCommandResult {
|
|
|
406
477
|
if (args.length === 0 || args[0] === "") {
|
|
407
478
|
return {
|
|
408
479
|
handled: true,
|
|
409
|
-
response: "
|
|
480
|
+
response: "",
|
|
481
|
+
dialog: {
|
|
482
|
+
id: generateId(),
|
|
483
|
+
title: "Create New Plan",
|
|
484
|
+
command: "/plan new",
|
|
485
|
+
component: "plan-create",
|
|
486
|
+
data: {
|
|
487
|
+
templates: [...KNOWN_TEMPLATES],
|
|
488
|
+
defaultTemplate: ctx.currentSettings.defaultTemplate,
|
|
489
|
+
suggestedSlug: "",
|
|
490
|
+
},
|
|
491
|
+
},
|
|
410
492
|
};
|
|
411
493
|
}
|
|
412
494
|
|
|
@@ -434,24 +516,27 @@ function handlePlanNew(args: string[], ctx: ParseContext): SlashCommandResult {
|
|
|
434
516
|
template = candidate;
|
|
435
517
|
}
|
|
436
518
|
|
|
437
|
-
// The response surfaces the resolved template name (the user-supplied
|
|
438
|
-
// argument, or the user's current default). The sideEffect carries
|
|
439
|
-
// the explicit `null` so the executor knows to fall back to
|
|
440
|
-
// `currentSettings.defaultTemplate` at write time.
|
|
441
519
|
const resolvedTemplate = template ?? ctx.currentSettings.defaultTemplate;
|
|
442
520
|
|
|
443
521
|
return {
|
|
444
522
|
handled: true,
|
|
445
|
-
response:
|
|
446
|
-
`Plan "${titleCase(slug)}" (slug: ${slug}) will be created with the ` +
|
|
447
|
-
`"${resolvedTemplate}" template.\n` +
|
|
448
|
-
`After creation, use /plan open ${slug} to get the URL.`,
|
|
523
|
+
response: "",
|
|
449
524
|
sideEffect: {
|
|
450
525
|
kind: "create_plan",
|
|
451
526
|
slug,
|
|
452
527
|
template,
|
|
453
528
|
},
|
|
454
529
|
settingsPatch: { lastUsedSlug: slug },
|
|
530
|
+
dialog: {
|
|
531
|
+
id: generateId(),
|
|
532
|
+
title: "Plan Created",
|
|
533
|
+
command: `/plan new ${slug}`,
|
|
534
|
+
component: "generic",
|
|
535
|
+
data: {
|
|
536
|
+
message: `Plan "${titleCase(slug)}" created with the "${resolvedTemplate}" template.`,
|
|
537
|
+
detail: `Use /plan open ${slug} to open it.`,
|
|
538
|
+
},
|
|
539
|
+
},
|
|
455
540
|
};
|
|
456
541
|
}
|
|
457
542
|
|
|
@@ -459,19 +544,20 @@ function handlePlanNew(args: string[], ctx: ParseContext): SlashCommandResult {
|
|
|
459
544
|
|
|
460
545
|
function handlePlanList(ctx: ParseContext): SlashCommandResult {
|
|
461
546
|
const slugs = ctx.availablePlanSlugs ?? [];
|
|
462
|
-
if (slugs.length === 0) {
|
|
463
|
-
return {
|
|
464
|
-
handled: true,
|
|
465
|
-
response:
|
|
466
|
-
"No plans found in this worktree. Use /plan new <slug> to create one.",
|
|
467
|
-
sideEffect: { kind: "list_plans" },
|
|
468
|
-
};
|
|
469
|
-
}
|
|
470
|
-
const lines = slugs.map((s) => ` - ${s}`);
|
|
471
547
|
return {
|
|
472
548
|
handled: true,
|
|
473
|
-
response:
|
|
549
|
+
response: "",
|
|
474
550
|
sideEffect: { kind: "list_plans" },
|
|
551
|
+
dialog: {
|
|
552
|
+
id: generateId(),
|
|
553
|
+
title: "Plans",
|
|
554
|
+
command: "/plan list",
|
|
555
|
+
component: "plan-list",
|
|
556
|
+
data: {
|
|
557
|
+
plans: slugs,
|
|
558
|
+
count: slugs.length,
|
|
559
|
+
},
|
|
560
|
+
},
|
|
475
561
|
};
|
|
476
562
|
}
|
|
477
563
|
|
|
@@ -498,16 +584,22 @@ function handlePlanOpen(args: string[], ctx: ParseContext): SlashCommandResult {
|
|
|
498
584
|
|
|
499
585
|
return {
|
|
500
586
|
handled: true,
|
|
501
|
-
response:
|
|
502
|
-
`Plan URL: ${url}\n` +
|
|
503
|
-
`(v0.5.0 MVP — server startup is a future enhancement; the URL is ` +
|
|
504
|
-
`informational. Use "bizar plan open ${slug}" in the terminal to ` +
|
|
505
|
-
`start the local viewer.)`,
|
|
587
|
+
response: "",
|
|
506
588
|
settingsPatch: { lastUsedSlug: slug },
|
|
507
589
|
sideEffect: {
|
|
508
590
|
kind: "open_plan_url",
|
|
509
591
|
slug,
|
|
510
592
|
},
|
|
593
|
+
dialog: {
|
|
594
|
+
id: generateId(),
|
|
595
|
+
title: "Opening Plan",
|
|
596
|
+
command: `/plan open ${slug}`,
|
|
597
|
+
component: "generic",
|
|
598
|
+
data: {
|
|
599
|
+
message: `Opening plan: ${slug}`,
|
|
600
|
+
url,
|
|
601
|
+
},
|
|
602
|
+
},
|
|
511
603
|
};
|
|
512
604
|
}
|
|
513
605
|
|
|
@@ -526,13 +618,22 @@ function handlePlanGet(args: string[]): SlashCommandResult {
|
|
|
526
618
|
}
|
|
527
619
|
return {
|
|
528
620
|
handled: true,
|
|
529
|
-
response:
|
|
621
|
+
response: "",
|
|
530
622
|
sideEffect: {
|
|
531
623
|
kind: "tool_invocation",
|
|
532
624
|
toolName: "bizar_plan_action",
|
|
533
625
|
args: { action: "get_canvas", planSlug: slug },
|
|
534
626
|
},
|
|
535
627
|
settingsPatch: { lastUsedSlug: slug },
|
|
628
|
+
dialog: {
|
|
629
|
+
id: generateId(),
|
|
630
|
+
title: "Plan Canvas",
|
|
631
|
+
command: `/plan get ${slug}`,
|
|
632
|
+
component: "generic",
|
|
633
|
+
data: {
|
|
634
|
+
message: `Fetching canvas for plan "${slug}"…`,
|
|
635
|
+
},
|
|
636
|
+
},
|
|
536
637
|
};
|
|
537
638
|
}
|
|
538
639
|
|
|
@@ -591,13 +692,22 @@ function handlePlanAdd(args: string[]): SlashCommandResult {
|
|
|
591
692
|
}
|
|
592
693
|
return {
|
|
593
694
|
handled: true,
|
|
594
|
-
response:
|
|
695
|
+
response: "",
|
|
595
696
|
sideEffect: {
|
|
596
697
|
kind: "tool_invocation",
|
|
597
698
|
toolName: "bizar_plan_action",
|
|
598
699
|
args: { action: "add_element", planSlug: slug, element },
|
|
599
700
|
},
|
|
600
701
|
settingsPatch: { lastUsedSlug: slug },
|
|
702
|
+
dialog: {
|
|
703
|
+
id: generateId(),
|
|
704
|
+
title: "Element Added",
|
|
705
|
+
command: `/plan add ${slug}`,
|
|
706
|
+
component: "generic",
|
|
707
|
+
data: {
|
|
708
|
+
message: `Adding element to plan "${slug}"…`,
|
|
709
|
+
},
|
|
710
|
+
},
|
|
601
711
|
};
|
|
602
712
|
}
|
|
603
713
|
|
|
@@ -637,13 +747,22 @@ function handlePlanUpdate(args: string[]): SlashCommandResult {
|
|
|
637
747
|
}
|
|
638
748
|
return {
|
|
639
749
|
handled: true,
|
|
640
|
-
response:
|
|
750
|
+
response: "",
|
|
641
751
|
sideEffect: {
|
|
642
752
|
kind: "tool_invocation",
|
|
643
753
|
toolName: "bizar_plan_action",
|
|
644
754
|
args: { action: "update_element", planSlug: slug, elementId, element },
|
|
645
755
|
},
|
|
646
756
|
settingsPatch: { lastUsedSlug: slug },
|
|
757
|
+
dialog: {
|
|
758
|
+
id: generateId(),
|
|
759
|
+
title: "Element Updated",
|
|
760
|
+
command: `/plan update ${slug}`,
|
|
761
|
+
component: "generic",
|
|
762
|
+
data: {
|
|
763
|
+
message: `Updating element ${elementId} in plan "${slug}"…`,
|
|
764
|
+
},
|
|
765
|
+
},
|
|
647
766
|
};
|
|
648
767
|
}
|
|
649
768
|
|
|
@@ -666,13 +785,22 @@ function handlePlanDelete(args: string[]): SlashCommandResult {
|
|
|
666
785
|
}
|
|
667
786
|
return {
|
|
668
787
|
handled: true,
|
|
669
|
-
response:
|
|
788
|
+
response: "",
|
|
670
789
|
sideEffect: {
|
|
671
790
|
kind: "tool_invocation",
|
|
672
791
|
toolName: "bizar_plan_action",
|
|
673
792
|
args: { action: "delete_element", planSlug: slug, elementId },
|
|
674
793
|
},
|
|
675
794
|
settingsPatch: { lastUsedSlug: slug },
|
|
795
|
+
dialog: {
|
|
796
|
+
id: generateId(),
|
|
797
|
+
title: "Element Deleted",
|
|
798
|
+
command: `/plan delete ${slug}`,
|
|
799
|
+
component: "generic",
|
|
800
|
+
data: {
|
|
801
|
+
message: `Deleting element ${elementId} from plan "${slug}"…`,
|
|
802
|
+
},
|
|
803
|
+
},
|
|
676
804
|
};
|
|
677
805
|
}
|
|
678
806
|
|
|
@@ -734,10 +862,7 @@ function commentSideEffect(
|
|
|
734
862
|
): SlashCommandResult {
|
|
735
863
|
return {
|
|
736
864
|
handled: true,
|
|
737
|
-
response:
|
|
738
|
-
elementId === null
|
|
739
|
-
? `Adding canvas-pinned comment to plan "${slug}"…`
|
|
740
|
-
: `Adding comment to element ${elementId} on plan "${slug}"…`,
|
|
865
|
+
response: "",
|
|
741
866
|
sideEffect: {
|
|
742
867
|
kind: "tool_invocation",
|
|
743
868
|
toolName: "bizar_plan_action",
|
|
@@ -752,6 +877,18 @@ function commentSideEffect(
|
|
|
752
877
|
},
|
|
753
878
|
},
|
|
754
879
|
settingsPatch: { lastUsedSlug: slug },
|
|
880
|
+
dialog: {
|
|
881
|
+
id: generateId(),
|
|
882
|
+
title: "Comment Added",
|
|
883
|
+
command: `/plan comment ${slug}`,
|
|
884
|
+
component: "generic",
|
|
885
|
+
data: {
|
|
886
|
+
message:
|
|
887
|
+
elementId === null
|
|
888
|
+
? `Adding canvas-pinned comment to plan "${slug}"…`
|
|
889
|
+
: `Adding comment to element ${elementId} on plan "${slug}"…`,
|
|
890
|
+
},
|
|
891
|
+
},
|
|
755
892
|
};
|
|
756
893
|
}
|
|
757
894
|
|
|
@@ -771,16 +908,25 @@ function handlePlanComments(args: string[]): SlashCommandResult {
|
|
|
771
908
|
const elementId = args.length >= 2 ? args[1]! : undefined;
|
|
772
909
|
return {
|
|
773
910
|
handled: true,
|
|
774
|
-
response:
|
|
775
|
-
elementId === undefined
|
|
776
|
-
? `Reading comments on plan "${slug}"…`
|
|
777
|
-
: `Reading comments on element ${elementId} of plan "${slug}"…`,
|
|
911
|
+
response: "",
|
|
778
912
|
sideEffect: {
|
|
779
913
|
kind: "tool_invocation",
|
|
780
914
|
toolName: "bizar_get_plan_comments",
|
|
781
915
|
args: elementId === undefined ? { planSlug: slug } : { planSlug: slug, elementId },
|
|
782
916
|
},
|
|
783
917
|
settingsPatch: { lastUsedSlug: slug },
|
|
918
|
+
dialog: {
|
|
919
|
+
id: generateId(),
|
|
920
|
+
title: "Comments",
|
|
921
|
+
command: `/plan comments ${slug}`,
|
|
922
|
+
component: "generic",
|
|
923
|
+
data: {
|
|
924
|
+
message:
|
|
925
|
+
elementId === undefined
|
|
926
|
+
? `Reading comments on plan "${slug}"…`
|
|
927
|
+
: `Reading comments on element ${elementId} of plan "${slug}"…`,
|
|
928
|
+
},
|
|
929
|
+
},
|
|
784
930
|
};
|
|
785
931
|
}
|
|
786
932
|
|
|
@@ -809,13 +955,22 @@ function handlePlanStatus(args: string[]): SlashCommandResult {
|
|
|
809
955
|
}
|
|
810
956
|
return {
|
|
811
957
|
handled: true,
|
|
812
|
-
response:
|
|
958
|
+
response: "",
|
|
813
959
|
sideEffect: {
|
|
814
960
|
kind: "tool_invocation",
|
|
815
961
|
toolName: "bizar_plan_action",
|
|
816
962
|
args: { action: "set_status", planSlug: slug, status },
|
|
817
963
|
},
|
|
818
964
|
settingsPatch: { lastUsedSlug: slug },
|
|
965
|
+
dialog: {
|
|
966
|
+
id: generateId(),
|
|
967
|
+
title: "Status Updated",
|
|
968
|
+
command: `/plan status ${slug}`,
|
|
969
|
+
component: "generic",
|
|
970
|
+
data: {
|
|
971
|
+
message: `Setting plan "${slug}" status to "${status}"…`,
|
|
972
|
+
},
|
|
973
|
+
},
|
|
819
974
|
};
|
|
820
975
|
}
|
|
821
976
|
|
|
@@ -858,7 +1013,7 @@ function handlePlanWait(args: string[]): SlashCommandResult {
|
|
|
858
1013
|
*
|
|
859
1014
|
* Behavior:
|
|
860
1015
|
* - `/bizar` (no args) — emits a `launch_dashboard` side-effect. The
|
|
861
|
-
* executor spawns `bizar
|
|
1016
|
+
* executor spawns `bizar dash start` as a detached child
|
|
862
1017
|
* process, then the host surfaces the URL in the response.
|
|
863
1018
|
* - `/bizar <args>` — passes the args to the menu command file. Today
|
|
864
1019
|
* the menu routes intent (`/explain`, `/plan`, `/audit`, etc.); the
|
|
@@ -876,25 +1031,45 @@ function handleBizar(arg: string, ctx: ParseContext): SlashCommandResult {
|
|
|
876
1031
|
const port = ctx.defaultPort ?? 4321;
|
|
877
1032
|
return {
|
|
878
1033
|
handled: true,
|
|
879
|
-
response:
|
|
880
|
-
`🪩 Bizar dashboard launching in the background.\n` +
|
|
881
|
-
`Visit http://localhost:${port}/ once the server is ready.\n` +
|
|
882
|
-
`(If the browser did not open automatically, click the URL above.)`,
|
|
1034
|
+
response: "",
|
|
883
1035
|
sideEffect: {
|
|
884
1036
|
kind: "launch_dashboard",
|
|
885
1037
|
defaultPort: port,
|
|
886
1038
|
},
|
|
1039
|
+
dialog: {
|
|
1040
|
+
id: generateId(),
|
|
1041
|
+
title: "Dashboard",
|
|
1042
|
+
command: "/bizar",
|
|
1043
|
+
component: "generic",
|
|
1044
|
+
data: {
|
|
1045
|
+
message: "Dashboard launching in the background…",
|
|
1046
|
+
url: `http://localhost:${port}/`,
|
|
1047
|
+
},
|
|
1048
|
+
},
|
|
887
1049
|
};
|
|
888
1050
|
}
|
|
889
1051
|
|
|
890
1052
|
// With args, defer to the menu command file shipped with the CLI.
|
|
891
1053
|
return {
|
|
892
1054
|
handled: true,
|
|
893
|
-
response:
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
1055
|
+
response: "",
|
|
1056
|
+
dialog: {
|
|
1057
|
+
id: generateId(),
|
|
1058
|
+
title: "Bizar Commands",
|
|
1059
|
+
command: `/bizar ${trimmed}`,
|
|
1060
|
+
component: "help",
|
|
1061
|
+
data: {
|
|
1062
|
+
commands: [
|
|
1063
|
+
{ cmd: "/bizar", desc: "Launch the Bizar dashboard" },
|
|
1064
|
+
{ cmd: "/bizar explain <question>", desc: "Read-only code Q&A" },
|
|
1065
|
+
{ cmd: "/bizar plan <args>", desc: "Manage plans" },
|
|
1066
|
+
{ cmd: "/bizar audit", desc: "Run security audit" },
|
|
1067
|
+
{ cmd: "/bizar learn", desc: "Extract patterns from session" },
|
|
1068
|
+
{ cmd: "/bizar init", desc: "Initialize .bizar/ in this project" },
|
|
1069
|
+
{ cmd: "/bizar pr-review", desc: "PR review" },
|
|
1070
|
+
],
|
|
1071
|
+
},
|
|
1072
|
+
},
|
|
898
1073
|
};
|
|
899
1074
|
}
|
|
900
1075
|
|
|
@@ -903,31 +1078,33 @@ function handleBizar(arg: string, ctx: ParseContext): SlashCommandResult {
|
|
|
903
1078
|
function helpResult(): SlashCommandResult {
|
|
904
1079
|
return {
|
|
905
1080
|
handled: true,
|
|
906
|
-
response:
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
1081
|
+
response: "",
|
|
1082
|
+
dialog: {
|
|
1083
|
+
id: generateId(),
|
|
1084
|
+
title: "Bizar Commands",
|
|
1085
|
+
command: "/help",
|
|
1086
|
+
component: "help",
|
|
1087
|
+
data: {
|
|
1088
|
+
commands: [
|
|
1089
|
+
{ cmd: "/visual-plan [on|off|status]", desc: "Toggle or view visual plan mode" },
|
|
1090
|
+
{ cmd: "/plan new <slug> [template]", desc: "Create a new plan" },
|
|
1091
|
+
{ cmd: "/plan list", desc: "List all plans in the worktree" },
|
|
1092
|
+
{ cmd: "/plan open <slug>", desc: "Open a plan in the viewer" },
|
|
1093
|
+
{ cmd: "/plan get <slug>", desc: "Fetch the full canvas" },
|
|
1094
|
+
{ cmd: "/plan add <slug> --title T --type kind", desc: "Add an element to a plan" },
|
|
1095
|
+
{ cmd: "/plan update <slug> <id> [flags]", desc: "Patch an existing element" },
|
|
1096
|
+
{ cmd: "/plan delete <slug> <id>", desc: "Remove an element" },
|
|
1097
|
+
{ cmd: "/plan comment <slug> [id] \"text\"", desc: "Add a comment" },
|
|
1098
|
+
{ cmd: "/plan comments <slug> [id]", desc: "Read comments on a plan" },
|
|
1099
|
+
{ cmd: "/plan status <slug> <status>", desc: "Set the plan's status" },
|
|
1100
|
+
{ cmd: "/plan wait <slug> [--timeout N]", desc: "Wait for feedback (deferred)" },
|
|
1101
|
+
{ cmd: "/bizar", desc: "Launch the Bizar dashboard" },
|
|
1102
|
+
{ cmd: "/bizar <args>", desc: "Route a request via the menu" },
|
|
1103
|
+
{ cmd: "/help | /commands", desc: "Show this help" },
|
|
1104
|
+
],
|
|
1105
|
+
templates: [...KNOWN_TEMPLATES],
|
|
1106
|
+
statuses: [...PLAN_STATUSES],
|
|
1107
|
+
},
|
|
1108
|
+
},
|
|
932
1109
|
};
|
|
933
1110
|
}
|