speckeeper 0.10.1 → 0.11.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 -0
- package/cli-contract.yaml +206 -208
- package/dist/cli.js +1505 -80
- package/dist/cli.js.map +1 -1
- package/dist/{config-api-CLVjdgIP.d.ts → config-api-coyCX1SB.d.ts} +21 -1
- package/dist/dsl/index.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +75 -3
- package/dist/index.js.map +1 -1
- package/docs/cli-reference.md +107 -154
- package/docs/design/cli-commands.md +36 -0
- package/docs/design/functional-requirements.md +101 -3
- package/docs/design/nonfunctional-requirements.md +3 -3
- package/docs/design/test-refs.md +26 -0
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { Command } from 'commander';
|
|
4
3
|
import { readFileSync, existsSync, writeFileSync, mkdirSync, readdirSync, statSync } from 'fs';
|
|
5
|
-
import { dirname, join, resolve, isAbsolute } from 'path';
|
|
4
|
+
import { dirname, join, resolve, basename, isAbsolute } from 'path';
|
|
6
5
|
import { fileURLToPath } from 'url';
|
|
6
|
+
import { Command } from 'commander';
|
|
7
7
|
import chalk4 from 'chalk';
|
|
8
|
-
import { parse } from 'yaml';
|
|
8
|
+
import { stringify, parse } from 'yaml';
|
|
9
9
|
import 'crypto';
|
|
10
10
|
import { glob } from 'glob';
|
|
11
11
|
import nodeSqlParser from 'node-sql-parser';
|
|
@@ -535,6 +535,1298 @@ var init_dsl = __esm({
|
|
|
535
535
|
init_workflows();
|
|
536
536
|
}
|
|
537
537
|
});
|
|
538
|
+
|
|
539
|
+
// src/generated/policy-runtime.ts
|
|
540
|
+
var RISK_ORDER = {
|
|
541
|
+
low: 0,
|
|
542
|
+
medium: 1,
|
|
543
|
+
high: 2,
|
|
544
|
+
critical: 3
|
|
545
|
+
};
|
|
546
|
+
function maxRiskLevel(...levels) {
|
|
547
|
+
let max = "low";
|
|
548
|
+
for (const level of levels) {
|
|
549
|
+
if (RISK_ORDER[level] > RISK_ORDER[max]) {
|
|
550
|
+
max = level;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return max;
|
|
554
|
+
}
|
|
555
|
+
function isOptionActive(definition, value, specified) {
|
|
556
|
+
const schemaType = definition.schema?.type;
|
|
557
|
+
if (schemaType === "boolean") {
|
|
558
|
+
return value === true;
|
|
559
|
+
}
|
|
560
|
+
if (definition.repeatable) {
|
|
561
|
+
return specified && Array.isArray(value) && value.length > 0;
|
|
562
|
+
}
|
|
563
|
+
return specified && value != null;
|
|
564
|
+
}
|
|
565
|
+
function derivePolicy(input) {
|
|
566
|
+
const sideEffects = /* @__PURE__ */ new Set();
|
|
567
|
+
const reads = [];
|
|
568
|
+
const writes = [];
|
|
569
|
+
const networkEffects = [];
|
|
570
|
+
const riskLevels = [];
|
|
571
|
+
let executionMode;
|
|
572
|
+
let explicitConfirmation;
|
|
573
|
+
if (input.commandEffects) {
|
|
574
|
+
const ce = input.commandEffects;
|
|
575
|
+
riskLevels.push(ce.riskLevel ?? "low");
|
|
576
|
+
if (ce.writes) {
|
|
577
|
+
sideEffects.add("file_write");
|
|
578
|
+
for (const w of ce.writes) {
|
|
579
|
+
writes.push({
|
|
580
|
+
kind: "semantic",
|
|
581
|
+
target: w.target,
|
|
582
|
+
description: w.description,
|
|
583
|
+
overwrite: w.overwrite,
|
|
584
|
+
destructive: w.destructive,
|
|
585
|
+
...w.idempotent !== void 0 ? { idempotent: w.idempotent } : {},
|
|
586
|
+
...w.idempotencyKey ? { idempotencyKey: w.idempotencyKey } : {},
|
|
587
|
+
...w.idempotentNote ? { idempotentNote: w.idempotentNote } : {},
|
|
588
|
+
source: `command:${input.commandId}`
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
if (ce.reads) {
|
|
593
|
+
for (const r of ce.reads) {
|
|
594
|
+
reads.push({
|
|
595
|
+
kind: "semantic",
|
|
596
|
+
target: r.target,
|
|
597
|
+
description: r.description,
|
|
598
|
+
source: `command:${input.commandId}`
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
if (ce.network) {
|
|
603
|
+
sideEffects.add("network");
|
|
604
|
+
if (typeof ce.network === "object") {
|
|
605
|
+
networkEffects.push({
|
|
606
|
+
...ce.network.description ? { description: ce.network.description } : {},
|
|
607
|
+
...ce.network.domains ? { domains: ce.network.domains } : {},
|
|
608
|
+
...ce.network.idempotent !== void 0 ? { idempotent: ce.network.idempotent } : {},
|
|
609
|
+
...ce.network.idempotencyKey ? { idempotencyKey: ce.network.idempotencyKey } : {},
|
|
610
|
+
...ce.network.idempotentNote ? { idempotentNote: ce.network.idempotentNote } : {},
|
|
611
|
+
source: `command:${input.commandId}`
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
if (ce.executionMode) {
|
|
616
|
+
executionMode = ce.executionMode;
|
|
617
|
+
}
|
|
618
|
+
if (ce.requiresConfirmation !== void 0) {
|
|
619
|
+
explicitConfirmation = ce.requiresConfirmation;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
for (const [optName, optInput] of Object.entries(input.options)) {
|
|
623
|
+
const { definition, value, specified } = optInput;
|
|
624
|
+
const active = isOptionActive(definition, value, specified);
|
|
625
|
+
if (!active) continue;
|
|
626
|
+
if (definition.file) {
|
|
627
|
+
const filePath = typeof value === "string" ? value : void 0;
|
|
628
|
+
const mode = definition.file.mode;
|
|
629
|
+
if (mode === "read" || mode === "readWrite") {
|
|
630
|
+
reads.push({
|
|
631
|
+
kind: "option-file",
|
|
632
|
+
option: optName,
|
|
633
|
+
path: filePath,
|
|
634
|
+
source: `option:${optName}`
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
if (mode === "write" || mode === "append" || mode === "readWrite") {
|
|
638
|
+
sideEffects.add("file_write");
|
|
639
|
+
writes.push({
|
|
640
|
+
kind: "option-file",
|
|
641
|
+
option: optName,
|
|
642
|
+
path: filePath,
|
|
643
|
+
mode,
|
|
644
|
+
source: `option:${optName}`
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
if (definition.effects) {
|
|
649
|
+
const eff = definition.effects;
|
|
650
|
+
riskLevels.push(eff.riskLevel ?? "low");
|
|
651
|
+
if (eff.writes) {
|
|
652
|
+
sideEffects.add("file_write");
|
|
653
|
+
for (const w of eff.writes) {
|
|
654
|
+
writes.push({
|
|
655
|
+
kind: "semantic",
|
|
656
|
+
target: w.target,
|
|
657
|
+
description: w.description,
|
|
658
|
+
overwrite: w.overwrite,
|
|
659
|
+
destructive: w.destructive,
|
|
660
|
+
...w.idempotent !== void 0 ? { idempotent: w.idempotent } : {},
|
|
661
|
+
...w.idempotencyKey ? { idempotencyKey: w.idempotencyKey } : {},
|
|
662
|
+
...w.idempotentNote ? { idempotentNote: w.idempotentNote } : {},
|
|
663
|
+
source: `option:${optName}`
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
if (eff.reads) {
|
|
668
|
+
for (const r of eff.reads) {
|
|
669
|
+
reads.push({
|
|
670
|
+
kind: "semantic",
|
|
671
|
+
target: r.target,
|
|
672
|
+
description: r.description,
|
|
673
|
+
source: `option:${optName}`
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
if (eff.network) {
|
|
678
|
+
sideEffects.add("network");
|
|
679
|
+
if (typeof eff.network === "object") {
|
|
680
|
+
networkEffects.push({
|
|
681
|
+
...eff.network.description ? { description: eff.network.description } : {},
|
|
682
|
+
...eff.network.domains ? { domains: eff.network.domains } : {},
|
|
683
|
+
...eff.network.idempotent !== void 0 ? { idempotent: eff.network.idempotent } : {},
|
|
684
|
+
...eff.network.idempotencyKey ? { idempotencyKey: eff.network.idempotencyKey } : {},
|
|
685
|
+
...eff.network.idempotentNote ? { idempotentNote: eff.network.idempotentNote } : {},
|
|
686
|
+
source: `option:${optName}`
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
if (eff.executionMode && !executionMode) {
|
|
691
|
+
executionMode = eff.executionMode;
|
|
692
|
+
}
|
|
693
|
+
if (eff.requiresConfirmation !== void 0 && explicitConfirmation === void 0) {
|
|
694
|
+
explicitConfirmation = eff.requiresConfirmation;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
const finalRiskLevel = riskLevels.length > 0 ? maxRiskLevel(...riskLevels) : "low";
|
|
699
|
+
const requiresConfirmation = explicitConfirmation ?? (finalRiskLevel === "high" || finalRiskLevel === "critical");
|
|
700
|
+
let requiresSecrets;
|
|
701
|
+
if (input.env) {
|
|
702
|
+
const secrets = [];
|
|
703
|
+
for (const [envName, envVar] of Object.entries(input.env)) {
|
|
704
|
+
if (envVar.sensitive) {
|
|
705
|
+
secrets.push(envName);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
if (secrets.length > 0) {
|
|
709
|
+
requiresSecrets = secrets;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
const semanticWrites = writes.filter((w) => w.kind === "semantic");
|
|
713
|
+
const idempotent = semanticWrites.every((w) => w.idempotent === true) && networkEffects.every((n) => n.idempotent === true);
|
|
714
|
+
return {
|
|
715
|
+
riskLevel: finalRiskLevel,
|
|
716
|
+
requiresConfirmation,
|
|
717
|
+
idempotent,
|
|
718
|
+
sideEffects: [...sideEffects],
|
|
719
|
+
reads,
|
|
720
|
+
writes,
|
|
721
|
+
...networkEffects.length > 0 ? { network: networkEffects } : {},
|
|
722
|
+
...executionMode ? { executionMode } : {},
|
|
723
|
+
...requiresSecrets ? { requiresSecrets } : {}
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// src/generated/policy.ts
|
|
728
|
+
var commandDefinitions = {
|
|
729
|
+
"init": {
|
|
730
|
+
"effects": {
|
|
731
|
+
"riskLevel": "medium",
|
|
732
|
+
"writes": [
|
|
733
|
+
{
|
|
734
|
+
"target": "speckeeper.config.ts, design/ directory",
|
|
735
|
+
"description": "generates config and starter template files",
|
|
736
|
+
"idempotent": false
|
|
737
|
+
}
|
|
738
|
+
]
|
|
739
|
+
},
|
|
740
|
+
"options": [
|
|
741
|
+
{
|
|
742
|
+
"name": "force",
|
|
743
|
+
"schema": {
|
|
744
|
+
"type": "boolean",
|
|
745
|
+
"default": false
|
|
746
|
+
},
|
|
747
|
+
"effects": {
|
|
748
|
+
"riskLevel": "high",
|
|
749
|
+
"writes": [
|
|
750
|
+
{
|
|
751
|
+
"target": "existing project files",
|
|
752
|
+
"description": "overwrites existing config and design files",
|
|
753
|
+
"overwrite": true,
|
|
754
|
+
"destructive": true
|
|
755
|
+
}
|
|
756
|
+
]
|
|
757
|
+
}
|
|
758
|
+
},
|
|
759
|
+
{
|
|
760
|
+
"name": "format",
|
|
761
|
+
"schema": {
|
|
762
|
+
"type": "string",
|
|
763
|
+
"default": "ts",
|
|
764
|
+
"enum": [
|
|
765
|
+
"ts",
|
|
766
|
+
"yaml"
|
|
767
|
+
]
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
],
|
|
771
|
+
"env": {
|
|
772
|
+
"CURSOR_API_KEY": {
|
|
773
|
+
"sensitive": true
|
|
774
|
+
},
|
|
775
|
+
"GEMINI_API_KEY": {
|
|
776
|
+
"sensitive": true
|
|
777
|
+
},
|
|
778
|
+
"OPENAI_API_KEY": {
|
|
779
|
+
"sensitive": true
|
|
780
|
+
},
|
|
781
|
+
"ANTHROPIC_API_KEY": {
|
|
782
|
+
"sensitive": true
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
},
|
|
786
|
+
"build": {
|
|
787
|
+
"effects": {
|
|
788
|
+
"riskLevel": "low",
|
|
789
|
+
"writes": [
|
|
790
|
+
{
|
|
791
|
+
"target": "docs/ directory",
|
|
792
|
+
"description": "generated Markdown documentation files",
|
|
793
|
+
"overwrite": true,
|
|
794
|
+
"idempotent": true
|
|
795
|
+
}
|
|
796
|
+
]
|
|
797
|
+
},
|
|
798
|
+
"options": [
|
|
799
|
+
{
|
|
800
|
+
"name": "config",
|
|
801
|
+
"schema": {
|
|
802
|
+
"type": "string"
|
|
803
|
+
},
|
|
804
|
+
"file": {
|
|
805
|
+
"mode": "read",
|
|
806
|
+
"exists": true,
|
|
807
|
+
"encoding": "utf-8"
|
|
808
|
+
}
|
|
809
|
+
},
|
|
810
|
+
{
|
|
811
|
+
"name": "output",
|
|
812
|
+
"schema": {
|
|
813
|
+
"type": "string",
|
|
814
|
+
"default": "."
|
|
815
|
+
}
|
|
816
|
+
},
|
|
817
|
+
{
|
|
818
|
+
"name": "format",
|
|
819
|
+
"schema": {
|
|
820
|
+
"type": "string",
|
|
821
|
+
"default": "both",
|
|
822
|
+
"enum": [
|
|
823
|
+
"markdown",
|
|
824
|
+
"json",
|
|
825
|
+
"both"
|
|
826
|
+
]
|
|
827
|
+
}
|
|
828
|
+
},
|
|
829
|
+
{
|
|
830
|
+
"name": "watch",
|
|
831
|
+
"schema": {
|
|
832
|
+
"type": "boolean",
|
|
833
|
+
"default": false
|
|
834
|
+
},
|
|
835
|
+
"effects": {
|
|
836
|
+
"executionMode": "watch"
|
|
837
|
+
}
|
|
838
|
+
},
|
|
839
|
+
{
|
|
840
|
+
"name": "verbose",
|
|
841
|
+
"schema": {
|
|
842
|
+
"type": "boolean",
|
|
843
|
+
"default": false
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
],
|
|
847
|
+
"env": {
|
|
848
|
+
"CURSOR_API_KEY": {
|
|
849
|
+
"sensitive": true
|
|
850
|
+
},
|
|
851
|
+
"GEMINI_API_KEY": {
|
|
852
|
+
"sensitive": true
|
|
853
|
+
},
|
|
854
|
+
"OPENAI_API_KEY": {
|
|
855
|
+
"sensitive": true
|
|
856
|
+
},
|
|
857
|
+
"ANTHROPIC_API_KEY": {
|
|
858
|
+
"sensitive": true
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
},
|
|
862
|
+
"lint": {
|
|
863
|
+
"options": [
|
|
864
|
+
{
|
|
865
|
+
"name": "config",
|
|
866
|
+
"schema": {
|
|
867
|
+
"type": "string"
|
|
868
|
+
},
|
|
869
|
+
"file": {
|
|
870
|
+
"mode": "read",
|
|
871
|
+
"exists": true,
|
|
872
|
+
"encoding": "utf-8"
|
|
873
|
+
}
|
|
874
|
+
},
|
|
875
|
+
{
|
|
876
|
+
"name": "phase",
|
|
877
|
+
"schema": {
|
|
878
|
+
"type": "string",
|
|
879
|
+
"enum": [
|
|
880
|
+
"REQ",
|
|
881
|
+
"HLD",
|
|
882
|
+
"LLD",
|
|
883
|
+
"OPS"
|
|
884
|
+
]
|
|
885
|
+
}
|
|
886
|
+
},
|
|
887
|
+
{
|
|
888
|
+
"name": "strict",
|
|
889
|
+
"schema": {
|
|
890
|
+
"type": "boolean",
|
|
891
|
+
"default": false
|
|
892
|
+
}
|
|
893
|
+
},
|
|
894
|
+
{
|
|
895
|
+
"name": "fix",
|
|
896
|
+
"schema": {
|
|
897
|
+
"type": "boolean",
|
|
898
|
+
"default": false
|
|
899
|
+
}
|
|
900
|
+
},
|
|
901
|
+
{
|
|
902
|
+
"name": "format",
|
|
903
|
+
"schema": {
|
|
904
|
+
"type": "string",
|
|
905
|
+
"default": "text",
|
|
906
|
+
"enum": [
|
|
907
|
+
"text",
|
|
908
|
+
"json",
|
|
909
|
+
"github"
|
|
910
|
+
]
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
],
|
|
914
|
+
"env": {
|
|
915
|
+
"CURSOR_API_KEY": {
|
|
916
|
+
"sensitive": true
|
|
917
|
+
},
|
|
918
|
+
"GEMINI_API_KEY": {
|
|
919
|
+
"sensitive": true
|
|
920
|
+
},
|
|
921
|
+
"OPENAI_API_KEY": {
|
|
922
|
+
"sensitive": true
|
|
923
|
+
},
|
|
924
|
+
"ANTHROPIC_API_KEY": {
|
|
925
|
+
"sensitive": true
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
},
|
|
929
|
+
"drift": {
|
|
930
|
+
"options": [
|
|
931
|
+
{
|
|
932
|
+
"name": "config",
|
|
933
|
+
"schema": {
|
|
934
|
+
"type": "string"
|
|
935
|
+
},
|
|
936
|
+
"file": {
|
|
937
|
+
"mode": "read",
|
|
938
|
+
"exists": true,
|
|
939
|
+
"encoding": "utf-8"
|
|
940
|
+
}
|
|
941
|
+
},
|
|
942
|
+
{
|
|
943
|
+
"name": "update",
|
|
944
|
+
"schema": {
|
|
945
|
+
"type": "boolean",
|
|
946
|
+
"default": false
|
|
947
|
+
}
|
|
948
|
+
},
|
|
949
|
+
{
|
|
950
|
+
"name": "format",
|
|
951
|
+
"schema": {
|
|
952
|
+
"type": "string",
|
|
953
|
+
"default": "text",
|
|
954
|
+
"enum": [
|
|
955
|
+
"text",
|
|
956
|
+
"json",
|
|
957
|
+
"diff"
|
|
958
|
+
]
|
|
959
|
+
}
|
|
960
|
+
},
|
|
961
|
+
{
|
|
962
|
+
"name": "fail-on-drift",
|
|
963
|
+
"schema": {
|
|
964
|
+
"type": "boolean",
|
|
965
|
+
"default": false
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
],
|
|
969
|
+
"env": {
|
|
970
|
+
"CURSOR_API_KEY": {
|
|
971
|
+
"sensitive": true
|
|
972
|
+
},
|
|
973
|
+
"GEMINI_API_KEY": {
|
|
974
|
+
"sensitive": true
|
|
975
|
+
},
|
|
976
|
+
"OPENAI_API_KEY": {
|
|
977
|
+
"sensitive": true
|
|
978
|
+
},
|
|
979
|
+
"ANTHROPIC_API_KEY": {
|
|
980
|
+
"sensitive": true
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
},
|
|
984
|
+
"check": {
|
|
985
|
+
"options": [
|
|
986
|
+
{
|
|
987
|
+
"name": "config",
|
|
988
|
+
"schema": {
|
|
989
|
+
"type": "string"
|
|
990
|
+
},
|
|
991
|
+
"file": {
|
|
992
|
+
"mode": "read",
|
|
993
|
+
"exists": true,
|
|
994
|
+
"encoding": "utf-8"
|
|
995
|
+
}
|
|
996
|
+
},
|
|
997
|
+
{
|
|
998
|
+
"name": "strict",
|
|
999
|
+
"schema": {
|
|
1000
|
+
"type": "boolean",
|
|
1001
|
+
"default": false
|
|
1002
|
+
}
|
|
1003
|
+
},
|
|
1004
|
+
{
|
|
1005
|
+
"name": "verbose",
|
|
1006
|
+
"schema": {
|
|
1007
|
+
"type": "boolean",
|
|
1008
|
+
"default": false
|
|
1009
|
+
}
|
|
1010
|
+
},
|
|
1011
|
+
{
|
|
1012
|
+
"name": "coverage",
|
|
1013
|
+
"schema": {
|
|
1014
|
+
"type": "boolean",
|
|
1015
|
+
"default": false
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
],
|
|
1019
|
+
"env": {
|
|
1020
|
+
"CURSOR_API_KEY": {
|
|
1021
|
+
"sensitive": true
|
|
1022
|
+
},
|
|
1023
|
+
"GEMINI_API_KEY": {
|
|
1024
|
+
"sensitive": true
|
|
1025
|
+
},
|
|
1026
|
+
"OPENAI_API_KEY": {
|
|
1027
|
+
"sensitive": true
|
|
1028
|
+
},
|
|
1029
|
+
"ANTHROPIC_API_KEY": {
|
|
1030
|
+
"sensitive": true
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
},
|
|
1034
|
+
"new": {
|
|
1035
|
+
"effects": {
|
|
1036
|
+
"riskLevel": "low",
|
|
1037
|
+
"writes": [
|
|
1038
|
+
{
|
|
1039
|
+
"target": "design/ directory",
|
|
1040
|
+
"description": "new TypeScript spec file with auto-generated ID",
|
|
1041
|
+
"idempotent": false
|
|
1042
|
+
}
|
|
1043
|
+
]
|
|
1044
|
+
},
|
|
1045
|
+
"options": [
|
|
1046
|
+
{
|
|
1047
|
+
"name": "kind",
|
|
1048
|
+
"schema": {
|
|
1049
|
+
"type": "string"
|
|
1050
|
+
}
|
|
1051
|
+
},
|
|
1052
|
+
{
|
|
1053
|
+
"name": "name",
|
|
1054
|
+
"schema": {
|
|
1055
|
+
"type": "string"
|
|
1056
|
+
}
|
|
1057
|
+
},
|
|
1058
|
+
{
|
|
1059
|
+
"name": "output",
|
|
1060
|
+
"schema": {
|
|
1061
|
+
"type": "string"
|
|
1062
|
+
}
|
|
1063
|
+
},
|
|
1064
|
+
{
|
|
1065
|
+
"name": "template",
|
|
1066
|
+
"schema": {
|
|
1067
|
+
"type": "string"
|
|
1068
|
+
},
|
|
1069
|
+
"file": {
|
|
1070
|
+
"mode": "read",
|
|
1071
|
+
"exists": true,
|
|
1072
|
+
"encoding": "utf-8"
|
|
1073
|
+
}
|
|
1074
|
+
},
|
|
1075
|
+
{
|
|
1076
|
+
"name": "dry-run",
|
|
1077
|
+
"schema": {
|
|
1078
|
+
"type": "boolean",
|
|
1079
|
+
"default": false
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
],
|
|
1083
|
+
"env": {
|
|
1084
|
+
"CURSOR_API_KEY": {
|
|
1085
|
+
"sensitive": true
|
|
1086
|
+
},
|
|
1087
|
+
"GEMINI_API_KEY": {
|
|
1088
|
+
"sensitive": true
|
|
1089
|
+
},
|
|
1090
|
+
"OPENAI_API_KEY": {
|
|
1091
|
+
"sensitive": true
|
|
1092
|
+
},
|
|
1093
|
+
"ANTHROPIC_API_KEY": {
|
|
1094
|
+
"sensitive": true
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
},
|
|
1098
|
+
"impact": {
|
|
1099
|
+
"options": [
|
|
1100
|
+
{
|
|
1101
|
+
"name": "config",
|
|
1102
|
+
"schema": {
|
|
1103
|
+
"type": "string"
|
|
1104
|
+
},
|
|
1105
|
+
"file": {
|
|
1106
|
+
"mode": "read",
|
|
1107
|
+
"exists": true,
|
|
1108
|
+
"encoding": "utf-8"
|
|
1109
|
+
}
|
|
1110
|
+
},
|
|
1111
|
+
{
|
|
1112
|
+
"name": "depth",
|
|
1113
|
+
"schema": {
|
|
1114
|
+
"type": "integer",
|
|
1115
|
+
"minimum": 1,
|
|
1116
|
+
"default": 3
|
|
1117
|
+
}
|
|
1118
|
+
},
|
|
1119
|
+
{
|
|
1120
|
+
"name": "direction",
|
|
1121
|
+
"schema": {
|
|
1122
|
+
"type": "string",
|
|
1123
|
+
"default": "both",
|
|
1124
|
+
"enum": [
|
|
1125
|
+
"upstream",
|
|
1126
|
+
"downstream",
|
|
1127
|
+
"both"
|
|
1128
|
+
]
|
|
1129
|
+
}
|
|
1130
|
+
},
|
|
1131
|
+
{
|
|
1132
|
+
"name": "format",
|
|
1133
|
+
"schema": {
|
|
1134
|
+
"type": "string",
|
|
1135
|
+
"default": "text",
|
|
1136
|
+
"enum": [
|
|
1137
|
+
"text",
|
|
1138
|
+
"json",
|
|
1139
|
+
"mermaid"
|
|
1140
|
+
]
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
],
|
|
1144
|
+
"env": {
|
|
1145
|
+
"CURSOR_API_KEY": {
|
|
1146
|
+
"sensitive": true
|
|
1147
|
+
},
|
|
1148
|
+
"GEMINI_API_KEY": {
|
|
1149
|
+
"sensitive": true
|
|
1150
|
+
},
|
|
1151
|
+
"OPENAI_API_KEY": {
|
|
1152
|
+
"sensitive": true
|
|
1153
|
+
},
|
|
1154
|
+
"ANTHROPIC_API_KEY": {
|
|
1155
|
+
"sensitive": true
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
},
|
|
1159
|
+
"scaffold": {
|
|
1160
|
+
"effects": {
|
|
1161
|
+
"riskLevel": "low",
|
|
1162
|
+
"writes": [
|
|
1163
|
+
{
|
|
1164
|
+
"target": "design/ directory",
|
|
1165
|
+
"description": "generated _models/ and spec data files",
|
|
1166
|
+
"idempotent": false
|
|
1167
|
+
}
|
|
1168
|
+
]
|
|
1169
|
+
},
|
|
1170
|
+
"options": [
|
|
1171
|
+
{
|
|
1172
|
+
"name": "source",
|
|
1173
|
+
"schema": {
|
|
1174
|
+
"type": "string"
|
|
1175
|
+
},
|
|
1176
|
+
"file": {
|
|
1177
|
+
"mode": "read",
|
|
1178
|
+
"exists": true,
|
|
1179
|
+
"encoding": "utf-8"
|
|
1180
|
+
}
|
|
1181
|
+
},
|
|
1182
|
+
{
|
|
1183
|
+
"name": "output",
|
|
1184
|
+
"schema": {
|
|
1185
|
+
"type": "string",
|
|
1186
|
+
"default": "design/"
|
|
1187
|
+
}
|
|
1188
|
+
},
|
|
1189
|
+
{
|
|
1190
|
+
"name": "force",
|
|
1191
|
+
"schema": {
|
|
1192
|
+
"type": "boolean",
|
|
1193
|
+
"default": false
|
|
1194
|
+
},
|
|
1195
|
+
"effects": {
|
|
1196
|
+
"riskLevel": "medium",
|
|
1197
|
+
"writes": [
|
|
1198
|
+
{
|
|
1199
|
+
"target": "existing model and spec files",
|
|
1200
|
+
"description": "overwrites existing TypeScript model source files",
|
|
1201
|
+
"overwrite": true
|
|
1202
|
+
}
|
|
1203
|
+
]
|
|
1204
|
+
}
|
|
1205
|
+
},
|
|
1206
|
+
{
|
|
1207
|
+
"name": "dry-run",
|
|
1208
|
+
"schema": {
|
|
1209
|
+
"type": "boolean",
|
|
1210
|
+
"default": false
|
|
1211
|
+
}
|
|
1212
|
+
},
|
|
1213
|
+
{
|
|
1214
|
+
"name": "format",
|
|
1215
|
+
"schema": {
|
|
1216
|
+
"type": "string",
|
|
1217
|
+
"default": "ts",
|
|
1218
|
+
"enum": [
|
|
1219
|
+
"ts",
|
|
1220
|
+
"yaml"
|
|
1221
|
+
]
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
],
|
|
1225
|
+
"env": {
|
|
1226
|
+
"CURSOR_API_KEY": {
|
|
1227
|
+
"sensitive": true
|
|
1228
|
+
},
|
|
1229
|
+
"GEMINI_API_KEY": {
|
|
1230
|
+
"sensitive": true
|
|
1231
|
+
},
|
|
1232
|
+
"OPENAI_API_KEY": {
|
|
1233
|
+
"sensitive": true
|
|
1234
|
+
},
|
|
1235
|
+
"ANTHROPIC_API_KEY": {
|
|
1236
|
+
"sensitive": true
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
},
|
|
1240
|
+
"convert": {
|
|
1241
|
+
"effects": {
|
|
1242
|
+
"riskLevel": "low",
|
|
1243
|
+
"writes": [
|
|
1244
|
+
{
|
|
1245
|
+
"target": ".yaml output file",
|
|
1246
|
+
"description": "YAML conversion of the TS spec data",
|
|
1247
|
+
"idempotent": true
|
|
1248
|
+
}
|
|
1249
|
+
]
|
|
1250
|
+
},
|
|
1251
|
+
"options": [
|
|
1252
|
+
{
|
|
1253
|
+
"name": "output",
|
|
1254
|
+
"schema": {
|
|
1255
|
+
"type": "string"
|
|
1256
|
+
},
|
|
1257
|
+
"file": {
|
|
1258
|
+
"mode": "write",
|
|
1259
|
+
"encoding": "utf-8"
|
|
1260
|
+
}
|
|
1261
|
+
},
|
|
1262
|
+
{
|
|
1263
|
+
"name": "dry-run",
|
|
1264
|
+
"schema": {
|
|
1265
|
+
"type": "boolean",
|
|
1266
|
+
"default": false
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
],
|
|
1270
|
+
"env": {
|
|
1271
|
+
"CURSOR_API_KEY": {
|
|
1272
|
+
"sensitive": true
|
|
1273
|
+
},
|
|
1274
|
+
"GEMINI_API_KEY": {
|
|
1275
|
+
"sensitive": true
|
|
1276
|
+
},
|
|
1277
|
+
"OPENAI_API_KEY": {
|
|
1278
|
+
"sensitive": true
|
|
1279
|
+
},
|
|
1280
|
+
"ANTHROPIC_API_KEY": {
|
|
1281
|
+
"sensitive": true
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
},
|
|
1285
|
+
"audit-requirements": {
|
|
1286
|
+
"effects": {
|
|
1287
|
+
"network": {
|
|
1288
|
+
"description": "LLM API calls to configured provider",
|
|
1289
|
+
"idempotent": true
|
|
1290
|
+
}
|
|
1291
|
+
},
|
|
1292
|
+
"options": [
|
|
1293
|
+
{
|
|
1294
|
+
"name": "config",
|
|
1295
|
+
"schema": {
|
|
1296
|
+
"type": "string"
|
|
1297
|
+
},
|
|
1298
|
+
"file": {
|
|
1299
|
+
"mode": "read",
|
|
1300
|
+
"exists": true,
|
|
1301
|
+
"encoding": "utf-8"
|
|
1302
|
+
}
|
|
1303
|
+
},
|
|
1304
|
+
{
|
|
1305
|
+
"name": "adapter",
|
|
1306
|
+
"schema": {
|
|
1307
|
+
"type": "string",
|
|
1308
|
+
"enum": [
|
|
1309
|
+
"cursor",
|
|
1310
|
+
"claude",
|
|
1311
|
+
"openai",
|
|
1312
|
+
"gemini",
|
|
1313
|
+
"mock"
|
|
1314
|
+
]
|
|
1315
|
+
}
|
|
1316
|
+
},
|
|
1317
|
+
{
|
|
1318
|
+
"name": "model",
|
|
1319
|
+
"schema": {
|
|
1320
|
+
"type": "string"
|
|
1321
|
+
}
|
|
1322
|
+
},
|
|
1323
|
+
{
|
|
1324
|
+
"name": "dry-run",
|
|
1325
|
+
"schema": {
|
|
1326
|
+
"type": "boolean",
|
|
1327
|
+
"default": false
|
|
1328
|
+
}
|
|
1329
|
+
},
|
|
1330
|
+
{
|
|
1331
|
+
"name": "show-prompt",
|
|
1332
|
+
"schema": {
|
|
1333
|
+
"type": "boolean",
|
|
1334
|
+
"default": false
|
|
1335
|
+
}
|
|
1336
|
+
},
|
|
1337
|
+
{
|
|
1338
|
+
"name": "fail-on",
|
|
1339
|
+
"schema": {
|
|
1340
|
+
"type": "string",
|
|
1341
|
+
"enum": [
|
|
1342
|
+
"warning",
|
|
1343
|
+
"error",
|
|
1344
|
+
"critical"
|
|
1345
|
+
],
|
|
1346
|
+
"default": "error"
|
|
1347
|
+
}
|
|
1348
|
+
},
|
|
1349
|
+
{
|
|
1350
|
+
"name": "output",
|
|
1351
|
+
"schema": {
|
|
1352
|
+
"type": "string"
|
|
1353
|
+
},
|
|
1354
|
+
"file": {
|
|
1355
|
+
"mode": "write",
|
|
1356
|
+
"encoding": "utf-8"
|
|
1357
|
+
}
|
|
1358
|
+
},
|
|
1359
|
+
{
|
|
1360
|
+
"name": "report-format",
|
|
1361
|
+
"schema": {
|
|
1362
|
+
"type": "string",
|
|
1363
|
+
"enum": [
|
|
1364
|
+
"json",
|
|
1365
|
+
"text",
|
|
1366
|
+
"yaml"
|
|
1367
|
+
],
|
|
1368
|
+
"default": "json"
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
],
|
|
1372
|
+
"env": {
|
|
1373
|
+
"CURSOR_API_KEY": {
|
|
1374
|
+
"sensitive": true
|
|
1375
|
+
},
|
|
1376
|
+
"GEMINI_API_KEY": {
|
|
1377
|
+
"sensitive": true
|
|
1378
|
+
},
|
|
1379
|
+
"OPENAI_API_KEY": {
|
|
1380
|
+
"sensitive": true
|
|
1381
|
+
},
|
|
1382
|
+
"ANTHROPIC_API_KEY": {
|
|
1383
|
+
"sensitive": true
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
},
|
|
1387
|
+
"propose-trace-links": {
|
|
1388
|
+
"effects": {
|
|
1389
|
+
"network": {
|
|
1390
|
+
"description": "LLM API calls to configured provider",
|
|
1391
|
+
"idempotent": true
|
|
1392
|
+
}
|
|
1393
|
+
},
|
|
1394
|
+
"options": [
|
|
1395
|
+
{
|
|
1396
|
+
"name": "config",
|
|
1397
|
+
"schema": {
|
|
1398
|
+
"type": "string"
|
|
1399
|
+
},
|
|
1400
|
+
"file": {
|
|
1401
|
+
"mode": "read",
|
|
1402
|
+
"exists": true,
|
|
1403
|
+
"encoding": "utf-8"
|
|
1404
|
+
}
|
|
1405
|
+
},
|
|
1406
|
+
{
|
|
1407
|
+
"name": "adapter",
|
|
1408
|
+
"schema": {
|
|
1409
|
+
"type": "string",
|
|
1410
|
+
"enum": [
|
|
1411
|
+
"cursor",
|
|
1412
|
+
"claude",
|
|
1413
|
+
"openai",
|
|
1414
|
+
"gemini",
|
|
1415
|
+
"mock"
|
|
1416
|
+
]
|
|
1417
|
+
}
|
|
1418
|
+
},
|
|
1419
|
+
{
|
|
1420
|
+
"name": "model",
|
|
1421
|
+
"schema": {
|
|
1422
|
+
"type": "string"
|
|
1423
|
+
}
|
|
1424
|
+
},
|
|
1425
|
+
{
|
|
1426
|
+
"name": "dry-run",
|
|
1427
|
+
"schema": {
|
|
1428
|
+
"type": "boolean",
|
|
1429
|
+
"default": false
|
|
1430
|
+
}
|
|
1431
|
+
},
|
|
1432
|
+
{
|
|
1433
|
+
"name": "show-prompt",
|
|
1434
|
+
"schema": {
|
|
1435
|
+
"type": "boolean",
|
|
1436
|
+
"default": false
|
|
1437
|
+
}
|
|
1438
|
+
},
|
|
1439
|
+
{
|
|
1440
|
+
"name": "fail-on",
|
|
1441
|
+
"schema": {
|
|
1442
|
+
"type": "string",
|
|
1443
|
+
"enum": [
|
|
1444
|
+
"warning",
|
|
1445
|
+
"error",
|
|
1446
|
+
"critical"
|
|
1447
|
+
],
|
|
1448
|
+
"default": "error"
|
|
1449
|
+
}
|
|
1450
|
+
},
|
|
1451
|
+
{
|
|
1452
|
+
"name": "output",
|
|
1453
|
+
"schema": {
|
|
1454
|
+
"type": "string"
|
|
1455
|
+
},
|
|
1456
|
+
"file": {
|
|
1457
|
+
"mode": "write",
|
|
1458
|
+
"encoding": "utf-8"
|
|
1459
|
+
}
|
|
1460
|
+
},
|
|
1461
|
+
{
|
|
1462
|
+
"name": "report-format",
|
|
1463
|
+
"schema": {
|
|
1464
|
+
"type": "string",
|
|
1465
|
+
"enum": [
|
|
1466
|
+
"json",
|
|
1467
|
+
"text",
|
|
1468
|
+
"yaml"
|
|
1469
|
+
],
|
|
1470
|
+
"default": "json"
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
],
|
|
1474
|
+
"env": {
|
|
1475
|
+
"CURSOR_API_KEY": {
|
|
1476
|
+
"sensitive": true
|
|
1477
|
+
},
|
|
1478
|
+
"GEMINI_API_KEY": {
|
|
1479
|
+
"sensitive": true
|
|
1480
|
+
},
|
|
1481
|
+
"OPENAI_API_KEY": {
|
|
1482
|
+
"sensitive": true
|
|
1483
|
+
},
|
|
1484
|
+
"ANTHROPIC_API_KEY": {
|
|
1485
|
+
"sensitive": true
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
},
|
|
1489
|
+
"explain-impact": {
|
|
1490
|
+
"effects": {
|
|
1491
|
+
"network": {
|
|
1492
|
+
"description": "LLM API calls to configured provider",
|
|
1493
|
+
"idempotent": true
|
|
1494
|
+
}
|
|
1495
|
+
},
|
|
1496
|
+
"options": [
|
|
1497
|
+
{
|
|
1498
|
+
"name": "adapter",
|
|
1499
|
+
"schema": {
|
|
1500
|
+
"type": "string",
|
|
1501
|
+
"enum": [
|
|
1502
|
+
"cursor",
|
|
1503
|
+
"claude",
|
|
1504
|
+
"openai",
|
|
1505
|
+
"gemini",
|
|
1506
|
+
"mock"
|
|
1507
|
+
]
|
|
1508
|
+
}
|
|
1509
|
+
},
|
|
1510
|
+
{
|
|
1511
|
+
"name": "model",
|
|
1512
|
+
"schema": {
|
|
1513
|
+
"type": "string"
|
|
1514
|
+
}
|
|
1515
|
+
},
|
|
1516
|
+
{
|
|
1517
|
+
"name": "dry-run",
|
|
1518
|
+
"schema": {
|
|
1519
|
+
"type": "boolean",
|
|
1520
|
+
"default": false
|
|
1521
|
+
}
|
|
1522
|
+
},
|
|
1523
|
+
{
|
|
1524
|
+
"name": "show-prompt",
|
|
1525
|
+
"schema": {
|
|
1526
|
+
"type": "boolean",
|
|
1527
|
+
"default": false
|
|
1528
|
+
}
|
|
1529
|
+
},
|
|
1530
|
+
{
|
|
1531
|
+
"name": "fail-on",
|
|
1532
|
+
"schema": {
|
|
1533
|
+
"type": "string",
|
|
1534
|
+
"enum": [
|
|
1535
|
+
"warning",
|
|
1536
|
+
"error",
|
|
1537
|
+
"critical"
|
|
1538
|
+
],
|
|
1539
|
+
"default": "error"
|
|
1540
|
+
}
|
|
1541
|
+
},
|
|
1542
|
+
{
|
|
1543
|
+
"name": "output",
|
|
1544
|
+
"schema": {
|
|
1545
|
+
"type": "string"
|
|
1546
|
+
},
|
|
1547
|
+
"file": {
|
|
1548
|
+
"mode": "write",
|
|
1549
|
+
"encoding": "utf-8"
|
|
1550
|
+
}
|
|
1551
|
+
},
|
|
1552
|
+
{
|
|
1553
|
+
"name": "report-format",
|
|
1554
|
+
"schema": {
|
|
1555
|
+
"type": "string",
|
|
1556
|
+
"enum": [
|
|
1557
|
+
"json",
|
|
1558
|
+
"text",
|
|
1559
|
+
"yaml"
|
|
1560
|
+
],
|
|
1561
|
+
"default": "json"
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
],
|
|
1565
|
+
"env": {
|
|
1566
|
+
"CURSOR_API_KEY": {
|
|
1567
|
+
"sensitive": true
|
|
1568
|
+
},
|
|
1569
|
+
"GEMINI_API_KEY": {
|
|
1570
|
+
"sensitive": true
|
|
1571
|
+
},
|
|
1572
|
+
"OPENAI_API_KEY": {
|
|
1573
|
+
"sensitive": true
|
|
1574
|
+
},
|
|
1575
|
+
"ANTHROPIC_API_KEY": {
|
|
1576
|
+
"sensitive": true
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
},
|
|
1580
|
+
"propose-acceptance-criteria": {
|
|
1581
|
+
"effects": {
|
|
1582
|
+
"network": {
|
|
1583
|
+
"description": "LLM API calls to configured provider",
|
|
1584
|
+
"idempotent": true
|
|
1585
|
+
}
|
|
1586
|
+
},
|
|
1587
|
+
"options": [
|
|
1588
|
+
{
|
|
1589
|
+
"name": "config",
|
|
1590
|
+
"schema": {
|
|
1591
|
+
"type": "string"
|
|
1592
|
+
},
|
|
1593
|
+
"file": {
|
|
1594
|
+
"mode": "read",
|
|
1595
|
+
"exists": true,
|
|
1596
|
+
"encoding": "utf-8"
|
|
1597
|
+
}
|
|
1598
|
+
},
|
|
1599
|
+
{
|
|
1600
|
+
"name": "adapter",
|
|
1601
|
+
"schema": {
|
|
1602
|
+
"type": "string",
|
|
1603
|
+
"enum": [
|
|
1604
|
+
"cursor",
|
|
1605
|
+
"claude",
|
|
1606
|
+
"openai",
|
|
1607
|
+
"gemini",
|
|
1608
|
+
"mock"
|
|
1609
|
+
]
|
|
1610
|
+
}
|
|
1611
|
+
},
|
|
1612
|
+
{
|
|
1613
|
+
"name": "model",
|
|
1614
|
+
"schema": {
|
|
1615
|
+
"type": "string"
|
|
1616
|
+
}
|
|
1617
|
+
},
|
|
1618
|
+
{
|
|
1619
|
+
"name": "dry-run",
|
|
1620
|
+
"schema": {
|
|
1621
|
+
"type": "boolean",
|
|
1622
|
+
"default": false
|
|
1623
|
+
}
|
|
1624
|
+
},
|
|
1625
|
+
{
|
|
1626
|
+
"name": "show-prompt",
|
|
1627
|
+
"schema": {
|
|
1628
|
+
"type": "boolean",
|
|
1629
|
+
"default": false
|
|
1630
|
+
}
|
|
1631
|
+
},
|
|
1632
|
+
{
|
|
1633
|
+
"name": "fail-on",
|
|
1634
|
+
"schema": {
|
|
1635
|
+
"type": "string",
|
|
1636
|
+
"enum": [
|
|
1637
|
+
"warning",
|
|
1638
|
+
"error",
|
|
1639
|
+
"critical"
|
|
1640
|
+
],
|
|
1641
|
+
"default": "error"
|
|
1642
|
+
}
|
|
1643
|
+
},
|
|
1644
|
+
{
|
|
1645
|
+
"name": "output",
|
|
1646
|
+
"schema": {
|
|
1647
|
+
"type": "string"
|
|
1648
|
+
},
|
|
1649
|
+
"file": {
|
|
1650
|
+
"mode": "write",
|
|
1651
|
+
"encoding": "utf-8"
|
|
1652
|
+
}
|
|
1653
|
+
},
|
|
1654
|
+
{
|
|
1655
|
+
"name": "report-format",
|
|
1656
|
+
"schema": {
|
|
1657
|
+
"type": "string",
|
|
1658
|
+
"enum": [
|
|
1659
|
+
"json",
|
|
1660
|
+
"text",
|
|
1661
|
+
"yaml"
|
|
1662
|
+
],
|
|
1663
|
+
"default": "json"
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
],
|
|
1667
|
+
"env": {
|
|
1668
|
+
"CURSOR_API_KEY": {
|
|
1669
|
+
"sensitive": true
|
|
1670
|
+
},
|
|
1671
|
+
"GEMINI_API_KEY": {
|
|
1672
|
+
"sensitive": true
|
|
1673
|
+
},
|
|
1674
|
+
"OPENAI_API_KEY": {
|
|
1675
|
+
"sensitive": true
|
|
1676
|
+
},
|
|
1677
|
+
"ANTHROPIC_API_KEY": {
|
|
1678
|
+
"sensitive": true
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
};
|
|
1683
|
+
function deriveCommandPolicy(commandId, optionValues) {
|
|
1684
|
+
const def = commandDefinitions[commandId];
|
|
1685
|
+
if (!def) throw new Error(`Unknown command: ${commandId}`);
|
|
1686
|
+
const cmdDef = def;
|
|
1687
|
+
const options = {};
|
|
1688
|
+
const activeOptions = [];
|
|
1689
|
+
for (const optDef of cmdDef.options ?? []) {
|
|
1690
|
+
const value = optionValues[optDef.name];
|
|
1691
|
+
const specified = optDef.name in optionValues && value !== void 0;
|
|
1692
|
+
options[optDef.name] = { value, specified, definition: optDef };
|
|
1693
|
+
if (isOptionActive(optDef, value, specified)) {
|
|
1694
|
+
activeOptions.push(optDef.name);
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
const policy = derivePolicy({
|
|
1698
|
+
commandId,
|
|
1699
|
+
commandEffects: cmdDef.effects,
|
|
1700
|
+
options,
|
|
1701
|
+
env: cmdDef.env
|
|
1702
|
+
});
|
|
1703
|
+
return { command: commandId, activeOptions, policy };
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
// src/generated/program.ts
|
|
1707
|
+
function createProgram(handlers2, version) {
|
|
1708
|
+
const program = new Command();
|
|
1709
|
+
program.name("speckeeper").version(version, "-V, --version").description("Requirements and design management framework with TypeScript DSL.");
|
|
1710
|
+
program.option("--introspect", "Output derived policy as JSON without executing the command");
|
|
1711
|
+
program.command("init").description("Initialize a new speckeeper project with starter templates.").option("-F, --force", "Overwrite existing files.", false).option("--format <format>", "Spec data format: ts (default) or yaml.", "ts").action(async (opts, cmd) => {
|
|
1712
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
1713
|
+
if (globalOpts.introspect) {
|
|
1714
|
+
const policy = deriveCommandPolicy("init", opts);
|
|
1715
|
+
console.log(JSON.stringify(policy, null, 2));
|
|
1716
|
+
return;
|
|
1717
|
+
}
|
|
1718
|
+
await handlers2.init(opts, globalOpts);
|
|
1719
|
+
});
|
|
1720
|
+
program.command("build").description("Generate docs/ and specs/ from TypeScript models.").option("-c, --config <path>", "Path to config file.").option("-o, --output <path>", "Base output directory path.", ".").option("-f, --format <format>", "Output format: markdown, json, both.", "both").option("-w, --watch", "Watch for changes and auto-regenerate.", false).option("-v, --verbose", "Show detailed output.", false).action(async (opts, cmd) => {
|
|
1721
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
1722
|
+
if (globalOpts.introspect) {
|
|
1723
|
+
const policy = deriveCommandPolicy("build", opts);
|
|
1724
|
+
console.log(JSON.stringify(policy, null, 2));
|
|
1725
|
+
return;
|
|
1726
|
+
}
|
|
1727
|
+
await handlers2.build(opts, globalOpts);
|
|
1728
|
+
});
|
|
1729
|
+
program.command("lint").description("Check design integrity (ID duplicates, references, layer violations, etc.).").option("-c, --config <path>", "Path to config file.").option("-p, --phase <phase>", "Phase gate to check against: REQ, HLD, LLD, OPS.").option("-s, --strict", "Treat warnings as errors.", false).option("--fix", "Attempt to fix auto-fixable issues (not yet implemented).", false).option("-f, --format <format>", "Output format: text, json, github.", "text").action(async (opts, cmd) => {
|
|
1730
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
1731
|
+
if (globalOpts.introspect) {
|
|
1732
|
+
const policy = deriveCommandPolicy("lint", opts);
|
|
1733
|
+
console.log(JSON.stringify(policy, null, 2));
|
|
1734
|
+
return;
|
|
1735
|
+
}
|
|
1736
|
+
await handlers2.lint(opts, globalOpts);
|
|
1737
|
+
});
|
|
1738
|
+
program.command("drift").description("Check if generated files have been manually edited.").option("-c, --config <path>", "Path to config file.").option("-u, --update", "Auto-update if differences are found (not yet implemented).", false).option("-f, --format <format>", "Output format: text, json, diff.", "text").option("--fail-on-drift", "Exit with code 1 if drift is detected (for CI).", false).action(async (opts, cmd) => {
|
|
1739
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
1740
|
+
if (globalOpts.introspect) {
|
|
1741
|
+
const policy = deriveCommandPolicy("drift", opts);
|
|
1742
|
+
console.log(JSON.stringify(policy, null, 2));
|
|
1743
|
+
return;
|
|
1744
|
+
}
|
|
1745
|
+
await handlers2.drift(opts, globalOpts);
|
|
1746
|
+
});
|
|
1747
|
+
program.command("check").description("Check external SSOT conformance (including custom models).").argument("[type]", "Type of check to run. Filters sources by type.").option("-c, --config <path>", "Path to config file.").option("--strict", "Treat warnings as errors.", false).option("-v, --verbose", "Show detailed output.", false).option("--coverage", "Check if all testable acceptance criteria are covered by TestRefs.", false).action(async (type, opts, cmd) => {
|
|
1748
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
1749
|
+
if (globalOpts.introspect) {
|
|
1750
|
+
const policy = deriveCommandPolicy("check", opts);
|
|
1751
|
+
console.log(JSON.stringify(policy, null, 2));
|
|
1752
|
+
return;
|
|
1753
|
+
}
|
|
1754
|
+
await handlers2.check(type, opts, globalOpts);
|
|
1755
|
+
});
|
|
1756
|
+
program.command("new").description("Create a new element with auto-generated ID.").argument("<type>", "Element type to create.").option("-k, --kind <kind>", "Sub-kind (e.g. functional, non-functional for requirements).").option("-n, --name <name>", "Name of the element.").option("-o, --output <path>", "Output directory path.").option("-t, --template <path>", "Path to template file.").option("--dry-run", "Preview generated file content without writing.", false).action(async (type, opts, cmd) => {
|
|
1757
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
1758
|
+
if (globalOpts.introspect) {
|
|
1759
|
+
const policy = deriveCommandPolicy("new", opts);
|
|
1760
|
+
console.log(JSON.stringify(policy, null, 2));
|
|
1761
|
+
return;
|
|
1762
|
+
}
|
|
1763
|
+
await handlers2.new(type, opts, globalOpts);
|
|
1764
|
+
});
|
|
1765
|
+
program.command("impact").description("Analyze impact of changes to an ID.").argument("<id>", "Spec ID to analyze (e.g. REQ-001, ENT-ORDER).").option("-c, --config <path>", "Path to config file.").option("-d, --depth <n>", "Analysis depth (reference tracking level).", "3").option("--direction <direction>", "Analysis direction: upstream, downstream, both.", "both").option("-f, --format <format>", "Output format: text, json, mermaid.", "text").action(async (id, opts, cmd) => {
|
|
1766
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
1767
|
+
if (globalOpts.introspect) {
|
|
1768
|
+
const policy = deriveCommandPolicy("impact", opts);
|
|
1769
|
+
console.log(JSON.stringify(policy, null, 2));
|
|
1770
|
+
return;
|
|
1771
|
+
}
|
|
1772
|
+
await handlers2.impact(id, opts, globalOpts);
|
|
1773
|
+
});
|
|
1774
|
+
program.command("scaffold").description("Generate _models/ from a Mermaid flowchart definition.").option("-s, --source <path>", "Path to Markdown file containing Mermaid flowchart.").option("-o, --output <path>", "Output directory.", "design/").option("-F, --force", "Overwrite existing files.", false).option("--dry-run", "Preview generated files without writing.", false).option("--format <format>", "Spec data format: ts (default) or yaml.", "ts").action(async (opts, cmd) => {
|
|
1775
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
1776
|
+
if (globalOpts.introspect) {
|
|
1777
|
+
const policy = deriveCommandPolicy("scaffold", opts);
|
|
1778
|
+
console.log(JSON.stringify(policy, null, 2));
|
|
1779
|
+
return;
|
|
1780
|
+
}
|
|
1781
|
+
await handlers2.scaffold(opts, globalOpts);
|
|
1782
|
+
});
|
|
1783
|
+
program.command("convert").description("Convert a TS spec data file to YAML format.").argument("<file>", "Path to TS spec data file.").option("-o, --output <path>", "Output file path (default: same name with .yaml extension).").option("-n, --dry-run", "Preview conversion without writing.", false).action(async (file, opts, cmd) => {
|
|
1784
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
1785
|
+
if (globalOpts.introspect) {
|
|
1786
|
+
const policy = deriveCommandPolicy("convert", opts);
|
|
1787
|
+
console.log(JSON.stringify(policy, null, 2));
|
|
1788
|
+
return;
|
|
1789
|
+
}
|
|
1790
|
+
await handlers2.convert(file, opts, globalOpts);
|
|
1791
|
+
});
|
|
1792
|
+
program.command("audit-requirements").description("Run LLM-based requirement quality audit.").option("-c, --config <path>", "Path to config file.").option("-a, --adapter <name>", "SDK adapter to use for LLM execution.").option("--model <name>", "LLM model override.").option("-n, --dry-run", "Output the constructed prompt without calling LLM.", false).option("--show-prompt", "Display the constructed LLM prompt on stderr.", false).option("--fail-on <level>", "Minimum severity that causes a non-zero exit.", "error").option("-o, --output <file>", "Write result to a file instead of stdout.").option("--report-format <fmt>", "Output format for the audit report.", "json").action(async (opts, cmd) => {
|
|
1793
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
1794
|
+
if (globalOpts.introspect) {
|
|
1795
|
+
const policy = deriveCommandPolicy("audit-requirements", opts);
|
|
1796
|
+
console.log(JSON.stringify(policy, null, 2));
|
|
1797
|
+
return;
|
|
1798
|
+
}
|
|
1799
|
+
await handlers2.auditRequirements(opts, globalOpts);
|
|
1800
|
+
});
|
|
1801
|
+
program.command("propose-trace-links").description("LLM-based traceability link proposal.").option("-c, --config <path>", "Path to config file.").option("-a, --adapter <name>", "SDK adapter to use for LLM execution.").option("--model <name>", "LLM model override.").option("-n, --dry-run", "Output the constructed prompt without calling LLM.", false).option("--show-prompt", "Display the constructed LLM prompt on stderr.", false).option("--fail-on <level>", "Minimum severity that causes a non-zero exit.", "error").option("-o, --output <file>", "Write result to a file instead of stdout.").option("--report-format <fmt>", "Output format for the report.", "json").action(async (opts, cmd) => {
|
|
1802
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
1803
|
+
if (globalOpts.introspect) {
|
|
1804
|
+
const policy = deriveCommandPolicy("propose-trace-links", opts);
|
|
1805
|
+
console.log(JSON.stringify(policy, null, 2));
|
|
1806
|
+
return;
|
|
1807
|
+
}
|
|
1808
|
+
await handlers2.proposeTraceLinks(opts, globalOpts);
|
|
1809
|
+
});
|
|
1810
|
+
program.command("explain-impact").description("LLM-based explanation of impact analysis output.").option("-a, --adapter <name>", "SDK adapter to use for LLM execution.").option("--model <name>", "LLM model override.").option("-n, --dry-run", "Output the constructed prompt without calling LLM.", false).option("--show-prompt", "Display the constructed LLM prompt on stderr.", false).option("--fail-on <level>", "Minimum severity that causes a non-zero exit.", "error").option("-o, --output <file>", "Write result to a file instead of stdout.").option("--report-format <fmt>", "Output format for the report.", "json").action(async (opts, cmd) => {
|
|
1811
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
1812
|
+
if (globalOpts.introspect) {
|
|
1813
|
+
const policy = deriveCommandPolicy("explain-impact", opts);
|
|
1814
|
+
console.log(JSON.stringify(policy, null, 2));
|
|
1815
|
+
return;
|
|
1816
|
+
}
|
|
1817
|
+
await handlers2.explainImpact(opts, globalOpts);
|
|
1818
|
+
});
|
|
1819
|
+
program.command("propose-acceptance-criteria").description("LLM-based acceptance criteria proposal.").argument("[specIds...]", "Spec IDs to propose criteria for. Defaults to all specs if omitted.").option("-c, --config <path>", "Path to config file.").option("-a, --adapter <name>", "SDK adapter to use for LLM execution.").option("--model <name>", "LLM model override.").option("-n, --dry-run", "Output the constructed prompt without calling LLM.", false).option("--show-prompt", "Display the constructed LLM prompt on stderr.", false).option("--fail-on <level>", "Minimum severity that causes a non-zero exit.", "error").option("-o, --output <file>", "Write result to a file instead of stdout.").option("--report-format <fmt>", "Output format for the report.", "json").action(async (specIds, opts, cmd) => {
|
|
1820
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
1821
|
+
if (globalOpts.introspect) {
|
|
1822
|
+
const policy = deriveCommandPolicy("propose-acceptance-criteria", opts);
|
|
1823
|
+
console.log(JSON.stringify(policy, null, 2));
|
|
1824
|
+
return;
|
|
1825
|
+
}
|
|
1826
|
+
await handlers2.proposeAcceptanceCriteria(specIds, opts, globalOpts);
|
|
1827
|
+
});
|
|
1828
|
+
return program;
|
|
1829
|
+
}
|
|
538
1830
|
var defaultConfig = {
|
|
539
1831
|
srcDir: "src",
|
|
540
1832
|
designDir: "design",
|
|
@@ -1961,6 +3253,8 @@ async function runInit(options = {}) {
|
|
|
1961
3253
|
console.log(chalk4.gray(" Please ensure the package is properly installed."));
|
|
1962
3254
|
return;
|
|
1963
3255
|
}
|
|
3256
|
+
const isYaml = options.format === "yaml";
|
|
3257
|
+
const skipForYaml = /* @__PURE__ */ new Set(["design/requirements.ts"]);
|
|
1964
3258
|
let packageJsonCreated = false;
|
|
1965
3259
|
copyTemplateDir(templatesDir, cwd, projectName, options.force || false, (relativePath, created) => {
|
|
1966
3260
|
if (created) {
|
|
@@ -1971,25 +3265,29 @@ async function runInit(options = {}) {
|
|
|
1971
3265
|
} else {
|
|
1972
3266
|
console.log(chalk4.yellow(` Skipped: ${relativePath} (already exists)`));
|
|
1973
3267
|
}
|
|
1974
|
-
});
|
|
3268
|
+
}, "", isYaml ? skipForYaml : void 0);
|
|
3269
|
+
if (isYaml) {
|
|
3270
|
+
writeYamlInitFiles(cwd, options.force || false);
|
|
3271
|
+
}
|
|
1975
3272
|
console.log("");
|
|
1976
3273
|
console.log(chalk4.cyan(" Project initialized successfully!"));
|
|
1977
3274
|
console.log("");
|
|
3275
|
+
const dataFormat = isYaml ? "design/*.yaml" : "design/*.ts using defineSpecs()";
|
|
1978
3276
|
console.log(" Next steps:");
|
|
1979
3277
|
if (packageJsonCreated) {
|
|
1980
3278
|
console.log(chalk4.gray(" 1. Run `npm install` to install dependencies"));
|
|
1981
|
-
console.log(chalk4.gray(
|
|
3279
|
+
console.log(chalk4.gray(` 2. Add spec data in ${dataFormat}`));
|
|
1982
3280
|
console.log(chalk4.gray(" 3. Import new spec files in design/index.ts"));
|
|
1983
3281
|
console.log(chalk4.gray(" 4. Run `npx speckeeper lint` to validate"));
|
|
1984
3282
|
} else {
|
|
1985
3283
|
console.log(chalk4.gray(" 1. Add speckeeper and zod to your package.json dependencies"));
|
|
1986
3284
|
console.log(chalk4.gray(' 2. Ensure "type": "module" is set in package.json'));
|
|
1987
|
-
console.log(chalk4.gray(
|
|
3285
|
+
console.log(chalk4.gray(` 3. Add spec data in ${dataFormat}`));
|
|
1988
3286
|
console.log(chalk4.gray(" 4. Import new spec files in design/index.ts"));
|
|
1989
3287
|
console.log(chalk4.gray(" 5. Run `npx speckeeper lint` to validate"));
|
|
1990
3288
|
}
|
|
1991
3289
|
}
|
|
1992
|
-
function copyTemplateDir(srcDir, destDir, projectName, force, onFile, relativePath = "") {
|
|
3290
|
+
function copyTemplateDir(srcDir, destDir, projectName, force, onFile, relativePath = "", skipRelPaths) {
|
|
1993
3291
|
const entries = readdirSync(srcDir);
|
|
1994
3292
|
for (const entry of entries) {
|
|
1995
3293
|
const srcPath = join(srcDir, entry);
|
|
@@ -2002,8 +3300,9 @@ function copyTemplateDir(srcDir, destDir, projectName, force, onFile, relativePa
|
|
|
2002
3300
|
mkdirSync(destPath, { recursive: true });
|
|
2003
3301
|
onFile(relPath + "/", true);
|
|
2004
3302
|
}
|
|
2005
|
-
copyTemplateDir(srcPath, destPath, projectName, force, onFile, relPath);
|
|
3303
|
+
copyTemplateDir(srcPath, destPath, projectName, force, onFile, relPath, skipRelPaths);
|
|
2006
3304
|
} else {
|
|
3305
|
+
if (skipRelPaths?.has(relPath)) continue;
|
|
2007
3306
|
if (!force && existsSync(destPath)) {
|
|
2008
3307
|
onFile(relPath, false);
|
|
2009
3308
|
continue;
|
|
@@ -2019,6 +3318,91 @@ function copyTemplateDir(srcDir, destDir, projectName, force, onFile, relativePa
|
|
|
2019
3318
|
}
|
|
2020
3319
|
}
|
|
2021
3320
|
}
|
|
3321
|
+
function writeYamlInitFiles(cwd, force) {
|
|
3322
|
+
const designDir = join(cwd, "design");
|
|
3323
|
+
if (!existsSync(designDir)) {
|
|
3324
|
+
mkdirSync(designDir, { recursive: true });
|
|
3325
|
+
}
|
|
3326
|
+
const reqYaml = join(designDir, "requirements.yaml");
|
|
3327
|
+
if (force || !existsSync(reqYaml)) {
|
|
3328
|
+
writeFileSync(reqYaml, `# Requirements
|
|
3329
|
+
model: requirement
|
|
3330
|
+
specs:
|
|
3331
|
+
- id: REQ-001
|
|
3332
|
+
name: User Authentication
|
|
3333
|
+
type: functional
|
|
3334
|
+
priority: must
|
|
3335
|
+
description: Users can authenticate using email and password
|
|
3336
|
+
acceptanceCriteria:
|
|
3337
|
+
- id: REQ-001-01
|
|
3338
|
+
description: Valid credentials grant access
|
|
3339
|
+
verificationMethod: test
|
|
3340
|
+
- id: REQ-001-02
|
|
3341
|
+
description: Invalid credentials show error message
|
|
3342
|
+
verificationMethod: test
|
|
3343
|
+
`);
|
|
3344
|
+
console.log(chalk4.green(" Created: design/requirements.yaml"));
|
|
3345
|
+
}
|
|
3346
|
+
const indexTs = join(designDir, "index.ts");
|
|
3347
|
+
if (force || !existsSync(indexTs)) {
|
|
3348
|
+
writeFileSync(indexTs, `/**
|
|
3349
|
+
* Design entry point
|
|
3350
|
+
*/
|
|
3351
|
+
import { mergeSpecs, loadYamlDir } from 'speckeeper';
|
|
3352
|
+
import { allModels } from './_models/index.ts';
|
|
3353
|
+
|
|
3354
|
+
const yamlSpecs = loadYamlDir(import.meta.dirname, allModels);
|
|
3355
|
+
|
|
3356
|
+
export default mergeSpecs(...yamlSpecs);
|
|
3357
|
+
`);
|
|
3358
|
+
console.log(chalk4.green(" Created: design/index.ts (yaml mode)"));
|
|
3359
|
+
}
|
|
3360
|
+
}
|
|
3361
|
+
async function runConvert(file, options = {}) {
|
|
3362
|
+
const filePath = resolve(file);
|
|
3363
|
+
if (!existsSync(filePath)) {
|
|
3364
|
+
console.error(chalk4.red(` Error: File not found: ${filePath}`));
|
|
3365
|
+
process.exit(1);
|
|
3366
|
+
}
|
|
3367
|
+
if (!filePath.endsWith(".ts") && !filePath.endsWith(".js") && !filePath.endsWith(".mjs")) {
|
|
3368
|
+
console.error(chalk4.red(" Error: Source file must be a .ts, .js, or .mjs file"));
|
|
3369
|
+
process.exit(1);
|
|
3370
|
+
}
|
|
3371
|
+
console.log(chalk4.cyan("speckeeper convert"));
|
|
3372
|
+
console.log(chalk4.gray(` Source: ${filePath}`));
|
|
3373
|
+
console.log("");
|
|
3374
|
+
let specModule;
|
|
3375
|
+
try {
|
|
3376
|
+
const imported = await import(filePath);
|
|
3377
|
+
specModule = imported.default ?? imported;
|
|
3378
|
+
} catch (err) {
|
|
3379
|
+
console.error(chalk4.red(` Error: Failed to import ${filePath}`));
|
|
3380
|
+
console.error(chalk4.gray(` ${err instanceof Error ? err.message : String(err)}`));
|
|
3381
|
+
process.exit(1);
|
|
3382
|
+
}
|
|
3383
|
+
if (!specModule?.entries || !Array.isArray(specModule.entries)) {
|
|
3384
|
+
console.error(chalk4.red(" Error: File does not export a valid SpecModule (missing entries array)"));
|
|
3385
|
+
console.error(chalk4.gray(" The file must export a SpecModule via defineSpecs()"));
|
|
3386
|
+
process.exit(1);
|
|
3387
|
+
}
|
|
3388
|
+
const yamlData = specModule.entries.length === 1 ? { model: specModule.entries[0].model.id, specs: specModule.entries[0].data } : { entries: specModule.entries.map((e) => ({ model: e.model.id, specs: e.data })) };
|
|
3389
|
+
const yamlString = stringify(yamlData, {
|
|
3390
|
+
lineWidth: 120,
|
|
3391
|
+
defaultStringType: "PLAIN",
|
|
3392
|
+
defaultKeyType: "PLAIN"
|
|
3393
|
+
});
|
|
3394
|
+
if (options.dryRun) {
|
|
3395
|
+
console.log(chalk4.yellow(" Dry run \u2014 showing conversion result:"));
|
|
3396
|
+
console.log("");
|
|
3397
|
+
console.log(yamlString);
|
|
3398
|
+
return;
|
|
3399
|
+
}
|
|
3400
|
+
const outputPath = options.output ? resolve(options.output) : join(dirname(filePath), basename(filePath).replace(/\.(ts|js|mjs)$/, ".yaml"));
|
|
3401
|
+
writeFileSync(outputPath, yamlString);
|
|
3402
|
+
console.log(chalk4.green(` Created: ${outputPath}`));
|
|
3403
|
+
console.log("");
|
|
3404
|
+
console.log(chalk4.gray(" Remember to update design/index.ts to use loadYamlDir() for YAML files."));
|
|
3405
|
+
}
|
|
2022
3406
|
|
|
2023
3407
|
// src/scaffold/mermaid-parser.ts
|
|
2024
3408
|
function extractMermaidBlocks(markdown) {
|
|
@@ -2549,12 +3933,27 @@ function generateModelFile(node, _incomingEdges, _outgoingEdges, _allNodes) {
|
|
|
2549
3933
|
content
|
|
2550
3934
|
};
|
|
2551
3935
|
}
|
|
2552
|
-
function generateSpecDataFile(node) {
|
|
3936
|
+
function generateSpecDataFile(node, format = "ts") {
|
|
2553
3937
|
const templateInfo = resolveModelTemplate(node.id, node.classes, node.subgraph);
|
|
2554
3938
|
const className = `${templateInfo.modelName}Model`;
|
|
2555
3939
|
const typeName = templateInfo.modelName;
|
|
2556
3940
|
const varName = toCamelCase(templateInfo.modelName) + "s";
|
|
2557
3941
|
const fileName = templateInfo.fileName;
|
|
3942
|
+
if (format === "yaml") {
|
|
3943
|
+
const content2 = `# ${templateInfo.modelName} Specifications
|
|
3944
|
+
#
|
|
3945
|
+
# Generated by speckeeper scaffold \u2014 add your specs below.
|
|
3946
|
+
model: ${templateInfo.fileName}
|
|
3947
|
+
specs:
|
|
3948
|
+
# - id: ${templateInfo.defaultIdPrefix}-001
|
|
3949
|
+
# name: "..."
|
|
3950
|
+
# description: "..."
|
|
3951
|
+
`;
|
|
3952
|
+
return {
|
|
3953
|
+
relativePath: `${fileName}.yaml`,
|
|
3954
|
+
content: content2
|
|
3955
|
+
};
|
|
3956
|
+
}
|
|
2558
3957
|
const content = `/**
|
|
2559
3958
|
* ${templateInfo.modelName} Specifications
|
|
2560
3959
|
*
|
|
@@ -2580,7 +3979,7 @@ export default defineSpecs(
|
|
|
2580
3979
|
function toCamelCase(pascalCase) {
|
|
2581
3980
|
return pascalCase.charAt(0).toLowerCase() + pascalCase.slice(1);
|
|
2582
3981
|
}
|
|
2583
|
-
function generateDesignIndex(speckeeperNodes) {
|
|
3982
|
+
function generateDesignIndex(speckeeperNodes, format = "ts") {
|
|
2584
3983
|
const generated = /* @__PURE__ */ new Set();
|
|
2585
3984
|
const specFiles = [];
|
|
2586
3985
|
for (const node of speckeeperNodes) {
|
|
@@ -2594,6 +3993,21 @@ function generateDesignIndex(speckeeperNodes) {
|
|
|
2594
3993
|
fileName: templateInfo.fileName
|
|
2595
3994
|
});
|
|
2596
3995
|
}
|
|
3996
|
+
if (format === "yaml") {
|
|
3997
|
+
const content2 = `/**
|
|
3998
|
+
* Design entry point \u2014 generated by speckeeper scaffold
|
|
3999
|
+
*
|
|
4000
|
+
* YAML spec files in this directory are auto-discovered by loadYamlDir().
|
|
4001
|
+
*/
|
|
4002
|
+
import { mergeSpecs, loadYamlDir } from 'speckeeper';
|
|
4003
|
+
import { allModels } from './_models';
|
|
4004
|
+
|
|
4005
|
+
const yamlSpecs = loadYamlDir(import.meta.dirname, allModels);
|
|
4006
|
+
|
|
4007
|
+
export default mergeSpecs(...yamlSpecs);
|
|
4008
|
+
`;
|
|
4009
|
+
return { relativePath: "index.ts", content: content2 };
|
|
4010
|
+
}
|
|
2597
4011
|
const imports = specFiles.map((f) => `import ${f.varName} from './${f.fileName}';`).join("\n");
|
|
2598
4012
|
const args = specFiles.map((f) => f.varName).join(", ");
|
|
2599
4013
|
const content = `/**
|
|
@@ -2609,7 +4023,7 @@ export default mergeSpecs(${args});
|
|
|
2609
4023
|
content
|
|
2610
4024
|
};
|
|
2611
4025
|
}
|
|
2612
|
-
function generateAllModelFiles(speckeeperNodes, resolvedEdges, allNodes) {
|
|
4026
|
+
function generateAllModelFiles(speckeeperNodes, resolvedEdges, allNodes, format = "ts") {
|
|
2613
4027
|
const files = [];
|
|
2614
4028
|
const generated = /* @__PURE__ */ new Set();
|
|
2615
4029
|
const templateNodeGroups = /* @__PURE__ */ new Map();
|
|
@@ -2632,9 +4046,9 @@ function generateAllModelFiles(speckeeperNodes, resolvedEdges, allNodes) {
|
|
|
2632
4046
|
resolvedEdges.filter((e) => groupNodeIds.has(e.targetId));
|
|
2633
4047
|
resolvedEdges.filter((e) => groupNodeIds.has(e.sourceId));
|
|
2634
4048
|
files.push(generateModelFile(node));
|
|
2635
|
-
files.push(generateSpecDataFile(node));
|
|
4049
|
+
files.push(generateSpecDataFile(node, format));
|
|
2636
4050
|
}
|
|
2637
|
-
files.push(generateDesignIndex(speckeeperNodes));
|
|
4051
|
+
files.push(generateDesignIndex(speckeeperNodes, format));
|
|
2638
4052
|
return files;
|
|
2639
4053
|
}
|
|
2640
4054
|
|
|
@@ -2727,7 +4141,8 @@ async function scaffoldCommand(options) {
|
|
|
2727
4141
|
);
|
|
2728
4142
|
printDiagnostics(diagnostics);
|
|
2729
4143
|
const outputDir = options.output ? resolve(options.output) : join(process.cwd(), "design");
|
|
2730
|
-
const
|
|
4144
|
+
const specFormat = options.format ?? "ts";
|
|
4145
|
+
const modelFiles = generateAllModelFiles(speckeeperNodes, resolved, flowchart.nodes, specFormat);
|
|
2731
4146
|
const indexFile = generateModelsIndex(modelFiles);
|
|
2732
4147
|
const allFiles = [...modelFiles, indexFile];
|
|
2733
4148
|
console.log("");
|
|
@@ -3330,13 +4745,13 @@ async function commandExplainImpact(opts) {
|
|
|
3330
4745
|
}
|
|
3331
4746
|
}
|
|
3332
4747
|
function readStdin() {
|
|
3333
|
-
return new Promise((
|
|
4748
|
+
return new Promise((resolve4, reject) => {
|
|
3334
4749
|
const chunks = [];
|
|
3335
4750
|
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
3336
|
-
process.stdin.on("end", () =>
|
|
4751
|
+
process.stdin.on("end", () => resolve4(Buffer.concat(chunks).toString("utf-8")));
|
|
3337
4752
|
process.stdin.on("error", reject);
|
|
3338
4753
|
if (process.stdin.isTTY) {
|
|
3339
|
-
|
|
4754
|
+
resolve4("");
|
|
3340
4755
|
}
|
|
3341
4756
|
});
|
|
3342
4757
|
}
|
|
@@ -3386,68 +4801,78 @@ function getVersion() {
|
|
|
3386
4801
|
return "0.0.0";
|
|
3387
4802
|
}
|
|
3388
4803
|
}
|
|
3389
|
-
var
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
});
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
4804
|
+
var handlers = {
|
|
4805
|
+
init: async (opts) => {
|
|
4806
|
+
await runInit(opts);
|
|
4807
|
+
},
|
|
4808
|
+
build: async (opts) => {
|
|
4809
|
+
await buildCommand(opts);
|
|
4810
|
+
},
|
|
4811
|
+
lint: async (opts) => {
|
|
4812
|
+
await lintCommand(opts);
|
|
4813
|
+
},
|
|
4814
|
+
drift: async (opts) => {
|
|
4815
|
+
await driftCommand(opts);
|
|
4816
|
+
},
|
|
4817
|
+
check: async (type, opts) => {
|
|
4818
|
+
await checkCommand(type, opts);
|
|
4819
|
+
},
|
|
4820
|
+
new: async (type, opts) => {
|
|
4821
|
+
await newCommand({ type, output: opts.output, dryRun: opts.dryRun });
|
|
4822
|
+
},
|
|
4823
|
+
impact: async (id, opts) => {
|
|
4824
|
+
await impactCommand(id, opts);
|
|
4825
|
+
},
|
|
4826
|
+
scaffold: async (opts) => {
|
|
4827
|
+
await scaffoldCommand(opts);
|
|
4828
|
+
},
|
|
4829
|
+
convert: async (file, opts) => {
|
|
4830
|
+
await runConvert(file, opts);
|
|
4831
|
+
},
|
|
4832
|
+
auditRequirements: async (opts) => {
|
|
4833
|
+
await commandAuditRequirements({
|
|
4834
|
+
config: opts.config,
|
|
4835
|
+
adapter: opts.adapter,
|
|
4836
|
+
model: opts.model,
|
|
4837
|
+
dryRun: opts.dryRun,
|
|
4838
|
+
failOn: opts.failOn,
|
|
4839
|
+
output: opts.output,
|
|
4840
|
+
reportFormat: opts.reportFormat
|
|
4841
|
+
});
|
|
4842
|
+
},
|
|
4843
|
+
proposeTraceLinks: async (opts) => {
|
|
4844
|
+
await commandProposeTraceLinks({
|
|
4845
|
+
config: opts.config,
|
|
4846
|
+
adapter: opts.adapter,
|
|
4847
|
+
model: opts.model,
|
|
4848
|
+
dryRun: opts.dryRun,
|
|
4849
|
+
failOn: opts.failOn,
|
|
4850
|
+
output: opts.output,
|
|
4851
|
+
reportFormat: opts.reportFormat
|
|
4852
|
+
});
|
|
4853
|
+
},
|
|
4854
|
+
explainImpact: async (opts) => {
|
|
4855
|
+
await commandExplainImpact({
|
|
4856
|
+
adapter: opts.adapter,
|
|
4857
|
+
model: opts.model,
|
|
4858
|
+
dryRun: opts.dryRun,
|
|
4859
|
+
failOn: opts.failOn,
|
|
4860
|
+
output: opts.output,
|
|
4861
|
+
reportFormat: opts.reportFormat
|
|
4862
|
+
});
|
|
4863
|
+
},
|
|
4864
|
+
proposeAcceptanceCriteria: async (specIds, opts) => {
|
|
4865
|
+
await commandProposeAcceptanceCriteria(specIds, {
|
|
4866
|
+
config: opts.config,
|
|
4867
|
+
adapter: opts.adapter,
|
|
4868
|
+
model: opts.model,
|
|
4869
|
+
dryRun: opts.dryRun,
|
|
4870
|
+
failOn: opts.failOn,
|
|
4871
|
+
output: opts.output,
|
|
4872
|
+
reportFormat: opts.reportFormat
|
|
4873
|
+
});
|
|
4874
|
+
}
|
|
4875
|
+
};
|
|
4876
|
+
createProgram(handlers, getVersion()).parse();
|
|
3452
4877
|
//# sourceMappingURL=cli.js.map
|
|
3453
4878
|
//# sourceMappingURL=cli.js.map
|